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"
58 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
60 static LPWSTR
*printer_array
;
61 static int nb_printers
;
63 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
64 WORD fwCapability
, LPSTR lpszOutput
,
66 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
67 LPSTR lpszDevice
, LPSTR lpszPort
,
68 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
71 static const char Printers
[] =
72 "System\\CurrentControlSet\\control\\Print\\Printers\\";
73 static const char Drivers
[] =
74 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
76 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
78 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
79 'i','o','n',' ','F','i','l','e',0};
80 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
81 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
82 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v',
84 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F',
86 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
87 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
88 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
89 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
90 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
91 static const WCHAR NameW
[] = {'N','a','m','e',0};
92 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
93 static const WCHAR PortW
[] = {'P','o','r','t',0};
94 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e',
96 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i',
98 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i',
99 'v','e','r','D','a','t','a',0};
100 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F',
102 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
103 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
104 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
105 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
106 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
107 static const WCHAR emptyStringW
[] = {0};
109 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
111 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
);
112 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
113 DWORD Level
, LPBYTE pDriverInfo
,
114 DWORD cbBuf
, LPDWORD pcbNeeded
,
116 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
);
118 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
119 if passed a NULL string. This returns NULLs to the result.
121 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
125 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
126 return usBufferPtr
->Buffer
;
128 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
133 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
,BOOL force
) {
136 /* If forcing, or no profile string entry for device yet, set the entry
138 * The always change entry if not WINEPS yet is discussable.
141 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
143 !strstr(qbuf
,"WINEPS")
145 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS,LPR:")+1);
147 sprintf(buf
,"%s,WINEPS,LPR:%s",devname
,name
);
148 WriteProfileStringA("windows","device",buf
);
149 HeapFree(GetProcessHeap(),0,buf
);
153 #ifdef HAVE_CUPS_CUPS_H
154 static BOOL
CUPS_LoadPrinters(void)
156 typeof(cupsGetDests
) *pcupsGetDests
= NULL
;
157 typeof(cupsGetPPD
) *pcupsGetPPD
= NULL
;
159 BOOL hadprinter
= FALSE
;
161 PRINTER_INFO_2A pinfo2a
;
162 void *cupshandle
= NULL
;
164 HKEY hkeyPrinter
, hkeyPrinters
;
166 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
169 TRACE("loaded %s\n", SONAME_LIBCUPS
);
172 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
173 if (!p##x) return FALSE;
176 DYNCUPS(cupsGetDests
);
179 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
181 ERR("Can't create Printers key\n");
185 nrofdests
= pcupsGetDests(&dests
);
186 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
187 for (i
=0;i
<nrofdests
;i
++) {
188 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
189 sprintf(port
,"LPR:%s",dests
[i
].name
);
190 devline
=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port
)+1);
191 sprintf(devline
,"WINEPS,%s",port
);
192 WriteProfileStringA("devices",dests
[i
].name
,devline
);
193 HeapFree(GetProcessHeap(),0,devline
);
195 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
196 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
197 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
199 TRACE("Printer already exists\n");
200 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
201 RegCloseKey(hkeyPrinter
);
203 memset(&pinfo2a
,0,sizeof(pinfo2a
));
204 pinfo2a
.pPrinterName
= dests
[i
].name
;
205 pinfo2a
.pDatatype
= "RAW";
206 pinfo2a
.pPrintProcessor
= "WinPrint";
207 pinfo2a
.pDriverName
= "PS Driver";
208 pinfo2a
.pComment
= "WINEPS Printer using CUPS";
209 pinfo2a
.pLocation
= "<physical location of printer>";
210 pinfo2a
.pPortName
= port
;
211 pinfo2a
.pParameters
= "<parameters?>";
212 pinfo2a
.pShareName
= "<share name?>";
213 pinfo2a
.pSepFile
= "<sep file?>";
215 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
216 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
217 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests
[i
].name
,GetLastError());
220 HeapFree(GetProcessHeap(),0,port
);
223 if (dests
[i
].is_default
)
224 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
226 RegCloseKey(hkeyPrinters
);
227 wine_dlclose(cupshandle
, NULL
, 0);
233 PRINTCAP_ParseEntry(char *pent
,BOOL isfirst
) {
234 PRINTER_INFO_2A pinfo2a
;
235 char *e
,*s
,*name
,*prettyname
,*devname
;
236 BOOL ret
= FALSE
, set_default
= FALSE
;
237 char *port
,*devline
,*env_default
;
238 HKEY hkeyPrinter
, hkeyPrinters
;
240 while (isspace(*pent
)) pent
++;
241 s
= strchr(pent
,':');
243 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
251 TRACE("name=%s entry=%s\n",name
, pent
);
253 if(ispunct(*name
)) { /* a tc entry, not a real printer */
254 TRACE("skipping tc entry\n");
258 if(strstr(pent
,":server")) { /* server only version so skip */
259 TRACE("skipping server entry\n");
263 /* Determine whether this is a postscript printer. */
266 env_default
= getenv("PRINTER");
268 /* Get longest name, usually the one at the right for later display. */
269 while((s
=strchr(prettyname
,'|'))) {
272 while(isspace(*--e
)) *e
= '\0';
273 TRACE("\t%s\n", debugstr_a(prettyname
));
274 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
275 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
278 e
= prettyname
+ strlen(prettyname
);
279 while(isspace(*--e
)) *e
= '\0';
280 TRACE("\t%s\n", debugstr_a(prettyname
));
281 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
283 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
284 * if it is too long, we use it as comment below. */
285 devname
= prettyname
;
286 if (strlen(devname
)>=CCHDEVICENAME
-1)
288 if (strlen(devname
)>=CCHDEVICENAME
-1) {
293 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
294 sprintf(port
,"LPR:%s",name
);
296 devline
=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port
)+1);
297 sprintf(devline
,"WINEPS,%s",port
);
298 WriteProfileStringA("devices",devname
,devline
);
299 HeapFree(GetProcessHeap(),0,devline
);
301 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
303 ERR("Can't create Printers key\n");
307 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
308 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
310 TRACE("Printer already exists\n");
311 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
312 RegCloseKey(hkeyPrinter
);
314 memset(&pinfo2a
,0,sizeof(pinfo2a
));
315 pinfo2a
.pPrinterName
= devname
;
316 pinfo2a
.pDatatype
= "RAW";
317 pinfo2a
.pPrintProcessor
= "WinPrint";
318 pinfo2a
.pDriverName
= "PS Driver";
319 pinfo2a
.pComment
= "WINEPS Printer using LPR";
320 pinfo2a
.pLocation
= prettyname
;
321 pinfo2a
.pPortName
= port
;
322 pinfo2a
.pParameters
= "<parameters?>";
323 pinfo2a
.pShareName
= "<share name?>";
324 pinfo2a
.pSepFile
= "<sep file?>";
326 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
327 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
328 ERR("%s not added by AddPrinterA (%ld)\n",name
,GetLastError());
331 RegCloseKey(hkeyPrinters
);
333 if (isfirst
|| set_default
)
334 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
336 HeapFree(GetProcessHeap(), 0, port
);
338 HeapFree(GetProcessHeap(), 0, name
);
343 PRINTCAP_LoadPrinters(void) {
344 BOOL hadprinter
= FALSE
;
348 BOOL had_bash
= FALSE
;
350 f
= fopen("/etc/printcap","r");
354 while(fgets(buf
,sizeof(buf
),f
)) {
357 end
=strchr(buf
,'\n');
361 while(isspace(*start
)) start
++;
362 if(*start
== '#' || *start
== '\0')
365 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
366 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
367 HeapFree(GetProcessHeap(),0,pent
);
371 if (end
&& *--end
== '\\') {
378 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
381 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
387 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
388 HeapFree(GetProcessHeap(),0,pent
);
394 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
397 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (LPBYTE
)value
,
398 lstrlenW(value
) * sizeof(WCHAR
));
400 return ERROR_FILE_NOT_FOUND
;
403 void WINSPOOL_LoadSystemPrinters(void)
405 HKEY hkey
, hkeyPrinters
;
408 DWORD needed
, num
, i
;
409 WCHAR PrinterName
[256];
412 di3a
.cVersion
= 0x400;
413 di3a
.pName
= "PS Driver";
414 di3a
.pEnvironment
= NULL
; /* NULL means auto */
415 di3a
.pDriverPath
= "wineps16";
416 di3a
.pDataFile
= "<datafile?>";
417 di3a
.pConfigFile
= "wineps16";
418 di3a
.pHelpFile
= "<helpfile?>";
419 di3a
.pDependentFiles
= "<dependend files?>";
420 di3a
.pMonitorName
= "<monitor name?>";
421 di3a
.pDefaultDataType
= "RAW";
423 if (!AddPrinterDriverA(NULL
,3,(LPBYTE
)&di3a
)) {
424 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
428 /* This ensures that all printer entries have a valid Name value. If causes
429 problems later if they don't. If one is found to be missed we create one
430 and set it equal to the name of the key */
431 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
432 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
433 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
434 for(i
= 0; i
< num
; i
++) {
435 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
436 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
437 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
438 set_reg_szW(hkey
, NameW
, PrinterName
);
445 RegCloseKey(hkeyPrinters
);
448 /* We want to avoid calling AddPrinter on printers as much as
449 possible, because on cups printers this will (eventually) lead
450 to a call to cupsGetPPD which takes forever, even with non-cups
451 printers AddPrinter takes a while. So we'll tag all printers that
452 were automatically added last time around, if they still exist
453 we'll leave them be otherwise we'll delete them. */
454 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
456 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
457 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
458 for(i
= 0; i
< num
; i
++) {
459 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
460 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
461 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
463 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
471 HeapFree(GetProcessHeap(), 0, pi
);
475 #ifdef HAVE_CUPS_CUPS_H
476 done
= CUPS_LoadPrinters();
479 if(!done
) { /* If we have any CUPS based printers, skip looking for printcap printers */
480 /* Check for [ppd] section in config file before parsing /etc/printcap */
481 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\ppd",
482 &hkey
) == ERROR_SUCCESS
) {
484 PRINTCAP_LoadPrinters();
488 /* Now enumerate the list again and delete any printers that a still tagged */
489 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
491 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
492 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
493 for(i
= 0; i
< num
; i
++) {
494 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
495 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
496 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
497 DWORD dw
, type
, size
= sizeof(dw
);
498 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
499 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
509 HeapFree(GetProcessHeap(), 0, pi
);
517 /******************************************************************
518 * WINSPOOL_GetOpenedPrinterEntry
519 * Get the first place empty in the opened printer table
521 static HANDLE
WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name
)
525 for (i
= 0; i
< nb_printers
; i
++) if (!printer_array
[i
]) break;
527 if (i
>= nb_printers
)
531 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_array
,
532 (nb_printers
+ 16) * sizeof(*new_array
) );
534 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
535 (nb_printers
+ 16) * sizeof(*new_array
) );
537 if (!new_array
) return 0;
538 printer_array
= new_array
;
542 if ((printer_array
[i
] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name
)+1)*sizeof(WCHAR
) )))
544 strcpyW( printer_array
[i
], name
);
545 return (HANDLE
)(i
+ 1);
550 /******************************************************************
551 * WINSPOOL_GetOpenedPrinter
552 * Get the pointer to the opened printer referred by the handle
554 static LPCWSTR
WINSPOOL_GetOpenedPrinter(HANDLE printerHandle
)
556 int idx
= (int)printerHandle
;
557 if ((idx
<= 0) || (idx
> nb_printers
))
559 SetLastError(ERROR_INVALID_HANDLE
);
562 return printer_array
[idx
- 1];
565 /******************************************************************
566 * WINSPOOL_GetOpenedPrinterRegKey
569 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
571 LPCWSTR name
= WINSPOOL_GetOpenedPrinter(hPrinter
);
575 if(!name
) return ERROR_INVALID_HANDLE
;
577 if((ret
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
)) !=
581 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
583 ERR("Can't find opened printer %s in registry\n",
585 RegCloseKey(hkeyPrinters
);
586 return ERROR_INVALID_PRINTER_NAME
; /* ? */
588 RegCloseKey(hkeyPrinters
);
589 return ERROR_SUCCESS
;
592 /***********************************************************
595 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
598 ptrdiff_t off_formname
= (char *)dmA
->dmFormName
- (char *)dmA
;
601 Formname
= (dmA
->dmSize
> off_formname
);
602 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
603 MultiByteToWideChar(CP_ACP
, 0, dmA
->dmDeviceName
, -1, dmW
->dmDeviceName
,
606 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
607 dmA
->dmSize
- CCHDEVICENAME
);
609 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
610 off_formname
- CCHDEVICENAME
);
611 MultiByteToWideChar(CP_ACP
, 0, dmA
->dmFormName
, -1, dmW
->dmFormName
,
613 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
614 (off_formname
+ CCHFORMNAME
));
617 memcpy((char *)dmW
+ dmW
->dmSize
, (char *)dmA
+ dmA
->dmSize
,
622 /***********************************************************
624 * Creates an ascii copy of supplied devmode on heap
626 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
631 ptrdiff_t off_formname
= (char *)dmW
->dmFormName
- (char *)dmW
;
633 if(!dmW
) return NULL
;
634 Formname
= (dmW
->dmSize
> off_formname
);
635 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
636 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
637 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1, dmA
->dmDeviceName
,
638 CCHDEVICENAME
, NULL
, NULL
);
640 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
641 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
643 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
644 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
645 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1, dmA
->dmFormName
,
646 CCHFORMNAME
, NULL
, NULL
);
647 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
648 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
651 memcpy((char *)dmA
+ dmA
->dmSize
, (char *)dmW
+ dmW
->dmSize
,
656 /***********************************************************
658 * Creates a unicode copy of PRINTER_INFO_2A on heap
660 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
662 LPPRINTER_INFO_2W piW
;
663 UNICODE_STRING usBuffer
;
665 if(!piA
) return NULL
;
666 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
667 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
669 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
670 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
671 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
672 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
673 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
674 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
675 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
676 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
677 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
678 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
679 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
680 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
684 /***********************************************************
685 * FREE_PRINTER_INFO_2W
686 * Free PRINTER_INFO_2W and all strings
688 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
692 HeapFree(heap
,0,piW
->pServerName
);
693 HeapFree(heap
,0,piW
->pPrinterName
);
694 HeapFree(heap
,0,piW
->pShareName
);
695 HeapFree(heap
,0,piW
->pPortName
);
696 HeapFree(heap
,0,piW
->pDriverName
);
697 HeapFree(heap
,0,piW
->pComment
);
698 HeapFree(heap
,0,piW
->pLocation
);
699 HeapFree(heap
,0,piW
->pDevMode
);
700 HeapFree(heap
,0,piW
->pSepFile
);
701 HeapFree(heap
,0,piW
->pPrintProcessor
);
702 HeapFree(heap
,0,piW
->pDatatype
);
703 HeapFree(heap
,0,piW
->pParameters
);
704 HeapFree(heap
,0,piW
);
708 /******************************************************************
709 * DeviceCapabilities [WINSPOOL.@]
710 * DeviceCapabilitiesA [WINSPOOL.@]
713 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
714 LPSTR pOutput
, LPDEVMODEA lpdm
)
718 if (!GDI_CallDeviceCapabilities16
)
720 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
722 if (!GDI_CallDeviceCapabilities16
) return -1;
724 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
726 /* If DC_PAPERSIZE map POINT16s to POINTs */
727 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
728 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
729 POINT
*pt
= (POINT
*)pOutput
;
731 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
732 for(i
= 0; i
< ret
; i
++, pt
++)
737 HeapFree( GetProcessHeap(), 0, tmp
);
743 /*****************************************************************************
744 * DeviceCapabilitiesW [WINSPOOL.@]
746 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
749 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
750 WORD fwCapability
, LPWSTR pOutput
,
751 const DEVMODEW
*pDevMode
)
753 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
754 LPSTR pDeviceA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDevice
);
755 LPSTR pPortA
= HEAP_strdupWtoA(GetProcessHeap(),0,pPort
);
758 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
759 fwCapability
== DC_FILEDEPENDENCIES
||
760 fwCapability
== DC_PAPERNAMES
)) {
761 /* These need A -> W translation */
764 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
768 switch(fwCapability
) {
773 case DC_FILEDEPENDENCIES
:
777 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
778 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
780 for(i
= 0; i
< ret
; i
++)
781 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
782 pOutput
+ (i
* size
), size
);
783 HeapFree(GetProcessHeap(), 0, pOutputA
);
785 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
786 (LPSTR
)pOutput
, dmA
);
788 HeapFree(GetProcessHeap(),0,pPortA
);
789 HeapFree(GetProcessHeap(),0,pDeviceA
);
790 HeapFree(GetProcessHeap(),0,dmA
);
794 /******************************************************************
795 * DocumentPropertiesA [WINSPOOL.@]
797 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
799 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
800 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
801 LPDEVMODEA pDevModeInput
,DWORD fMode
)
803 LPSTR lpName
= pDeviceName
;
806 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
807 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
811 LPCWSTR lpNameW
= WINSPOOL_GetOpenedPrinter(hPrinter
);
813 ERR("no name from hPrinter?\n");
816 lpName
= HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW
);
819 if (!GDI_CallExtDeviceMode16
)
821 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
823 if (!GDI_CallExtDeviceMode16
) {
824 ERR("No CallExtDeviceMode16?\n");
828 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, "LPT1:",
829 pDevModeInput
, NULL
, fMode
);
832 HeapFree(GetProcessHeap(),0,lpName
);
837 /*****************************************************************************
838 * DocumentPropertiesW (WINSPOOL.@)
840 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
842 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
844 LPDEVMODEW pDevModeOutput
,
845 LPDEVMODEW pDevModeInput
, DWORD fMode
)
848 LPSTR pDeviceNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName
);
849 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
850 LPDEVMODEA pDevModeOutputA
= NULL
;
853 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
854 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
857 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
858 if(ret
< 0) return ret
;
859 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
861 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
862 pDevModeInputA
, fMode
);
864 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
865 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
867 if(fMode
== 0 && ret
> 0)
868 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
869 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
870 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
874 /******************************************************************
875 * OpenPrinterA [WINSPOOL.@]
878 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
879 LPPRINTER_DEFAULTSA pDefault
)
881 UNICODE_STRING lpPrinterNameW
;
882 UNICODE_STRING usBuffer
;
883 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
884 PWSTR pwstrPrinterNameW
;
887 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
890 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
891 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
892 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
893 pDefaultW
= &DefaultW
;
895 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
897 RtlFreeUnicodeString(&usBuffer
);
898 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
900 RtlFreeUnicodeString(&lpPrinterNameW
);
904 /******************************************************************
905 * OpenPrinterW [WINSPOOL.@]
908 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
,
909 LPPRINTER_DEFAULTSW pDefault
)
911 HKEY hkeyPrinters
, hkeyPrinter
;
913 if (!lpPrinterName
) {
914 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault
);
915 SetLastError(ERROR_INVALID_PARAMETER
);
919 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName
),
922 /* Check Printer exists */
923 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
925 ERR("Can't create Printers key\n");
926 SetLastError(ERROR_FILE_NOT_FOUND
); /* ?? */
930 if(lpPrinterName
[0] == '\0' || /* explicitly exclude "" */
931 RegOpenKeyW(hkeyPrinters
, lpPrinterName
, &hkeyPrinter
)
933 TRACE("Can't find printer %s in registry\n",
934 debugstr_w(lpPrinterName
));
935 RegCloseKey(hkeyPrinters
);
936 SetLastError(ERROR_INVALID_PRINTER_NAME
);
939 RegCloseKey(hkeyPrinter
);
940 RegCloseKey(hkeyPrinters
);
942 if(!phPrinter
) /* This seems to be what win95 does anyway */
945 /* Get the unique handle of the printer*/
946 *phPrinter
= WINSPOOL_GetOpenedPrinterEntry( lpPrinterName
);
948 if (pDefault
!= NULL
)
949 FIXME("Not handling pDefault\n");
954 /******************************************************************
955 * AddMonitorA [WINSPOOL.@]
958 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
960 FIXME("(%s,%lx,%p):stub!\n", pName
, Level
, pMonitors
);
961 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
965 /******************************************************************
966 * DeletePrinterDriverA [WINSPOOL.@]
970 DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
972 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
973 debugstr_a(pDriverName
));
974 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
979 /******************************************************************
980 * DeleteMonitorA [WINSPOOL.@]
984 DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
986 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
987 debugstr_a(pMonitorName
));
988 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
993 /******************************************************************
994 * DeletePortA [WINSPOOL.@]
998 DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
1000 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName
),hWnd
,
1001 debugstr_a(pPortName
));
1002 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1006 /******************************************************************************
1007 * SetPrinterW [WINSPOOL.@]
1017 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1021 /******************************************************************************
1022 * WritePrinter [WINSPOOL.@]
1029 LPDWORD pcWritten
) {
1032 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1036 /*****************************************************************************
1037 * AddFormA [WINSPOOL.@]
1039 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1041 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1045 /*****************************************************************************
1046 * AddFormW [WINSPOOL.@]
1048 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1050 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1054 /*****************************************************************************
1055 * AddJobA [WINSPOOL.@]
1057 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
,
1058 DWORD cbBuf
, LPDWORD pcbNeeded
)
1060 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter
, Level
, pData
, cbBuf
,
1065 /*****************************************************************************
1066 * AddJobW [WINSPOOL.@]
1068 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
,
1071 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter
, Level
, pData
, cbBuf
,
1076 /*****************************************************************************
1077 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1079 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
1080 DWORD level
, LPBYTE Info
,
1081 DWORD cbBuf
, LPDWORD needed
)
1083 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", server
, env
, level
, Info
, cbBuf
);
1087 /*****************************************************************************
1088 * WINSPOOL_OpenDriverReg [internal]
1090 * opens the registry for the printer drivers depending on the given input
1091 * variable pEnvironment
1094 * the opened hkey on success
1097 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
)
1099 LPSTR lpKey
, p
= NULL
;
1102 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
));
1105 p
= (unicode
) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment
) :
1109 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1111 if(!GetVersionExA( &ver
))
1114 switch (ver
.dwPlatformId
) {
1115 case VER_PLATFORM_WIN32s
:
1116 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1119 case VER_PLATFORM_WIN32_NT
:
1120 p
= "Windows NT x86";
1126 TRACE("set environment to %s\n", p
);
1129 lpKey
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1130 strlen(p
) + strlen(Drivers
));
1131 sprintf( lpKey
, Drivers
, p
);
1133 TRACE("%s\n", lpKey
);
1135 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, lpKey
, &retval
) !=
1139 if(pEnvironment
&& unicode
)
1140 HeapFree( GetProcessHeap(), 0, p
);
1141 HeapFree( GetProcessHeap(), 0, lpKey
);
1146 /*****************************************************************************
1147 * AddPrinterW [WINSPOOL.@]
1149 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1151 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
1155 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
1158 TRACE("(%s,%ld,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
1161 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
1162 SetLastError(ERROR_INVALID_PARAMETER
);
1166 ERR("Level = %ld, unsupported!\n", Level
);
1167 SetLastError(ERROR_INVALID_LEVEL
);
1170 if (strlenW(pi
->pPrinterName
) >= CCHDEVICENAME
) {
1171 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1172 debugstr_w(pi
->pPrinterName
)
1174 SetLastError(ERROR_INVALID_LEVEL
);
1178 SetLastError(ERROR_INVALID_PARAMETER
);
1181 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1183 ERR("Can't create Printers key\n");
1186 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
1187 if (!RegQueryValueA(hkeyPrinter
,"Attributes",NULL
,NULL
)) {
1188 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
1189 RegCloseKey(hkeyPrinter
);
1190 RegCloseKey(hkeyPrinters
);
1193 RegCloseKey(hkeyPrinter
);
1195 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
1197 ERR("Can't create Drivers key\n");
1198 RegCloseKey(hkeyPrinters
);
1201 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
1203 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
1204 RegCloseKey(hkeyPrinters
);
1205 RegCloseKey(hkeyDrivers
);
1206 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
1209 RegCloseKey(hkeyDriver
);
1210 RegCloseKey(hkeyDrivers
);
1212 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
1213 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
1214 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
1215 RegCloseKey(hkeyPrinters
);
1219 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
1221 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
1222 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1223 RegCloseKey(hkeyPrinters
);
1226 RegSetValueExA(hkeyPrinter
, "Attributes", 0, REG_DWORD
,
1227 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
1228 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
1230 /* See if we can load the driver. We may need the devmode structure anyway
1233 * Note that DocumentPropertiesW will briefly try to open the printer we
1234 * just create to find a DEVMODEA struct (it will use the WINEPS default
1235 * one in case it is not there, so we are ok).
1237 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
1240 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi
->pPrinterName
));
1241 size
= sizeof(DEVMODEW
);
1247 dmW
= HeapAlloc(GetProcessHeap(), 0, size
);
1248 ZeroMemory(dmW
,size
);
1250 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
1252 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi
->pPrinterName
));
1253 HeapFree(GetProcessHeap(),0,dmW
);
1258 /* set devmode to printer name */
1259 strcpyW(dmW
->dmDeviceName
,pi
->pPrinterName
);
1263 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1264 and we support these drivers. NT writes DEVMODEW so somehow
1265 we'll need to distinguish between these when we support NT
1269 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
1270 RegSetValueExA(hkeyPrinter
, "Default DevMode", 0, REG_BINARY
,
1271 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1272 HeapFree(GetProcessHeap(), 0, dmA
);
1274 HeapFree(GetProcessHeap(), 0, dmW
);
1276 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
1277 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
1278 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
1279 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
1281 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
1282 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
1283 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
1284 RegSetValueExA(hkeyPrinter
, "Priority", 0, REG_DWORD
,
1285 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
1286 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
1287 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
1288 RegSetValueExA(hkeyPrinter
, "StartTime", 0, REG_DWORD
,
1289 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
1290 RegSetValueExA(hkeyPrinter
, "Status", 0, REG_DWORD
,
1291 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
1292 RegSetValueExA(hkeyPrinter
, "UntilTime", 0, REG_DWORD
,
1293 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
1295 RegCloseKey(hkeyPrinter
);
1296 RegCloseKey(hkeyPrinters
);
1297 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
1298 ERR("OpenPrinter failing\n");
1304 /*****************************************************************************
1305 * AddPrinterA [WINSPOOL.@]
1307 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1309 UNICODE_STRING pNameW
;
1311 PRINTER_INFO_2W
*piW
;
1312 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
1315 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
1317 ERR("Level = %ld, unsupported!\n", Level
);
1318 SetLastError(ERROR_INVALID_LEVEL
);
1321 pwstrNameW
= asciitounicode(&pNameW
,pName
);
1322 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
1324 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
1326 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
1327 RtlFreeUnicodeString(&pNameW
);
1332 /*****************************************************************************
1333 * ClosePrinter [WINSPOOL.@]
1335 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
1337 int i
= (int)hPrinter
;
1339 TRACE("Handle %p\n", hPrinter
);
1341 if ((i
<= 0) || (i
> nb_printers
)) return FALSE
;
1342 HeapFree( GetProcessHeap(), 0, printer_array
[i
- 1] );
1343 printer_array
[i
- 1] = NULL
;
1347 /*****************************************************************************
1348 * DeleteFormA [WINSPOOL.@]
1350 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
1352 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
1356 /*****************************************************************************
1357 * DeleteFormW [WINSPOOL.@]
1359 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
1361 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
1365 /*****************************************************************************
1366 * WINSPOOL_SHRegDeleteKey
1368 * Recursively delete subkeys.
1369 * Cut & paste from shlwapi.
1372 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
)
1374 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1375 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1378 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1381 /* Find how many subkeys there are */
1382 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1383 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1387 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1388 /* Name too big: alloc a buffer for it */
1389 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
1392 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1395 /* Recursively delete all the subkeys */
1396 for(i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1398 dwSize
= dwMaxSubkeyLen
;
1399 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1401 dwRet
= WINSPOOL_SHDeleteKeyW(hSubKey
, lpszName
);
1404 if (lpszName
!= szNameBuf
)
1405 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
1409 RegCloseKey(hSubKey
);
1411 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1416 /*****************************************************************************
1417 * DeletePrinter [WINSPOOL.@]
1419 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
1421 LPCWSTR lpNameW
= WINSPOOL_GetOpenedPrinter(hPrinter
);
1424 if(!lpNameW
) return FALSE
;
1425 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1426 WINSPOOL_SHDeleteKeyW(hkeyPrinters
, lpNameW
);
1427 RegCloseKey(hkeyPrinters
);
1429 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
1433 /*****************************************************************************
1434 * SetPrinterA [WINSPOOL.@]
1436 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
1439 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter
,Level
,pPrinter
,Command
);
1443 /*****************************************************************************
1444 * SetJobA [WINSPOOL.@]
1446 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1447 LPBYTE pJob
, DWORD Command
)
1449 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter
,JobId
,Level
,pJob
,
1454 /*****************************************************************************
1455 * SetJobW [WINSPOOL.@]
1457 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1458 LPBYTE pJob
, DWORD Command
)
1460 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter
,JobId
,Level
,pJob
,
1465 /*****************************************************************************
1466 * EndDocPrinter [WINSPOOL.@]
1468 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
1470 FIXME("(hPrinter=%p): stub\n", hPrinter
);
1474 /*****************************************************************************
1475 * EndPagePrinter [WINSPOOL.@]
1477 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
1479 FIXME("(hPrinter=%p): stub\n", hPrinter
);
1483 /*****************************************************************************
1484 * StartDocPrinterA [WINSPOOL.@]
1486 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
1488 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter
, Level
, pDocInfo
);
1492 /*****************************************************************************
1493 * StartDocPrinterW [WINSPOOL.@]
1495 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
1497 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter
, Level
, pDocInfo
);
1501 /*****************************************************************************
1502 * StartPagePrinter [WINSPOOL.@]
1504 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
1506 FIXME("(hPrinter=%p): stub\n", hPrinter
);
1510 /*****************************************************************************
1511 * GetFormA [WINSPOOL.@]
1513 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
1514 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1516 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,pFormName
,
1517 Level
,pForm
,cbBuf
,pcbNeeded
);
1521 /*****************************************************************************
1522 * GetFormW [WINSPOOL.@]
1524 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
1525 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1527 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,
1528 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
1532 /*****************************************************************************
1533 * SetFormA [WINSPOOL.@]
1535 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
1538 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
1542 /*****************************************************************************
1543 * SetFormW [WINSPOOL.@]
1545 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
1548 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
1552 /*****************************************************************************
1553 * ReadPrinter [WINSPOOL.@]
1555 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
1556 LPDWORD pNoBytesRead
)
1558 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
1562 /*****************************************************************************
1563 * ResetPrinterA [WINSPOOL.@]
1565 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
1567 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
1571 /*****************************************************************************
1572 * ResetPrinterW [WINSPOOL.@]
1574 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1576 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
1580 /*****************************************************************************
1581 * WINSPOOL_GetDWORDFromReg
1583 * Return DWORD associated with ValueName from hkey.
1585 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
1587 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
1590 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
1592 if(ret
!= ERROR_SUCCESS
) {
1593 WARN("Got ret = %ld on name %s\n", ret
, ValueName
);
1596 if(type
!= REG_DWORD
) {
1597 ERR("Got type %ld\n", type
);
1603 /*****************************************************************************
1604 * WINSPOOL_GetStringFromReg
1606 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1607 * String is stored either as unicode or ascii.
1608 * Bit of a hack here to get the ValueName if we want ascii.
1610 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
1611 DWORD buflen
, DWORD
*needed
,
1614 DWORD sz
= buflen
, type
;
1618 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
1620 LPSTR ValueNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,ValueName
);
1621 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
1622 HeapFree(GetProcessHeap(),0,ValueNameA
);
1624 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
1625 WARN("Got ret = %ld\n", ret
);
1633 /*****************************************************************************
1634 * WINSPOOL_GetDefaultDevMode
1636 * Get a default DevMode values for wineps.
1640 static void WINSPOOL_GetDefaultDevMode(
1642 DWORD buflen
, DWORD
*needed
,
1647 /* fill default DEVMODE - should be read from ppd... */
1648 ZeroMemory( &dm
, sizeof(dm
) );
1649 strcpy(dm
.dmDeviceName
,"wineps");
1650 dm
.dmSpecVersion
= DM_SPECVERSION
;
1651 dm
.dmDriverVersion
= 1;
1652 dm
.dmSize
= sizeof(DEVMODEA
);
1653 dm
.dmDriverExtra
= 0;
1655 DM_ORIENTATION
| DM_PAPERSIZE
|
1656 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
1659 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
1660 DM_YRESOLUTION
| DM_TTOPTION
;
1662 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
1663 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
1664 dm
.u1
.s1
.dmPaperLength
= 2970;
1665 dm
.u1
.s1
.dmPaperWidth
= 2100;
1669 dm
.dmDefaultSource
= DMBIN_AUTO
;
1670 dm
.dmPrintQuality
= DMRES_MEDIUM
;
1673 dm
.dmYResolution
= 300; /* 300dpi */
1674 dm
.dmTTOption
= DMTT_BITMAP
;
1677 /* dm.dmLogPixels */
1678 /* dm.dmBitsPerPel */
1679 /* dm.dmPelsWidth */
1680 /* dm.dmPelsHeight */
1681 /* dm.dmDisplayFlags */
1682 /* dm.dmDisplayFrequency */
1683 /* dm.dmICMMethod */
1684 /* dm.dmICMIntent */
1685 /* dm.dmMediaType */
1686 /* dm.dmDitherType */
1687 /* dm.dmReserved1 */
1688 /* dm.dmReserved2 */
1689 /* dm.dmPanningWidth */
1690 /* dm.dmPanningHeight */
1693 if(buflen
>= sizeof(DEVMODEW
)) {
1694 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
1695 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
1696 HeapFree(GetProcessHeap(),0,pdmW
);
1698 *needed
= sizeof(DEVMODEW
);
1702 if(buflen
>= sizeof(DEVMODEA
)) {
1703 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
1705 *needed
= sizeof(DEVMODEA
);
1709 /*****************************************************************************
1710 * WINSPOOL_GetDevModeFromReg
1712 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1713 * DevMode is stored either as unicode or ascii.
1715 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
1717 DWORD buflen
, DWORD
*needed
,
1720 DWORD sz
= buflen
, type
;
1723 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
1724 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
1725 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
1726 if (sz
< sizeof(DEVMODEA
))
1728 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName
),sz
);
1731 /* ensures that dmSize is not erratically bogus if registry is invalid */
1732 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
1733 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
1735 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1737 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
1738 memcpy(ptr
, dmW
, sz
);
1739 HeapFree(GetProcessHeap(),0,dmW
);
1746 /*********************************************************************
1747 * WINSPOOL_GetPrinter_2
1749 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1750 * The strings are either stored as unicode or ascii.
1752 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
1753 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
1756 DWORD size
, left
= cbBuf
;
1757 BOOL space
= (cbBuf
> 0);
1762 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
1764 if(space
&& size
<= left
) {
1765 pi2
->pPrinterName
= (LPWSTR
)ptr
;
1772 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
1774 if(space
&& size
<= left
) {
1775 pi2
->pShareName
= (LPWSTR
)ptr
;
1782 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
1784 if(space
&& size
<= left
) {
1785 pi2
->pPortName
= (LPWSTR
)ptr
;
1792 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
1794 if(space
&& size
<= left
) {
1795 pi2
->pDriverName
= (LPWSTR
)ptr
;
1802 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
1804 if(space
&& size
<= left
) {
1805 pi2
->pComment
= (LPWSTR
)ptr
;
1812 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
1814 if(space
&& size
<= left
) {
1815 pi2
->pLocation
= (LPWSTR
)ptr
;
1822 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
1824 if(space
&& size
<= left
) {
1825 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
1834 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
1835 if(space
&& size
<= left
) {
1836 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
1843 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
1845 if(space
&& size
<= left
) {
1846 pi2
->pSepFile
= (LPWSTR
)ptr
;
1853 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
1855 if(space
&& size
<= left
) {
1856 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
1863 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
1865 if(space
&& size
<= left
) {
1866 pi2
->pDatatype
= (LPWSTR
)ptr
;
1873 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
1875 if(space
&& size
<= left
) {
1876 pi2
->pParameters
= (LPWSTR
)ptr
;
1884 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
1885 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
1886 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
1887 "Default Priority");
1888 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
1889 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
1892 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
1893 memset(pi2
, 0, sizeof(*pi2
));
1898 /*********************************************************************
1899 * WINSPOOL_GetPrinter_4
1901 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1903 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
1904 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
1907 DWORD size
, left
= cbBuf
;
1908 BOOL space
= (cbBuf
> 0);
1913 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
1915 if(space
&& size
<= left
) {
1916 pi4
->pPrinterName
= (LPWSTR
)ptr
;
1924 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
1927 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
1928 memset(pi4
, 0, sizeof(*pi4
));
1933 /*********************************************************************
1934 * WINSPOOL_GetPrinter_5
1936 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1938 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
1939 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
1942 DWORD size
, left
= cbBuf
;
1943 BOOL space
= (cbBuf
> 0);
1948 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
1950 if(space
&& size
<= left
) {
1951 pi5
->pPrinterName
= (LPWSTR
)ptr
;
1958 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
1960 if(space
&& size
<= left
) {
1961 pi5
->pPortName
= (LPWSTR
)ptr
;
1969 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
1970 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
1972 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
1976 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
1977 memset(pi5
, 0, sizeof(*pi5
));
1982 /*****************************************************************************
1983 * WINSPOOL_GetPrinter
1985 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1986 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1987 * just a collection of pointers to strings.
1989 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
1990 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
1993 DWORD size
, needed
= 0;
1995 HKEY hkeyPrinter
, hkeyPrinters
;
1998 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
2000 if (!(name
= WINSPOOL_GetOpenedPrinter(hPrinter
))) return FALSE
;
2002 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2004 ERR("Can't create Printers key\n");
2007 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
2009 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
2010 RegCloseKey(hkeyPrinters
);
2011 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
2018 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
2020 size
= sizeof(PRINTER_INFO_2W
);
2022 ptr
= pPrinter
+ size
;
2024 memset(pPrinter
, 0, size
);
2029 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
2037 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
2039 size
= sizeof(PRINTER_INFO_4W
);
2041 ptr
= pPrinter
+ size
;
2043 memset(pPrinter
, 0, size
);
2048 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
2057 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
2059 size
= sizeof(PRINTER_INFO_5W
);
2061 ptr
= pPrinter
+ size
;
2063 memset(pPrinter
, 0, size
);
2069 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
2076 FIXME("Unimplemented level %ld\n", Level
);
2077 SetLastError(ERROR_INVALID_LEVEL
);
2078 RegCloseKey(hkeyPrinters
);
2079 RegCloseKey(hkeyPrinter
);
2083 RegCloseKey(hkeyPrinter
);
2084 RegCloseKey(hkeyPrinters
);
2086 TRACE("returning %d needed = %ld\n", ret
, needed
);
2087 if(pcbNeeded
) *pcbNeeded
= needed
;
2089 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2093 /*****************************************************************************
2094 * GetPrinterW [WINSPOOL.@]
2096 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2097 DWORD cbBuf
, LPDWORD pcbNeeded
)
2099 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2103 /*****************************************************************************
2104 * GetPrinterA [WINSPOOL.@]
2106 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2107 DWORD cbBuf
, LPDWORD pcbNeeded
)
2109 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2113 /*****************************************************************************
2114 * WINSPOOL_EnumPrinters
2116 * Implementation of EnumPrintersA|W
2118 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
2119 DWORD dwLevel
, LPBYTE lpbPrinters
,
2120 DWORD cbBuf
, LPDWORD lpdwNeeded
,
2121 LPDWORD lpdwReturned
, BOOL unicode
)
2124 HKEY hkeyPrinters
, hkeyPrinter
;
2125 WCHAR PrinterName
[255];
2126 DWORD needed
= 0, number
= 0;
2127 DWORD used
, i
, left
;
2131 memset(lpbPrinters
, 0, cbBuf
);
2137 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2138 if(dwType
== PRINTER_ENUM_DEFAULT
)
2141 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
2142 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2143 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
2144 if(!dwType
) return TRUE
;
2147 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
2148 FIXME("dwType = %08lx\n", dwType
);
2149 SetLastError(ERROR_INVALID_FLAGS
);
2153 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2155 ERR("Can't create Printers key\n");
2159 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
2160 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
2161 RegCloseKey(hkeyPrinters
);
2162 ERR("Can't query Printers key\n");
2165 TRACE("Found %ld printers\n", number
);
2169 RegCloseKey(hkeyPrinters
);
2171 *lpdwReturned
= number
;
2175 used
= number
* sizeof(PRINTER_INFO_2W
);
2178 used
= number
* sizeof(PRINTER_INFO_4W
);
2181 used
= number
* sizeof(PRINTER_INFO_5W
);
2185 SetLastError(ERROR_INVALID_LEVEL
);
2186 RegCloseKey(hkeyPrinters
);
2189 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
2191 for(i
= 0; i
< number
; i
++) {
2192 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
2194 ERR("Can't enum key number %ld\n", i
);
2195 RegCloseKey(hkeyPrinters
);
2198 TRACE("Printer %ld is %s\n", i
, debugstr_w(PrinterName
));
2199 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
2201 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
2202 RegCloseKey(hkeyPrinters
);
2207 buf
= lpbPrinters
+ used
;
2208 left
= cbBuf
- used
;
2216 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
2217 left
, &needed
, unicode
);
2219 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
2222 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
2223 left
, &needed
, unicode
);
2225 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
2228 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
2229 left
, &needed
, unicode
);
2231 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
2234 ERR("Shouldn't be here!\n");
2235 RegCloseKey(hkeyPrinter
);
2236 RegCloseKey(hkeyPrinters
);
2239 RegCloseKey(hkeyPrinter
);
2241 RegCloseKey(hkeyPrinters
);
2248 memset(lpbPrinters
, 0, cbBuf
);
2249 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2253 *lpdwReturned
= number
;
2254 SetLastError(ERROR_SUCCESS
);
2259 /******************************************************************
2260 * EnumPrintersW [WINSPOOL.@]
2262 * Enumerates the available printers, print servers and print
2263 * providers, depending on the specified flags, name and level.
2267 * If level is set to 1:
2268 * Not implemented yet!
2269 * Returns TRUE with an empty list.
2271 * If level is set to 2:
2272 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2273 * Returns an array of PRINTER_INFO_2 data structures in the
2274 * lpbPrinters buffer. Note that according to MSDN also an
2275 * OpenPrinter should be performed on every remote printer.
2277 * If level is set to 4 (officially WinNT only):
2278 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2279 * Fast: Only the registry is queried to retrieve printer names,
2280 * no connection to the driver is made.
2281 * Returns an array of PRINTER_INFO_4 data structures in the
2282 * lpbPrinters buffer.
2284 * If level is set to 5 (officially WinNT4/Win9x only):
2285 * Fast: Only the registry is queried to retrieve printer names,
2286 * no connection to the driver is made.
2287 * Returns an array of PRINTER_INFO_5 data structures in the
2288 * lpbPrinters buffer.
2290 * If level set to 3 or 6+:
2291 * returns zero (failure!)
2293 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2297 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2298 * - Only levels 2, 4 and 5 are implemented at the moment.
2299 * - 16-bit printer drivers are not enumerated.
2300 * - Returned amount of bytes used/needed does not match the real Windoze
2301 * implementation (as in this implementation, all strings are part
2302 * of the buffer, whereas Win32 keeps them somewhere else)
2303 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2306 * - In a regular Wine installation, no registry settings for printers
2307 * exist, which makes this function return an empty list.
2309 BOOL WINAPI
EnumPrintersW(
2310 DWORD dwType
, /* [in] Types of print objects to enumerate */
2311 LPWSTR lpszName
, /* [in] name of objects to enumerate */
2312 DWORD dwLevel
, /* [in] type of printer info structure */
2313 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
2314 DWORD cbBuf
, /* [in] max size of buffer in bytes */
2315 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
2316 LPDWORD lpdwReturned
/* [out] number of entries returned */
2319 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
2320 lpdwNeeded
, lpdwReturned
, TRUE
);
2323 /******************************************************************
2324 * EnumPrintersA [WINSPOOL.@]
2327 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
2328 DWORD dwLevel
, LPBYTE lpbPrinters
,
2329 DWORD cbBuf
, LPDWORD lpdwNeeded
,
2330 LPDWORD lpdwReturned
)
2333 UNICODE_STRING lpszNameW
;
2336 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
2337 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
2338 lpdwNeeded
, lpdwReturned
, FALSE
);
2339 RtlFreeUnicodeString(&lpszNameW
);
2343 /*****************************************************************************
2344 * WINSPOOL_GetDriverInfoFromReg [internal]
2346 * Enters the information from the registry into the DRIVER_INFO struct
2349 * zero if the printer driver does not exist in the registry
2350 * (only if Level > 1) otherwise nonzero
2352 static BOOL
WINSPOOL_GetDriverInfoFromReg(
2355 LPWSTR pEnvironment
,
2357 LPBYTE ptr
, /* DRIVER_INFO */
2358 LPBYTE pDriverStrings
, /* strings buffer */
2359 DWORD cbBuf
, /* size of string buffer */
2360 LPDWORD pcbNeeded
, /* space needed for str. */
2361 BOOL unicode
) /* type of strings */
2362 { DWORD dw
, size
, tmp
, type
;
2364 LPBYTE strPtr
= pDriverStrings
;
2366 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2367 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
2368 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
2371 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
2372 if (*pcbNeeded
<= cbBuf
)
2373 strcpyW((LPWSTR
)strPtr
, DriverName
);
2375 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
2377 if(*pcbNeeded
<= cbBuf
)
2378 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, strPtr
, *pcbNeeded
,
2383 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
2387 ((PDRIVER_INFO_3W
) ptr
)->pName
= (LPWSTR
) strPtr
;
2388 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
2391 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
2392 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName
));
2393 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
2398 if(RegQueryValueExA(hkeyDriver
, "Version", 0, &type
, (PBYTE
)&dw
, &size
) !=
2400 WARN("Can't get Version\n");
2402 ((PDRIVER_INFO_3A
) ptr
)->cVersion
= dw
;
2405 pEnvironment
= (LPWSTR
)DefaultEnvironmentW
;
2407 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
2409 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
2412 if(*pcbNeeded
<= cbBuf
) {
2414 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
2416 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, strPtr
, size
,
2419 ((PDRIVER_INFO_3W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
2420 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
2423 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
2426 if(*pcbNeeded
<= cbBuf
)
2427 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
2430 ((PDRIVER_INFO_3W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
2431 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
2434 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
2437 if(*pcbNeeded
<= cbBuf
)
2438 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
2441 ((PDRIVER_INFO_3W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
2442 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2445 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
2446 0, &size
, unicode
)) {
2448 if(*pcbNeeded
<= cbBuf
)
2449 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
2450 size
, &tmp
, unicode
);
2452 ((PDRIVER_INFO_3W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
2453 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2457 RegCloseKey(hkeyDriver
);
2458 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
2462 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
2465 if(*pcbNeeded
<= cbBuf
)
2466 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
2467 size
, &tmp
, unicode
);
2469 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
2470 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2473 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
2476 if(*pcbNeeded
<= cbBuf
)
2477 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
2478 size
, &tmp
, unicode
);
2480 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
2481 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2484 if(WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
2487 if(*pcbNeeded
<= cbBuf
)
2488 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
2489 size
, &tmp
, unicode
);
2491 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
2492 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2495 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
2498 if(*pcbNeeded
<= cbBuf
)
2499 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
2500 size
, &tmp
, unicode
);
2502 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
2503 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2506 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
2507 RegCloseKey(hkeyDriver
);
2511 /*****************************************************************************
2512 * WINSPOOL_GetPrinterDriver
2514 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
2515 DWORD Level
, LPBYTE pDriverInfo
,
2516 DWORD cbBuf
, LPDWORD pcbNeeded
,
2520 WCHAR DriverName
[100];
2521 DWORD ret
, type
, size
, needed
= 0;
2523 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
2525 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
2526 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
2528 ZeroMemory(pDriverInfo
, cbBuf
);
2530 if (!(name
= WINSPOOL_GetOpenedPrinter(hPrinter
))) return FALSE
;
2532 if(Level
< 1 || Level
> 3) {
2533 SetLastError(ERROR_INVALID_LEVEL
);
2536 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2538 ERR("Can't create Printers key\n");
2541 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
2543 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
2544 RegCloseKey(hkeyPrinters
);
2545 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
2548 size
= sizeof(DriverName
);
2550 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
2551 (LPBYTE
)DriverName
, &size
);
2552 RegCloseKey(hkeyPrinter
);
2553 RegCloseKey(hkeyPrinters
);
2554 if(ret
!= ERROR_SUCCESS
) {
2555 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
2559 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
2561 ERR("Can't create Drivers key\n");
2567 size
= sizeof(DRIVER_INFO_1W
);
2570 size
= sizeof(DRIVER_INFO_2W
);
2573 size
= sizeof(DRIVER_INFO_3W
);
2576 ERR("Invalid level\n");
2581 ptr
= pDriverInfo
+ size
;
2583 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
2584 pEnvironment
, Level
, pDriverInfo
,
2585 (cbBuf
< size
) ? NULL
: ptr
,
2586 (cbBuf
< size
) ? 0 : cbBuf
- size
,
2587 &needed
, unicode
)) {
2588 RegCloseKey(hkeyDrivers
);
2592 RegCloseKey(hkeyDrivers
);
2594 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
2595 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
2596 if(cbBuf
>= needed
) return TRUE
;
2597 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2601 /*****************************************************************************
2602 * GetPrinterDriverA [WINSPOOL.@]
2604 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
2605 DWORD Level
, LPBYTE pDriverInfo
,
2606 DWORD cbBuf
, LPDWORD pcbNeeded
)
2609 UNICODE_STRING pEnvW
;
2612 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
2613 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
2614 cbBuf
, pcbNeeded
, FALSE
);
2615 RtlFreeUnicodeString(&pEnvW
);
2618 /*****************************************************************************
2619 * GetPrinterDriverW [WINSPOOL.@]
2621 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
2622 DWORD Level
, LPBYTE pDriverInfo
,
2623 DWORD cbBuf
, LPDWORD pcbNeeded
)
2625 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
2626 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
2629 /*****************************************************************************
2630 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2632 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
2633 DWORD Level
, LPBYTE pDriverDirectory
,
2634 DWORD cbBuf
, LPDWORD pcbNeeded
)
2638 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
2639 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
2641 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName
));
2642 SetLastError(ERROR_INVALID_PARAMETER
);
2645 if(pEnvironment
!= NULL
) {
2646 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment
));
2647 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2650 if(Level
!= 1) /* win95 ignores this so we just carry on */
2651 WARN("Level = %ld - assuming 1\n", Level
);
2653 /* FIXME should read from registry */
2654 needed
= GetSystemDirectoryW( (LPWSTR
)pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
2655 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2659 needed
*=sizeof(WCHAR
);
2662 *pcbNeeded
= needed
;
2663 TRACE("required <%08lx>\n", *pcbNeeded
);
2664 if(needed
> cbBuf
) {
2665 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2672 /*****************************************************************************
2673 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2675 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
2676 DWORD Level
, LPBYTE pDriverDirectory
,
2677 DWORD cbBuf
, LPDWORD pcbNeeded
)
2679 UNICODE_STRING nameW
, environmentW
;
2682 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
2683 WCHAR
*driverDirectoryW
= NULL
;
2685 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
2687 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
2688 else nameW
.Buffer
= NULL
;
2689 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
2690 else environmentW
.Buffer
= NULL
;
2692 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
2693 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
2696 needed
= 1 + WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
2697 pDriverDirectory
, cbBuf
, NULL
, NULL
);
2699 *pcbNeeded
= needed
;
2700 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
2702 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
2704 TRACE("provided<%ld> required <%ld>\n", cbBuf
, *pcbNeeded
);
2706 if(driverDirectoryW
)
2707 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
2708 RtlFreeUnicodeString(&environmentW
);
2709 RtlFreeUnicodeString(&nameW
);
2714 /*****************************************************************************
2715 * AddPrinterDriverA [WINSPOOL.@]
2717 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
2720 HKEY hkeyDrivers
, hkeyName
;
2722 TRACE("(%s,%ld,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
2724 if(level
!= 2 && level
!= 3) {
2725 SetLastError(ERROR_INVALID_LEVEL
);
2729 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
2730 SetLastError(ERROR_INVALID_PARAMETER
);
2734 WARN("pDriverInfo == NULL\n");
2735 SetLastError(ERROR_INVALID_PARAMETER
);
2740 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
2742 memset(&di3
, 0, sizeof(di3
));
2743 *(DRIVER_INFO_2A
*)&di3
= *(DRIVER_INFO_2A
*)pDriverInfo
;
2746 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
2748 SetLastError(ERROR_INVALID_PARAMETER
);
2751 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= "";
2752 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= "\0";
2753 if(!di3
.pHelpFile
) di3
.pHelpFile
= "";
2754 if(!di3
.pMonitorName
) di3
.pMonitorName
= "";
2756 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
2759 ERR("Can't create Drivers key\n");
2763 if(level
== 2) { /* apparently can't overwrite with level2 */
2764 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
2765 RegCloseKey(hkeyName
);
2766 RegCloseKey(hkeyDrivers
);
2767 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
2768 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
2772 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
2773 RegCloseKey(hkeyDrivers
);
2774 ERR("Can't create Name key\n");
2777 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, di3
.pConfigFile
,
2779 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, di3
.pDataFile
, 0);
2780 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, di3
.pDriverPath
, 0);
2781 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPSTR
)&di3
.cVersion
,
2783 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, di3
.pDefaultDataType
, 0);
2784 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
2785 di3
.pDependentFiles
, 0);
2786 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, di3
.pHelpFile
, 0);
2787 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, di3
.pMonitorName
, 0);
2788 RegCloseKey(hkeyName
);
2789 RegCloseKey(hkeyDrivers
);
2793 /*****************************************************************************
2794 * AddPrinterDriverW [WINSPOOL.@]
2796 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
2799 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName
),
2805 /*****************************************************************************
2806 * PrinterProperties [WINSPOOL.@]
2808 * Displays a dialog to set the properties of the printer.
2811 * nonzero on success or zero on failure
2814 * implemented as stub only
2816 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
2817 HANDLE hPrinter
/* [in] handle to printer object */
2819 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
2820 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2824 /*****************************************************************************
2825 * EnumJobsA [WINSPOOL.@]
2828 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
2829 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2832 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2833 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
2835 if(pcbNeeded
) *pcbNeeded
= 0;
2836 if(pcReturned
) *pcReturned
= 0;
2841 /*****************************************************************************
2842 * EnumJobsW [WINSPOOL.@]
2845 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
2846 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2849 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2850 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
2852 if(pcbNeeded
) *pcbNeeded
= 0;
2853 if(pcReturned
) *pcReturned
= 0;
2857 /*****************************************************************************
2858 * WINSPOOL_EnumPrinterDrivers [internal]
2860 * Delivers information about all printer drivers installed on the
2861 * localhost or a given server
2864 * nonzero on success or zero on failure. If the buffer for the returned
2865 * information is too small the function will return an error
2868 * - only implemented for localhost, foreign hosts will return an error
2870 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPWSTR pEnvironment
,
2871 DWORD Level
, LPBYTE pDriverInfo
,
2872 DWORD cbBuf
, LPDWORD pcbNeeded
,
2873 LPDWORD pcReturned
, BOOL unicode
)
2876 DWORD i
, needed
, number
= 0, size
= 0;
2877 WCHAR DriverNameW
[255];
2880 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2881 debugstr_w(pName
), debugstr_w(pEnvironment
),
2882 Level
, pDriverInfo
, cbBuf
, unicode
);
2884 /* check for local drivers */
2886 ERR("remote drivers unsupported! Current remote host is %s\n",
2891 /* check input parameter */
2892 if((Level
< 1) || (Level
> 3)) {
2893 ERR("unsupported level %ld \n", Level
);
2897 /* initialize return values */
2899 memset( pDriverInfo
, 0, cbBuf
);
2903 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
2905 ERR("Can't open Drivers key\n");
2909 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
2910 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
2911 RegCloseKey(hkeyDrivers
);
2912 ERR("Can't query Drivers key\n");
2915 TRACE("Found %ld Drivers\n", number
);
2917 /* get size of single struct
2918 * unicode and ascii structure have the same size
2922 size
= sizeof(DRIVER_INFO_1A
);
2925 size
= sizeof(DRIVER_INFO_2A
);
2928 size
= sizeof(DRIVER_INFO_3A
);
2932 /* calculate required buffer size */
2933 *pcbNeeded
= size
* number
;
2935 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
2937 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
2938 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
2940 ERR("Can't enum key number %ld\n", i
);
2941 RegCloseKey(hkeyDrivers
);
2944 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
2945 pEnvironment
, Level
, ptr
,
2946 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
2947 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
2948 &needed
, unicode
)) {
2949 RegCloseKey(hkeyDrivers
);
2952 (*pcbNeeded
) += needed
;
2955 RegCloseKey(hkeyDrivers
);
2957 if(cbBuf
< *pcbNeeded
){
2958 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2965 /*****************************************************************************
2966 * EnumPrinterDriversW [WINSPOOL.@]
2968 * see function EnumPrinterDrivers for RETURNS, BUGS
2970 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2971 LPBYTE pDriverInfo
, DWORD cbBuf
,
2972 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2974 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
2975 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
2978 /*****************************************************************************
2979 * EnumPrinterDriversA [WINSPOOL.@]
2981 * see function EnumPrinterDrivers for RETURNS, BUGS
2983 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
2984 LPBYTE pDriverInfo
, DWORD cbBuf
,
2985 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2987 UNICODE_STRING pNameW
, pEnvironmentW
;
2988 PWSTR pwstrNameW
, pwstrEnvironmentW
;
2990 pwstrNameW
= asciitounicode(&pNameW
, pName
);
2991 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
2993 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
2994 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
2996 RtlFreeUnicodeString(&pNameW
);
2997 RtlFreeUnicodeString(&pEnvironmentW
);
3002 static CHAR PortMonitor
[] = "Wine Port Monitor";
3003 static CHAR PortDescription
[] = "Wine Port";
3005 /******************************************************************************
3006 * EnumPortsA (WINSPOOL.@)
3008 BOOL WINAPI
EnumPortsA(LPSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
3009 LPDWORD bufneeded
,LPDWORD bufreturned
)
3012 DWORD info_size
, ofs
, i
, printer_count
, serial_count
, count
, n
, r
;
3013 const LPCSTR szSerialPortKey
= "Software\\Wine\\Wine\\Config\\serialports";
3014 const LPCSTR szPrinterPortKey
= "Software\\Wine\\Wine\\Config\\spooler";
3015 HKEY hkey_serial
, hkey_printer
;
3017 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3018 name
,level
,buffer
,bufsize
,bufneeded
,bufreturned
);
3023 info_size
= sizeof (PORT_INFO_1A
);
3026 info_size
= sizeof (PORT_INFO_2A
);
3029 SetLastError(ERROR_INVALID_LEVEL
);
3033 /* see how many exist */
3039 r
= RegOpenKeyA( HKEY_LOCAL_MACHINE
, szSerialPortKey
, &hkey_serial
);
3040 if (r
== ERROR_SUCCESS
)
3042 RegQueryInfoKeyA ( hkey_serial
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3043 &serial_count
, NULL
, NULL
, NULL
, NULL
);
3046 r
= RegOpenKeyA( HKEY_LOCAL_MACHINE
, szPrinterPortKey
, &hkey_printer
);
3047 if ( r
== ERROR_SUCCESS
)
3049 RegQueryInfoKeyA( hkey_printer
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3050 &printer_count
, NULL
, NULL
, NULL
, NULL
);
3052 count
= serial_count
+ printer_count
;
3054 /* then fill in the structure info structure once
3055 we know the offset to the first string */
3057 memset( buffer
, 0, bufsize
);
3059 ofs
= info_size
*count
;
3060 for ( i
=0; i
<count
; i
++)
3062 DWORD vallen
= sizeof(portname
) - 1;
3064 /* get the serial port values, then the printer values */
3065 if ( i
< serial_count
)
3066 r
= RegEnumValueA( hkey_serial
, i
,
3067 portname
, &vallen
, NULL
, NULL
, NULL
, 0 );
3069 r
= RegEnumValueA( hkey_printer
, i
-serial_count
,
3070 portname
, &vallen
, NULL
, NULL
, NULL
, 0 );
3075 /* add a colon if necessary, and make it upper case */
3076 CharUpperBuffA(portname
,vallen
);
3077 if (strcasecmp(portname
,"nul")!=0)
3078 if (vallen
&& (portname
[vallen
-1] != ':') )
3079 lstrcatA(portname
,":");
3081 /* add the port info structure if we can fit it */
3082 if ( info_size
*(n
+1) < bufsize
)
3086 PORT_INFO_1A
*info
= (PORT_INFO_1A
*) &buffer
[info_size
*n
];
3087 info
->pName
= (LPSTR
) &buffer
[ofs
];
3089 else if ( level
== 2)
3091 PORT_INFO_2A
*info
= (PORT_INFO_2A
*) &buffer
[info_size
*n
];
3092 info
->pPortName
= (LPSTR
) &buffer
[ofs
];
3093 /* FIXME: fill in more stuff here */
3094 info
->pMonitorName
= PortMonitor
;
3095 info
->pDescription
= PortDescription
;
3096 info
->fPortType
= PORT_TYPE_WRITE
|PORT_TYPE_READ
;
3099 /* add the name of the port if we can fit it */
3100 if ( ofs
< bufsize
)
3101 lstrcpynA(&buffer
[ofs
],portname
,bufsize
- ofs
);
3104 ofs
+= lstrlenA(portname
)+1;
3108 RegCloseKey(hkey_serial
);
3109 RegCloseKey(hkey_printer
);
3115 *bufreturned
= count
;
3121 /******************************************************************************
3122 * GetDefaultPrinterW (WINSPOOL.@)
3125 * This function must read the value from data 'device' of key
3126 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3128 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
3132 WCHAR
*buffer
, *ptr
;
3136 SetLastError(ERROR_INVALID_PARAMETER
);
3140 /* make the buffer big enough for the stuff from the profile/registry,
3141 * the content must fit into the local buffer to compute the correct
3142 * size even if the extern buffer is to small or not given.
3143 * (20 for ,driver,port) */
3145 len
= max(100, (insize
+ 20));
3146 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3148 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
3150 SetLastError (ERROR_FILE_NOT_FOUND
);
3154 TRACE("%s\n", debugstr_w(buffer
));
3156 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
3158 SetLastError(ERROR_INVALID_NAME
);
3164 *namesize
= strlenW(buffer
) + 1;
3165 if(!name
|| (*namesize
> insize
))
3167 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3171 strcpyW(name
, buffer
);
3174 if(buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
3179 /******************************************************************************
3180 * GetDefaultPrinterA (WINSPOOL.@)
3182 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
3186 WCHAR
*bufferW
= NULL
;
3190 SetLastError(ERROR_INVALID_PARAMETER
);
3194 if(name
&& *namesize
) {
3196 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
3199 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
3204 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
3208 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
3211 TRACE("0x%08lx/0x%08lx:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
3214 if(bufferW
) HeapFree( GetProcessHeap(), 0, bufferW
);
3219 /******************************************************************************
3220 * SetPrinterDataExA (WINSPOOL.@)
3222 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
3223 LPCSTR pValueName
, DWORD Type
,
3224 LPBYTE pData
, DWORD cbData
)
3226 HKEY hkeyPrinter
, hkeySubkey
;
3229 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_a(pKeyName
),
3230 debugstr_a(pValueName
), Type
, pData
, cbData
);
3232 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3236 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3238 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
3239 RegCloseKey(hkeyPrinter
);
3242 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
3243 RegCloseKey(hkeySubkey
);
3244 RegCloseKey(hkeyPrinter
);
3248 /******************************************************************************
3249 * SetPrinterDataExW (WINSPOOL.@)
3251 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
3252 LPCWSTR pValueName
, DWORD Type
,
3253 LPBYTE pData
, DWORD cbData
)
3255 HKEY hkeyPrinter
, hkeySubkey
;
3258 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_w(pKeyName
),
3259 debugstr_w(pValueName
), Type
, pData
, cbData
);
3261 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3265 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3267 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
3268 RegCloseKey(hkeyPrinter
);
3271 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
3272 RegCloseKey(hkeySubkey
);
3273 RegCloseKey(hkeyPrinter
);
3277 /******************************************************************************
3278 * SetPrinterDataA (WINSPOOL.@)
3280 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
3281 LPBYTE pData
, DWORD cbData
)
3283 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
3287 /******************************************************************************
3288 * SetPrinterDataW (WINSPOOL.@)
3290 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
3291 LPBYTE pData
, DWORD cbData
)
3293 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
3297 /******************************************************************************
3298 * GetPrinterDataExA (WINSPOOL.@)
3300 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
3301 LPCSTR pValueName
, LPDWORD pType
,
3302 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
3304 HKEY hkeyPrinter
, hkeySubkey
;
3307 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
3308 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
3311 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3315 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3317 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
3318 RegCloseKey(hkeyPrinter
);
3322 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
3323 RegCloseKey(hkeySubkey
);
3324 RegCloseKey(hkeyPrinter
);
3328 /******************************************************************************
3329 * GetPrinterDataExW (WINSPOOL.@)
3331 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
3332 LPCWSTR pValueName
, LPDWORD pType
,
3333 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
3335 HKEY hkeyPrinter
, hkeySubkey
;
3338 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
3339 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
3342 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3346 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3348 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
3349 RegCloseKey(hkeyPrinter
);
3353 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
3354 RegCloseKey(hkeySubkey
);
3355 RegCloseKey(hkeyPrinter
);
3359 /******************************************************************************
3360 * GetPrinterDataA (WINSPOOL.@)
3362 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
3363 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
3365 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
3366 pData
, nSize
, pcbNeeded
);
3369 /******************************************************************************
3370 * GetPrinterDataW (WINSPOOL.@)
3372 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
3373 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
3375 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
3376 pData
, nSize
, pcbNeeded
);
3379 /*******************************************************************************
3380 * EnumPrinterDataExW [WINSPOOL.@]
3382 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
3383 LPBYTE pEnumValues
, DWORD cbEnumValues
,
3384 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
3386 HKEY hkPrinter
, hkSubKey
;
3387 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
3388 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
3393 PPRINTER_ENUM_VALUESW ppev
;
3395 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
3397 if (pKeyName
== NULL
|| *pKeyName
== 0)
3398 return ERROR_INVALID_PARAMETER
;
3400 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
3401 if (ret
!= ERROR_SUCCESS
)
3403 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3408 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
3409 if (ret
!= ERROR_SUCCESS
)
3411 r
= RegCloseKey (hkPrinter
);
3412 if (r
!= ERROR_SUCCESS
)
3413 WARN ("RegCloseKey returned %li\n", r
);
3414 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter
,
3415 debugstr_w (pKeyName
), ret
);
3419 ret
= RegCloseKey (hkPrinter
);
3420 if (ret
!= ERROR_SUCCESS
)
3422 ERR ("RegCloseKey returned %li\n", ret
);
3423 r
= RegCloseKey (hkSubKey
);
3424 if (r
!= ERROR_SUCCESS
)
3425 WARN ("RegCloseKey returned %li\n", r
);
3429 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3430 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
3431 if (ret
!= ERROR_SUCCESS
)
3433 r
= RegCloseKey (hkSubKey
);
3434 if (r
!= ERROR_SUCCESS
)
3435 WARN ("RegCloseKey returned %li\n", r
);
3436 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey
, ret
);
3440 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3441 "cbMaxValueLen = %li\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
3443 if (cValues
== 0) /* empty key */
3445 r
= RegCloseKey (hkSubKey
);
3446 if (r
!= ERROR_SUCCESS
)
3447 WARN ("RegCloseKey returned %li\n", r
);
3448 *pcbEnumValues
= *pnEnumValues
= 0;
3449 return ERROR_SUCCESS
;
3452 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
3454 hHeap
= GetProcessHeap ();
3457 ERR ("GetProcessHeap failed\n");
3458 r
= RegCloseKey (hkSubKey
);
3459 if (r
!= ERROR_SUCCESS
)
3460 WARN ("RegCloseKey returned %li\n", r
);
3461 return ERROR_OUTOFMEMORY
;
3464 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
3465 if (lpValueName
== NULL
)
3467 ERR ("Failed to allocate %li bytes from process heap\n",
3468 cbMaxValueNameLen
* sizeof (WCHAR
));
3469 r
= RegCloseKey (hkSubKey
);
3470 if (r
!= ERROR_SUCCESS
)
3471 WARN ("RegCloseKey returned %li\n", r
);
3472 return ERROR_OUTOFMEMORY
;
3475 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
3476 if (lpValue
== NULL
)
3478 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen
);
3479 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3480 WARN ("HeapFree failed with code %li\n", GetLastError ());
3481 r
= RegCloseKey (hkSubKey
);
3482 if (r
!= ERROR_SUCCESS
)
3483 WARN ("RegCloseKey returned %li\n", r
);
3484 return ERROR_OUTOFMEMORY
;
3487 TRACE ("pass 1: calculating buffer required for all names and values\n");
3489 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
3491 TRACE ("%li bytes required for %li headers\n", cbBufSize
, cValues
);
3493 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
3495 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
3496 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
3497 NULL
, NULL
, lpValue
, &cbValueLen
);
3498 if (ret
!= ERROR_SUCCESS
)
3500 if (HeapFree (hHeap
, 0, lpValue
) == 0)
3501 WARN ("HeapFree failed with code %li\n", GetLastError ());
3502 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3503 WARN ("HeapFree failed with code %li\n", GetLastError ());
3504 r
= RegCloseKey (hkSubKey
);
3505 if (r
!= ERROR_SUCCESS
)
3506 WARN ("RegCloseKey returned %li\n", r
);
3507 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
3511 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3512 debugstr_w (lpValueName
), dwIndex
,
3513 (cbValueNameLen
+ 1) * sizeof (WCHAR
), cbValueLen
);
3515 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
3516 cbBufSize
+= cbValueLen
;
3519 TRACE ("%li bytes required for all %li values\n", cbBufSize
, cValues
);
3521 *pcbEnumValues
= cbBufSize
;
3522 *pnEnumValues
= cValues
;
3524 if (cbEnumValues
< cbBufSize
) /* buffer too small */
3526 if (HeapFree (hHeap
, 0, lpValue
) == 0)
3527 WARN ("HeapFree failed with code %li\n", GetLastError ());
3528 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3529 WARN ("HeapFree failed with code %li\n", GetLastError ());
3530 r
= RegCloseKey (hkSubKey
);
3531 if (r
!= ERROR_SUCCESS
)
3532 WARN ("RegCloseKey returned %li\n", r
);
3533 TRACE ("%li byte buffer is not large enough\n", cbEnumValues
);
3534 return ERROR_MORE_DATA
;
3537 TRACE ("pass 2: copying all names and values to buffer\n");
3539 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
3540 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
3542 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
3544 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
3545 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
3546 NULL
, &dwType
, lpValue
, &cbValueLen
);
3547 if (ret
!= ERROR_SUCCESS
)
3549 if (HeapFree (hHeap
, 0, lpValue
) == 0)
3550 WARN ("HeapFree failed with code %li\n", GetLastError ());
3551 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3552 WARN ("HeapFree failed with code %li\n", GetLastError ());
3553 r
= RegCloseKey (hkSubKey
);
3554 if (r
!= ERROR_SUCCESS
)
3555 WARN ("RegCloseKey returned %li\n", r
);
3556 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
3560 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
3561 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
3562 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
3563 pEnumValues
+= cbValueNameLen
;
3565 /* return # of *bytes* (including trailing \0), not # of chars */
3566 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
3568 ppev
[dwIndex
].dwType
= dwType
;
3570 memcpy (pEnumValues
, lpValue
, cbValueLen
);
3571 ppev
[dwIndex
].pData
= pEnumValues
;
3572 pEnumValues
+= cbValueLen
;
3574 ppev
[dwIndex
].cbData
= cbValueLen
;
3576 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3577 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
3580 if (HeapFree (hHeap
, 0, lpValue
) == 0)
3582 ret
= GetLastError ();
3583 ERR ("HeapFree failed with code %li\n", ret
);
3584 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3585 WARN ("HeapFree failed with code %li\n", GetLastError ());
3586 r
= RegCloseKey (hkSubKey
);
3587 if (r
!= ERROR_SUCCESS
)
3588 WARN ("RegCloseKey returned %li\n", r
);
3592 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3594 ret
= GetLastError ();
3595 ERR ("HeapFree failed with code %li\n", ret
);
3596 r
= RegCloseKey (hkSubKey
);
3597 if (r
!= ERROR_SUCCESS
)
3598 WARN ("RegCloseKey returned %li\n", r
);
3602 ret
= RegCloseKey (hkSubKey
);
3603 if (ret
!= ERROR_SUCCESS
)
3605 ERR ("RegCloseKey returned %li\n", ret
);
3609 return ERROR_SUCCESS
;
3612 /*******************************************************************************
3613 * EnumPrinterDataExA [WINSPOOL.@]
3615 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3616 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3617 * what Windows 2000 SP1 does.
3620 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
3621 LPBYTE pEnumValues
, DWORD cbEnumValues
,
3622 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
3626 DWORD ret
, dwIndex
, dwBufSize
;
3630 TRACE ("%p %s\n", hPrinter
, pKeyName
);
3632 if (pKeyName
== NULL
|| *pKeyName
== 0)
3633 return ERROR_INVALID_PARAMETER
;
3635 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
3638 ret
= GetLastError ();
3639 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
3643 hHeap
= GetProcessHeap ();
3646 ERR ("GetProcessHeap failed\n");
3647 return ERROR_OUTOFMEMORY
;
3650 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
3651 if (pKeyNameW
== NULL
)
3653 ERR ("Failed to allocate %li bytes from process heap\n",
3654 (LONG
) len
* sizeof (WCHAR
));
3655 return ERROR_OUTOFMEMORY
;
3658 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
3660 ret
= GetLastError ();
3661 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
3662 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
3663 WARN ("HeapFree failed with code %li\n", GetLastError ());
3667 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
3668 pcbEnumValues
, pnEnumValues
);
3669 if (ret
!= ERROR_SUCCESS
)
3671 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
3672 WARN ("HeapFree failed with code %li\n", GetLastError ());
3673 TRACE ("EnumPrinterDataExW returned %li\n", ret
);
3677 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
3679 ret
= GetLastError ();
3680 ERR ("HeapFree failed with code %li\n", ret
);
3684 if (*pnEnumValues
== 0) /* empty key */
3685 return ERROR_SUCCESS
;
3688 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
3690 PPRINTER_ENUM_VALUESW ppev
=
3691 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
3693 if (dwBufSize
< ppev
->cbValueName
)
3694 dwBufSize
= ppev
->cbValueName
;
3696 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
3697 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
3698 dwBufSize
= ppev
->cbData
;
3701 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize
);
3703 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
3704 if (pBuffer
== NULL
)
3706 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize
);
3707 return ERROR_OUTOFMEMORY
;
3710 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
3712 PPRINTER_ENUM_VALUESW ppev
=
3713 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
3715 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
3716 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
3720 ret
= GetLastError ();
3721 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
3722 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
3723 WARN ("HeapFree failed with code %li\n", GetLastError ());
3727 memcpy (ppev
->pValueName
, pBuffer
, len
);
3729 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
3731 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
3732 ppev
->dwType
!= REG_MULTI_SZ
)
3735 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
3736 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
3739 ret
= GetLastError ();
3740 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
3741 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
3742 WARN ("HeapFree failed with code %li\n", GetLastError ());
3746 memcpy (ppev
->pData
, pBuffer
, len
);
3748 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
3749 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3752 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
3754 ret
= GetLastError ();
3755 ERR ("HeapFree failed with code %li\n", ret
);
3759 return ERROR_SUCCESS
;
3762 /******************************************************************************
3763 * AddPortA (WINSPOOL.@)
3765 BOOL WINAPI
AddPortA(LPSTR pName
,HWND hWnd
, LPSTR pMonitorName
)
3767 FIXME("(%s, %p, %s\n), stub!\n",pName
,hWnd
,pMonitorName
);
3771 /******************************************************************************
3772 * AddPrinterDriverExW (WINSPOOL.@)
3774 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
3775 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
3777 FIXME("%s %ld %p %ld\n", debugstr_w(pName
),
3778 Level
, pDriverInfo
, dwFileCopyFlags
);
3779 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
3783 /******************************************************************************
3784 * AddPrinterDriverExA (WINSPOOL.@)
3786 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
3787 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
3789 FIXME("%s %ld %p %ld\n", debugstr_a(pName
),
3790 Level
, pDriverInfo
, dwFileCopyFlags
);
3791 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
3795 /******************************************************************************
3796 * DeletePrinterDriverExW (WINSPOOL.@)
3798 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
3799 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
3801 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
3802 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
3806 /******************************************************************************
3807 * DeletePrinterDriverExA (WINSPOOL.@)
3809 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
3810 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
3812 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
3813 debugstr_a(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
3817 /******************************************************************************
3818 * DeletePrinterDataExW (WINSPOOL.@)
3820 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
3823 FIXME("%p %s %s\n", hPrinter
,
3824 debugstr_w(pKeyName
), debugstr_w(pValueName
));
3825 return ERROR_INVALID_PARAMETER
;
3828 /******************************************************************************
3829 * DeletePrinterDataExA (WINSPOOL.@)
3831 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
3834 FIXME("%p %s %s\n", hPrinter
,
3835 debugstr_a(pKeyName
), debugstr_a(pValueName
));
3836 return ERROR_INVALID_PARAMETER
;
3839 /*****************************************************************************
3840 * EnumMonitorsA [WINSPOOL.@]
3843 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
3844 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3846 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName
), Level
, pMonitors
,
3847 cbBuf
, pcbNeeded
, pcReturned
);
3848 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3852 /*****************************************************************************
3853 * EnumMonitorsW [WINSPOOL.@]
3856 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
3857 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3859 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName
), Level
, pMonitors
,
3860 cbBuf
, pcbNeeded
, pcReturned
);
3861 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3865 /******************************************************************************
3866 * XcvDataW (WINSPOOL.@)
3869 * There doesn't seem to be an A version...
3871 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
3872 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
3873 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
3875 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv
, debugstr_w(pszDataName
),
3876 pInputData
, cbInputData
, pOutputData
,
3877 cbOutputData
, pcbOutputNeeded
, pdwStatus
);