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"
38 #ifdef HAVE_CUPS_CUPS_H
39 # include <cups/cups.h>
40 # ifndef SONAME_LIBCUPS
41 # define SONAME_LIBCUPS "libcups.so"
45 #define NONAMELESSUNION
46 #define NONAMELESSSTRUCT
47 #include "wine/library.h"
56 #include "wine/windef16.h"
57 #include "wine/unicode.h"
58 #include "wine/debug.h"
59 #include "wine/list.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
67 static CRITICAL_SECTION printer_handles_cs
;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
70 0, 0, &printer_handles_cs
,
71 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
72 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
96 WCHAR
*document_title
;
99 static opened_printer_t
**printer_handles
;
100 static int nb_printer_handles
;
101 static LONG next_job_id
= 1;
103 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
104 WORD fwCapability
, LPSTR lpszOutput
,
106 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
107 LPSTR lpszDevice
, LPSTR lpszPort
,
108 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
111 static const char Printers
[] =
112 "System\\CurrentControlSet\\control\\Print\\Printers\\";
114 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
115 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
116 'c','o','n','t','r','o','l','\\',
117 'P','r','i','n','t','\\',
118 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
119 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
121 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
122 'M','i','c','r','o','s','o','f','t','\\',
123 'W','i','n','d','o','w','s',' ','N','T','\\',
124 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
125 'W','i','n','d','o','w','s',0};
127 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
128 'M','i','c','r','o','s','o','f','t','\\',
129 'W','i','n','d','o','w','s',' ','N','T','\\',
130 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
131 'D','e','v','i','c','e','s',0};
133 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
135 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
136 'i','o','n',' ','F','i','l','e',0};
137 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
138 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
139 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v',
141 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F',
143 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
144 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
145 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
146 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
147 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
148 static const WCHAR NameW
[] = {'N','a','m','e',0};
149 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
150 static const WCHAR PortW
[] = {'P','o','r','t',0};
151 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e',
153 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i',
155 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i',
156 'v','e','r','D','a','t','a',0};
157 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F',
159 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
160 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
161 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
162 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
163 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
164 static const WCHAR emptyStringW
[] = {0};
166 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
168 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
169 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
170 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
172 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
173 'D','o','c','u','m','e','n','t',0};
175 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
);
176 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
177 DWORD Level
, LPBYTE pDriverInfo
,
178 DWORD cbBuf
, LPDWORD pcbNeeded
,
180 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
);
182 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
183 if passed a NULL string. This returns NULLs to the result.
185 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
189 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
190 return usBufferPtr
->Buffer
;
192 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
196 static LPWSTR
strdupW(LPCWSTR p
)
202 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
203 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
209 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
,BOOL force
) {
212 /* If forcing, or no profile string entry for device yet, set the entry
214 * The always change entry if not WINEPS yet is discussable.
217 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
219 !strstr(qbuf
,"WINEPS.DRV")
221 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
224 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
225 WriteProfileStringA("windows","device",buf
);
226 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
227 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
230 HeapFree(GetProcessHeap(),0,buf
);
234 #ifdef HAVE_CUPS_CUPS_H
235 static typeof(cupsGetDests
) *pcupsGetDests
;
236 static typeof(cupsGetPPD
) *pcupsGetPPD
;
237 static typeof(cupsPrintFile
) *pcupsPrintFile
;
238 static void *cupshandle
;
240 static BOOL
CUPS_LoadPrinters(void)
243 BOOL hadprinter
= FALSE
;
245 PRINTER_INFO_2A pinfo2a
;
247 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
249 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
252 TRACE("loaded %s\n", SONAME_LIBCUPS
);
255 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
256 if (!p##x) return FALSE;
259 DYNCUPS(cupsGetDests
);
260 DYNCUPS(cupsPrintFile
);
263 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
265 ERR("Can't create Printers key\n");
269 nrofdests
= pcupsGetDests(&dests
);
270 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
271 for (i
=0;i
<nrofdests
;i
++) {
272 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
273 sprintf(port
,"LPR:%s",dests
[i
].name
);
274 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
275 sprintf(devline
,"WINEPS.DRV,%s",port
);
276 WriteProfileStringA("devices",dests
[i
].name
,devline
);
277 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
278 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
281 HeapFree(GetProcessHeap(),0,devline
);
283 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
284 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
285 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
287 TRACE("Printer already exists\n");
288 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
289 RegCloseKey(hkeyPrinter
);
291 memset(&pinfo2a
,0,sizeof(pinfo2a
));
292 pinfo2a
.pPrinterName
= dests
[i
].name
;
293 pinfo2a
.pDatatype
= "RAW";
294 pinfo2a
.pPrintProcessor
= "WinPrint";
295 pinfo2a
.pDriverName
= "PS Driver";
296 pinfo2a
.pComment
= "WINEPS Printer using CUPS";
297 pinfo2a
.pLocation
= "<physical location of printer>";
298 pinfo2a
.pPortName
= port
;
299 pinfo2a
.pParameters
= "<parameters?>";
300 pinfo2a
.pShareName
= "<share name?>";
301 pinfo2a
.pSepFile
= "<sep file?>";
303 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
304 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
305 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests
[i
].name
,GetLastError());
308 HeapFree(GetProcessHeap(),0,port
);
311 if (dests
[i
].is_default
)
312 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
314 RegCloseKey(hkeyPrinters
);
320 PRINTCAP_ParseEntry(char *pent
,BOOL isfirst
) {
321 PRINTER_INFO_2A pinfo2a
;
322 char *e
,*s
,*name
,*prettyname
,*devname
;
323 BOOL ret
= FALSE
, set_default
= FALSE
;
324 char *port
,*devline
,*env_default
;
325 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
327 while (isspace(*pent
)) pent
++;
328 s
= strchr(pent
,':');
330 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
338 TRACE("name=%s entry=%s\n",name
, pent
);
340 if(ispunct(*name
)) { /* a tc entry, not a real printer */
341 TRACE("skipping tc entry\n");
345 if(strstr(pent
,":server")) { /* server only version so skip */
346 TRACE("skipping server entry\n");
350 /* Determine whether this is a postscript printer. */
353 env_default
= getenv("PRINTER");
355 /* Get longest name, usually the one at the right for later display. */
356 while((s
=strchr(prettyname
,'|'))) {
359 while(isspace(*--e
)) *e
= '\0';
360 TRACE("\t%s\n", debugstr_a(prettyname
));
361 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
362 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
365 e
= prettyname
+ strlen(prettyname
);
366 while(isspace(*--e
)) *e
= '\0';
367 TRACE("\t%s\n", debugstr_a(prettyname
));
368 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
370 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
371 * if it is too long, we use it as comment below. */
372 devname
= prettyname
;
373 if (strlen(devname
)>=CCHDEVICENAME
-1)
375 if (strlen(devname
)>=CCHDEVICENAME
-1) {
380 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
381 sprintf(port
,"LPR:%s",name
);
383 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
384 sprintf(devline
,"WINEPS.DRV,%s",port
);
385 WriteProfileStringA("devices",devname
,devline
);
386 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
387 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
390 HeapFree(GetProcessHeap(),0,devline
);
392 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
394 ERR("Can't create Printers key\n");
398 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
399 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
401 TRACE("Printer already exists\n");
402 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
403 RegCloseKey(hkeyPrinter
);
405 memset(&pinfo2a
,0,sizeof(pinfo2a
));
406 pinfo2a
.pPrinterName
= devname
;
407 pinfo2a
.pDatatype
= "RAW";
408 pinfo2a
.pPrintProcessor
= "WinPrint";
409 pinfo2a
.pDriverName
= "PS Driver";
410 pinfo2a
.pComment
= "WINEPS Printer using LPR";
411 pinfo2a
.pLocation
= prettyname
;
412 pinfo2a
.pPortName
= port
;
413 pinfo2a
.pParameters
= "<parameters?>";
414 pinfo2a
.pShareName
= "<share name?>";
415 pinfo2a
.pSepFile
= "<sep file?>";
417 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
418 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
419 ERR("%s not added by AddPrinterA (%ld)\n",name
,GetLastError());
422 RegCloseKey(hkeyPrinters
);
424 if (isfirst
|| set_default
)
425 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
427 HeapFree(GetProcessHeap(), 0, port
);
429 HeapFree(GetProcessHeap(), 0, name
);
434 PRINTCAP_LoadPrinters(void) {
435 BOOL hadprinter
= FALSE
;
439 BOOL had_bash
= FALSE
;
441 f
= fopen("/etc/printcap","r");
445 while(fgets(buf
,sizeof(buf
),f
)) {
448 end
=strchr(buf
,'\n');
452 while(isspace(*start
)) start
++;
453 if(*start
== '#' || *start
== '\0')
456 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
457 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
458 HeapFree(GetProcessHeap(),0,pent
);
462 if (end
&& *--end
== '\\') {
469 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
472 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
478 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
479 HeapFree(GetProcessHeap(),0,pent
);
485 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
488 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
489 lstrlenW(value
) * sizeof(WCHAR
));
491 return ERROR_FILE_NOT_FOUND
;
494 void WINSPOOL_LoadSystemPrinters(void)
496 HKEY hkey
, hkeyPrinters
;
499 DWORD needed
, num
, i
;
500 WCHAR PrinterName
[256];
503 di3a
.cVersion
= 0x400;
504 di3a
.pName
= "PS Driver";
505 di3a
.pEnvironment
= NULL
; /* NULL means auto */
506 di3a
.pDriverPath
= "wineps16";
507 di3a
.pDataFile
= "<datafile?>";
508 di3a
.pConfigFile
= "wineps16";
509 di3a
.pHelpFile
= "<helpfile?>";
510 di3a
.pDependentFiles
= "<dependend files?>";
511 di3a
.pMonitorName
= "<monitor name?>";
512 di3a
.pDefaultDataType
= "RAW";
514 if (!AddPrinterDriverA(NULL
,3,(LPBYTE
)&di3a
)) {
515 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
519 /* This ensures that all printer entries have a valid Name value. If causes
520 problems later if they don't. If one is found to be missed we create one
521 and set it equal to the name of the key */
522 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
523 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
524 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
525 for(i
= 0; i
< num
; i
++) {
526 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
527 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
528 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
529 set_reg_szW(hkey
, NameW
, PrinterName
);
536 RegCloseKey(hkeyPrinters
);
539 /* We want to avoid calling AddPrinter on printers as much as
540 possible, because on cups printers this will (eventually) lead
541 to a call to cupsGetPPD which takes forever, even with non-cups
542 printers AddPrinter takes a while. So we'll tag all printers that
543 were automatically added last time around, if they still exist
544 we'll leave them be otherwise we'll delete them. */
545 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
547 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
548 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
549 for(i
= 0; i
< num
; i
++) {
550 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
551 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
552 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
554 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
562 HeapFree(GetProcessHeap(), 0, pi
);
566 #ifdef HAVE_CUPS_CUPS_H
567 done
= CUPS_LoadPrinters();
570 if(!done
) { /* If we have any CUPS based printers, skip looking for printcap printers */
571 /* Check for [ppd] section in config file before parsing /etc/printcap */
572 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
573 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Printing\\PPD Files",
574 &hkey
) == ERROR_SUCCESS
) {
576 PRINTCAP_LoadPrinters();
580 /* Now enumerate the list again and delete any printers that a still tagged */
581 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
583 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
584 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
585 for(i
= 0; i
< num
; i
++) {
586 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
587 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
588 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
589 DWORD dw
, type
, size
= sizeof(dw
);
590 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
591 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
601 HeapFree(GetProcessHeap(), 0, pi
);
609 /******************************************************************
610 * get_opened_printer_entry
611 * Get the first place empty in the opened printer table
613 static HANDLE
get_opened_printer_entry( LPCWSTR name
)
615 UINT_PTR handle
= nb_printer_handles
, i
;
616 jobqueue_t
*queue
= NULL
;
617 opened_printer_t
*printer
;
619 EnterCriticalSection(&printer_handles_cs
);
621 for (i
= 0; i
< nb_printer_handles
; i
++)
623 if (!printer_handles
[i
])
625 if(handle
== nb_printer_handles
)
628 else if(!queue
&& !strcmpW(name
, printer_handles
[i
]->name
))
629 queue
= printer_handles
[i
]->queue
;
632 if (handle
>= nb_printer_handles
)
634 opened_printer_t
**new_array
;
636 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
637 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
639 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
640 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
647 printer_handles
= new_array
;
648 nb_printer_handles
+= 16;
651 if (!(printer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
))))
657 printer
->name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(name
) + 1) * sizeof(WCHAR
));
658 strcpyW(printer
->name
, name
);
660 printer
->queue
= queue
;
663 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
664 list_init(&printer
->queue
->jobs
);
665 printer
->queue
->ref
= 0;
667 InterlockedIncrement(&printer
->queue
->ref
);
670 printer_handles
[handle
] = printer
;
673 LeaveCriticalSection(&printer_handles_cs
);
675 return (HANDLE
)handle
;
678 /******************************************************************
680 * Get the pointer to the opened printer referred by the handle
682 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
684 UINT_PTR idx
= (UINT_PTR
)hprn
;
685 opened_printer_t
*ret
= NULL
;
687 EnterCriticalSection(&printer_handles_cs
);
689 if ((idx
<= 0) || (idx
> nb_printer_handles
))
692 ret
= printer_handles
[idx
- 1];
694 LeaveCriticalSection(&printer_handles_cs
);
698 /******************************************************************
699 * get_opened_printer_name
700 * Get the pointer to the opened printer name referred by the handle
702 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
704 opened_printer_t
*printer
= get_opened_printer(hprn
);
705 if(!printer
) return NULL
;
706 return printer
->name
;
709 /******************************************************************
710 * WINSPOOL_GetOpenedPrinterRegKey
713 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
715 LPCWSTR name
= get_opened_printer_name(hPrinter
);
719 if(!name
) return ERROR_INVALID_HANDLE
;
721 if((ret
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
)) !=
725 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
727 ERR("Can't find opened printer %s in registry\n",
729 RegCloseKey(hkeyPrinters
);
730 return ERROR_INVALID_PRINTER_NAME
; /* ? */
732 RegCloseKey(hkeyPrinters
);
733 return ERROR_SUCCESS
;
736 /******************************************************************
739 * Get the pointer to the specified job.
740 * Should hold the printer_handles_cs before calling.
742 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
744 opened_printer_t
*printer
= get_opened_printer(hprn
);
747 if(!printer
) return NULL
;
748 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
750 if(job
->job_id
== JobId
)
756 /***********************************************************
759 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
762 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
765 Formname
= (dmA
->dmSize
> off_formname
);
766 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
767 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
768 dmW
->dmDeviceName
, CCHDEVICENAME
);
770 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
771 dmA
->dmSize
- CCHDEVICENAME
);
773 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
774 off_formname
- CCHDEVICENAME
);
775 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
776 dmW
->dmFormName
, CCHFORMNAME
);
777 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
778 (off_formname
+ CCHFORMNAME
));
781 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
786 /***********************************************************
788 * Creates an ascii copy of supplied devmode on heap
790 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
795 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
797 if(!dmW
) return NULL
;
798 Formname
= (dmW
->dmSize
> off_formname
);
799 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
800 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
801 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
802 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
804 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
805 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
807 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
808 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
809 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
810 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
811 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
812 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
815 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
820 /***********************************************************
822 * Creates a unicode copy of PRINTER_INFO_2A on heap
824 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
826 LPPRINTER_INFO_2W piW
;
827 UNICODE_STRING usBuffer
;
829 if(!piA
) return NULL
;
830 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
831 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
833 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
834 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
835 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
836 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
837 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
838 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
839 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
840 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
841 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
842 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
843 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
844 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
848 /***********************************************************
849 * FREE_PRINTER_INFO_2W
850 * Free PRINTER_INFO_2W and all strings
852 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
856 HeapFree(heap
,0,piW
->pServerName
);
857 HeapFree(heap
,0,piW
->pPrinterName
);
858 HeapFree(heap
,0,piW
->pShareName
);
859 HeapFree(heap
,0,piW
->pPortName
);
860 HeapFree(heap
,0,piW
->pDriverName
);
861 HeapFree(heap
,0,piW
->pComment
);
862 HeapFree(heap
,0,piW
->pLocation
);
863 HeapFree(heap
,0,piW
->pDevMode
);
864 HeapFree(heap
,0,piW
->pSepFile
);
865 HeapFree(heap
,0,piW
->pPrintProcessor
);
866 HeapFree(heap
,0,piW
->pDatatype
);
867 HeapFree(heap
,0,piW
->pParameters
);
868 HeapFree(heap
,0,piW
);
872 /******************************************************************
873 * DeviceCapabilities [WINSPOOL.@]
874 * DeviceCapabilitiesA [WINSPOOL.@]
877 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
878 LPSTR pOutput
, LPDEVMODEA lpdm
)
882 if (!GDI_CallDeviceCapabilities16
)
884 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
886 if (!GDI_CallDeviceCapabilities16
) return -1;
888 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
890 /* If DC_PAPERSIZE map POINT16s to POINTs */
891 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
892 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
893 POINT
*pt
= (POINT
*)pOutput
;
895 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
896 for(i
= 0; i
< ret
; i
++, pt
++)
901 HeapFree( GetProcessHeap(), 0, tmp
);
907 /*****************************************************************************
908 * DeviceCapabilitiesW [WINSPOOL.@]
910 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
913 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
914 WORD fwCapability
, LPWSTR pOutput
,
915 const DEVMODEW
*pDevMode
)
917 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
918 LPSTR pDeviceA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDevice
);
919 LPSTR pPortA
= HEAP_strdupWtoA(GetProcessHeap(),0,pPort
);
922 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
923 fwCapability
== DC_FILEDEPENDENCIES
||
924 fwCapability
== DC_PAPERNAMES
)) {
925 /* These need A -> W translation */
928 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
932 switch(fwCapability
) {
937 case DC_FILEDEPENDENCIES
:
941 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
942 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
944 for(i
= 0; i
< ret
; i
++)
945 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
946 pOutput
+ (i
* size
), size
);
947 HeapFree(GetProcessHeap(), 0, pOutputA
);
949 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
950 (LPSTR
)pOutput
, dmA
);
952 HeapFree(GetProcessHeap(),0,pPortA
);
953 HeapFree(GetProcessHeap(),0,pDeviceA
);
954 HeapFree(GetProcessHeap(),0,dmA
);
958 /******************************************************************
959 * DocumentPropertiesA [WINSPOOL.@]
961 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
963 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
964 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
965 LPDEVMODEA pDevModeInput
,DWORD fMode
)
967 LPSTR lpName
= pDeviceName
;
970 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
971 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
975 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
977 ERR("no name from hPrinter?\n");
978 SetLastError(ERROR_INVALID_HANDLE
);
981 lpName
= HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW
);
984 if (!GDI_CallExtDeviceMode16
)
986 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
988 if (!GDI_CallExtDeviceMode16
) {
989 ERR("No CallExtDeviceMode16?\n");
993 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, "LPT1:",
994 pDevModeInput
, NULL
, fMode
);
997 HeapFree(GetProcessHeap(),0,lpName
);
1002 /*****************************************************************************
1003 * DocumentPropertiesW (WINSPOOL.@)
1005 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1007 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1009 LPDEVMODEW pDevModeOutput
,
1010 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1013 LPSTR pDeviceNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName
);
1014 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1015 LPDEVMODEA pDevModeOutputA
= NULL
;
1018 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1019 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1021 if(pDevModeOutput
) {
1022 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1023 if(ret
< 0) return ret
;
1024 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1026 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1027 pDevModeInputA
, fMode
);
1028 if(pDevModeOutput
) {
1029 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1030 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1032 if(fMode
== 0 && ret
> 0)
1033 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1034 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1035 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1039 /******************************************************************
1040 * OpenPrinterA [WINSPOOL.@]
1045 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1046 LPPRINTER_DEFAULTSA pDefault
)
1048 UNICODE_STRING lpPrinterNameW
;
1049 UNICODE_STRING usBuffer
;
1050 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1051 PWSTR pwstrPrinterNameW
;
1054 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1057 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1058 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1059 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1060 pDefaultW
= &DefaultW
;
1062 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1064 RtlFreeUnicodeString(&usBuffer
);
1065 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1067 RtlFreeUnicodeString(&lpPrinterNameW
);
1071 /******************************************************************
1072 * OpenPrinterW [WINSPOOL.@]
1074 * Open a Printer / Printserver or a Printer-Object
1077 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1078 * phPrinter [O] The resulting Handle is stored here
1079 * pDefault [I] PTR to Default Printer Settings or NULL
1086 * lpPrinterName is one of:
1087 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1088 *| Printer: "PrinterName"
1089 *| Printer-Object: "PrinterName,Job xxx"
1090 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1091 *| XcvPort: "Servername,XcvPort PortName"
1094 *| Printserver not supported
1095 *| Printer-Object not supported
1096 *| XcvMonitor not supported
1097 *| XcvPort not supported
1098 *| pDefaults not supported
1101 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
,
1102 LPPRINTER_DEFAULTSW pDefault
)
1104 HKEY hkeyPrinters
, hkeyPrinter
;
1106 if (!lpPrinterName
) {
1107 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault
);
1108 SetLastError(ERROR_INVALID_PARAMETER
);
1112 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName
),
1115 /* Check Printer exists */
1116 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1118 ERR("Can't create Printers key\n");
1119 SetLastError(ERROR_FILE_NOT_FOUND
); /* ?? */
1123 if(lpPrinterName
[0] == '\0' || /* explicitly exclude "" */
1124 RegOpenKeyW(hkeyPrinters
, lpPrinterName
, &hkeyPrinter
)
1126 TRACE("Can't find printer %s in registry\n",
1127 debugstr_w(lpPrinterName
));
1128 RegCloseKey(hkeyPrinters
);
1129 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1132 RegCloseKey(hkeyPrinter
);
1133 RegCloseKey(hkeyPrinters
);
1135 if(!phPrinter
) /* This seems to be what win95 does anyway */
1138 /* Get the unique handle of the printer*/
1139 *phPrinter
= get_opened_printer_entry( lpPrinterName
);
1141 if (pDefault
!= NULL
)
1142 FIXME("Not handling pDefault\n");
1147 /******************************************************************
1148 * AddMonitorA [WINSPOOL.@]
1153 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1155 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName
), Level
, pMonitors
);
1156 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1160 /******************************************************************************
1161 * AddMonitorW [WINSPOOL.@]
1163 * Install a Printmonitor
1166 * pName [I] Servername or NULL (local Computer)
1167 * Level [I] Structure-Level (Must be 2)
1168 * pMonitors [I] PTR to MONITOR_INFO_2
1175 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1181 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1183 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName
), Level
, pMonitors
);
1184 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1188 /******************************************************************
1189 * DeletePrinterDriverA [WINSPOOL.@]
1193 DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
1195 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1196 debugstr_a(pDriverName
));
1197 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1201 /******************************************************************
1202 * DeletePrinterDriverW [WINSPOOL.@]
1206 DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
1208 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1209 debugstr_w(pDriverName
));
1210 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1214 /******************************************************************
1215 * DeleteMonitorA [WINSPOOL.@]
1217 * See DeleteMonitorW.
1221 DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
1223 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1224 debugstr_a(pMonitorName
));
1225 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1229 /******************************************************************
1230 * DeleteMonitorW [WINSPOOL.@]
1232 * Delete a specific Printmonitor from a Printing-Environment
1235 * pName [I] Servername or NULL (local Computer)
1236 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1237 * pMonitorName [I] Name of the Monitor, that should be deleted
1248 DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1250 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1251 debugstr_w(pMonitorName
));
1252 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1256 /******************************************************************
1257 * DeletePortA [WINSPOOL.@]
1263 DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
1265 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName
),hWnd
,
1266 debugstr_a(pPortName
));
1267 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1271 /******************************************************************
1272 * DeletePortW [WINSPOOL.@]
1274 * Delete a specific Port
1277 * pName [I] Servername or NULL (local Computer)
1278 * hWnd [I] Handle to parent Window for the Dialog-Box
1279 * pPortName [I] Name of the Port, that should be deleted
1290 DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1292 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName
),hWnd
,
1293 debugstr_w(pPortName
));
1294 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1298 /******************************************************************************
1299 * SetPrinterW [WINSPOOL.@]
1309 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1313 /******************************************************************************
1314 * WritePrinter [WINSPOOL.@]
1316 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
1318 opened_printer_t
*printer
;
1321 TRACE("(%p, %p, %ld, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
1323 EnterCriticalSection(&printer_handles_cs
);
1324 printer
= get_opened_printer(hPrinter
);
1327 SetLastError(ERROR_INVALID_HANDLE
);
1333 SetLastError(ERROR_SPL_NO_STARTDOC
);
1337 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
1339 LeaveCriticalSection(&printer_handles_cs
);
1343 /*****************************************************************************
1344 * AddFormA [WINSPOOL.@]
1346 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1348 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1352 /*****************************************************************************
1353 * AddFormW [WINSPOOL.@]
1355 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1357 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1361 /*****************************************************************************
1362 * AddJobA [WINSPOOL.@]
1364 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1367 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
1371 SetLastError(ERROR_INVALID_LEVEL
);
1375 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
1378 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
1379 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
1380 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
1381 if(*pcbNeeded
> cbBuf
) {
1382 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1385 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
1386 addjobA
->JobId
= addjobW
->JobId
;
1387 addjobA
->Path
= (char *)(addjobA
+ 1);
1388 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
1394 /*****************************************************************************
1395 * AddJobW [WINSPOOL.@]
1397 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1399 opened_printer_t
*printer
;
1402 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1403 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
1404 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
1406 ADDJOB_INFO_1W
*addjob
;
1408 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
1410 EnterCriticalSection(&printer_handles_cs
);
1412 printer
= get_opened_printer(hPrinter
);
1415 SetLastError(ERROR_INVALID_HANDLE
);
1420 SetLastError(ERROR_INVALID_LEVEL
);
1424 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
1428 job
->job_id
= InterlockedIncrement(&next_job_id
);
1430 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
1431 if(path
[len
- 1] != '\\')
1433 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
1434 sprintfW(filename
, fmtW
, path
, job
->job_id
);
1436 len
= strlenW(filename
);
1437 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1438 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
1439 job
->document_title
= strdupW(default_doc_title
);
1440 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
1442 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
1443 if(*pcbNeeded
<= cbBuf
) {
1444 addjob
= (ADDJOB_INFO_1W
*)pData
;
1445 addjob
->JobId
= job
->job_id
;
1446 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
1447 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
1450 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1453 LeaveCriticalSection(&printer_handles_cs
);
1457 /*****************************************************************************
1458 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1460 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
1461 DWORD level
, LPBYTE Info
,
1462 DWORD cbBuf
, LPDWORD needed
)
1464 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server
), debugstr_a(env
),
1465 level
, Info
, cbBuf
);
1469 /*****************************************************************************
1470 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1472 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
1473 DWORD level
, LPBYTE Info
,
1474 DWORD cbBuf
, LPDWORD needed
)
1476 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server
), debugstr_w(env
),
1477 level
, Info
, cbBuf
);
1481 /*****************************************************************************
1482 * WINSPOOL_OpenDriverReg [internal]
1484 * opens the registry for the printer drivers depending on the given input
1485 * variable pEnvironment
1488 * the opened hkey on success
1491 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
)
1493 static const WCHAR WinNTW
[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1494 static const WCHAR Win40W
[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1496 LPWSTR lpKey
, buffer
= NULL
;
1500 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
));
1504 pEnvW
= pEnvironment
;
1506 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
1507 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1508 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
1513 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
1515 if(!GetVersionExW( &ver
))
1518 switch (ver
.dwPlatformId
) {
1519 case VER_PLATFORM_WIN32s
:
1520 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1522 case VER_PLATFORM_WIN32_NT
:
1529 TRACE("set environment to %s\n", debugstr_w(pEnvW
));
1532 lpKey
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1533 (strlenW(pEnvW
) + strlenW(DriversW
) + 1) * sizeof(WCHAR
));
1534 wsprintfW( lpKey
, DriversW
, pEnvW
);
1536 TRACE("%s\n", debugstr_w(lpKey
));
1538 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, lpKey
, &retval
) != ERROR_SUCCESS
)
1541 HeapFree( GetProcessHeap(), 0, buffer
);
1542 HeapFree( GetProcessHeap(), 0, lpKey
);
1547 /*****************************************************************************
1548 * AddPrinterW [WINSPOOL.@]
1550 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1552 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
1556 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
1559 TRACE("(%s,%ld,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
1562 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
1563 SetLastError(ERROR_INVALID_PARAMETER
);
1567 ERR("Level = %ld, unsupported!\n", Level
);
1568 SetLastError(ERROR_INVALID_LEVEL
);
1571 if (strlenW(pi
->pPrinterName
) >= CCHDEVICENAME
) {
1572 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1573 debugstr_w(pi
->pPrinterName
)
1575 SetLastError(ERROR_INVALID_LEVEL
);
1579 SetLastError(ERROR_INVALID_PARAMETER
);
1582 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1584 ERR("Can't create Printers key\n");
1587 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
1588 if (!RegQueryValueA(hkeyPrinter
,"Attributes",NULL
,NULL
)) {
1589 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
1590 RegCloseKey(hkeyPrinter
);
1591 RegCloseKey(hkeyPrinters
);
1594 RegCloseKey(hkeyPrinter
);
1596 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
1598 ERR("Can't create Drivers key\n");
1599 RegCloseKey(hkeyPrinters
);
1602 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
1604 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
1605 RegCloseKey(hkeyPrinters
);
1606 RegCloseKey(hkeyDrivers
);
1607 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
1610 RegCloseKey(hkeyDriver
);
1611 RegCloseKey(hkeyDrivers
);
1613 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
1614 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
1615 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
1616 RegCloseKey(hkeyPrinters
);
1620 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
1622 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
1623 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1624 RegCloseKey(hkeyPrinters
);
1627 RegSetValueExA(hkeyPrinter
, "Attributes", 0, REG_DWORD
,
1628 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
1629 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
1631 /* See if we can load the driver. We may need the devmode structure anyway
1634 * Note that DocumentPropertiesW will briefly try to open the printer we
1635 * just create to find a DEVMODEA struct (it will use the WINEPS default
1636 * one in case it is not there, so we are ok).
1638 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
1641 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi
->pPrinterName
));
1642 size
= sizeof(DEVMODEW
);
1648 dmW
= HeapAlloc(GetProcessHeap(), 0, size
);
1649 ZeroMemory(dmW
,size
);
1651 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
1653 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi
->pPrinterName
));
1654 HeapFree(GetProcessHeap(),0,dmW
);
1659 /* set devmode to printer name */
1660 strcpyW(dmW
->dmDeviceName
,pi
->pPrinterName
);
1664 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1665 and we support these drivers. NT writes DEVMODEW so somehow
1666 we'll need to distinguish between these when we support NT
1670 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
1671 RegSetValueExA(hkeyPrinter
, "Default DevMode", 0, REG_BINARY
,
1672 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1673 HeapFree(GetProcessHeap(), 0, dmA
);
1675 HeapFree(GetProcessHeap(), 0, dmW
);
1677 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
1678 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
1679 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
1680 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
1682 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
1683 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
1684 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
1685 RegSetValueExA(hkeyPrinter
, "Priority", 0, REG_DWORD
,
1686 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
1687 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
1688 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
1689 RegSetValueExA(hkeyPrinter
, "StartTime", 0, REG_DWORD
,
1690 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
1691 RegSetValueExA(hkeyPrinter
, "Status", 0, REG_DWORD
,
1692 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
1693 RegSetValueExA(hkeyPrinter
, "UntilTime", 0, REG_DWORD
,
1694 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
1696 RegCloseKey(hkeyPrinter
);
1697 RegCloseKey(hkeyPrinters
);
1698 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
1699 ERR("OpenPrinter failing\n");
1705 /*****************************************************************************
1706 * AddPrinterA [WINSPOOL.@]
1708 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1710 UNICODE_STRING pNameW
;
1712 PRINTER_INFO_2W
*piW
;
1713 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
1716 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
1718 ERR("Level = %ld, unsupported!\n", Level
);
1719 SetLastError(ERROR_INVALID_LEVEL
);
1722 pwstrNameW
= asciitounicode(&pNameW
,pName
);
1723 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
1725 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
1727 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
1728 RtlFreeUnicodeString(&pNameW
);
1733 /*****************************************************************************
1734 * ClosePrinter [WINSPOOL.@]
1736 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
1738 UINT_PTR i
= (UINT_PTR
)hPrinter
;
1739 opened_printer_t
*printer
= NULL
;
1742 TRACE("Handle %p\n", hPrinter
);
1744 EnterCriticalSection(&printer_handles_cs
);
1746 if ((i
> 0) && (i
<= nb_printer_handles
))
1747 printer
= printer_handles
[i
- 1];
1751 struct list
*cursor
, *cursor2
;
1754 EndDocPrinter(hPrinter
);
1756 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
1758 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
1760 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
1761 ScheduleJob(hPrinter
, job
->job_id
);
1763 HeapFree(GetProcessHeap(), 0, printer
->queue
);
1765 HeapFree(GetProcessHeap(), 0, printer
->name
);
1766 HeapFree(GetProcessHeap(), 0, printer
);
1767 printer_handles
[i
- 1] = NULL
;
1770 LeaveCriticalSection(&printer_handles_cs
);
1774 /*****************************************************************************
1775 * DeleteFormA [WINSPOOL.@]
1777 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
1779 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
1783 /*****************************************************************************
1784 * DeleteFormW [WINSPOOL.@]
1786 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
1788 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
1792 /*****************************************************************************
1793 * WINSPOOL_SHRegDeleteKey
1795 * Recursively delete subkeys.
1796 * Cut & paste from shlwapi.
1799 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
)
1801 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1802 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1805 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1808 /* Find how many subkeys there are */
1809 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1810 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1814 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1815 /* Name too big: alloc a buffer for it */
1816 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
1819 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1822 /* Recursively delete all the subkeys */
1823 for(i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1825 dwSize
= dwMaxSubkeyLen
;
1826 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1828 dwRet
= WINSPOOL_SHDeleteKeyW(hSubKey
, lpszName
);
1831 if (lpszName
!= szNameBuf
)
1832 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
1836 RegCloseKey(hSubKey
);
1838 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1843 /*****************************************************************************
1844 * DeletePrinter [WINSPOOL.@]
1846 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
1848 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1849 HKEY hkeyPrinters
, hkey
;
1852 SetLastError(ERROR_INVALID_HANDLE
);
1855 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1856 WINSPOOL_SHDeleteKeyW(hkeyPrinters
, lpNameW
);
1857 RegCloseKey(hkeyPrinters
);
1859 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
1860 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1861 RegDeleteValueW(hkey
, lpNameW
);
1867 /*****************************************************************************
1868 * SetPrinterA [WINSPOOL.@]
1870 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
1873 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter
,Level
,pPrinter
,Command
);
1877 /*****************************************************************************
1878 * SetJobA [WINSPOOL.@]
1880 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1881 LPBYTE pJob
, DWORD Command
)
1885 UNICODE_STRING usBuffer
;
1887 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
1889 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1890 are all ignored by SetJob, so we don't bother copying them */
1898 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
1899 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
1901 JobW
= (LPBYTE
)info1W
;
1902 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
1903 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
1904 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
1905 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
1906 info1W
->Status
= info1A
->Status
;
1907 info1W
->Priority
= info1A
->Priority
;
1908 info1W
->Position
= info1A
->Position
;
1909 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
1914 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
1915 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
1917 JobW
= (LPBYTE
)info2W
;
1918 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
1919 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
1920 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
1921 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
1922 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
1923 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
1924 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
1925 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
1926 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
1927 info2W
->Status
= info2A
->Status
;
1928 info2W
->Priority
= info2A
->Priority
;
1929 info2W
->Position
= info2A
->Position
;
1930 info2W
->StartTime
= info2A
->StartTime
;
1931 info2W
->UntilTime
= info2A
->UntilTime
;
1932 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
1936 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
1937 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
1940 SetLastError(ERROR_INVALID_LEVEL
);
1944 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
1950 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
1951 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
1952 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
1953 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
1954 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
1959 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
1960 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
1961 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
1962 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
1963 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
1964 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
1965 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
1966 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
1967 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
1971 HeapFree(GetProcessHeap(), 0, JobW
);
1976 /*****************************************************************************
1977 * SetJobW [WINSPOOL.@]
1979 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1980 LPBYTE pJob
, DWORD Command
)
1985 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
1986 FIXME("Ignoring everything other than document title\n");
1988 EnterCriticalSection(&printer_handles_cs
);
1989 job
= get_job(hPrinter
, JobId
);
1999 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2000 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2001 job
->document_title
= strdupW(info1
->pDocument
);
2006 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2007 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2008 job
->document_title
= strdupW(info2
->pDocument
);
2014 SetLastError(ERROR_INVALID_LEVEL
);
2019 LeaveCriticalSection(&printer_handles_cs
);
2023 /*****************************************************************************
2024 * EndDocPrinter [WINSPOOL.@]
2026 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2028 opened_printer_t
*printer
;
2030 TRACE("(%p)\n", hPrinter
);
2032 EnterCriticalSection(&printer_handles_cs
);
2034 printer
= get_opened_printer(hPrinter
);
2037 SetLastError(ERROR_INVALID_HANDLE
);
2043 SetLastError(ERROR_SPL_NO_STARTDOC
);
2047 CloseHandle(printer
->doc
->hf
);
2048 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2049 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2050 printer
->doc
= NULL
;
2053 LeaveCriticalSection(&printer_handles_cs
);
2057 /*****************************************************************************
2058 * EndPagePrinter [WINSPOOL.@]
2060 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2062 FIXME("(%p): stub\n", hPrinter
);
2066 /*****************************************************************************
2067 * StartDocPrinterA [WINSPOOL.@]
2069 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2071 UNICODE_STRING usBuffer
;
2073 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2076 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2077 or one (DOC_INFO_3) extra DWORDs */
2081 doc2W
.JobId
= doc2
->JobId
;
2084 doc2W
.dwMode
= doc2
->dwMode
;
2087 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2088 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2089 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
2093 SetLastError(ERROR_INVALID_LEVEL
);
2097 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
2099 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
2100 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
2101 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
2106 /*****************************************************************************
2107 * StartDocPrinterW [WINSPOOL.@]
2109 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2111 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
2112 opened_printer_t
*printer
;
2113 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2114 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
2115 JOB_INFO_1W job_info
;
2116 DWORD needed
, ret
= 0;
2120 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2121 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
2122 debugstr_w(doc
->pDatatype
));
2124 if(Level
< 1 || Level
> 3)
2126 SetLastError(ERROR_INVALID_LEVEL
);
2130 EnterCriticalSection(&printer_handles_cs
);
2131 printer
= get_opened_printer(hPrinter
);
2134 SetLastError(ERROR_INVALID_HANDLE
);
2140 SetLastError(ERROR_INVALID_PRINTER_STATE
);
2144 /* Even if we're printing to a file we still add a print job, we'll
2145 just ignore the spool file name */
2147 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
2149 ERR("AddJob failed gle %08lx\n", GetLastError());
2153 if(doc
->pOutputFile
)
2154 filename
= doc
->pOutputFile
;
2156 filename
= addjob
->Path
;
2158 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
2159 if(hf
== INVALID_HANDLE_VALUE
)
2162 memset(&job_info
, 0, sizeof(job_info
));
2163 job_info
.pDocument
= doc
->pDocName
;
2164 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
2166 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
2167 printer
->doc
->hf
= hf
;
2168 ret
= printer
->doc
->job_id
= addjob
->JobId
;
2170 LeaveCriticalSection(&printer_handles_cs
);
2175 /*****************************************************************************
2176 * StartPagePrinter [WINSPOOL.@]
2178 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
2180 FIXME("(%p): stub\n", hPrinter
);
2184 /*****************************************************************************
2185 * GetFormA [WINSPOOL.@]
2187 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2188 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2190 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,pFormName
,
2191 Level
,pForm
,cbBuf
,pcbNeeded
);
2195 /*****************************************************************************
2196 * GetFormW [WINSPOOL.@]
2198 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2199 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2201 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,
2202 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
2206 /*****************************************************************************
2207 * SetFormA [WINSPOOL.@]
2209 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2212 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2216 /*****************************************************************************
2217 * SetFormW [WINSPOOL.@]
2219 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2222 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2226 /*****************************************************************************
2227 * ReadPrinter [WINSPOOL.@]
2229 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
2230 LPDWORD pNoBytesRead
)
2232 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
2236 /*****************************************************************************
2237 * ResetPrinterA [WINSPOOL.@]
2239 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
2241 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2245 /*****************************************************************************
2246 * ResetPrinterW [WINSPOOL.@]
2248 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2250 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2254 /*****************************************************************************
2255 * WINSPOOL_GetDWORDFromReg
2257 * Return DWORD associated with ValueName from hkey.
2259 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
2261 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
2264 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
2266 if(ret
!= ERROR_SUCCESS
) {
2267 WARN("Got ret = %ld on name %s\n", ret
, ValueName
);
2270 if(type
!= REG_DWORD
) {
2271 ERR("Got type %ld\n", type
);
2277 /*****************************************************************************
2278 * WINSPOOL_GetStringFromReg
2280 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2281 * String is stored either as unicode or ascii.
2282 * Bit of a hack here to get the ValueName if we want ascii.
2284 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
2285 DWORD buflen
, DWORD
*needed
,
2288 DWORD sz
= buflen
, type
;
2292 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2294 LPSTR ValueNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,ValueName
);
2295 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
2296 HeapFree(GetProcessHeap(),0,ValueNameA
);
2298 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
2299 WARN("Got ret = %ld\n", ret
);
2307 /*****************************************************************************
2308 * WINSPOOL_GetDefaultDevMode
2310 * Get a default DevMode values for wineps.
2314 static void WINSPOOL_GetDefaultDevMode(
2316 DWORD buflen
, DWORD
*needed
,
2320 static const char szwps
[] = "wineps.drv";
2322 /* fill default DEVMODE - should be read from ppd... */
2323 ZeroMemory( &dm
, sizeof(dm
) );
2324 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
2325 dm
.dmSpecVersion
= DM_SPECVERSION
;
2326 dm
.dmDriverVersion
= 1;
2327 dm
.dmSize
= sizeof(DEVMODEA
);
2328 dm
.dmDriverExtra
= 0;
2330 DM_ORIENTATION
| DM_PAPERSIZE
|
2331 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
2334 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
2335 DM_YRESOLUTION
| DM_TTOPTION
;
2337 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
2338 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
2339 dm
.u1
.s1
.dmPaperLength
= 2970;
2340 dm
.u1
.s1
.dmPaperWidth
= 2100;
2344 dm
.dmDefaultSource
= DMBIN_AUTO
;
2345 dm
.dmPrintQuality
= DMRES_MEDIUM
;
2348 dm
.dmYResolution
= 300; /* 300dpi */
2349 dm
.dmTTOption
= DMTT_BITMAP
;
2352 /* dm.dmLogPixels */
2353 /* dm.dmBitsPerPel */
2354 /* dm.dmPelsWidth */
2355 /* dm.dmPelsHeight */
2356 /* dm.dmDisplayFlags */
2357 /* dm.dmDisplayFrequency */
2358 /* dm.dmICMMethod */
2359 /* dm.dmICMIntent */
2360 /* dm.dmMediaType */
2361 /* dm.dmDitherType */
2362 /* dm.dmReserved1 */
2363 /* dm.dmReserved2 */
2364 /* dm.dmPanningWidth */
2365 /* dm.dmPanningHeight */
2368 if(buflen
>= sizeof(DEVMODEW
)) {
2369 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
2370 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
2371 HeapFree(GetProcessHeap(),0,pdmW
);
2373 *needed
= sizeof(DEVMODEW
);
2377 if(buflen
>= sizeof(DEVMODEA
)) {
2378 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
2380 *needed
= sizeof(DEVMODEA
);
2384 /*****************************************************************************
2385 * WINSPOOL_GetDevModeFromReg
2387 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2388 * DevMode is stored either as unicode or ascii.
2390 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
2392 DWORD buflen
, DWORD
*needed
,
2395 DWORD sz
= buflen
, type
;
2398 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
2399 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2400 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
2401 if (sz
< sizeof(DEVMODEA
))
2403 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName
),sz
);
2406 /* ensures that dmSize is not erratically bogus if registry is invalid */
2407 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
2408 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
2410 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2412 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
2413 memcpy(ptr
, dmW
, sz
);
2414 HeapFree(GetProcessHeap(),0,dmW
);
2421 /*********************************************************************
2422 * WINSPOOL_GetPrinter_2
2424 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2425 * The strings are either stored as unicode or ascii.
2427 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
2428 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2431 DWORD size
, left
= cbBuf
;
2432 BOOL space
= (cbBuf
> 0);
2437 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2439 if(space
&& size
<= left
) {
2440 pi2
->pPrinterName
= (LPWSTR
)ptr
;
2447 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
2449 if(space
&& size
<= left
) {
2450 pi2
->pShareName
= (LPWSTR
)ptr
;
2457 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2459 if(space
&& size
<= left
) {
2460 pi2
->pPortName
= (LPWSTR
)ptr
;
2467 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
2469 if(space
&& size
<= left
) {
2470 pi2
->pDriverName
= (LPWSTR
)ptr
;
2477 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
2479 if(space
&& size
<= left
) {
2480 pi2
->pComment
= (LPWSTR
)ptr
;
2487 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
2489 if(space
&& size
<= left
) {
2490 pi2
->pLocation
= (LPWSTR
)ptr
;
2497 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
2499 if(space
&& size
<= left
) {
2500 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2509 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
2510 if(space
&& size
<= left
) {
2511 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2518 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
2520 if(space
&& size
<= left
) {
2521 pi2
->pSepFile
= (LPWSTR
)ptr
;
2528 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
2530 if(space
&& size
<= left
) {
2531 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
2538 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
2540 if(space
&& size
<= left
) {
2541 pi2
->pDatatype
= (LPWSTR
)ptr
;
2548 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
2550 if(space
&& size
<= left
) {
2551 pi2
->pParameters
= (LPWSTR
)ptr
;
2559 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2560 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
2561 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2562 "Default Priority");
2563 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
2564 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
2567 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
2568 memset(pi2
, 0, sizeof(*pi2
));
2573 /*********************************************************************
2574 * WINSPOOL_GetPrinter_4
2576 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2578 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
2579 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2582 DWORD size
, left
= cbBuf
;
2583 BOOL space
= (cbBuf
> 0);
2588 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2590 if(space
&& size
<= left
) {
2591 pi4
->pPrinterName
= (LPWSTR
)ptr
;
2599 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2602 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
2603 memset(pi4
, 0, sizeof(*pi4
));
2608 /*********************************************************************
2609 * WINSPOOL_GetPrinter_5
2611 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2613 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
2614 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2617 DWORD size
, left
= cbBuf
;
2618 BOOL space
= (cbBuf
> 0);
2623 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2625 if(space
&& size
<= left
) {
2626 pi5
->pPrinterName
= (LPWSTR
)ptr
;
2633 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2635 if(space
&& size
<= left
) {
2636 pi5
->pPortName
= (LPWSTR
)ptr
;
2644 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2645 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2647 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2651 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
2652 memset(pi5
, 0, sizeof(*pi5
));
2657 /*****************************************************************************
2658 * WINSPOOL_GetPrinter
2660 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2661 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2662 * just a collection of pointers to strings.
2664 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2665 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
2668 DWORD size
, needed
= 0;
2670 HKEY hkeyPrinter
, hkeyPrinters
;
2673 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
2675 if (!(name
= get_opened_printer_name(hPrinter
))) {
2676 SetLastError(ERROR_INVALID_HANDLE
);
2680 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2682 ERR("Can't create Printers key\n");
2685 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
2687 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
2688 RegCloseKey(hkeyPrinters
);
2689 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
2696 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
2698 size
= sizeof(PRINTER_INFO_2W
);
2700 ptr
= pPrinter
+ size
;
2702 memset(pPrinter
, 0, size
);
2707 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
2715 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
2717 size
= sizeof(PRINTER_INFO_4W
);
2719 ptr
= pPrinter
+ size
;
2721 memset(pPrinter
, 0, size
);
2726 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
2735 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
2737 size
= sizeof(PRINTER_INFO_5W
);
2739 ptr
= pPrinter
+ size
;
2741 memset(pPrinter
, 0, size
);
2747 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
2754 FIXME("Unimplemented level %ld\n", Level
);
2755 SetLastError(ERROR_INVALID_LEVEL
);
2756 RegCloseKey(hkeyPrinters
);
2757 RegCloseKey(hkeyPrinter
);
2761 RegCloseKey(hkeyPrinter
);
2762 RegCloseKey(hkeyPrinters
);
2764 TRACE("returning %d needed = %ld\n", ret
, needed
);
2765 if(pcbNeeded
) *pcbNeeded
= needed
;
2767 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2771 /*****************************************************************************
2772 * GetPrinterW [WINSPOOL.@]
2774 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2775 DWORD cbBuf
, LPDWORD pcbNeeded
)
2777 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2781 /*****************************************************************************
2782 * GetPrinterA [WINSPOOL.@]
2784 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2785 DWORD cbBuf
, LPDWORD pcbNeeded
)
2787 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2791 /*****************************************************************************
2792 * WINSPOOL_EnumPrinters
2794 * Implementation of EnumPrintersA|W
2796 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
2797 DWORD dwLevel
, LPBYTE lpbPrinters
,
2798 DWORD cbBuf
, LPDWORD lpdwNeeded
,
2799 LPDWORD lpdwReturned
, BOOL unicode
)
2802 HKEY hkeyPrinters
, hkeyPrinter
;
2803 WCHAR PrinterName
[255];
2804 DWORD needed
= 0, number
= 0;
2805 DWORD used
, i
, left
;
2809 memset(lpbPrinters
, 0, cbBuf
);
2815 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2816 if(dwType
== PRINTER_ENUM_DEFAULT
)
2819 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
2820 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2821 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
2822 if(!dwType
) return TRUE
;
2825 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
2826 FIXME("dwType = %08lx\n", dwType
);
2827 SetLastError(ERROR_INVALID_FLAGS
);
2831 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2833 ERR("Can't create Printers key\n");
2837 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
2838 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
2839 RegCloseKey(hkeyPrinters
);
2840 ERR("Can't query Printers key\n");
2843 TRACE("Found %ld printers\n", number
);
2847 RegCloseKey(hkeyPrinters
);
2849 *lpdwReturned
= number
;
2853 used
= number
* sizeof(PRINTER_INFO_2W
);
2856 used
= number
* sizeof(PRINTER_INFO_4W
);
2859 used
= number
* sizeof(PRINTER_INFO_5W
);
2863 SetLastError(ERROR_INVALID_LEVEL
);
2864 RegCloseKey(hkeyPrinters
);
2867 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
2869 for(i
= 0; i
< number
; i
++) {
2870 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
2872 ERR("Can't enum key number %ld\n", i
);
2873 RegCloseKey(hkeyPrinters
);
2876 TRACE("Printer %ld is %s\n", i
, debugstr_w(PrinterName
));
2877 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
2879 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
2880 RegCloseKey(hkeyPrinters
);
2885 buf
= lpbPrinters
+ used
;
2886 left
= cbBuf
- used
;
2894 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
2895 left
, &needed
, unicode
);
2897 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
2900 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
2901 left
, &needed
, unicode
);
2903 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
2906 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
2907 left
, &needed
, unicode
);
2909 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
2912 ERR("Shouldn't be here!\n");
2913 RegCloseKey(hkeyPrinter
);
2914 RegCloseKey(hkeyPrinters
);
2917 RegCloseKey(hkeyPrinter
);
2919 RegCloseKey(hkeyPrinters
);
2926 memset(lpbPrinters
, 0, cbBuf
);
2927 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2931 *lpdwReturned
= number
;
2932 SetLastError(ERROR_SUCCESS
);
2937 /******************************************************************
2938 * EnumPrintersW [WINSPOOL.@]
2940 * Enumerates the available printers, print servers and print
2941 * providers, depending on the specified flags, name and level.
2945 * If level is set to 1:
2946 * Not implemented yet!
2947 * Returns TRUE with an empty list.
2949 * If level is set to 2:
2950 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2951 * Returns an array of PRINTER_INFO_2 data structures in the
2952 * lpbPrinters buffer. Note that according to MSDN also an
2953 * OpenPrinter should be performed on every remote printer.
2955 * If level is set to 4 (officially WinNT only):
2956 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2957 * Fast: Only the registry is queried to retrieve printer names,
2958 * no connection to the driver is made.
2959 * Returns an array of PRINTER_INFO_4 data structures in the
2960 * lpbPrinters buffer.
2962 * If level is set to 5 (officially WinNT4/Win9x only):
2963 * Fast: Only the registry is queried to retrieve printer names,
2964 * no connection to the driver is made.
2965 * Returns an array of PRINTER_INFO_5 data structures in the
2966 * lpbPrinters buffer.
2968 * If level set to 3 or 6+:
2969 * returns zero (failure!)
2971 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2975 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2976 * - Only levels 2, 4 and 5 are implemented at the moment.
2977 * - 16-bit printer drivers are not enumerated.
2978 * - Returned amount of bytes used/needed does not match the real Windoze
2979 * implementation (as in this implementation, all strings are part
2980 * of the buffer, whereas Win32 keeps them somewhere else)
2981 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2984 * - In a regular Wine installation, no registry settings for printers
2985 * exist, which makes this function return an empty list.
2987 BOOL WINAPI
EnumPrintersW(
2988 DWORD dwType
, /* [in] Types of print objects to enumerate */
2989 LPWSTR lpszName
, /* [in] name of objects to enumerate */
2990 DWORD dwLevel
, /* [in] type of printer info structure */
2991 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
2992 DWORD cbBuf
, /* [in] max size of buffer in bytes */
2993 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
2994 LPDWORD lpdwReturned
/* [out] number of entries returned */
2997 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
2998 lpdwNeeded
, lpdwReturned
, TRUE
);
3001 /******************************************************************
3002 * EnumPrintersA [WINSPOOL.@]
3005 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
3006 DWORD dwLevel
, LPBYTE lpbPrinters
,
3007 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3008 LPDWORD lpdwReturned
)
3011 UNICODE_STRING lpszNameW
;
3014 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
3015 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
3016 lpdwNeeded
, lpdwReturned
, FALSE
);
3017 RtlFreeUnicodeString(&lpszNameW
);
3021 /*****************************************************************************
3022 * WINSPOOL_GetDriverInfoFromReg [internal]
3024 * Enters the information from the registry into the DRIVER_INFO struct
3027 * zero if the printer driver does not exist in the registry
3028 * (only if Level > 1) otherwise nonzero
3030 static BOOL
WINSPOOL_GetDriverInfoFromReg(
3033 LPWSTR pEnvironment
,
3035 LPBYTE ptr
, /* DRIVER_INFO */
3036 LPBYTE pDriverStrings
, /* strings buffer */
3037 DWORD cbBuf
, /* size of string buffer */
3038 LPDWORD pcbNeeded
, /* space needed for str. */
3039 BOOL unicode
) /* type of strings */
3040 { DWORD dw
, size
, tmp
, type
;
3042 LPBYTE strPtr
= pDriverStrings
;
3044 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3045 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
3046 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
3049 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
3050 if (*pcbNeeded
<= cbBuf
)
3051 strcpyW((LPWSTR
)strPtr
, DriverName
);
3053 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
3055 if(*pcbNeeded
<= cbBuf
)
3056 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1,
3057 (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
3061 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
3065 ((PDRIVER_INFO_3W
) ptr
)->pName
= (LPWSTR
) strPtr
;
3066 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3069 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
3070 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName
));
3071 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
3076 if(RegQueryValueExA(hkeyDriver
, "Version", 0, &type
, (PBYTE
)&dw
, &size
) !=
3078 WARN("Can't get Version\n");
3080 ((PDRIVER_INFO_3A
) ptr
)->cVersion
= dw
;
3083 pEnvironment
= (LPWSTR
)DefaultEnvironmentW
;
3085 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
3087 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
3090 if(*pcbNeeded
<= cbBuf
) {
3092 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
3094 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1,
3095 (LPSTR
)strPtr
, size
, NULL
, NULL
);
3097 ((PDRIVER_INFO_3W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
3098 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3101 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
3104 if(*pcbNeeded
<= cbBuf
)
3105 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
3108 ((PDRIVER_INFO_3W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
3109 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3112 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
3115 if(*pcbNeeded
<= cbBuf
)
3116 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
3119 ((PDRIVER_INFO_3W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
3120 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3123 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3124 0, &size
, unicode
)) {
3126 if(*pcbNeeded
<= cbBuf
)
3127 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3128 size
, &tmp
, unicode
);
3130 ((PDRIVER_INFO_3W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
3131 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3135 RegCloseKey(hkeyDriver
);
3136 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3140 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
3143 if(*pcbNeeded
<= cbBuf
)
3144 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
3145 size
, &tmp
, unicode
);
3147 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
3148 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3151 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
3154 if(*pcbNeeded
<= cbBuf
)
3155 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
3156 size
, &tmp
, unicode
);
3158 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
3159 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3162 if(WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
3165 if(*pcbNeeded
<= cbBuf
)
3166 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
3167 size
, &tmp
, unicode
);
3169 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
3170 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3173 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
3176 if(*pcbNeeded
<= cbBuf
)
3177 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
,
3178 size
, &tmp
, unicode
);
3180 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
3181 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3184 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3185 RegCloseKey(hkeyDriver
);
3189 /*****************************************************************************
3190 * WINSPOOL_GetPrinterDriver
3192 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
3193 DWORD Level
, LPBYTE pDriverInfo
,
3194 DWORD cbBuf
, LPDWORD pcbNeeded
,
3198 WCHAR DriverName
[100];
3199 DWORD ret
, type
, size
, needed
= 0;
3201 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
3203 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
3204 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
3206 ZeroMemory(pDriverInfo
, cbBuf
);
3208 if (!(name
= get_opened_printer_name(hPrinter
))) {
3209 SetLastError(ERROR_INVALID_HANDLE
);
3212 if(Level
< 1 || Level
> 3) {
3213 SetLastError(ERROR_INVALID_LEVEL
);
3216 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
3218 ERR("Can't create Printers key\n");
3221 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
3223 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3224 RegCloseKey(hkeyPrinters
);
3225 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3228 size
= sizeof(DriverName
);
3230 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
3231 (LPBYTE
)DriverName
, &size
);
3232 RegCloseKey(hkeyPrinter
);
3233 RegCloseKey(hkeyPrinters
);
3234 if(ret
!= ERROR_SUCCESS
) {
3235 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
3239 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
3241 ERR("Can't create Drivers key\n");
3247 size
= sizeof(DRIVER_INFO_1W
);
3250 size
= sizeof(DRIVER_INFO_2W
);
3253 size
= sizeof(DRIVER_INFO_3W
);
3256 ERR("Invalid level\n");
3261 ptr
= pDriverInfo
+ size
;
3263 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
3264 pEnvironment
, Level
, pDriverInfo
,
3265 (cbBuf
< size
) ? NULL
: ptr
,
3266 (cbBuf
< size
) ? 0 : cbBuf
- size
,
3267 &needed
, unicode
)) {
3268 RegCloseKey(hkeyDrivers
);
3272 RegCloseKey(hkeyDrivers
);
3274 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
3275 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3276 if(cbBuf
>= needed
) return TRUE
;
3277 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3281 /*****************************************************************************
3282 * GetPrinterDriverA [WINSPOOL.@]
3284 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
3285 DWORD Level
, LPBYTE pDriverInfo
,
3286 DWORD cbBuf
, LPDWORD pcbNeeded
)
3289 UNICODE_STRING pEnvW
;
3292 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
3293 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
3294 cbBuf
, pcbNeeded
, FALSE
);
3295 RtlFreeUnicodeString(&pEnvW
);
3298 /*****************************************************************************
3299 * GetPrinterDriverW [WINSPOOL.@]
3301 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
3302 DWORD Level
, LPBYTE pDriverInfo
,
3303 DWORD cbBuf
, LPDWORD pcbNeeded
)
3305 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
3306 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
3309 /*****************************************************************************
3310 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3312 * Return the PATH for the Printer-Drivers (UNICODE)
3315 * pName [I] Servername (NT only) or NULL (local Computer)
3316 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3317 * Level [I] Structure-Level (must be 1)
3318 * pDriverDirectory [O] PTR to Buffer that receives the Result
3319 * cbBuf [I] Size of Buffer at pDriverDirectory
3320 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3321 * required for pDriverDirectory
3324 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3325 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3326 * if cbBuf is too small
3328 * Native Values returned in pDriverDirectory on Success:
3329 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3330 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3331 *| win9x(Windows 4.0): "%winsysdir%"
3333 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3336 *- pName != NULL not supported
3337 *- pEnvironment != NULL not supported
3338 *- Current Implementation returns always "%winsysdir%"
3341 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
3342 DWORD Level
, LPBYTE pDriverDirectory
,
3343 DWORD cbBuf
, LPDWORD pcbNeeded
)
3347 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
3348 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
3350 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName
));
3351 SetLastError(ERROR_INVALID_PARAMETER
);
3354 if(pEnvironment
!= NULL
) {
3355 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment
));
3356 SetLastError(ERROR_INVALID_ENVIRONMENT
);
3359 if(Level
!= 1) /* win95 ignores this so we just carry on */
3360 WARN("Level = %ld - assuming 1\n", Level
);
3362 /* FIXME should read from registry */
3363 needed
= GetSystemDirectoryW( (LPWSTR
)pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
3364 /* GetSystemDirectoryW returns number of TCHAR without '\0'
3368 needed
*=sizeof(WCHAR
);
3371 *pcbNeeded
= needed
;
3372 TRACE("required <%08lx>\n", *pcbNeeded
);
3373 if(needed
> cbBuf
) {
3374 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3381 /*****************************************************************************
3382 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3384 * Return the PATH for the Printer-Drivers (ANSI)
3386 * See GetPrinterDriverDirectoryW.
3389 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3392 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
3393 DWORD Level
, LPBYTE pDriverDirectory
,
3394 DWORD cbBuf
, LPDWORD pcbNeeded
)
3396 UNICODE_STRING nameW
, environmentW
;
3399 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
3400 WCHAR
*driverDirectoryW
= NULL
;
3402 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
3404 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
3405 else nameW
.Buffer
= NULL
;
3406 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
3407 else environmentW
.Buffer
= NULL
;
3409 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
3410 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
3413 needed
= 1 + WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
3414 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
3416 *pcbNeeded
= needed
;
3417 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
3419 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
3421 TRACE("provided<%ld> required <%ld>\n", cbBuf
, *pcbNeeded
);
3423 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
3424 RtlFreeUnicodeString(&environmentW
);
3425 RtlFreeUnicodeString(&nameW
);
3430 /*****************************************************************************
3431 * AddPrinterDriverA [WINSPOOL.@]
3433 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
3436 HKEY hkeyDrivers
, hkeyName
;
3438 TRACE("(%s,%ld,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
3440 if(level
!= 2 && level
!= 3) {
3441 SetLastError(ERROR_INVALID_LEVEL
);
3445 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
3446 SetLastError(ERROR_INVALID_PARAMETER
);
3450 WARN("pDriverInfo == NULL\n");
3451 SetLastError(ERROR_INVALID_PARAMETER
);
3456 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
3458 memset(&di3
, 0, sizeof(di3
));
3459 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
3462 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
3464 SetLastError(ERROR_INVALID_PARAMETER
);
3467 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= "";
3468 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= "\0";
3469 if(!di3
.pHelpFile
) di3
.pHelpFile
= "";
3470 if(!di3
.pMonitorName
) di3
.pMonitorName
= "";
3472 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
3475 ERR("Can't create Drivers key\n");
3479 if(level
== 2) { /* apparently can't overwrite with level2 */
3480 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
3481 RegCloseKey(hkeyName
);
3482 RegCloseKey(hkeyDrivers
);
3483 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
3484 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
3488 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
3489 RegCloseKey(hkeyDrivers
);
3490 ERR("Can't create Name key\n");
3493 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
3495 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, 0);
3496 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, 0);
3497 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
3499 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, 0);
3500 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
3501 (LPBYTE
) di3
.pDependentFiles
, 0);
3502 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, 0);
3503 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, 0);
3504 RegCloseKey(hkeyName
);
3505 RegCloseKey(hkeyDrivers
);
3510 /*****************************************************************************
3511 * AddPrinterDriverW [WINSPOOL.@]
3513 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
3516 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName
),
3521 /*****************************************************************************
3522 * AddPrintProcessorA [WINSPOOL.@]
3524 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
3525 LPSTR pPrintProcessorName
)
3527 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
3528 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
3532 /*****************************************************************************
3533 * AddPrintProcessorW [WINSPOOL.@]
3535 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
3536 LPWSTR pPrintProcessorName
)
3538 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
3539 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
3543 /*****************************************************************************
3544 * AddPrintProvidorA [WINSPOOL.@]
3546 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3548 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
3552 /*****************************************************************************
3553 * AddPrintProvidorW [WINSPOOL.@]
3555 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3557 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
3561 /*****************************************************************************
3562 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3564 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
3565 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
3567 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
3568 pDevModeOutput
, pDevModeInput
);
3572 /*****************************************************************************
3573 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3575 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
3576 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
3578 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
3579 pDevModeOutput
, pDevModeInput
);
3583 /*****************************************************************************
3584 * PrinterProperties [WINSPOOL.@]
3586 * Displays a dialog to set the properties of the printer.
3589 * nonzero on success or zero on failure
3592 * implemented as stub only
3594 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
3595 HANDLE hPrinter
/* [in] handle to printer object */
3597 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
3598 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3602 /*****************************************************************************
3603 * EnumJobsA [WINSPOOL.@]
3606 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3607 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3610 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3611 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3613 if(pcbNeeded
) *pcbNeeded
= 0;
3614 if(pcReturned
) *pcReturned
= 0;
3619 /*****************************************************************************
3620 * EnumJobsW [WINSPOOL.@]
3623 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3624 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3627 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3628 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3630 if(pcbNeeded
) *pcbNeeded
= 0;
3631 if(pcReturned
) *pcReturned
= 0;
3635 /*****************************************************************************
3636 * WINSPOOL_EnumPrinterDrivers [internal]
3638 * Delivers information about all printer drivers installed on the
3639 * localhost or a given server
3642 * nonzero on success or zero on failure. If the buffer for the returned
3643 * information is too small the function will return an error
3646 * - only implemented for localhost, foreign hosts will return an error
3648 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPWSTR pEnvironment
,
3649 DWORD Level
, LPBYTE pDriverInfo
,
3650 DWORD cbBuf
, LPDWORD pcbNeeded
,
3651 LPDWORD pcReturned
, BOOL unicode
)
3654 DWORD i
, needed
, number
= 0, size
= 0;
3655 WCHAR DriverNameW
[255];
3658 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3659 debugstr_w(pName
), debugstr_w(pEnvironment
),
3660 Level
, pDriverInfo
, cbBuf
, unicode
);
3662 /* check for local drivers */
3664 ERR("remote drivers unsupported! Current remote host is %s\n",
3669 /* check input parameter */
3670 if((Level
< 1) || (Level
> 3)) {
3671 ERR("unsupported level %ld\n", Level
);
3672 SetLastError(ERROR_INVALID_LEVEL
);
3676 /* initialize return values */
3678 memset( pDriverInfo
, 0, cbBuf
);
3682 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
3684 ERR("Can't open Drivers key\n");
3688 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3689 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3690 RegCloseKey(hkeyDrivers
);
3691 ERR("Can't query Drivers key\n");
3694 TRACE("Found %ld Drivers\n", number
);
3696 /* get size of single struct
3697 * unicode and ascii structure have the same size
3701 size
= sizeof(DRIVER_INFO_1A
);
3704 size
= sizeof(DRIVER_INFO_2A
);
3707 size
= sizeof(DRIVER_INFO_3A
);
3711 /* calculate required buffer size */
3712 *pcbNeeded
= size
* number
;
3714 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
3716 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
3717 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
3719 ERR("Can't enum key number %ld\n", i
);
3720 RegCloseKey(hkeyDrivers
);
3723 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
3724 pEnvironment
, Level
, ptr
,
3725 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
3726 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
3727 &needed
, unicode
)) {
3728 RegCloseKey(hkeyDrivers
);
3731 (*pcbNeeded
) += needed
;
3734 RegCloseKey(hkeyDrivers
);
3736 if(cbBuf
< *pcbNeeded
){
3737 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3741 *pcReturned
= number
;
3745 /*****************************************************************************
3746 * EnumPrinterDriversW [WINSPOOL.@]
3748 * see function EnumPrinterDrivers for RETURNS, BUGS
3750 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
3751 LPBYTE pDriverInfo
, DWORD cbBuf
,
3752 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3754 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
3755 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
3758 /*****************************************************************************
3759 * EnumPrinterDriversA [WINSPOOL.@]
3761 * see function EnumPrinterDrivers for RETURNS, BUGS
3763 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
3764 LPBYTE pDriverInfo
, DWORD cbBuf
,
3765 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3767 UNICODE_STRING pNameW
, pEnvironmentW
;
3768 PWSTR pwstrNameW
, pwstrEnvironmentW
;
3770 pwstrNameW
= asciitounicode(&pNameW
, pName
);
3771 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
3773 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
3774 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
3776 RtlFreeUnicodeString(&pNameW
);
3777 RtlFreeUnicodeString(&pEnvironmentW
);
3782 static CHAR PortMonitor
[] = "Wine Port Monitor";
3783 static CHAR PortDescription
[] = "Wine Port";
3785 static BOOL
WINSPOOL_ComPortExists( LPCSTR name
)
3789 handle
= CreateFileA( name
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3790 NULL
, OPEN_EXISTING
, 0, NULL
);
3791 if (handle
== INVALID_HANDLE_VALUE
)
3793 TRACE("Checking %s exists\n", name
);
3794 CloseHandle( handle
);
3798 static DWORD
WINSPOOL_CountSerialPorts(void)
3805 strcpy( name
, "COMx:" );
3807 if (WINSPOOL_ComPortExists( name
))
3814 /******************************************************************************
3815 * EnumPortsA (WINSPOOL.@)
3820 * ANSI-Version did not call the UNICODE-Version
3823 BOOL WINAPI
EnumPortsA(LPSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
3824 LPDWORD bufneeded
,LPDWORD bufreturned
)
3827 DWORD info_size
, ofs
, i
, printer_count
, serial_count
, count
, n
, r
;
3828 const LPCSTR szPrinterPortKey
= "Software\\Wine\\Wine\\Config\\spooler";
3832 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3833 debugstr_a(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
3838 info_size
= sizeof (PORT_INFO_1A
);
3841 info_size
= sizeof (PORT_INFO_2A
);
3844 SetLastError(ERROR_INVALID_LEVEL
);
3848 /* see how many exist */
3851 serial_count
= WINSPOOL_CountSerialPorts();
3854 r
= RegOpenKeyA( HKEY_LOCAL_MACHINE
, szPrinterPortKey
, &hkey_printer
);
3855 if ( r
== ERROR_SUCCESS
)
3857 RegQueryInfoKeyA( hkey_printer
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3858 &printer_count
, NULL
, NULL
, NULL
, NULL
);
3860 count
= serial_count
+ printer_count
;
3862 /* then fill in the structure info structure once
3863 we know the offset to the first string */
3865 memset( buffer
, 0, bufsize
);
3867 ofs
= info_size
*count
;
3868 for ( i
=0; i
<count
; i
++)
3870 DWORD vallen
= sizeof(portname
) - 1;
3872 /* get the serial port values, then the printer values */
3873 if ( i
< serial_count
)
3875 strcpy( portname
, "COMx:" );
3876 portname
[3] = '1' + i
;
3877 if (!WINSPOOL_ComPortExists( portname
))
3880 TRACE("Found %s\n", portname
);
3881 vallen
= strlen( portname
);
3885 r
= RegEnumValueA( hkey_printer
, i
-serial_count
,
3886 portname
, &vallen
, NULL
, NULL
, NULL
, 0 );
3891 /* add a colon if necessary, and make it upper case */
3892 CharUpperBuffA(portname
,vallen
);
3893 if (strcasecmp(portname
,"nul")!=0)
3894 if (vallen
&& (portname
[vallen
-1] != ':') )
3895 lstrcatA(portname
,":");
3897 /* add the port info structure if we can fit it */
3898 if ( info_size
*(n
+1) < bufsize
)
3902 PORT_INFO_1A
*info
= (PORT_INFO_1A
*) &buffer
[info_size
*n
];
3903 info
->pName
= (LPSTR
) &buffer
[ofs
];
3905 else if ( level
== 2)
3907 PORT_INFO_2A
*info
= (PORT_INFO_2A
*) &buffer
[info_size
*n
];
3908 info
->pPortName
= (LPSTR
) &buffer
[ofs
];
3909 /* FIXME: fill in more stuff here */
3910 info
->pMonitorName
= PortMonitor
;
3911 info
->pDescription
= PortDescription
;
3912 info
->fPortType
= PORT_TYPE_WRITE
|PORT_TYPE_READ
;
3915 /* add the name of the port if we can fit it */
3916 if ( ofs
< bufsize
)
3917 lstrcpynA((LPSTR
)&buffer
[ofs
],portname
,bufsize
- ofs
);
3923 ofs
+= lstrlenA(portname
)+1;
3926 RegCloseKey(hkey_printer
);
3937 /******************************************************************************
3938 * EnumPortsW (WINSPOOL.@)
3940 * Enumerate available Ports
3943 * name [I] Servername or NULL (local Computer)
3944 * level [I] Structure-Level (1 or 2)
3945 * buffer [O] PTR to Buffer that receives the Result
3946 * bufsize [I] Size of Buffer at buffer
3947 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
3948 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
3952 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
3955 * UNICODE-Version is a stub
3958 BOOL WINAPI
EnumPortsW(LPWSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
3959 LPDWORD bufneeded
,LPDWORD bufreturned
)
3961 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3962 debugstr_w(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
3966 /******************************************************************************
3967 * GetDefaultPrinterW (WINSPOOL.@)
3970 * This function must read the value from data 'device' of key
3971 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3973 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
3977 WCHAR
*buffer
, *ptr
;
3981 SetLastError(ERROR_INVALID_PARAMETER
);
3985 /* make the buffer big enough for the stuff from the profile/registry,
3986 * the content must fit into the local buffer to compute the correct
3987 * size even if the extern buffer is too small or not given.
3988 * (20 for ,driver,port) */
3990 len
= max(100, (insize
+ 20));
3991 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3993 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
3995 SetLastError (ERROR_FILE_NOT_FOUND
);
3999 TRACE("%s\n", debugstr_w(buffer
));
4001 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
4003 SetLastError(ERROR_INVALID_NAME
);
4009 *namesize
= strlenW(buffer
) + 1;
4010 if(!name
|| (*namesize
> insize
))
4012 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4016 strcpyW(name
, buffer
);
4019 HeapFree( GetProcessHeap(), 0, buffer
);
4024 /******************************************************************************
4025 * GetDefaultPrinterA (WINSPOOL.@)
4027 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
4031 WCHAR
*bufferW
= NULL
;
4035 SetLastError(ERROR_INVALID_PARAMETER
);
4039 if(name
&& *namesize
) {
4041 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
4044 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
4049 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
4053 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
4056 TRACE("0x%08lx/0x%08lx:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
4059 HeapFree( GetProcessHeap(), 0, bufferW
);
4064 /******************************************************************************
4065 * SetPrinterDataExA (WINSPOOL.@)
4067 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4068 LPCSTR pValueName
, DWORD Type
,
4069 LPBYTE pData
, DWORD cbData
)
4071 HKEY hkeyPrinter
, hkeySubkey
;
4074 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_a(pKeyName
),
4075 debugstr_a(pValueName
), Type
, pData
, cbData
);
4077 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4081 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4083 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
4084 RegCloseKey(hkeyPrinter
);
4087 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
4088 RegCloseKey(hkeySubkey
);
4089 RegCloseKey(hkeyPrinter
);
4093 /******************************************************************************
4094 * SetPrinterDataExW (WINSPOOL.@)
4096 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4097 LPCWSTR pValueName
, DWORD Type
,
4098 LPBYTE pData
, DWORD cbData
)
4100 HKEY hkeyPrinter
, hkeySubkey
;
4103 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_w(pKeyName
),
4104 debugstr_w(pValueName
), Type
, pData
, cbData
);
4106 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4110 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4112 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
4113 RegCloseKey(hkeyPrinter
);
4116 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
4117 RegCloseKey(hkeySubkey
);
4118 RegCloseKey(hkeyPrinter
);
4122 /******************************************************************************
4123 * SetPrinterDataA (WINSPOOL.@)
4125 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
4126 LPBYTE pData
, DWORD cbData
)
4128 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
4132 /******************************************************************************
4133 * SetPrinterDataW (WINSPOOL.@)
4135 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
4136 LPBYTE pData
, DWORD cbData
)
4138 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
4142 /******************************************************************************
4143 * GetPrinterDataExA (WINSPOOL.@)
4145 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4146 LPCSTR pValueName
, LPDWORD pType
,
4147 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4149 HKEY hkeyPrinter
, hkeySubkey
;
4152 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4153 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
4156 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4160 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4162 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
4163 RegCloseKey(hkeyPrinter
);
4167 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4168 RegCloseKey(hkeySubkey
);
4169 RegCloseKey(hkeyPrinter
);
4173 /******************************************************************************
4174 * GetPrinterDataExW (WINSPOOL.@)
4176 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4177 LPCWSTR pValueName
, LPDWORD pType
,
4178 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4180 HKEY hkeyPrinter
, hkeySubkey
;
4183 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4184 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
4187 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4191 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4193 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
4194 RegCloseKey(hkeyPrinter
);
4198 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4199 RegCloseKey(hkeySubkey
);
4200 RegCloseKey(hkeyPrinter
);
4204 /******************************************************************************
4205 * GetPrinterDataA (WINSPOOL.@)
4207 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
4208 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4210 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
4211 pData
, nSize
, pcbNeeded
);
4214 /******************************************************************************
4215 * GetPrinterDataW (WINSPOOL.@)
4217 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
4218 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4220 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
4221 pData
, nSize
, pcbNeeded
);
4224 /*******************************************************************************
4225 * EnumPrinterDataExW [WINSPOOL.@]
4227 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4228 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4229 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4231 HKEY hkPrinter
, hkSubKey
;
4232 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
4233 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
4238 PPRINTER_ENUM_VALUESW ppev
;
4240 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
4242 if (pKeyName
== NULL
|| *pKeyName
== 0)
4243 return ERROR_INVALID_PARAMETER
;
4245 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
4246 if (ret
!= ERROR_SUCCESS
)
4248 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4253 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
4254 if (ret
!= ERROR_SUCCESS
)
4256 r
= RegCloseKey (hkPrinter
);
4257 if (r
!= ERROR_SUCCESS
)
4258 WARN ("RegCloseKey returned %li\n", r
);
4259 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter
,
4260 debugstr_w (pKeyName
), ret
);
4264 ret
= RegCloseKey (hkPrinter
);
4265 if (ret
!= ERROR_SUCCESS
)
4267 ERR ("RegCloseKey returned %li\n", ret
);
4268 r
= RegCloseKey (hkSubKey
);
4269 if (r
!= ERROR_SUCCESS
)
4270 WARN ("RegCloseKey returned %li\n", r
);
4274 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4275 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
4276 if (ret
!= ERROR_SUCCESS
)
4278 r
= RegCloseKey (hkSubKey
);
4279 if (r
!= ERROR_SUCCESS
)
4280 WARN ("RegCloseKey returned %li\n", r
);
4281 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey
, ret
);
4285 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4286 "cbMaxValueLen = %li\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
4288 if (cValues
== 0) /* empty key */
4290 r
= RegCloseKey (hkSubKey
);
4291 if (r
!= ERROR_SUCCESS
)
4292 WARN ("RegCloseKey returned %li\n", r
);
4293 *pcbEnumValues
= *pnEnumValues
= 0;
4294 return ERROR_SUCCESS
;
4297 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
4299 hHeap
= GetProcessHeap ();
4302 ERR ("GetProcessHeap failed\n");
4303 r
= RegCloseKey (hkSubKey
);
4304 if (r
!= ERROR_SUCCESS
)
4305 WARN ("RegCloseKey returned %li\n", r
);
4306 return ERROR_OUTOFMEMORY
;
4309 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
4310 if (lpValueName
== NULL
)
4312 ERR ("Failed to allocate %li bytes from process heap\n",
4313 cbMaxValueNameLen
* sizeof (WCHAR
));
4314 r
= RegCloseKey (hkSubKey
);
4315 if (r
!= ERROR_SUCCESS
)
4316 WARN ("RegCloseKey returned %li\n", r
);
4317 return ERROR_OUTOFMEMORY
;
4320 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
4321 if (lpValue
== NULL
)
4323 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen
);
4324 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4325 WARN ("HeapFree failed with code %li\n", GetLastError ());
4326 r
= RegCloseKey (hkSubKey
);
4327 if (r
!= ERROR_SUCCESS
)
4328 WARN ("RegCloseKey returned %li\n", r
);
4329 return ERROR_OUTOFMEMORY
;
4332 TRACE ("pass 1: calculating buffer required for all names and values\n");
4334 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4336 TRACE ("%li bytes required for %li headers\n", cbBufSize
, cValues
);
4338 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4340 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4341 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4342 NULL
, NULL
, lpValue
, &cbValueLen
);
4343 if (ret
!= ERROR_SUCCESS
)
4345 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4346 WARN ("HeapFree failed with code %li\n", GetLastError ());
4347 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4348 WARN ("HeapFree failed with code %li\n", GetLastError ());
4349 r
= RegCloseKey (hkSubKey
);
4350 if (r
!= ERROR_SUCCESS
)
4351 WARN ("RegCloseKey returned %li\n", r
);
4352 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4356 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4357 debugstr_w (lpValueName
), dwIndex
,
4358 (cbValueNameLen
+ 1) * sizeof (WCHAR
), cbValueLen
);
4360 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4361 cbBufSize
+= cbValueLen
;
4364 TRACE ("%li bytes required for all %li values\n", cbBufSize
, cValues
);
4366 *pcbEnumValues
= cbBufSize
;
4367 *pnEnumValues
= cValues
;
4369 if (cbEnumValues
< cbBufSize
) /* buffer too small */
4371 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4372 WARN ("HeapFree failed with code %li\n", GetLastError ());
4373 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4374 WARN ("HeapFree failed with code %li\n", GetLastError ());
4375 r
= RegCloseKey (hkSubKey
);
4376 if (r
!= ERROR_SUCCESS
)
4377 WARN ("RegCloseKey returned %li\n", r
);
4378 TRACE ("%li byte buffer is not large enough\n", cbEnumValues
);
4379 return ERROR_MORE_DATA
;
4382 TRACE ("pass 2: copying all names and values to buffer\n");
4384 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
4385 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4387 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4389 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4390 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4391 NULL
, &dwType
, lpValue
, &cbValueLen
);
4392 if (ret
!= ERROR_SUCCESS
)
4394 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4395 WARN ("HeapFree failed with code %li\n", GetLastError ());
4396 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4397 WARN ("HeapFree failed with code %li\n", GetLastError ());
4398 r
= RegCloseKey (hkSubKey
);
4399 if (r
!= ERROR_SUCCESS
)
4400 WARN ("RegCloseKey returned %li\n", r
);
4401 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4405 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4406 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
4407 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
4408 pEnumValues
+= cbValueNameLen
;
4410 /* return # of *bytes* (including trailing \0), not # of chars */
4411 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
4413 ppev
[dwIndex
].dwType
= dwType
;
4415 memcpy (pEnumValues
, lpValue
, cbValueLen
);
4416 ppev
[dwIndex
].pData
= pEnumValues
;
4417 pEnumValues
+= cbValueLen
;
4419 ppev
[dwIndex
].cbData
= cbValueLen
;
4421 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4422 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
4425 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4427 ret
= GetLastError ();
4428 ERR ("HeapFree failed with code %li\n", ret
);
4429 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4430 WARN ("HeapFree failed with code %li\n", GetLastError ());
4431 r
= RegCloseKey (hkSubKey
);
4432 if (r
!= ERROR_SUCCESS
)
4433 WARN ("RegCloseKey returned %li\n", r
);
4437 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4439 ret
= GetLastError ();
4440 ERR ("HeapFree failed with code %li\n", ret
);
4441 r
= RegCloseKey (hkSubKey
);
4442 if (r
!= ERROR_SUCCESS
)
4443 WARN ("RegCloseKey returned %li\n", r
);
4447 ret
= RegCloseKey (hkSubKey
);
4448 if (ret
!= ERROR_SUCCESS
)
4450 ERR ("RegCloseKey returned %li\n", ret
);
4454 return ERROR_SUCCESS
;
4457 /*******************************************************************************
4458 * EnumPrinterDataExA [WINSPOOL.@]
4460 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4461 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4462 * what Windows 2000 SP1 does.
4465 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4466 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4467 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4471 DWORD ret
, dwIndex
, dwBufSize
;
4475 TRACE ("%p %s\n", hPrinter
, pKeyName
);
4477 if (pKeyName
== NULL
|| *pKeyName
== 0)
4478 return ERROR_INVALID_PARAMETER
;
4480 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
4483 ret
= GetLastError ();
4484 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4488 hHeap
= GetProcessHeap ();
4491 ERR ("GetProcessHeap failed\n");
4492 return ERROR_OUTOFMEMORY
;
4495 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
4496 if (pKeyNameW
== NULL
)
4498 ERR ("Failed to allocate %li bytes from process heap\n",
4499 (LONG
) len
* sizeof (WCHAR
));
4500 return ERROR_OUTOFMEMORY
;
4503 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
4505 ret
= GetLastError ();
4506 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4507 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4508 WARN ("HeapFree failed with code %li\n", GetLastError ());
4512 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
4513 pcbEnumValues
, pnEnumValues
);
4514 if (ret
!= ERROR_SUCCESS
)
4516 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4517 WARN ("HeapFree failed with code %li\n", GetLastError ());
4518 TRACE ("EnumPrinterDataExW returned %li\n", ret
);
4522 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4524 ret
= GetLastError ();
4525 ERR ("HeapFree failed with code %li\n", ret
);
4529 if (*pnEnumValues
== 0) /* empty key */
4530 return ERROR_SUCCESS
;
4533 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4535 PPRINTER_ENUM_VALUESW ppev
=
4536 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4538 if (dwBufSize
< ppev
->cbValueName
)
4539 dwBufSize
= ppev
->cbValueName
;
4541 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
4542 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
4543 dwBufSize
= ppev
->cbData
;
4546 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize
);
4548 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
4549 if (pBuffer
== NULL
)
4551 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize
);
4552 return ERROR_OUTOFMEMORY
;
4555 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4557 PPRINTER_ENUM_VALUESW ppev
=
4558 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4560 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
4561 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
4565 ret
= GetLastError ();
4566 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4567 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4568 WARN ("HeapFree failed with code %li\n", GetLastError ());
4572 memcpy (ppev
->pValueName
, pBuffer
, len
);
4574 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4576 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
4577 ppev
->dwType
!= REG_MULTI_SZ
)
4580 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
4581 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
4584 ret
= GetLastError ();
4585 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4586 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4587 WARN ("HeapFree failed with code %li\n", GetLastError ());
4591 memcpy (ppev
->pData
, pBuffer
, len
);
4593 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4594 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4597 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4599 ret
= GetLastError ();
4600 ERR ("HeapFree failed with code %li\n", ret
);
4604 return ERROR_SUCCESS
;
4607 /******************************************************************************
4608 * AbortPrinter (WINSPOOL.@)
4610 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
4612 FIXME("(%p), stub!\n", hPrinter
);
4616 /******************************************************************************
4617 * AddPortA (WINSPOOL.@)
4622 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
4624 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName
),hWnd
,debugstr_a(pMonitorName
));
4628 /******************************************************************************
4629 * AddPortW (WINSPOOL.@)
4631 * Add a Port for a specific Monitor
4634 * pName [I] Servername or NULL (local Computer)
4635 * hWnd [I] Handle to parent Window for the Dialog-Box
4636 * pMonitorName [I] Name of the Monitor that manage the Port
4646 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
4648 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName
),hWnd
,debugstr_w(pMonitorName
));
4652 /******************************************************************************
4653 * AddPortExA (WINSPOOL.@)
4658 BOOL WINAPI
AddPortExA(HANDLE hMonitor
, LPSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPSTR lpMonitorName
)
4660 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor
, debugstr_a(pName
), Level
,
4661 lpBuffer
, debugstr_a(lpMonitorName
));
4665 /******************************************************************************
4666 * AddPortExW (WINSPOOL.@)
4668 * Add a Port for a specific Monitor, without presenting a user interface
4671 * hMonitor [I] Handle from InitializePrintMonitor2()
4672 * pName [I] Servername or NULL (local Computer)
4673 * Level [I] Structure-Level (1 or 2) for lpBuffer
4674 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
4675 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
4685 BOOL WINAPI
AddPortExW(HANDLE hMonitor
, LPWSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPWSTR lpMonitorName
)
4687 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor
, debugstr_w(pName
), Level
,
4688 lpBuffer
, debugstr_w(lpMonitorName
));
4692 /******************************************************************************
4693 * AddPrinterConnectionA (WINSPOOL.@)
4695 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
4697 FIXME("%s\n", debugstr_a(pName
));
4701 /******************************************************************************
4702 * AddPrinterConnectionW (WINSPOOL.@)
4704 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
4706 FIXME("%s\n", debugstr_w(pName
));
4710 /******************************************************************************
4711 * AddPrinterDriverExW (WINSPOOL.@)
4713 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
4714 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4716 FIXME("%s %ld %p %ld\n", debugstr_w(pName
),
4717 Level
, pDriverInfo
, dwFileCopyFlags
);
4718 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4722 /******************************************************************************
4723 * AddPrinterDriverExA (WINSPOOL.@)
4725 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
4726 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4728 FIXME("%s %ld %p %ld\n", debugstr_a(pName
),
4729 Level
, pDriverInfo
, dwFileCopyFlags
);
4730 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4734 /******************************************************************************
4735 * ConfigurePortA (WINSPOOL.@)
4737 * See ConfigurePortW.
4740 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
4742 FIXME("%s %p %s\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
4746 /******************************************************************************
4747 * ConfigurePortW (WINSPOOL.@)
4749 * Display the Configuration-Dialog for a specific Port
4752 * pName [I] Servername or NULL (local Computer)
4753 * hWnd [I] Handle to parent Window for the Dialog-Box
4754 * pPortName [I] Name of the Port, that should be configured
4764 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
4766 FIXME("%s %p %s\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
4770 /******************************************************************************
4771 * ConnectToPrinterDlg (WINSPOOL.@)
4773 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
4775 FIXME("%p %lx\n", hWnd
, Flags
);
4779 /******************************************************************************
4780 * DeletePrinterConnectionA (WINSPOOL.@)
4782 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
4784 FIXME("%s\n", debugstr_a(pName
));
4788 /******************************************************************************
4789 * DeletePrinterConnectionW (WINSPOOL.@)
4791 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
4793 FIXME("%s\n", debugstr_w(pName
));
4797 /******************************************************************************
4798 * DeletePrinterDriverExW (WINSPOOL.@)
4800 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
4801 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4803 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4804 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4808 /******************************************************************************
4809 * DeletePrinterDriverExA (WINSPOOL.@)
4811 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
4812 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4814 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4815 debugstr_a(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4819 /******************************************************************************
4820 * DeletePrinterDataExW (WINSPOOL.@)
4822 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
4825 FIXME("%p %s %s\n", hPrinter
,
4826 debugstr_w(pKeyName
), debugstr_w(pValueName
));
4827 return ERROR_INVALID_PARAMETER
;
4830 /******************************************************************************
4831 * DeletePrinterDataExA (WINSPOOL.@)
4833 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
4836 FIXME("%p %s %s\n", hPrinter
,
4837 debugstr_a(pKeyName
), debugstr_a(pValueName
));
4838 return ERROR_INVALID_PARAMETER
;
4841 /******************************************************************************
4842 * DeletePrintProcessorA (WINSPOOL.@)
4844 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
4846 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4847 debugstr_a(pPrintProcessorName
));
4851 /******************************************************************************
4852 * DeletePrintProcessorW (WINSPOOL.@)
4854 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
4856 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4857 debugstr_w(pPrintProcessorName
));
4861 /******************************************************************************
4862 * DeletePrintProvidorA (WINSPOOL.@)
4864 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
4866 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4867 debugstr_a(pPrintProviderName
));
4871 /******************************************************************************
4872 * DeletePrintProvidorW (WINSPOOL.@)
4874 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
4876 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4877 debugstr_w(pPrintProviderName
));
4881 /******************************************************************************
4882 * EnumFormsA (WINSPOOL.@)
4884 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
4885 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4887 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
4891 /******************************************************************************
4892 * EnumFormsW (WINSPOOL.@)
4894 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
4895 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4897 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
4901 /*****************************************************************************
4902 * EnumMonitorsA [WINSPOOL.@]
4904 * See EnumMonitorsW.
4907 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
4908 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4910 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName
), Level
, pMonitors
,
4911 cbBuf
, pcbNeeded
, pcReturned
);
4912 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4916 /*****************************************************************************
4917 * EnumMonitorsW [WINSPOOL.@]
4919 * Enumerate available Monitors
4922 * pName [I] Servername or NULL (local Computer)
4923 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
4924 * pMonitors [O] PTR to Buffer that receives the Result
4925 * cbBuf [I] Size of Buffer at pMonitors
4926 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
4927 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
4931 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4937 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
4938 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4940 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName
), Level
, pMonitors
,
4941 cbBuf
, pcbNeeded
, pcReturned
);
4942 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4946 /******************************************************************************
4947 * XcvDataW (WINSPOOL.@)
4950 * There doesn't seem to be an A version...
4952 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
4953 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
4954 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
4956 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv
, debugstr_w(pszDataName
),
4957 pInputData
, cbInputData
, pOutputData
,
4958 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
4962 /*****************************************************************************
4963 * EnumPrinterDataA [WINSPOOL.@]
4966 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
4967 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
4968 DWORD cbData
, LPDWORD pcbData
)
4970 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
4971 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
4972 return ERROR_NO_MORE_ITEMS
;
4975 /*****************************************************************************
4976 * EnumPrinterDataW [WINSPOOL.@]
4979 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
4980 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
4981 DWORD cbData
, LPDWORD pcbData
)
4983 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
4984 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
4985 return ERROR_NO_MORE_ITEMS
;
4988 /*****************************************************************************
4989 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4992 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
4993 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
4994 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4996 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName
),
4997 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
4998 pcbNeeded
, pcReturned
);
5002 /*****************************************************************************
5003 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5006 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
5007 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
5008 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5010 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
5011 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
5012 pcbNeeded
, pcReturned
);
5016 /*****************************************************************************
5017 * EnumPrintProcessorsA [WINSPOOL.@]
5020 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5021 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
5023 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName
, pEnvironment
, Level
,
5024 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
5028 /*****************************************************************************
5029 * EnumPrintProcessorsW [WINSPOOL.@]
5032 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5033 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
5035 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
5036 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
5037 cbBuf
, pcbNeeded
, pcbReturned
);
5041 /*****************************************************************************
5042 * ExtDeviceMode [WINSPOOL.@]
5045 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
5046 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
5049 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd
, hInst
, pDevModeOutput
,
5050 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
5051 debugstr_a(pProfile
), fMode
);
5055 /*****************************************************************************
5056 * FindClosePrinterChangeNotification [WINSPOOL.@]
5059 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
5061 FIXME("Stub: %p\n", hChange
);
5065 /*****************************************************************************
5066 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5069 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
5070 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
5072 FIXME("Stub: %p %lx %lx %p\n",
5073 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
5074 return INVALID_HANDLE_VALUE
;
5077 /*****************************************************************************
5078 * FindNextPrinterChangeNotification [WINSPOOL.@]
5081 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
5082 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
5084 FIXME("Stub: %p %p %p %p\n",
5085 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
5089 /*****************************************************************************
5090 * FreePrinterNotifyInfo [WINSPOOL.@]
5093 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
5095 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
5099 /*****************************************************************************
5102 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5103 * ansi depending on the unicode parameter.
5105 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
5115 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
5118 memcpy(ptr
, str
, *size
);
5125 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
5128 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
5135 /*****************************************************************************
5138 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
5139 LPDWORD pcbNeeded
, BOOL unicode
)
5141 DWORD size
, left
= cbBuf
;
5142 BOOL space
= (cbBuf
> 0);
5149 ji1
->JobId
= job
->job_id
;
5152 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
5153 if(space
&& size
<= left
)
5155 ji1
->pDocument
= (LPWSTR
)ptr
;
5166 /*****************************************************************************
5169 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
5170 LPDWORD pcbNeeded
, BOOL unicode
)
5172 DWORD size
, left
= cbBuf
;
5173 BOOL space
= (cbBuf
> 0);
5180 ji2
->JobId
= job
->job_id
;
5183 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
5184 if(space
&& size
<= left
)
5186 ji2
->pDocument
= (LPWSTR
)ptr
;
5197 /*****************************************************************************
5200 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5201 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
5204 DWORD needed
= 0, size
;
5208 TRACE("%p %ld %ld %p %ld %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
5210 EnterCriticalSection(&printer_handles_cs
);
5211 job
= get_job(hPrinter
, JobId
);
5218 size
= sizeof(JOB_INFO_1W
);
5223 memset(pJob
, 0, size
);
5227 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5232 size
= sizeof(JOB_INFO_2W
);
5237 memset(pJob
, 0, size
);
5241 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5246 size
= sizeof(JOB_INFO_3
);
5250 memset(pJob
, 0, size
);
5259 SetLastError(ERROR_INVALID_LEVEL
);
5263 *pcbNeeded
= needed
;
5265 LeaveCriticalSection(&printer_handles_cs
);
5269 /*****************************************************************************
5270 * GetJobA [WINSPOOL.@]
5273 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5274 DWORD cbBuf
, LPDWORD pcbNeeded
)
5276 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
5279 /*****************************************************************************
5280 * GetJobW [WINSPOOL.@]
5283 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5284 DWORD cbBuf
, LPDWORD pcbNeeded
)
5286 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
5289 /*****************************************************************************
5292 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
5294 char *unixname
, *queue
, *cmd
;
5295 char fmt
[] = "lpr -P%s %s";
5298 if(!(unixname
= wine_get_unix_file_name(filename
)))
5301 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5302 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5303 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5305 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
5306 sprintf(cmd
, fmt
, queue
, unixname
);
5308 TRACE("printing with: %s\n", cmd
);
5311 HeapFree(GetProcessHeap(), 0, cmd
);
5312 HeapFree(GetProcessHeap(), 0, queue
);
5313 HeapFree(GetProcessHeap(), 0, unixname
);
5317 /*****************************************************************************
5320 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
5322 #if HAVE_CUPS_CUPS_H
5325 char *unixname
, *queue
, *doc_titleA
;
5329 if(!(unixname
= wine_get_unix_file_name(filename
)))
5332 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5333 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5334 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5336 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
5337 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
5338 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
5340 TRACE("printing via cups\n");
5341 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
5342 HeapFree(GetProcessHeap(), 0, doc_titleA
);
5343 HeapFree(GetProcessHeap(), 0, queue
);
5344 HeapFree(GetProcessHeap(), 0, unixname
);
5350 return schedule_lpr(printer_name
, filename
);
5354 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
5361 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
5365 if(HIWORD(wparam
) == BN_CLICKED
)
5367 if(LOWORD(wparam
) == IDOK
)
5370 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
5373 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
5374 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
5376 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
5378 WCHAR caption
[200], message
[200];
5381 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5382 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
5383 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
5384 if(mb_ret
== IDCANCEL
)
5386 HeapFree(GetProcessHeap(), 0, filename
);
5390 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5391 if(hf
== INVALID_HANDLE_VALUE
)
5393 WCHAR caption
[200], message
[200];
5395 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5396 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
5397 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
5398 HeapFree(GetProcessHeap(), 0, filename
);
5402 DeleteFileW(filename
);
5403 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5405 EndDialog(hwnd
, IDOK
);
5408 if(LOWORD(wparam
) == IDCANCEL
)
5410 EndDialog(hwnd
, IDCANCEL
);
5419 /*****************************************************************************
5422 static BOOL
get_filename(LPWSTR
*filename
)
5424 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
5425 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
5428 /*****************************************************************************
5431 static BOOL
schedule_file(LPCWSTR filename
)
5433 LPWSTR output
= NULL
;
5435 if(get_filename(&output
))
5437 TRACE("copy to %s\n", debugstr_w(output
));
5438 CopyFileW(filename
, output
, FALSE
);
5439 HeapFree(GetProcessHeap(), 0, output
);
5445 /*****************************************************************************
5448 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
5451 char *unixname
, *cmdA
;
5453 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
5457 if(!(unixname
= wine_get_unix_file_name(filename
)))
5460 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
5461 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
5462 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
5464 TRACE("printing with: %s\n", cmdA
);
5466 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
5471 ERR("pipe() failed!\n");
5481 /* reset signals that we previously set to SIG_IGN */
5482 signal(SIGPIPE
, SIG_DFL
);
5483 signal(SIGCHLD
, SIG_DFL
);
5489 while((no_read
= read(file_fd
, buf
, sizeof(buf
))))
5490 write(fds
[1], buf
, no_read
);
5495 if(file_fd
!= -1) close(file_fd
);
5496 if(fds
[0] != -1) close(fds
[0]);
5497 if(fds
[1] != -1) close(fds
[1]);
5499 HeapFree(GetProcessHeap(), 0, cmdA
);
5500 HeapFree(GetProcessHeap(), 0, unixname
);
5507 /*****************************************************************************
5510 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
5512 int in_fd
, out_fd
, no_read
;
5515 char *unixname
, *outputA
;
5518 if(!(unixname
= wine_get_unix_file_name(filename
)))
5521 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
5522 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
5523 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
5525 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
5526 in_fd
= open(unixname
, O_RDONLY
);
5527 if(out_fd
== -1 || in_fd
== -1)
5530 while((no_read
= read(in_fd
, buf
, sizeof(buf
))))
5531 write(out_fd
, buf
, no_read
);
5535 if(in_fd
!= -1) close(in_fd
);
5536 if(out_fd
!= -1) close(out_fd
);
5537 HeapFree(GetProcessHeap(), 0, outputA
);
5538 HeapFree(GetProcessHeap(), 0, unixname
);
5542 /*****************************************************************************
5543 * ScheduleJob [WINSPOOL.@]
5546 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
5548 opened_printer_t
*printer
;
5550 struct list
*cursor
, *cursor2
;
5552 TRACE("(%p, %lx)\n", hPrinter
, dwJobID
);
5553 EnterCriticalSection(&printer_handles_cs
);
5554 printer
= get_opened_printer(hPrinter
);
5558 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
5560 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
5563 if(job
->job_id
!= dwJobID
) continue;
5565 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
5566 if(hf
!= INVALID_HANDLE_VALUE
)
5568 PRINTER_INFO_5W
*pi5
;
5572 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5573 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5575 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
5576 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
5577 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
5578 TRACE("need to schedule job %ld filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
5579 debugstr_w(pi5
->pPortName
));
5583 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5584 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
5586 DWORD type
, count
= sizeof(output
);
5587 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
5590 if(output
[0] == '|')
5592 schedule_pipe(output
+ 1, job
->filename
);
5596 schedule_unixfile(output
, job
->filename
);
5598 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
5600 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
5602 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
5604 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
5606 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
5608 schedule_file(job
->filename
);
5612 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
5614 HeapFree(GetProcessHeap(), 0, pi5
);
5616 DeleteFileW(job
->filename
);
5618 list_remove(cursor
);
5619 HeapFree(GetProcessHeap(), 0, job
->document_title
);
5620 HeapFree(GetProcessHeap(), 0, job
->filename
);
5621 HeapFree(GetProcessHeap(), 0, job
);
5626 LeaveCriticalSection(&printer_handles_cs
);
5630 /*****************************************************************************
5631 * StartDocDlgA [WINSPOOL.@]
5633 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
5635 UNICODE_STRING usBuffer
;
5640 docW
.cbSize
= sizeof(docW
);
5641 docW
.lpszDocName
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
5642 docW
.lpszOutput
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
5643 docW
.lpszDatatype
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
5644 docW
.fwType
= doc
->fwType
;
5646 retW
= StartDocDlgW(hPrinter
, &docW
);
5650 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
5651 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
5652 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
5653 HeapFree(GetProcessHeap(), 0, retW
);
5656 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDatatype
);
5657 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszOutput
);
5658 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDocName
);
5663 /*****************************************************************************
5664 * StartDocDlgW [WINSPOOL.@]
5666 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5667 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5668 * port is "FILE:". Also returns the full path if passed a relative path.
5670 * The caller should free the returned string from the process heap.
5672 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
5677 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
5679 PRINTER_INFO_5W
*pi5
;
5680 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
5681 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
5683 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
5684 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
5685 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
5687 HeapFree(GetProcessHeap(), 0, pi5
);
5690 HeapFree(GetProcessHeap(), 0, pi5
);
5693 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
5696 get_filename(&name
);
5699 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
5701 HeapFree(GetProcessHeap(), 0, name
);
5704 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5705 GetFullPathNameW(name
, len
, ret
, NULL
);
5706 HeapFree(GetProcessHeap(), 0, name
);
5711 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
5714 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5715 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
5717 attr
= GetFileAttributesW(ret
);
5718 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
5720 HeapFree(GetProcessHeap(), 0, ret
);