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 queue_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.@]
1043 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1044 LPPRINTER_DEFAULTSA pDefault
)
1046 UNICODE_STRING lpPrinterNameW
;
1047 UNICODE_STRING usBuffer
;
1048 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1049 PWSTR pwstrPrinterNameW
;
1052 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1055 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1056 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1057 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1058 pDefaultW
= &DefaultW
;
1060 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1062 RtlFreeUnicodeString(&usBuffer
);
1063 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1065 RtlFreeUnicodeString(&lpPrinterNameW
);
1069 /******************************************************************
1070 * OpenPrinterW [WINSPOOL.@]
1073 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
,
1074 LPPRINTER_DEFAULTSW pDefault
)
1076 HKEY hkeyPrinters
, hkeyPrinter
;
1078 if (!lpPrinterName
) {
1079 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault
);
1080 SetLastError(ERROR_INVALID_PARAMETER
);
1084 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName
),
1087 /* Check Printer exists */
1088 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1090 ERR("Can't create Printers key\n");
1091 SetLastError(ERROR_FILE_NOT_FOUND
); /* ?? */
1095 if(lpPrinterName
[0] == '\0' || /* explicitly exclude "" */
1096 RegOpenKeyW(hkeyPrinters
, lpPrinterName
, &hkeyPrinter
)
1098 TRACE("Can't find printer %s in registry\n",
1099 debugstr_w(lpPrinterName
));
1100 RegCloseKey(hkeyPrinters
);
1101 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1104 RegCloseKey(hkeyPrinter
);
1105 RegCloseKey(hkeyPrinters
);
1107 if(!phPrinter
) /* This seems to be what win95 does anyway */
1110 /* Get the unique handle of the printer*/
1111 *phPrinter
= get_opened_printer_entry( lpPrinterName
);
1113 if (pDefault
!= NULL
)
1114 FIXME("Not handling pDefault\n");
1119 /******************************************************************
1120 * AddMonitorA [WINSPOOL.@]
1123 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1125 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName
), Level
, pMonitors
);
1126 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1130 /******************************************************************************
1131 * AddMonitorW [WINSPOOL.@]
1133 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1135 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName
), Level
, pMonitors
);
1136 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1140 /******************************************************************
1141 * DeletePrinterDriverA [WINSPOOL.@]
1145 DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
1147 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1148 debugstr_a(pDriverName
));
1149 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1153 /******************************************************************
1154 * DeletePrinterDriverW [WINSPOOL.@]
1158 DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
1160 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1161 debugstr_w(pDriverName
));
1162 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1166 /******************************************************************
1167 * DeleteMonitorA [WINSPOOL.@]
1171 DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
1173 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1174 debugstr_a(pMonitorName
));
1175 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1179 /******************************************************************
1180 * DeleteMonitorW [WINSPOOL.@]
1184 DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1186 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1187 debugstr_w(pMonitorName
));
1188 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1192 /******************************************************************
1193 * DeletePortA [WINSPOOL.@]
1197 DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
1199 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName
),hWnd
,
1200 debugstr_a(pPortName
));
1201 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1205 /******************************************************************
1206 * DeletePortW [WINSPOOL.@]
1210 DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1212 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName
),hWnd
,
1213 debugstr_w(pPortName
));
1214 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1218 /******************************************************************************
1219 * SetPrinterW [WINSPOOL.@]
1229 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1233 /******************************************************************************
1234 * WritePrinter [WINSPOOL.@]
1236 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
1238 opened_printer_t
*printer
;
1241 TRACE("(%p, %p, %ld, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
1243 EnterCriticalSection(&printer_handles_cs
);
1244 printer
= get_opened_printer(hPrinter
);
1247 SetLastError(ERROR_INVALID_HANDLE
);
1253 SetLastError(ERROR_SPL_NO_STARTDOC
);
1257 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
1259 LeaveCriticalSection(&printer_handles_cs
);
1263 /*****************************************************************************
1264 * AddFormA [WINSPOOL.@]
1266 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1268 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1272 /*****************************************************************************
1273 * AddFormW [WINSPOOL.@]
1275 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1277 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1281 /*****************************************************************************
1282 * AddJobA [WINSPOOL.@]
1284 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1287 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
1291 SetLastError(ERROR_INVALID_LEVEL
);
1295 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
1298 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
1299 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
1300 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
1301 if(*pcbNeeded
> cbBuf
) {
1302 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1305 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
1306 addjobA
->JobId
= addjobW
->JobId
;
1307 addjobA
->Path
= (char *)(addjobA
+ 1);
1308 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
1314 /*****************************************************************************
1315 * AddJobW [WINSPOOL.@]
1317 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1319 opened_printer_t
*printer
;
1322 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1323 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
1324 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
1326 ADDJOB_INFO_1W
*addjob
;
1328 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
1330 EnterCriticalSection(&printer_handles_cs
);
1332 printer
= get_opened_printer(hPrinter
);
1335 SetLastError(ERROR_INVALID_HANDLE
);
1340 SetLastError(ERROR_INVALID_LEVEL
);
1344 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
1348 job
->job_id
= InterlockedIncrement(&next_job_id
);
1350 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
1351 if(path
[len
- 1] != '\\')
1353 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
1354 sprintfW(filename
, fmtW
, path
, job
->job_id
);
1356 len
= strlenW(filename
);
1357 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1358 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
1359 job
->document_title
= strdupW(default_doc_title
);
1360 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
1362 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
1363 if(*pcbNeeded
<= cbBuf
) {
1364 addjob
= (ADDJOB_INFO_1W
*)pData
;
1365 addjob
->JobId
= job
->job_id
;
1366 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
1367 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
1370 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1373 LeaveCriticalSection(&printer_handles_cs
);
1377 /*****************************************************************************
1378 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1380 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
1381 DWORD level
, LPBYTE Info
,
1382 DWORD cbBuf
, LPDWORD needed
)
1384 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server
), debugstr_a(env
),
1385 level
, Info
, cbBuf
);
1389 /*****************************************************************************
1390 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1392 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
1393 DWORD level
, LPBYTE Info
,
1394 DWORD cbBuf
, LPDWORD needed
)
1396 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server
), debugstr_w(env
),
1397 level
, Info
, cbBuf
);
1401 /*****************************************************************************
1402 * WINSPOOL_OpenDriverReg [internal]
1404 * opens the registry for the printer drivers depending on the given input
1405 * variable pEnvironment
1408 * the opened hkey on success
1411 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
)
1413 static const WCHAR WinNTW
[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1414 static const WCHAR Win40W
[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1416 LPWSTR lpKey
, buffer
= NULL
;
1420 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
));
1424 pEnvW
= pEnvironment
;
1426 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
1427 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1428 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
1433 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
1435 if(!GetVersionExW( &ver
))
1438 switch (ver
.dwPlatformId
) {
1439 case VER_PLATFORM_WIN32s
:
1440 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1442 case VER_PLATFORM_WIN32_NT
:
1449 TRACE("set environment to %s\n", debugstr_w(pEnvW
));
1452 lpKey
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1453 (strlenW(pEnvW
) + strlenW(DriversW
) + 1) * sizeof(WCHAR
));
1454 wsprintfW( lpKey
, DriversW
, pEnvW
);
1456 TRACE("%s\n", debugstr_w(lpKey
));
1458 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, lpKey
, &retval
) != ERROR_SUCCESS
)
1461 HeapFree( GetProcessHeap(), 0, buffer
);
1462 HeapFree( GetProcessHeap(), 0, lpKey
);
1467 /*****************************************************************************
1468 * AddPrinterW [WINSPOOL.@]
1470 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1472 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
1476 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
1479 TRACE("(%s,%ld,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
1482 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
1483 SetLastError(ERROR_INVALID_PARAMETER
);
1487 ERR("Level = %ld, unsupported!\n", Level
);
1488 SetLastError(ERROR_INVALID_LEVEL
);
1491 if (strlenW(pi
->pPrinterName
) >= CCHDEVICENAME
) {
1492 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1493 debugstr_w(pi
->pPrinterName
)
1495 SetLastError(ERROR_INVALID_LEVEL
);
1499 SetLastError(ERROR_INVALID_PARAMETER
);
1502 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1504 ERR("Can't create Printers key\n");
1507 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
1508 if (!RegQueryValueA(hkeyPrinter
,"Attributes",NULL
,NULL
)) {
1509 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
1510 RegCloseKey(hkeyPrinter
);
1511 RegCloseKey(hkeyPrinters
);
1514 RegCloseKey(hkeyPrinter
);
1516 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
1518 ERR("Can't create Drivers key\n");
1519 RegCloseKey(hkeyPrinters
);
1522 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
1524 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
1525 RegCloseKey(hkeyPrinters
);
1526 RegCloseKey(hkeyDrivers
);
1527 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
1530 RegCloseKey(hkeyDriver
);
1531 RegCloseKey(hkeyDrivers
);
1533 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
1534 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
1535 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
1536 RegCloseKey(hkeyPrinters
);
1540 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
1542 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
1543 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1544 RegCloseKey(hkeyPrinters
);
1547 RegSetValueExA(hkeyPrinter
, "Attributes", 0, REG_DWORD
,
1548 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
1549 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
1551 /* See if we can load the driver. We may need the devmode structure anyway
1554 * Note that DocumentPropertiesW will briefly try to open the printer we
1555 * just create to find a DEVMODEA struct (it will use the WINEPS default
1556 * one in case it is not there, so we are ok).
1558 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
1561 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi
->pPrinterName
));
1562 size
= sizeof(DEVMODEW
);
1568 dmW
= HeapAlloc(GetProcessHeap(), 0, size
);
1569 ZeroMemory(dmW
,size
);
1571 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
1573 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi
->pPrinterName
));
1574 HeapFree(GetProcessHeap(),0,dmW
);
1579 /* set devmode to printer name */
1580 strcpyW(dmW
->dmDeviceName
,pi
->pPrinterName
);
1584 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1585 and we support these drivers. NT writes DEVMODEW so somehow
1586 we'll need to distinguish between these when we support NT
1590 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
1591 RegSetValueExA(hkeyPrinter
, "Default DevMode", 0, REG_BINARY
,
1592 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1593 HeapFree(GetProcessHeap(), 0, dmA
);
1595 HeapFree(GetProcessHeap(), 0, dmW
);
1597 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
1598 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
1599 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
1600 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
1602 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
1603 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
1604 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
1605 RegSetValueExA(hkeyPrinter
, "Priority", 0, REG_DWORD
,
1606 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
1607 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
1608 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
1609 RegSetValueExA(hkeyPrinter
, "StartTime", 0, REG_DWORD
,
1610 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
1611 RegSetValueExA(hkeyPrinter
, "Status", 0, REG_DWORD
,
1612 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
1613 RegSetValueExA(hkeyPrinter
, "UntilTime", 0, REG_DWORD
,
1614 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
1616 RegCloseKey(hkeyPrinter
);
1617 RegCloseKey(hkeyPrinters
);
1618 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
1619 ERR("OpenPrinter failing\n");
1625 /*****************************************************************************
1626 * AddPrinterA [WINSPOOL.@]
1628 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1630 UNICODE_STRING pNameW
;
1632 PRINTER_INFO_2W
*piW
;
1633 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
1636 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
1638 ERR("Level = %ld, unsupported!\n", Level
);
1639 SetLastError(ERROR_INVALID_LEVEL
);
1642 pwstrNameW
= asciitounicode(&pNameW
,pName
);
1643 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
1645 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
1647 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
1648 RtlFreeUnicodeString(&pNameW
);
1653 /*****************************************************************************
1654 * ClosePrinter [WINSPOOL.@]
1656 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
1658 UINT_PTR i
= (UINT_PTR
)hPrinter
;
1659 opened_printer_t
*printer
= NULL
;
1662 TRACE("Handle %p\n", hPrinter
);
1664 EnterCriticalSection(&printer_handles_cs
);
1666 if ((i
> 0) && (i
<= nb_printer_handles
))
1667 printer
= printer_handles
[i
- 1];
1671 struct list
*cursor
, *cursor2
;
1674 EndDocPrinter(hPrinter
);
1676 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
1678 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
1680 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
1681 ScheduleJob(hPrinter
, job
->job_id
);
1683 HeapFree(GetProcessHeap(), 0, printer
->queue
);
1685 HeapFree(GetProcessHeap(), 0, printer
->name
);
1686 HeapFree(GetProcessHeap(), 0, printer
);
1687 printer_handles
[i
- 1] = NULL
;
1690 LeaveCriticalSection(&printer_handles_cs
);
1694 /*****************************************************************************
1695 * DeleteFormA [WINSPOOL.@]
1697 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
1699 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
1703 /*****************************************************************************
1704 * DeleteFormW [WINSPOOL.@]
1706 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
1708 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
1712 /*****************************************************************************
1713 * WINSPOOL_SHRegDeleteKey
1715 * Recursively delete subkeys.
1716 * Cut & paste from shlwapi.
1719 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
)
1721 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1722 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1725 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1728 /* Find how many subkeys there are */
1729 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1730 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1734 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1735 /* Name too big: alloc a buffer for it */
1736 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
1739 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1742 /* Recursively delete all the subkeys */
1743 for(i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1745 dwSize
= dwMaxSubkeyLen
;
1746 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1748 dwRet
= WINSPOOL_SHDeleteKeyW(hSubKey
, lpszName
);
1751 if (lpszName
!= szNameBuf
)
1752 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
1756 RegCloseKey(hSubKey
);
1758 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1763 /*****************************************************************************
1764 * DeletePrinter [WINSPOOL.@]
1766 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
1768 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1769 HKEY hkeyPrinters
, hkey
;
1772 SetLastError(ERROR_INVALID_HANDLE
);
1775 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1776 WINSPOOL_SHDeleteKeyW(hkeyPrinters
, lpNameW
);
1777 RegCloseKey(hkeyPrinters
);
1779 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
1780 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1781 RegDeleteValueW(hkey
, lpNameW
);
1787 /*****************************************************************************
1788 * SetPrinterA [WINSPOOL.@]
1790 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
1793 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter
,Level
,pPrinter
,Command
);
1797 /*****************************************************************************
1798 * SetJobA [WINSPOOL.@]
1800 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1801 LPBYTE pJob
, DWORD Command
)
1805 UNICODE_STRING usBuffer
;
1807 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
1809 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1810 are all ignored by SetJob, so we don't bother copying them */
1818 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
1819 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
1821 JobW
= (LPBYTE
)info1W
;
1822 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
1823 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
1824 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
1825 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
1826 info1W
->Status
= info1A
->Status
;
1827 info1W
->Priority
= info1A
->Priority
;
1828 info1W
->Position
= info1A
->Position
;
1829 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
1834 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
1835 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
1837 JobW
= (LPBYTE
)info2W
;
1838 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
1839 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
1840 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
1841 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
1842 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
1843 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
1844 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
1845 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
1846 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
1847 info2W
->Status
= info2A
->Status
;
1848 info2W
->Priority
= info2A
->Priority
;
1849 info2W
->Position
= info2A
->Position
;
1850 info2W
->StartTime
= info2A
->StartTime
;
1851 info2W
->UntilTime
= info2A
->UntilTime
;
1852 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
1856 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
1857 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
1860 SetLastError(ERROR_INVALID_LEVEL
);
1864 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
1870 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
1871 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
1872 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
1873 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
1874 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
1879 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
1880 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
1881 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
1882 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
1883 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
1884 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
1885 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
1886 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
1887 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
1891 HeapFree(GetProcessHeap(), 0, JobW
);
1896 /*****************************************************************************
1897 * SetJobW [WINSPOOL.@]
1899 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1900 LPBYTE pJob
, DWORD Command
)
1905 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
1906 FIXME("Ignoring everything other than document title\n");
1908 EnterCriticalSection(&printer_handles_cs
);
1909 job
= get_job(hPrinter
, JobId
);
1919 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
1920 HeapFree(GetProcessHeap(), 0, job
->document_title
);
1921 job
->document_title
= strdupW(info1
->pDocument
);
1926 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
1927 HeapFree(GetProcessHeap(), 0, job
->document_title
);
1928 job
->document_title
= strdupW(info2
->pDocument
);
1934 SetLastError(ERROR_INVALID_LEVEL
);
1939 LeaveCriticalSection(&printer_handles_cs
);
1943 /*****************************************************************************
1944 * EndDocPrinter [WINSPOOL.@]
1946 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
1948 opened_printer_t
*printer
;
1950 TRACE("(%p)\n", hPrinter
);
1952 EnterCriticalSection(&printer_handles_cs
);
1954 printer
= get_opened_printer(hPrinter
);
1957 SetLastError(ERROR_INVALID_HANDLE
);
1963 SetLastError(ERROR_SPL_NO_STARTDOC
);
1967 CloseHandle(printer
->doc
->hf
);
1968 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
1969 HeapFree(GetProcessHeap(), 0, printer
->doc
);
1970 printer
->doc
= NULL
;
1973 LeaveCriticalSection(&printer_handles_cs
);
1977 /*****************************************************************************
1978 * EndPagePrinter [WINSPOOL.@]
1980 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
1982 FIXME("(%p): stub\n", hPrinter
);
1986 /*****************************************************************************
1987 * StartDocPrinterA [WINSPOOL.@]
1989 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
1991 UNICODE_STRING usBuffer
;
1993 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
1996 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
1997 or one (DOC_INFO_3) extra DWORDs */
2001 doc2W
.JobId
= doc2
->JobId
;
2004 doc2W
.dwMode
= doc2
->dwMode
;
2007 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2008 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2009 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
2013 SetLastError(ERROR_INVALID_LEVEL
);
2017 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
2019 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
2020 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
2021 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
2026 /*****************************************************************************
2027 * StartDocPrinterW [WINSPOOL.@]
2029 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2031 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
2032 opened_printer_t
*printer
;
2033 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2034 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
2035 JOB_INFO_1W job_info
;
2036 DWORD needed
, ret
= 0;
2040 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2041 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
2042 debugstr_w(doc
->pDatatype
));
2044 if(Level
< 1 || Level
> 3)
2046 SetLastError(ERROR_INVALID_LEVEL
);
2050 EnterCriticalSection(&printer_handles_cs
);
2051 printer
= get_opened_printer(hPrinter
);
2054 SetLastError(ERROR_INVALID_HANDLE
);
2060 SetLastError(ERROR_INVALID_PRINTER_STATE
);
2064 /* Even if we're printing to a file we still add a print job, we'll
2065 just ignore the spool file name */
2067 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
2069 ERR("AddJob failed gle %08lx\n", GetLastError());
2073 if(doc
->pOutputFile
)
2074 filename
= doc
->pOutputFile
;
2076 filename
= addjob
->Path
;
2078 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
2079 if(hf
== INVALID_HANDLE_VALUE
)
2082 memset(&job_info
, 0, sizeof(job_info
));
2083 job_info
.pDocument
= doc
->pDocName
;
2084 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
2086 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
2087 printer
->doc
->hf
= hf
;
2088 ret
= printer
->doc
->job_id
= addjob
->JobId
;
2090 LeaveCriticalSection(&printer_handles_cs
);
2095 /*****************************************************************************
2096 * StartPagePrinter [WINSPOOL.@]
2098 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
2100 FIXME("(%p): stub\n", hPrinter
);
2104 /*****************************************************************************
2105 * GetFormA [WINSPOOL.@]
2107 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2108 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2110 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,pFormName
,
2111 Level
,pForm
,cbBuf
,pcbNeeded
);
2115 /*****************************************************************************
2116 * GetFormW [WINSPOOL.@]
2118 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2119 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2121 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,
2122 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
2126 /*****************************************************************************
2127 * SetFormA [WINSPOOL.@]
2129 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2132 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2136 /*****************************************************************************
2137 * SetFormW [WINSPOOL.@]
2139 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2142 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2146 /*****************************************************************************
2147 * ReadPrinter [WINSPOOL.@]
2149 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
2150 LPDWORD pNoBytesRead
)
2152 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
2156 /*****************************************************************************
2157 * ResetPrinterA [WINSPOOL.@]
2159 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
2161 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2165 /*****************************************************************************
2166 * ResetPrinterW [WINSPOOL.@]
2168 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2170 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2174 /*****************************************************************************
2175 * WINSPOOL_GetDWORDFromReg
2177 * Return DWORD associated with ValueName from hkey.
2179 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
2181 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
2184 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
2186 if(ret
!= ERROR_SUCCESS
) {
2187 WARN("Got ret = %ld on name %s\n", ret
, ValueName
);
2190 if(type
!= REG_DWORD
) {
2191 ERR("Got type %ld\n", type
);
2197 /*****************************************************************************
2198 * WINSPOOL_GetStringFromReg
2200 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2201 * String is stored either as unicode or ascii.
2202 * Bit of a hack here to get the ValueName if we want ascii.
2204 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
2205 DWORD buflen
, DWORD
*needed
,
2208 DWORD sz
= buflen
, type
;
2212 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2214 LPSTR ValueNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,ValueName
);
2215 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
2216 HeapFree(GetProcessHeap(),0,ValueNameA
);
2218 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
2219 WARN("Got ret = %ld\n", ret
);
2227 /*****************************************************************************
2228 * WINSPOOL_GetDefaultDevMode
2230 * Get a default DevMode values for wineps.
2234 static void WINSPOOL_GetDefaultDevMode(
2236 DWORD buflen
, DWORD
*needed
,
2240 static const char szwps
[] = "wineps.drv";
2242 /* fill default DEVMODE - should be read from ppd... */
2243 ZeroMemory( &dm
, sizeof(dm
) );
2244 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
2245 dm
.dmSpecVersion
= DM_SPECVERSION
;
2246 dm
.dmDriverVersion
= 1;
2247 dm
.dmSize
= sizeof(DEVMODEA
);
2248 dm
.dmDriverExtra
= 0;
2250 DM_ORIENTATION
| DM_PAPERSIZE
|
2251 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
2254 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
2255 DM_YRESOLUTION
| DM_TTOPTION
;
2257 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
2258 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
2259 dm
.u1
.s1
.dmPaperLength
= 2970;
2260 dm
.u1
.s1
.dmPaperWidth
= 2100;
2264 dm
.dmDefaultSource
= DMBIN_AUTO
;
2265 dm
.dmPrintQuality
= DMRES_MEDIUM
;
2268 dm
.dmYResolution
= 300; /* 300dpi */
2269 dm
.dmTTOption
= DMTT_BITMAP
;
2272 /* dm.dmLogPixels */
2273 /* dm.dmBitsPerPel */
2274 /* dm.dmPelsWidth */
2275 /* dm.dmPelsHeight */
2276 /* dm.dmDisplayFlags */
2277 /* dm.dmDisplayFrequency */
2278 /* dm.dmICMMethod */
2279 /* dm.dmICMIntent */
2280 /* dm.dmMediaType */
2281 /* dm.dmDitherType */
2282 /* dm.dmReserved1 */
2283 /* dm.dmReserved2 */
2284 /* dm.dmPanningWidth */
2285 /* dm.dmPanningHeight */
2288 if(buflen
>= sizeof(DEVMODEW
)) {
2289 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
2290 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
2291 HeapFree(GetProcessHeap(),0,pdmW
);
2293 *needed
= sizeof(DEVMODEW
);
2297 if(buflen
>= sizeof(DEVMODEA
)) {
2298 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
2300 *needed
= sizeof(DEVMODEA
);
2304 /*****************************************************************************
2305 * WINSPOOL_GetDevModeFromReg
2307 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2308 * DevMode is stored either as unicode or ascii.
2310 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
2312 DWORD buflen
, DWORD
*needed
,
2315 DWORD sz
= buflen
, type
;
2318 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
2319 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2320 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
2321 if (sz
< sizeof(DEVMODEA
))
2323 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName
),sz
);
2326 /* ensures that dmSize is not erratically bogus if registry is invalid */
2327 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
2328 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
2330 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2332 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
2333 memcpy(ptr
, dmW
, sz
);
2334 HeapFree(GetProcessHeap(),0,dmW
);
2341 /*********************************************************************
2342 * WINSPOOL_GetPrinter_2
2344 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2345 * The strings are either stored as unicode or ascii.
2347 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
2348 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2351 DWORD size
, left
= cbBuf
;
2352 BOOL space
= (cbBuf
> 0);
2357 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2359 if(space
&& size
<= left
) {
2360 pi2
->pPrinterName
= (LPWSTR
)ptr
;
2367 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
2369 if(space
&& size
<= left
) {
2370 pi2
->pShareName
= (LPWSTR
)ptr
;
2377 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2379 if(space
&& size
<= left
) {
2380 pi2
->pPortName
= (LPWSTR
)ptr
;
2387 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
2389 if(space
&& size
<= left
) {
2390 pi2
->pDriverName
= (LPWSTR
)ptr
;
2397 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
2399 if(space
&& size
<= left
) {
2400 pi2
->pComment
= (LPWSTR
)ptr
;
2407 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
2409 if(space
&& size
<= left
) {
2410 pi2
->pLocation
= (LPWSTR
)ptr
;
2417 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
2419 if(space
&& size
<= left
) {
2420 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2429 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
2430 if(space
&& size
<= left
) {
2431 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2438 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
2440 if(space
&& size
<= left
) {
2441 pi2
->pSepFile
= (LPWSTR
)ptr
;
2448 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
2450 if(space
&& size
<= left
) {
2451 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
2458 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
2460 if(space
&& size
<= left
) {
2461 pi2
->pDatatype
= (LPWSTR
)ptr
;
2468 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
2470 if(space
&& size
<= left
) {
2471 pi2
->pParameters
= (LPWSTR
)ptr
;
2479 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2480 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
2481 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2482 "Default Priority");
2483 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
2484 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
2487 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
2488 memset(pi2
, 0, sizeof(*pi2
));
2493 /*********************************************************************
2494 * WINSPOOL_GetPrinter_4
2496 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2498 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
2499 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2502 DWORD size
, left
= cbBuf
;
2503 BOOL space
= (cbBuf
> 0);
2508 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2510 if(space
&& size
<= left
) {
2511 pi4
->pPrinterName
= (LPWSTR
)ptr
;
2519 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2522 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
2523 memset(pi4
, 0, sizeof(*pi4
));
2528 /*********************************************************************
2529 * WINSPOOL_GetPrinter_5
2531 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2533 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
2534 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2537 DWORD size
, left
= cbBuf
;
2538 BOOL space
= (cbBuf
> 0);
2543 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2545 if(space
&& size
<= left
) {
2546 pi5
->pPrinterName
= (LPWSTR
)ptr
;
2553 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2555 if(space
&& size
<= left
) {
2556 pi5
->pPortName
= (LPWSTR
)ptr
;
2564 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2565 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2567 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2571 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
2572 memset(pi5
, 0, sizeof(*pi5
));
2577 /*****************************************************************************
2578 * WINSPOOL_GetPrinter
2580 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2581 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2582 * just a collection of pointers to strings.
2584 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2585 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
2588 DWORD size
, needed
= 0;
2590 HKEY hkeyPrinter
, hkeyPrinters
;
2593 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
2595 if (!(name
= get_opened_printer_name(hPrinter
))) {
2596 SetLastError(ERROR_INVALID_HANDLE
);
2600 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2602 ERR("Can't create Printers key\n");
2605 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
2607 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
2608 RegCloseKey(hkeyPrinters
);
2609 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
2616 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
2618 size
= sizeof(PRINTER_INFO_2W
);
2620 ptr
= pPrinter
+ size
;
2622 memset(pPrinter
, 0, size
);
2627 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
2635 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
2637 size
= sizeof(PRINTER_INFO_4W
);
2639 ptr
= pPrinter
+ size
;
2641 memset(pPrinter
, 0, size
);
2646 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
2655 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
2657 size
= sizeof(PRINTER_INFO_5W
);
2659 ptr
= pPrinter
+ size
;
2661 memset(pPrinter
, 0, size
);
2667 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
2674 FIXME("Unimplemented level %ld\n", Level
);
2675 SetLastError(ERROR_INVALID_LEVEL
);
2676 RegCloseKey(hkeyPrinters
);
2677 RegCloseKey(hkeyPrinter
);
2681 RegCloseKey(hkeyPrinter
);
2682 RegCloseKey(hkeyPrinters
);
2684 TRACE("returning %d needed = %ld\n", ret
, needed
);
2685 if(pcbNeeded
) *pcbNeeded
= needed
;
2687 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2691 /*****************************************************************************
2692 * GetPrinterW [WINSPOOL.@]
2694 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2695 DWORD cbBuf
, LPDWORD pcbNeeded
)
2697 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2701 /*****************************************************************************
2702 * GetPrinterA [WINSPOOL.@]
2704 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2705 DWORD cbBuf
, LPDWORD pcbNeeded
)
2707 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2711 /*****************************************************************************
2712 * WINSPOOL_EnumPrinters
2714 * Implementation of EnumPrintersA|W
2716 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
2717 DWORD dwLevel
, LPBYTE lpbPrinters
,
2718 DWORD cbBuf
, LPDWORD lpdwNeeded
,
2719 LPDWORD lpdwReturned
, BOOL unicode
)
2722 HKEY hkeyPrinters
, hkeyPrinter
;
2723 WCHAR PrinterName
[255];
2724 DWORD needed
= 0, number
= 0;
2725 DWORD used
, i
, left
;
2729 memset(lpbPrinters
, 0, cbBuf
);
2735 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2736 if(dwType
== PRINTER_ENUM_DEFAULT
)
2739 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
2740 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2741 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
2742 if(!dwType
) return TRUE
;
2745 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
2746 FIXME("dwType = %08lx\n", dwType
);
2747 SetLastError(ERROR_INVALID_FLAGS
);
2751 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2753 ERR("Can't create Printers key\n");
2757 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
2758 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
2759 RegCloseKey(hkeyPrinters
);
2760 ERR("Can't query Printers key\n");
2763 TRACE("Found %ld printers\n", number
);
2767 RegCloseKey(hkeyPrinters
);
2769 *lpdwReturned
= number
;
2773 used
= number
* sizeof(PRINTER_INFO_2W
);
2776 used
= number
* sizeof(PRINTER_INFO_4W
);
2779 used
= number
* sizeof(PRINTER_INFO_5W
);
2783 SetLastError(ERROR_INVALID_LEVEL
);
2784 RegCloseKey(hkeyPrinters
);
2787 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
2789 for(i
= 0; i
< number
; i
++) {
2790 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
2792 ERR("Can't enum key number %ld\n", i
);
2793 RegCloseKey(hkeyPrinters
);
2796 TRACE("Printer %ld is %s\n", i
, debugstr_w(PrinterName
));
2797 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
2799 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
2800 RegCloseKey(hkeyPrinters
);
2805 buf
= lpbPrinters
+ used
;
2806 left
= cbBuf
- used
;
2814 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
2815 left
, &needed
, unicode
);
2817 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
2820 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
2821 left
, &needed
, unicode
);
2823 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
2826 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
2827 left
, &needed
, unicode
);
2829 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
2832 ERR("Shouldn't be here!\n");
2833 RegCloseKey(hkeyPrinter
);
2834 RegCloseKey(hkeyPrinters
);
2837 RegCloseKey(hkeyPrinter
);
2839 RegCloseKey(hkeyPrinters
);
2846 memset(lpbPrinters
, 0, cbBuf
);
2847 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2851 *lpdwReturned
= number
;
2852 SetLastError(ERROR_SUCCESS
);
2857 /******************************************************************
2858 * EnumPrintersW [WINSPOOL.@]
2860 * Enumerates the available printers, print servers and print
2861 * providers, depending on the specified flags, name and level.
2865 * If level is set to 1:
2866 * Not implemented yet!
2867 * Returns TRUE with an empty list.
2869 * If level is set to 2:
2870 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2871 * Returns an array of PRINTER_INFO_2 data structures in the
2872 * lpbPrinters buffer. Note that according to MSDN also an
2873 * OpenPrinter should be performed on every remote printer.
2875 * If level is set to 4 (officially WinNT only):
2876 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2877 * Fast: Only the registry is queried to retrieve printer names,
2878 * no connection to the driver is made.
2879 * Returns an array of PRINTER_INFO_4 data structures in the
2880 * lpbPrinters buffer.
2882 * If level is set to 5 (officially WinNT4/Win9x only):
2883 * Fast: Only the registry is queried to retrieve printer names,
2884 * no connection to the driver is made.
2885 * Returns an array of PRINTER_INFO_5 data structures in the
2886 * lpbPrinters buffer.
2888 * If level set to 3 or 6+:
2889 * returns zero (failure!)
2891 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2895 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2896 * - Only levels 2, 4 and 5 are implemented at the moment.
2897 * - 16-bit printer drivers are not enumerated.
2898 * - Returned amount of bytes used/needed does not match the real Windoze
2899 * implementation (as in this implementation, all strings are part
2900 * of the buffer, whereas Win32 keeps them somewhere else)
2901 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2904 * - In a regular Wine installation, no registry settings for printers
2905 * exist, which makes this function return an empty list.
2907 BOOL WINAPI
EnumPrintersW(
2908 DWORD dwType
, /* [in] Types of print objects to enumerate */
2909 LPWSTR lpszName
, /* [in] name of objects to enumerate */
2910 DWORD dwLevel
, /* [in] type of printer info structure */
2911 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
2912 DWORD cbBuf
, /* [in] max size of buffer in bytes */
2913 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
2914 LPDWORD lpdwReturned
/* [out] number of entries returned */
2917 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
2918 lpdwNeeded
, lpdwReturned
, TRUE
);
2921 /******************************************************************
2922 * EnumPrintersA [WINSPOOL.@]
2925 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
2926 DWORD dwLevel
, LPBYTE lpbPrinters
,
2927 DWORD cbBuf
, LPDWORD lpdwNeeded
,
2928 LPDWORD lpdwReturned
)
2931 UNICODE_STRING lpszNameW
;
2934 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
2935 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
2936 lpdwNeeded
, lpdwReturned
, FALSE
);
2937 RtlFreeUnicodeString(&lpszNameW
);
2941 /*****************************************************************************
2942 * WINSPOOL_GetDriverInfoFromReg [internal]
2944 * Enters the information from the registry into the DRIVER_INFO struct
2947 * zero if the printer driver does not exist in the registry
2948 * (only if Level > 1) otherwise nonzero
2950 static BOOL
WINSPOOL_GetDriverInfoFromReg(
2953 LPWSTR pEnvironment
,
2955 LPBYTE ptr
, /* DRIVER_INFO */
2956 LPBYTE pDriverStrings
, /* strings buffer */
2957 DWORD cbBuf
, /* size of string buffer */
2958 LPDWORD pcbNeeded
, /* space needed for str. */
2959 BOOL unicode
) /* type of strings */
2960 { DWORD dw
, size
, tmp
, type
;
2962 LPBYTE strPtr
= pDriverStrings
;
2964 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2965 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
2966 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
2969 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
2970 if (*pcbNeeded
<= cbBuf
)
2971 strcpyW((LPWSTR
)strPtr
, DriverName
);
2973 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
2975 if(*pcbNeeded
<= cbBuf
)
2976 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1,
2977 (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
2981 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
2985 ((PDRIVER_INFO_3W
) ptr
)->pName
= (LPWSTR
) strPtr
;
2986 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
2989 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
2990 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName
));
2991 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
2996 if(RegQueryValueExA(hkeyDriver
, "Version", 0, &type
, (PBYTE
)&dw
, &size
) !=
2998 WARN("Can't get Version\n");
3000 ((PDRIVER_INFO_3A
) ptr
)->cVersion
= dw
;
3003 pEnvironment
= (LPWSTR
)DefaultEnvironmentW
;
3005 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
3007 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
3010 if(*pcbNeeded
<= cbBuf
) {
3012 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
3014 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1,
3015 (LPSTR
)strPtr
, size
, NULL
, NULL
);
3017 ((PDRIVER_INFO_3W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
3018 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3021 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
3024 if(*pcbNeeded
<= cbBuf
)
3025 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
3028 ((PDRIVER_INFO_3W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
3029 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3032 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
3035 if(*pcbNeeded
<= cbBuf
)
3036 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
3039 ((PDRIVER_INFO_3W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
3040 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3043 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3044 0, &size
, unicode
)) {
3046 if(*pcbNeeded
<= cbBuf
)
3047 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3048 size
, &tmp
, unicode
);
3050 ((PDRIVER_INFO_3W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
3051 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3055 RegCloseKey(hkeyDriver
);
3056 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3060 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
3063 if(*pcbNeeded
<= cbBuf
)
3064 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
3065 size
, &tmp
, unicode
);
3067 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
3068 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3071 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
3074 if(*pcbNeeded
<= cbBuf
)
3075 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
3076 size
, &tmp
, unicode
);
3078 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
3079 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3082 if(WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
3085 if(*pcbNeeded
<= cbBuf
)
3086 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
3087 size
, &tmp
, unicode
);
3089 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
3090 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3093 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
3096 if(*pcbNeeded
<= cbBuf
)
3097 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
3098 size
, &tmp
, unicode
);
3100 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
3101 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3104 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3105 RegCloseKey(hkeyDriver
);
3109 /*****************************************************************************
3110 * WINSPOOL_GetPrinterDriver
3112 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
3113 DWORD Level
, LPBYTE pDriverInfo
,
3114 DWORD cbBuf
, LPDWORD pcbNeeded
,
3118 WCHAR DriverName
[100];
3119 DWORD ret
, type
, size
, needed
= 0;
3121 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
3123 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
3124 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
3126 ZeroMemory(pDriverInfo
, cbBuf
);
3128 if (!(name
= get_opened_printer_name(hPrinter
))) {
3129 SetLastError(ERROR_INVALID_HANDLE
);
3132 if(Level
< 1 || Level
> 3) {
3133 SetLastError(ERROR_INVALID_LEVEL
);
3136 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
3138 ERR("Can't create Printers key\n");
3141 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
3143 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3144 RegCloseKey(hkeyPrinters
);
3145 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3148 size
= sizeof(DriverName
);
3150 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
3151 (LPBYTE
)DriverName
, &size
);
3152 RegCloseKey(hkeyPrinter
);
3153 RegCloseKey(hkeyPrinters
);
3154 if(ret
!= ERROR_SUCCESS
) {
3155 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
3159 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
3161 ERR("Can't create Drivers key\n");
3167 size
= sizeof(DRIVER_INFO_1W
);
3170 size
= sizeof(DRIVER_INFO_2W
);
3173 size
= sizeof(DRIVER_INFO_3W
);
3176 ERR("Invalid level\n");
3181 ptr
= pDriverInfo
+ size
;
3183 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
3184 pEnvironment
, Level
, pDriverInfo
,
3185 (cbBuf
< size
) ? NULL
: ptr
,
3186 (cbBuf
< size
) ? 0 : cbBuf
- size
,
3187 &needed
, unicode
)) {
3188 RegCloseKey(hkeyDrivers
);
3192 RegCloseKey(hkeyDrivers
);
3194 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
3195 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3196 if(cbBuf
>= needed
) return TRUE
;
3197 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3201 /*****************************************************************************
3202 * GetPrinterDriverA [WINSPOOL.@]
3204 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
3205 DWORD Level
, LPBYTE pDriverInfo
,
3206 DWORD cbBuf
, LPDWORD pcbNeeded
)
3209 UNICODE_STRING pEnvW
;
3212 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
3213 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
3214 cbBuf
, pcbNeeded
, FALSE
);
3215 RtlFreeUnicodeString(&pEnvW
);
3218 /*****************************************************************************
3219 * GetPrinterDriverW [WINSPOOL.@]
3221 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
3222 DWORD Level
, LPBYTE pDriverInfo
,
3223 DWORD cbBuf
, LPDWORD pcbNeeded
)
3225 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
3226 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
3229 /*****************************************************************************
3230 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3232 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
3233 DWORD Level
, LPBYTE pDriverDirectory
,
3234 DWORD cbBuf
, LPDWORD pcbNeeded
)
3238 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
3239 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
3241 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName
));
3242 SetLastError(ERROR_INVALID_PARAMETER
);
3245 if(pEnvironment
!= NULL
) {
3246 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment
));
3247 SetLastError(ERROR_INVALID_ENVIRONMENT
);
3250 if(Level
!= 1) /* win95 ignores this so we just carry on */
3251 WARN("Level = %ld - assuming 1\n", Level
);
3253 /* FIXME should read from registry */
3254 needed
= GetSystemDirectoryW( (LPWSTR
)pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
3255 /* GetSystemDirectoryW returns number of TCHAR without '\0'
3259 needed
*=sizeof(WCHAR
);
3262 *pcbNeeded
= needed
;
3263 TRACE("required <%08lx>\n", *pcbNeeded
);
3264 if(needed
> cbBuf
) {
3265 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3272 /*****************************************************************************
3273 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3275 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
3276 DWORD Level
, LPBYTE pDriverDirectory
,
3277 DWORD cbBuf
, LPDWORD pcbNeeded
)
3279 UNICODE_STRING nameW
, environmentW
;
3282 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
3283 WCHAR
*driverDirectoryW
= NULL
;
3285 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
3287 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
3288 else nameW
.Buffer
= NULL
;
3289 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
3290 else environmentW
.Buffer
= NULL
;
3292 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
3293 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
3296 needed
= 1 + WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
3297 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
3299 *pcbNeeded
= needed
;
3300 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
3302 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
3304 TRACE("provided<%ld> required <%ld>\n", cbBuf
, *pcbNeeded
);
3306 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
3307 RtlFreeUnicodeString(&environmentW
);
3308 RtlFreeUnicodeString(&nameW
);
3313 /*****************************************************************************
3314 * AddPrinterDriverA [WINSPOOL.@]
3316 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
3319 HKEY hkeyDrivers
, hkeyName
;
3321 TRACE("(%s,%ld,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
3323 if(level
!= 2 && level
!= 3) {
3324 SetLastError(ERROR_INVALID_LEVEL
);
3328 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
3329 SetLastError(ERROR_INVALID_PARAMETER
);
3333 WARN("pDriverInfo == NULL\n");
3334 SetLastError(ERROR_INVALID_PARAMETER
);
3339 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
3341 memset(&di3
, 0, sizeof(di3
));
3342 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
3345 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
3347 SetLastError(ERROR_INVALID_PARAMETER
);
3350 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= "";
3351 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= "\0";
3352 if(!di3
.pHelpFile
) di3
.pHelpFile
= "";
3353 if(!di3
.pMonitorName
) di3
.pMonitorName
= "";
3355 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
3358 ERR("Can't create Drivers key\n");
3362 if(level
== 2) { /* apparently can't overwrite with level2 */
3363 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
3364 RegCloseKey(hkeyName
);
3365 RegCloseKey(hkeyDrivers
);
3366 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
3367 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
3371 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
3372 RegCloseKey(hkeyDrivers
);
3373 ERR("Can't create Name key\n");
3376 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
3378 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, 0);
3379 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, 0);
3380 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
3382 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, 0);
3383 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
3384 (LPBYTE
) di3
.pDependentFiles
, 0);
3385 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, 0);
3386 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, 0);
3387 RegCloseKey(hkeyName
);
3388 RegCloseKey(hkeyDrivers
);
3393 /*****************************************************************************
3394 * AddPrinterDriverW [WINSPOOL.@]
3396 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
3399 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName
),
3404 /*****************************************************************************
3405 * AddPrintProcessorA [WINSPOOL.@]
3407 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
3408 LPSTR pPrintProcessorName
)
3410 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
3411 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
3415 /*****************************************************************************
3416 * AddPrintProcessorW [WINSPOOL.@]
3418 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
3419 LPWSTR pPrintProcessorName
)
3421 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
3422 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
3426 /*****************************************************************************
3427 * AddPrintProvidorA [WINSPOOL.@]
3429 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3431 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
3435 /*****************************************************************************
3436 * AddPrintProvidorW [WINSPOOL.@]
3438 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3440 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
3444 /*****************************************************************************
3445 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3447 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
3448 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
3450 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
3451 pDevModeOutput
, pDevModeInput
);
3455 /*****************************************************************************
3456 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3458 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
3459 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
3461 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
3462 pDevModeOutput
, pDevModeInput
);
3466 /*****************************************************************************
3467 * PrinterProperties [WINSPOOL.@]
3469 * Displays a dialog to set the properties of the printer.
3472 * nonzero on success or zero on failure
3475 * implemented as stub only
3477 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
3478 HANDLE hPrinter
/* [in] handle to printer object */
3480 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
3481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3485 /*****************************************************************************
3486 * EnumJobsA [WINSPOOL.@]
3489 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3490 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3493 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3494 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3496 if(pcbNeeded
) *pcbNeeded
= 0;
3497 if(pcReturned
) *pcReturned
= 0;
3502 /*****************************************************************************
3503 * EnumJobsW [WINSPOOL.@]
3506 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3507 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3510 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3511 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3513 if(pcbNeeded
) *pcbNeeded
= 0;
3514 if(pcReturned
) *pcReturned
= 0;
3518 /*****************************************************************************
3519 * WINSPOOL_EnumPrinterDrivers [internal]
3521 * Delivers information about all printer drivers installed on the
3522 * localhost or a given server
3525 * nonzero on success or zero on failure. If the buffer for the returned
3526 * information is too small the function will return an error
3529 * - only implemented for localhost, foreign hosts will return an error
3531 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPWSTR pEnvironment
,
3532 DWORD Level
, LPBYTE pDriverInfo
,
3533 DWORD cbBuf
, LPDWORD pcbNeeded
,
3534 LPDWORD pcReturned
, BOOL unicode
)
3537 DWORD i
, needed
, number
= 0, size
= 0;
3538 WCHAR DriverNameW
[255];
3541 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3542 debugstr_w(pName
), debugstr_w(pEnvironment
),
3543 Level
, pDriverInfo
, cbBuf
, unicode
);
3545 /* check for local drivers */
3547 ERR("remote drivers unsupported! Current remote host is %s\n",
3552 /* check input parameter */
3553 if((Level
< 1) || (Level
> 3)) {
3554 ERR("unsupported level %ld\n", Level
);
3555 SetLastError(ERROR_INVALID_LEVEL
);
3559 /* initialize return values */
3561 memset( pDriverInfo
, 0, cbBuf
);
3565 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
3567 ERR("Can't open Drivers key\n");
3571 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3572 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3573 RegCloseKey(hkeyDrivers
);
3574 ERR("Can't query Drivers key\n");
3577 TRACE("Found %ld Drivers\n", number
);
3579 /* get size of single struct
3580 * unicode and ascii structure have the same size
3584 size
= sizeof(DRIVER_INFO_1A
);
3587 size
= sizeof(DRIVER_INFO_2A
);
3590 size
= sizeof(DRIVER_INFO_3A
);
3594 /* calculate required buffer size */
3595 *pcbNeeded
= size
* number
;
3597 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
3599 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
3600 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
3602 ERR("Can't enum key number %ld\n", i
);
3603 RegCloseKey(hkeyDrivers
);
3606 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
3607 pEnvironment
, Level
, ptr
,
3608 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
3609 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
3610 &needed
, unicode
)) {
3611 RegCloseKey(hkeyDrivers
);
3614 (*pcbNeeded
) += needed
;
3617 RegCloseKey(hkeyDrivers
);
3619 if(cbBuf
< *pcbNeeded
){
3620 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3624 *pcReturned
= number
;
3628 /*****************************************************************************
3629 * EnumPrinterDriversW [WINSPOOL.@]
3631 * see function EnumPrinterDrivers for RETURNS, BUGS
3633 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
3634 LPBYTE pDriverInfo
, DWORD cbBuf
,
3635 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3637 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
3638 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
3641 /*****************************************************************************
3642 * EnumPrinterDriversA [WINSPOOL.@]
3644 * see function EnumPrinterDrivers for RETURNS, BUGS
3646 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
3647 LPBYTE pDriverInfo
, DWORD cbBuf
,
3648 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3650 UNICODE_STRING pNameW
, pEnvironmentW
;
3651 PWSTR pwstrNameW
, pwstrEnvironmentW
;
3653 pwstrNameW
= asciitounicode(&pNameW
, pName
);
3654 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
3656 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
3657 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
3659 RtlFreeUnicodeString(&pNameW
);
3660 RtlFreeUnicodeString(&pEnvironmentW
);
3665 static CHAR PortMonitor
[] = "Wine Port Monitor";
3666 static CHAR PortDescription
[] = "Wine Port";
3668 static BOOL
WINSPOOL_ComPortExists( LPCSTR name
)
3672 handle
= CreateFileA( name
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3673 NULL
, OPEN_EXISTING
, 0, NULL
);
3674 if (handle
== INVALID_HANDLE_VALUE
)
3676 TRACE("Checking %s exists\n", name
);
3677 CloseHandle( handle
);
3681 static DWORD
WINSPOOL_CountSerialPorts(void)
3688 strcpy( name
, "COMx:" );
3690 if (WINSPOOL_ComPortExists( name
))
3697 /******************************************************************************
3698 * EnumPortsA (WINSPOOL.@)
3700 BOOL WINAPI
EnumPortsA(LPSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
3701 LPDWORD bufneeded
,LPDWORD bufreturned
)
3704 DWORD info_size
, ofs
, i
, printer_count
, serial_count
, count
, n
, r
;
3705 const LPCSTR szPrinterPortKey
= "Software\\Wine\\Wine\\Config\\spooler";
3709 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3710 debugstr_a(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
3715 info_size
= sizeof (PORT_INFO_1A
);
3718 info_size
= sizeof (PORT_INFO_2A
);
3721 SetLastError(ERROR_INVALID_LEVEL
);
3725 /* see how many exist */
3728 serial_count
= WINSPOOL_CountSerialPorts();
3731 r
= RegOpenKeyA( HKEY_LOCAL_MACHINE
, szPrinterPortKey
, &hkey_printer
);
3732 if ( r
== ERROR_SUCCESS
)
3734 RegQueryInfoKeyA( hkey_printer
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3735 &printer_count
, NULL
, NULL
, NULL
, NULL
);
3737 count
= serial_count
+ printer_count
;
3739 /* then fill in the structure info structure once
3740 we know the offset to the first string */
3742 memset( buffer
, 0, bufsize
);
3744 ofs
= info_size
*count
;
3745 for ( i
=0; i
<count
; i
++)
3747 DWORD vallen
= sizeof(portname
) - 1;
3749 /* get the serial port values, then the printer values */
3750 if ( i
< serial_count
)
3752 strcpy( portname
, "COMx:" );
3753 portname
[3] = '1' + i
;
3754 if (!WINSPOOL_ComPortExists( portname
))
3757 TRACE("Found %s\n", portname
);
3758 vallen
= strlen( portname
);
3762 r
= RegEnumValueA( hkey_printer
, i
-serial_count
,
3763 portname
, &vallen
, NULL
, NULL
, NULL
, 0 );
3768 /* add a colon if necessary, and make it upper case */
3769 CharUpperBuffA(portname
,vallen
);
3770 if (strcasecmp(portname
,"nul")!=0)
3771 if (vallen
&& (portname
[vallen
-1] != ':') )
3772 lstrcatA(portname
,":");
3774 /* add the port info structure if we can fit it */
3775 if ( info_size
*(n
+1) < bufsize
)
3779 PORT_INFO_1A
*info
= (PORT_INFO_1A
*) &buffer
[info_size
*n
];
3780 info
->pName
= (LPSTR
) &buffer
[ofs
];
3782 else if ( level
== 2)
3784 PORT_INFO_2A
*info
= (PORT_INFO_2A
*) &buffer
[info_size
*n
];
3785 info
->pPortName
= (LPSTR
) &buffer
[ofs
];
3786 /* FIXME: fill in more stuff here */
3787 info
->pMonitorName
= PortMonitor
;
3788 info
->pDescription
= PortDescription
;
3789 info
->fPortType
= PORT_TYPE_WRITE
|PORT_TYPE_READ
;
3792 /* add the name of the port if we can fit it */
3793 if ( ofs
< bufsize
)
3794 lstrcpynA((LPSTR
)&buffer
[ofs
],portname
,bufsize
- ofs
);
3800 ofs
+= lstrlenA(portname
)+1;
3803 RegCloseKey(hkey_printer
);
3814 /******************************************************************************
3815 * EnumPortsW (WINSPOOL.@)
3817 BOOL WINAPI
EnumPortsW(LPWSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
3818 LPDWORD bufneeded
,LPDWORD bufreturned
)
3820 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3821 debugstr_w(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
3825 /******************************************************************************
3826 * GetDefaultPrinterW (WINSPOOL.@)
3829 * This function must read the value from data 'device' of key
3830 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3832 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
3836 WCHAR
*buffer
, *ptr
;
3840 SetLastError(ERROR_INVALID_PARAMETER
);
3844 /* make the buffer big enough for the stuff from the profile/registry,
3845 * the content must fit into the local buffer to compute the correct
3846 * size even if the extern buffer is too small or not given.
3847 * (20 for ,driver,port) */
3849 len
= max(100, (insize
+ 20));
3850 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3852 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
3854 SetLastError (ERROR_FILE_NOT_FOUND
);
3858 TRACE("%s\n", debugstr_w(buffer
));
3860 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
3862 SetLastError(ERROR_INVALID_NAME
);
3868 *namesize
= strlenW(buffer
) + 1;
3869 if(!name
|| (*namesize
> insize
))
3871 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3875 strcpyW(name
, buffer
);
3878 HeapFree( GetProcessHeap(), 0, buffer
);
3883 /******************************************************************************
3884 * GetDefaultPrinterA (WINSPOOL.@)
3886 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
3890 WCHAR
*bufferW
= NULL
;
3894 SetLastError(ERROR_INVALID_PARAMETER
);
3898 if(name
&& *namesize
) {
3900 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
3903 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
3908 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
3912 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
3915 TRACE("0x%08lx/0x%08lx:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
3918 HeapFree( GetProcessHeap(), 0, bufferW
);
3923 /******************************************************************************
3924 * SetPrinterDataExA (WINSPOOL.@)
3926 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
3927 LPCSTR pValueName
, DWORD Type
,
3928 LPBYTE pData
, DWORD cbData
)
3930 HKEY hkeyPrinter
, hkeySubkey
;
3933 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_a(pKeyName
),
3934 debugstr_a(pValueName
), Type
, pData
, cbData
);
3936 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3940 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3942 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
3943 RegCloseKey(hkeyPrinter
);
3946 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
3947 RegCloseKey(hkeySubkey
);
3948 RegCloseKey(hkeyPrinter
);
3952 /******************************************************************************
3953 * SetPrinterDataExW (WINSPOOL.@)
3955 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
3956 LPCWSTR pValueName
, DWORD Type
,
3957 LPBYTE pData
, DWORD cbData
)
3959 HKEY hkeyPrinter
, hkeySubkey
;
3962 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_w(pKeyName
),
3963 debugstr_w(pValueName
), Type
, pData
, cbData
);
3965 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3969 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3971 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
3972 RegCloseKey(hkeyPrinter
);
3975 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
3976 RegCloseKey(hkeySubkey
);
3977 RegCloseKey(hkeyPrinter
);
3981 /******************************************************************************
3982 * SetPrinterDataA (WINSPOOL.@)
3984 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
3985 LPBYTE pData
, DWORD cbData
)
3987 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
3991 /******************************************************************************
3992 * SetPrinterDataW (WINSPOOL.@)
3994 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
3995 LPBYTE pData
, DWORD cbData
)
3997 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
4001 /******************************************************************************
4002 * GetPrinterDataExA (WINSPOOL.@)
4004 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4005 LPCSTR pValueName
, LPDWORD pType
,
4006 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4008 HKEY hkeyPrinter
, hkeySubkey
;
4011 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4012 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
4015 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4019 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4021 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
4022 RegCloseKey(hkeyPrinter
);
4026 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4027 RegCloseKey(hkeySubkey
);
4028 RegCloseKey(hkeyPrinter
);
4032 /******************************************************************************
4033 * GetPrinterDataExW (WINSPOOL.@)
4035 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4036 LPCWSTR pValueName
, LPDWORD pType
,
4037 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4039 HKEY hkeyPrinter
, hkeySubkey
;
4042 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4043 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
4046 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4050 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4052 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
4053 RegCloseKey(hkeyPrinter
);
4057 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4058 RegCloseKey(hkeySubkey
);
4059 RegCloseKey(hkeyPrinter
);
4063 /******************************************************************************
4064 * GetPrinterDataA (WINSPOOL.@)
4066 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
4067 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4069 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
4070 pData
, nSize
, pcbNeeded
);
4073 /******************************************************************************
4074 * GetPrinterDataW (WINSPOOL.@)
4076 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
4077 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4079 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
4080 pData
, nSize
, pcbNeeded
);
4083 /*******************************************************************************
4084 * EnumPrinterDataExW [WINSPOOL.@]
4086 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4087 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4088 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4090 HKEY hkPrinter
, hkSubKey
;
4091 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
4092 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
4097 PPRINTER_ENUM_VALUESW ppev
;
4099 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
4101 if (pKeyName
== NULL
|| *pKeyName
== 0)
4102 return ERROR_INVALID_PARAMETER
;
4104 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
4105 if (ret
!= ERROR_SUCCESS
)
4107 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4112 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
4113 if (ret
!= ERROR_SUCCESS
)
4115 r
= RegCloseKey (hkPrinter
);
4116 if (r
!= ERROR_SUCCESS
)
4117 WARN ("RegCloseKey returned %li\n", r
);
4118 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter
,
4119 debugstr_w (pKeyName
), ret
);
4123 ret
= RegCloseKey (hkPrinter
);
4124 if (ret
!= ERROR_SUCCESS
)
4126 ERR ("RegCloseKey returned %li\n", ret
);
4127 r
= RegCloseKey (hkSubKey
);
4128 if (r
!= ERROR_SUCCESS
)
4129 WARN ("RegCloseKey returned %li\n", r
);
4133 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4134 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
4135 if (ret
!= ERROR_SUCCESS
)
4137 r
= RegCloseKey (hkSubKey
);
4138 if (r
!= ERROR_SUCCESS
)
4139 WARN ("RegCloseKey returned %li\n", r
);
4140 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey
, ret
);
4144 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4145 "cbMaxValueLen = %li\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
4147 if (cValues
== 0) /* empty key */
4149 r
= RegCloseKey (hkSubKey
);
4150 if (r
!= ERROR_SUCCESS
)
4151 WARN ("RegCloseKey returned %li\n", r
);
4152 *pcbEnumValues
= *pnEnumValues
= 0;
4153 return ERROR_SUCCESS
;
4156 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
4158 hHeap
= GetProcessHeap ();
4161 ERR ("GetProcessHeap failed\n");
4162 r
= RegCloseKey (hkSubKey
);
4163 if (r
!= ERROR_SUCCESS
)
4164 WARN ("RegCloseKey returned %li\n", r
);
4165 return ERROR_OUTOFMEMORY
;
4168 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
4169 if (lpValueName
== NULL
)
4171 ERR ("Failed to allocate %li bytes from process heap\n",
4172 cbMaxValueNameLen
* sizeof (WCHAR
));
4173 r
= RegCloseKey (hkSubKey
);
4174 if (r
!= ERROR_SUCCESS
)
4175 WARN ("RegCloseKey returned %li\n", r
);
4176 return ERROR_OUTOFMEMORY
;
4179 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
4180 if (lpValue
== NULL
)
4182 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen
);
4183 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4184 WARN ("HeapFree failed with code %li\n", GetLastError ());
4185 r
= RegCloseKey (hkSubKey
);
4186 if (r
!= ERROR_SUCCESS
)
4187 WARN ("RegCloseKey returned %li\n", r
);
4188 return ERROR_OUTOFMEMORY
;
4191 TRACE ("pass 1: calculating buffer required for all names and values\n");
4193 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4195 TRACE ("%li bytes required for %li headers\n", cbBufSize
, cValues
);
4197 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4199 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4200 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4201 NULL
, NULL
, lpValue
, &cbValueLen
);
4202 if (ret
!= ERROR_SUCCESS
)
4204 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4205 WARN ("HeapFree failed with code %li\n", GetLastError ());
4206 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4207 WARN ("HeapFree failed with code %li\n", GetLastError ());
4208 r
= RegCloseKey (hkSubKey
);
4209 if (r
!= ERROR_SUCCESS
)
4210 WARN ("RegCloseKey returned %li\n", r
);
4211 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4215 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4216 debugstr_w (lpValueName
), dwIndex
,
4217 (cbValueNameLen
+ 1) * sizeof (WCHAR
), cbValueLen
);
4219 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4220 cbBufSize
+= cbValueLen
;
4223 TRACE ("%li bytes required for all %li values\n", cbBufSize
, cValues
);
4225 *pcbEnumValues
= cbBufSize
;
4226 *pnEnumValues
= cValues
;
4228 if (cbEnumValues
< cbBufSize
) /* buffer too small */
4230 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4231 WARN ("HeapFree failed with code %li\n", GetLastError ());
4232 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4233 WARN ("HeapFree failed with code %li\n", GetLastError ());
4234 r
= RegCloseKey (hkSubKey
);
4235 if (r
!= ERROR_SUCCESS
)
4236 WARN ("RegCloseKey returned %li\n", r
);
4237 TRACE ("%li byte buffer is not large enough\n", cbEnumValues
);
4238 return ERROR_MORE_DATA
;
4241 TRACE ("pass 2: copying all names and values to buffer\n");
4243 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
4244 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4246 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4248 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4249 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4250 NULL
, &dwType
, lpValue
, &cbValueLen
);
4251 if (ret
!= ERROR_SUCCESS
)
4253 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4254 WARN ("HeapFree failed with code %li\n", GetLastError ());
4255 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4256 WARN ("HeapFree failed with code %li\n", GetLastError ());
4257 r
= RegCloseKey (hkSubKey
);
4258 if (r
!= ERROR_SUCCESS
)
4259 WARN ("RegCloseKey returned %li\n", r
);
4260 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4264 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4265 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
4266 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
4267 pEnumValues
+= cbValueNameLen
;
4269 /* return # of *bytes* (including trailing \0), not # of chars */
4270 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
4272 ppev
[dwIndex
].dwType
= dwType
;
4274 memcpy (pEnumValues
, lpValue
, cbValueLen
);
4275 ppev
[dwIndex
].pData
= pEnumValues
;
4276 pEnumValues
+= cbValueLen
;
4278 ppev
[dwIndex
].cbData
= cbValueLen
;
4280 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4281 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
4284 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4286 ret
= GetLastError ();
4287 ERR ("HeapFree failed with code %li\n", ret
);
4288 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4289 WARN ("HeapFree failed with code %li\n", GetLastError ());
4290 r
= RegCloseKey (hkSubKey
);
4291 if (r
!= ERROR_SUCCESS
)
4292 WARN ("RegCloseKey returned %li\n", r
);
4296 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4298 ret
= GetLastError ();
4299 ERR ("HeapFree failed with code %li\n", ret
);
4300 r
= RegCloseKey (hkSubKey
);
4301 if (r
!= ERROR_SUCCESS
)
4302 WARN ("RegCloseKey returned %li\n", r
);
4306 ret
= RegCloseKey (hkSubKey
);
4307 if (ret
!= ERROR_SUCCESS
)
4309 ERR ("RegCloseKey returned %li\n", ret
);
4313 return ERROR_SUCCESS
;
4316 /*******************************************************************************
4317 * EnumPrinterDataExA [WINSPOOL.@]
4319 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4320 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4321 * what Windows 2000 SP1 does.
4324 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4325 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4326 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4330 DWORD ret
, dwIndex
, dwBufSize
;
4334 TRACE ("%p %s\n", hPrinter
, pKeyName
);
4336 if (pKeyName
== NULL
|| *pKeyName
== 0)
4337 return ERROR_INVALID_PARAMETER
;
4339 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
4342 ret
= GetLastError ();
4343 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4347 hHeap
= GetProcessHeap ();
4350 ERR ("GetProcessHeap failed\n");
4351 return ERROR_OUTOFMEMORY
;
4354 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
4355 if (pKeyNameW
== NULL
)
4357 ERR ("Failed to allocate %li bytes from process heap\n",
4358 (LONG
) len
* sizeof (WCHAR
));
4359 return ERROR_OUTOFMEMORY
;
4362 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
4364 ret
= GetLastError ();
4365 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4366 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4367 WARN ("HeapFree failed with code %li\n", GetLastError ());
4371 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
4372 pcbEnumValues
, pnEnumValues
);
4373 if (ret
!= ERROR_SUCCESS
)
4375 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4376 WARN ("HeapFree failed with code %li\n", GetLastError ());
4377 TRACE ("EnumPrinterDataExW returned %li\n", ret
);
4381 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4383 ret
= GetLastError ();
4384 ERR ("HeapFree failed with code %li\n", ret
);
4388 if (*pnEnumValues
== 0) /* empty key */
4389 return ERROR_SUCCESS
;
4392 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4394 PPRINTER_ENUM_VALUESW ppev
=
4395 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4397 if (dwBufSize
< ppev
->cbValueName
)
4398 dwBufSize
= ppev
->cbValueName
;
4400 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
4401 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
4402 dwBufSize
= ppev
->cbData
;
4405 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize
);
4407 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
4408 if (pBuffer
== NULL
)
4410 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize
);
4411 return ERROR_OUTOFMEMORY
;
4414 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4416 PPRINTER_ENUM_VALUESW ppev
=
4417 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4419 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
4420 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
4424 ret
= GetLastError ();
4425 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4426 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4427 WARN ("HeapFree failed with code %li\n", GetLastError ());
4431 memcpy (ppev
->pValueName
, pBuffer
, len
);
4433 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4435 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
4436 ppev
->dwType
!= REG_MULTI_SZ
)
4439 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
4440 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
4443 ret
= GetLastError ();
4444 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4445 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4446 WARN ("HeapFree failed with code %li\n", GetLastError ());
4450 memcpy (ppev
->pData
, pBuffer
, len
);
4452 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4453 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4456 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4458 ret
= GetLastError ();
4459 ERR ("HeapFree failed with code %li\n", ret
);
4463 return ERROR_SUCCESS
;
4466 /******************************************************************************
4467 * AbortPrinter (WINSPOOL.@)
4469 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
4471 FIXME("(%p), stub!\n", hPrinter
);
4475 /******************************************************************************
4476 * AddPortA (WINSPOOL.@)
4478 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
4480 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName
),hWnd
,debugstr_a(pMonitorName
));
4484 /******************************************************************************
4485 * AddPortW (WINSPOOL.@)
4487 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
4489 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName
),hWnd
,debugstr_w(pMonitorName
));
4493 /******************************************************************************
4494 * AddPortExA (WINSPOOL.@)
4496 * Adds a print spooler port without presenting a user interface.
4498 BOOL WINAPI
AddPortExA(HANDLE hMonitor
, LPSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPSTR lpMonitorName
)
4500 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor
, debugstr_a(pName
), Level
,
4501 lpBuffer
, debugstr_a(lpMonitorName
));
4505 /******************************************************************************
4506 * AddPortExW (WINSPOOL.@)
4510 BOOL WINAPI
AddPortExW(HANDLE hMonitor
, LPWSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPWSTR lpMonitorName
)
4512 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor
, debugstr_w(pName
), Level
,
4513 lpBuffer
, debugstr_w(lpMonitorName
));
4517 /******************************************************************************
4518 * AddPrinterConnectionA (WINSPOOL.@)
4520 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
4522 FIXME("%s\n", debugstr_a(pName
));
4526 /******************************************************************************
4527 * AddPrinterConnectionW (WINSPOOL.@)
4529 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
4531 FIXME("%s\n", debugstr_w(pName
));
4535 /******************************************************************************
4536 * AddPrinterDriverExW (WINSPOOL.@)
4538 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
4539 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4541 FIXME("%s %ld %p %ld\n", debugstr_w(pName
),
4542 Level
, pDriverInfo
, dwFileCopyFlags
);
4543 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4547 /******************************************************************************
4548 * AddPrinterDriverExA (WINSPOOL.@)
4550 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
4551 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4553 FIXME("%s %ld %p %ld\n", debugstr_a(pName
),
4554 Level
, pDriverInfo
, dwFileCopyFlags
);
4555 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4559 /******************************************************************************
4560 * ConfigurePortA (WINSPOOL.@)
4562 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
4564 FIXME("%s %p %s\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
4568 /******************************************************************************
4569 * ConfigurePortW (WINSPOOL.@)
4571 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
4573 FIXME("%s %p %s\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
4577 /******************************************************************************
4578 * ConnectToPrinterDlg (WINSPOOL.@)
4580 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
4582 FIXME("%p %lx\n", hWnd
, Flags
);
4586 /******************************************************************************
4587 * DeletePrinterConnectionA (WINSPOOL.@)
4589 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
4591 FIXME("%s\n", debugstr_a(pName
));
4595 /******************************************************************************
4596 * DeletePrinterConnectionW (WINSPOOL.@)
4598 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
4600 FIXME("%s\n", debugstr_w(pName
));
4604 /******************************************************************************
4605 * DeletePrinterDriverExW (WINSPOOL.@)
4607 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
4608 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4610 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4611 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4615 /******************************************************************************
4616 * DeletePrinterDriverExA (WINSPOOL.@)
4618 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
4619 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4621 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4622 debugstr_a(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4626 /******************************************************************************
4627 * DeletePrinterDataExW (WINSPOOL.@)
4629 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
4632 FIXME("%p %s %s\n", hPrinter
,
4633 debugstr_w(pKeyName
), debugstr_w(pValueName
));
4634 return ERROR_INVALID_PARAMETER
;
4637 /******************************************************************************
4638 * DeletePrinterDataExA (WINSPOOL.@)
4640 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
4643 FIXME("%p %s %s\n", hPrinter
,
4644 debugstr_a(pKeyName
), debugstr_a(pValueName
));
4645 return ERROR_INVALID_PARAMETER
;
4648 /******************************************************************************
4649 * DeletePrintProcessorA (WINSPOOL.@)
4651 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
4653 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4654 debugstr_a(pPrintProcessorName
));
4658 /******************************************************************************
4659 * DeletePrintProcessorW (WINSPOOL.@)
4661 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
4663 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4664 debugstr_w(pPrintProcessorName
));
4668 /******************************************************************************
4669 * DeletePrintProvidorA (WINSPOOL.@)
4671 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
4673 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4674 debugstr_a(pPrintProviderName
));
4678 /******************************************************************************
4679 * DeletePrintProvidorW (WINSPOOL.@)
4681 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
4683 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4684 debugstr_w(pPrintProviderName
));
4688 /******************************************************************************
4689 * EnumFormsA (WINSPOOL.@)
4691 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
4692 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4694 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
4698 /******************************************************************************
4699 * EnumFormsW (WINSPOOL.@)
4701 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
4702 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4704 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
4708 /*****************************************************************************
4709 * EnumMonitorsA [WINSPOOL.@]
4712 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
4713 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4715 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName
), Level
, pMonitors
,
4716 cbBuf
, pcbNeeded
, pcReturned
);
4717 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4721 /*****************************************************************************
4722 * EnumMonitorsW [WINSPOOL.@]
4725 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
4726 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4728 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName
), Level
, pMonitors
,
4729 cbBuf
, pcbNeeded
, pcReturned
);
4730 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4734 /******************************************************************************
4735 * XcvDataW (WINSPOOL.@)
4738 * There doesn't seem to be an A version...
4740 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
4741 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
4742 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
4744 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv
, debugstr_w(pszDataName
),
4745 pInputData
, cbInputData
, pOutputData
,
4746 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
4750 /*****************************************************************************
4751 * EnumPrinterDataA [WINSPOOL.@]
4754 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
4755 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
4756 DWORD cbData
, LPDWORD pcbData
)
4758 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
4759 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
4760 return ERROR_NO_MORE_ITEMS
;
4763 /*****************************************************************************
4764 * EnumPrinterDataW [WINSPOOL.@]
4767 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
4768 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
4769 DWORD cbData
, LPDWORD pcbData
)
4771 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
4772 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
4773 return ERROR_NO_MORE_ITEMS
;
4776 /*****************************************************************************
4777 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4780 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
4781 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
4782 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4784 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName
),
4785 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
4786 pcbNeeded
, pcReturned
);
4790 /*****************************************************************************
4791 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4794 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
4795 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
4796 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4798 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
4799 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
4800 pcbNeeded
, pcReturned
);
4804 /*****************************************************************************
4805 * EnumPrintProcessorsA [WINSPOOL.@]
4808 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4809 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
4811 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName
, pEnvironment
, Level
,
4812 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
4816 /*****************************************************************************
4817 * EnumPrintProcessorsW [WINSPOOL.@]
4820 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4821 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
4823 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
4824 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
4825 cbBuf
, pcbNeeded
, pcbReturned
);
4829 /*****************************************************************************
4830 * ExtDeviceMode [WINSPOOL.@]
4833 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
4834 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
4837 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd
, hInst
, pDevModeOutput
,
4838 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
4839 debugstr_a(pProfile
), fMode
);
4843 /*****************************************************************************
4844 * FindClosePrinterChangeNotification [WINSPOOL.@]
4847 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
4849 FIXME("Stub: %p\n", hChange
);
4853 /*****************************************************************************
4854 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4857 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
4858 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
4860 FIXME("Stub: %p %lx %lx %p\n",
4861 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
4862 return INVALID_HANDLE_VALUE
;
4865 /*****************************************************************************
4866 * FindNextPrinterChangeNotification [WINSPOOL.@]
4869 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
4870 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
4872 FIXME("Stub: %p %p %p %p\n",
4873 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
4877 /*****************************************************************************
4878 * FreePrinterNotifyInfo [WINSPOOL.@]
4881 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
4883 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
4887 /*****************************************************************************
4890 * Copies a unicode string into a buffer. The buffer will either contain unicode or
4891 * ansi depending on the unicode parameter.
4893 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
4903 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
4906 memcpy(ptr
, str
, *size
);
4913 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
4916 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
4923 /*****************************************************************************
4926 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
4927 LPDWORD pcbNeeded
, BOOL unicode
)
4929 DWORD size
, left
= cbBuf
;
4930 BOOL space
= (cbBuf
> 0);
4937 ji1
->JobId
= job
->job_id
;
4940 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
4941 if(space
&& size
<= left
)
4943 ji1
->pDocument
= (LPWSTR
)ptr
;
4954 /*****************************************************************************
4957 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
4958 LPDWORD pcbNeeded
, BOOL unicode
)
4960 DWORD size
, left
= cbBuf
;
4961 BOOL space
= (cbBuf
> 0);
4968 ji2
->JobId
= job
->job_id
;
4971 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
4972 if(space
&& size
<= left
)
4974 ji2
->pDocument
= (LPWSTR
)ptr
;
4985 /*****************************************************************************
4988 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
4989 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4992 DWORD needed
= 0, size
;
4996 TRACE("%p %ld %ld %p %ld %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
4998 EnterCriticalSection(&printer_handles_cs
);
4999 job
= get_job(hPrinter
, JobId
);
5006 size
= sizeof(JOB_INFO_1W
);
5011 memset(pJob
, 0, size
);
5015 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5020 size
= sizeof(JOB_INFO_2W
);
5025 memset(pJob
, 0, size
);
5029 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5034 size
= sizeof(JOB_INFO_3
);
5038 memset(pJob
, 0, size
);
5047 SetLastError(ERROR_INVALID_LEVEL
);
5051 *pcbNeeded
= needed
;
5053 LeaveCriticalSection(&printer_handles_cs
);
5057 /*****************************************************************************
5058 * GetJobA [WINSPOOL.@]
5061 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5062 DWORD cbBuf
, LPDWORD pcbNeeded
)
5064 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
5067 /*****************************************************************************
5068 * GetJobW [WINSPOOL.@]
5071 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5072 DWORD cbBuf
, LPDWORD pcbNeeded
)
5074 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
5077 /*****************************************************************************
5080 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
5082 char *unixname
, *queue
, *cmd
;
5083 char fmt
[] = "lpr -P%s %s";
5086 if(!(unixname
= wine_get_unix_file_name(filename
)))
5089 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5090 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5091 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5093 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
5094 sprintf(cmd
, fmt
, queue
, unixname
);
5096 TRACE("printing with: %s\n", cmd
);
5099 HeapFree(GetProcessHeap(), 0, cmd
);
5100 HeapFree(GetProcessHeap(), 0, queue
);
5101 HeapFree(GetProcessHeap(), 0, unixname
);
5105 /*****************************************************************************
5108 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
5110 #if HAVE_CUPS_CUPS_H
5113 char *unixname
, *queue
, *doc_titleA
;
5117 if(!(unixname
= wine_get_unix_file_name(filename
)))
5120 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5121 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5122 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5124 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
5125 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
5126 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
5128 TRACE("printing via cups\n");
5129 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
5130 HeapFree(GetProcessHeap(), 0, doc_titleA
);
5131 HeapFree(GetProcessHeap(), 0, queue
);
5132 HeapFree(GetProcessHeap(), 0, unixname
);
5138 return schedule_lpr(printer_name
, filename
);
5142 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
5149 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
5153 if(HIWORD(wparam
) == BN_CLICKED
)
5155 if(LOWORD(wparam
) == IDOK
)
5158 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
5161 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
5162 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
5164 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
5166 WCHAR caption
[200], message
[200];
5169 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5170 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
5171 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
5172 if(mb_ret
== IDCANCEL
)
5174 HeapFree(GetProcessHeap(), 0, filename
);
5178 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5179 if(hf
== INVALID_HANDLE_VALUE
)
5181 WCHAR caption
[200], message
[200];
5183 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5184 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
5185 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
5186 HeapFree(GetProcessHeap(), 0, filename
);
5190 DeleteFileW(filename
);
5191 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5193 EndDialog(hwnd
, IDOK
);
5196 if(LOWORD(wparam
) == IDCANCEL
)
5198 EndDialog(hwnd
, IDCANCEL
);
5207 /*****************************************************************************
5210 static BOOL
get_filename(LPWSTR
*filename
)
5212 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
5213 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
5216 /*****************************************************************************
5219 static BOOL
schedule_file(LPCWSTR filename
)
5221 LPWSTR output
= NULL
;
5223 if(get_filename(&output
))
5225 TRACE("copy to %s\n", debugstr_w(output
));
5226 CopyFileW(filename
, output
, FALSE
);
5227 HeapFree(GetProcessHeap(), 0, output
);
5233 /*****************************************************************************
5236 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
5239 char *unixname
, *cmdA
;
5241 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
5245 if(!(unixname
= wine_get_unix_file_name(filename
)))
5248 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
5249 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
5250 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
5252 TRACE("printing with: %s\n", cmdA
);
5254 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
5259 ERR("pipe() failed!\n");
5269 /* reset signals that we previously set to SIG_IGN */
5270 signal(SIGPIPE
, SIG_DFL
);
5271 signal(SIGCHLD
, SIG_DFL
);
5277 while((no_read
= read(file_fd
, buf
, sizeof(buf
))))
5278 write(fds
[1], buf
, no_read
);
5283 if(file_fd
!= -1) close(file_fd
);
5284 if(fds
[0] != -1) close(fds
[0]);
5285 if(fds
[1] != -1) close(fds
[1]);
5287 HeapFree(GetProcessHeap(), 0, cmdA
);
5288 HeapFree(GetProcessHeap(), 0, unixname
);
5295 /*****************************************************************************
5298 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
5300 int in_fd
, out_fd
, no_read
;
5303 char *unixname
, *outputA
;
5306 if(!(unixname
= wine_get_unix_file_name(filename
)))
5309 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
5310 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
5311 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
5313 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
5314 in_fd
= open(unixname
, O_RDONLY
);
5315 if(out_fd
== -1 || in_fd
== -1)
5318 while((no_read
= read(in_fd
, buf
, sizeof(buf
))))
5319 write(out_fd
, buf
, no_read
);
5323 if(in_fd
!= -1) close(in_fd
);
5324 if(out_fd
!= -1) close(out_fd
);
5325 HeapFree(GetProcessHeap(), 0, outputA
);
5326 HeapFree(GetProcessHeap(), 0, unixname
);
5330 /*****************************************************************************
5331 * ScheduleJob [WINSPOOL.@]
5334 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
5336 opened_printer_t
*printer
;
5338 struct list
*cursor
, *cursor2
;
5340 TRACE("(%p, %lx)\n", hPrinter
, dwJobID
);
5341 EnterCriticalSection(&printer_handles_cs
);
5342 printer
= get_opened_printer(hPrinter
);
5346 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
5348 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
5351 if(job
->job_id
!= dwJobID
) continue;
5353 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
5354 if(hf
!= INVALID_HANDLE_VALUE
)
5356 PRINTER_INFO_5W
*pi5
;
5360 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5361 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5363 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
5364 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
5365 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
5366 TRACE("need to schedule job %ld filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
5367 debugstr_w(pi5
->pPortName
));
5371 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5372 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
5374 DWORD type
, count
= sizeof(output
);
5375 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
5378 if(output
[0] == '|')
5380 schedule_pipe(output
+ 1, job
->filename
);
5384 schedule_unixfile(output
, job
->filename
);
5386 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
5388 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
5390 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
5392 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
5394 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
5396 schedule_file(job
->filename
);
5400 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
5402 HeapFree(GetProcessHeap(), 0, pi5
);
5404 DeleteFileW(job
->filename
);
5406 list_remove(cursor
);
5407 HeapFree(GetProcessHeap(), 0, job
->document_title
);
5408 HeapFree(GetProcessHeap(), 0, job
->filename
);
5409 HeapFree(GetProcessHeap(), 0, job
);
5414 LeaveCriticalSection(&printer_handles_cs
);
5418 /*****************************************************************************
5419 * StartDocDlgA [WINSPOOL.@]
5421 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
5423 UNICODE_STRING usBuffer
;
5428 docW
.cbSize
= sizeof(docW
);
5429 docW
.lpszDocName
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
5430 docW
.lpszOutput
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
5431 docW
.lpszDatatype
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
5432 docW
.fwType
= doc
->fwType
;
5434 retW
= StartDocDlgW(hPrinter
, &docW
);
5438 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
5439 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
5440 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
5441 HeapFree(GetProcessHeap(), 0, retW
);
5444 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDatatype
);
5445 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszOutput
);
5446 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDocName
);
5451 /*****************************************************************************
5452 * StartDocDlgW [WINSPOOL.@]
5454 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5455 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5456 * port is "FILE:". Also returns the full path if passed a relative path.
5458 * The caller should free the returned string from the process heap.
5460 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
5465 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
5467 PRINTER_INFO_5W
*pi5
;
5468 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
5469 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
5471 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
5472 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
5473 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
5475 HeapFree(GetProcessHeap(), 0, pi5
);
5478 HeapFree(GetProcessHeap(), 0, pi5
);
5481 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
5484 get_filename(&name
);
5487 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
5489 HeapFree(GetProcessHeap(), 0, name
);
5492 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5493 GetFullPathNameW(name
, len
, ret
, NULL
);
5494 HeapFree(GetProcessHeap(), 0, name
);
5499 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
5502 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5503 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
5505 attr
= GetFileAttributesW(ret
);
5506 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
5508 HeapFree(GetProcessHeap(), 0, ret
);