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
;
105 /* ############################### */
107 static opened_printer_t
**printer_handles
;
108 static int nb_printer_handles
;
109 static LONG next_job_id
= 1;
111 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
112 WORD fwCapability
, LPSTR lpszOutput
,
114 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
115 LPSTR lpszDevice
, LPSTR lpszPort
,
116 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
119 static const char Printers
[] =
120 "System\\CurrentControlSet\\control\\Print\\Printers\\";
122 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
123 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
124 'c','o','n','t','r','o','l','\\',
125 'P','r','i','n','t','\\',
126 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
127 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
129 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
130 'M','i','c','r','o','s','o','f','t','\\',
131 'W','i','n','d','o','w','s',' ','N','T','\\',
132 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
133 'W','i','n','d','o','w','s',0};
135 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
136 'M','i','c','r','o','s','o','f','t','\\',
137 'W','i','n','d','o','w','s',' ','N','T','\\',
138 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
139 'D','e','v','i','c','e','s',0};
141 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
142 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
143 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
144 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
145 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
147 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
149 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
150 'i','o','n',' ','F','i','l','e',0};
151 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
152 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
153 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v',
155 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F',
157 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
158 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
159 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
160 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
161 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
162 static const WCHAR NameW
[] = {'N','a','m','e',0};
163 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
164 static const WCHAR PortW
[] = {'P','o','r','t',0};
165 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e',
167 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i',
169 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i',
170 'v','e','r','D','a','t','a',0};
171 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F',
173 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
174 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
175 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
176 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
177 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
178 static const WCHAR emptyStringW
[] = {0};
180 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
182 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
183 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
184 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
186 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
187 'D','o','c','u','m','e','n','t',0};
189 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
);
190 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
191 DWORD Level
, LPBYTE pDriverInfo
,
192 DWORD cbBuf
, LPDWORD pcbNeeded
,
194 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
);
196 /******************************************************************
197 * validate the user-supplied printing-environment [internal]
200 * env [I] PTR to Environment-String or NULL
204 * Success: PTR to printenv_t
207 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
211 static const printenv_t
* validate_envW(LPCWSTR env
)
213 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
};
214 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
};
215 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
217 const printenv_t
*result
= NULL
;
220 TRACE("testing %s\n", debugstr_w(env
));
223 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
225 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
227 result
= all_printenv
[i
];
232 if (result
== NULL
) {
233 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
234 SetLastError(ERROR_INVALID_ENVIRONMENT
);
236 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
240 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
242 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
248 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
249 if passed a NULL string. This returns NULLs to the result.
251 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
255 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
256 return usBufferPtr
->Buffer
;
258 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
262 static LPWSTR
strdupW(LPCWSTR p
)
268 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
269 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
275 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
,BOOL force
) {
278 /* If forcing, or no profile string entry for device yet, set the entry
280 * The always change entry if not WINEPS yet is discussable.
283 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
285 !strstr(qbuf
,"WINEPS.DRV")
287 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
290 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
291 WriteProfileStringA("windows","device",buf
);
292 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
293 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
296 HeapFree(GetProcessHeap(),0,buf
);
300 #ifdef HAVE_CUPS_CUPS_H
301 static typeof(cupsGetDests
) *pcupsGetDests
;
302 static typeof(cupsGetPPD
) *pcupsGetPPD
;
303 static typeof(cupsPrintFile
) *pcupsPrintFile
;
304 static void *cupshandle
;
306 static BOOL
CUPS_LoadPrinters(void)
309 BOOL hadprinter
= FALSE
;
311 PRINTER_INFO_2A pinfo2a
;
313 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
315 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
318 TRACE("loaded %s\n", SONAME_LIBCUPS
);
321 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
322 if (!p##x) return FALSE;
325 DYNCUPS(cupsGetDests
);
326 DYNCUPS(cupsPrintFile
);
329 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
331 ERR("Can't create Printers key\n");
335 nrofdests
= pcupsGetDests(&dests
);
336 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
337 for (i
=0;i
<nrofdests
;i
++) {
338 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
339 sprintf(port
,"LPR:%s",dests
[i
].name
);
340 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
341 sprintf(devline
,"WINEPS.DRV,%s",port
);
342 WriteProfileStringA("devices",dests
[i
].name
,devline
);
343 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
344 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
347 HeapFree(GetProcessHeap(),0,devline
);
349 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
350 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
351 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
353 TRACE("Printer already exists\n");
354 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
355 RegCloseKey(hkeyPrinter
);
357 memset(&pinfo2a
,0,sizeof(pinfo2a
));
358 pinfo2a
.pPrinterName
= dests
[i
].name
;
359 pinfo2a
.pDatatype
= "RAW";
360 pinfo2a
.pPrintProcessor
= "WinPrint";
361 pinfo2a
.pDriverName
= "PS Driver";
362 pinfo2a
.pComment
= "WINEPS Printer using CUPS";
363 pinfo2a
.pLocation
= "<physical location of printer>";
364 pinfo2a
.pPortName
= port
;
365 pinfo2a
.pParameters
= "<parameters?>";
366 pinfo2a
.pShareName
= "<share name?>";
367 pinfo2a
.pSepFile
= "<sep file?>";
369 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
370 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
371 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests
[i
].name
,GetLastError());
374 HeapFree(GetProcessHeap(),0,port
);
377 if (dests
[i
].is_default
)
378 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
380 RegCloseKey(hkeyPrinters
);
386 PRINTCAP_ParseEntry(char *pent
,BOOL isfirst
) {
387 PRINTER_INFO_2A pinfo2a
;
388 char *e
,*s
,*name
,*prettyname
,*devname
;
389 BOOL ret
= FALSE
, set_default
= FALSE
;
390 char *port
,*devline
,*env_default
;
391 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
393 while (isspace(*pent
)) pent
++;
394 s
= strchr(pent
,':');
396 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
404 TRACE("name=%s entry=%s\n",name
, pent
);
406 if(ispunct(*name
)) { /* a tc entry, not a real printer */
407 TRACE("skipping tc entry\n");
411 if(strstr(pent
,":server")) { /* server only version so skip */
412 TRACE("skipping server entry\n");
416 /* Determine whether this is a postscript printer. */
419 env_default
= getenv("PRINTER");
421 /* Get longest name, usually the one at the right for later display. */
422 while((s
=strchr(prettyname
,'|'))) {
425 while(isspace(*--e
)) *e
= '\0';
426 TRACE("\t%s\n", debugstr_a(prettyname
));
427 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
428 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
431 e
= prettyname
+ strlen(prettyname
);
432 while(isspace(*--e
)) *e
= '\0';
433 TRACE("\t%s\n", debugstr_a(prettyname
));
434 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
436 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
437 * if it is too long, we use it as comment below. */
438 devname
= prettyname
;
439 if (strlen(devname
)>=CCHDEVICENAME
-1)
441 if (strlen(devname
)>=CCHDEVICENAME
-1) {
446 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
447 sprintf(port
,"LPR:%s",name
);
449 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
450 sprintf(devline
,"WINEPS.DRV,%s",port
);
451 WriteProfileStringA("devices",devname
,devline
);
452 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
453 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
456 HeapFree(GetProcessHeap(),0,devline
);
458 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
460 ERR("Can't create Printers key\n");
464 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
465 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
467 TRACE("Printer already exists\n");
468 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
469 RegCloseKey(hkeyPrinter
);
471 memset(&pinfo2a
,0,sizeof(pinfo2a
));
472 pinfo2a
.pPrinterName
= devname
;
473 pinfo2a
.pDatatype
= "RAW";
474 pinfo2a
.pPrintProcessor
= "WinPrint";
475 pinfo2a
.pDriverName
= "PS Driver";
476 pinfo2a
.pComment
= "WINEPS Printer using LPR";
477 pinfo2a
.pLocation
= prettyname
;
478 pinfo2a
.pPortName
= port
;
479 pinfo2a
.pParameters
= "<parameters?>";
480 pinfo2a
.pShareName
= "<share name?>";
481 pinfo2a
.pSepFile
= "<sep file?>";
483 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
484 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
485 ERR("%s not added by AddPrinterA (%ld)\n",name
,GetLastError());
488 RegCloseKey(hkeyPrinters
);
490 if (isfirst
|| set_default
)
491 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
493 HeapFree(GetProcessHeap(), 0, port
);
495 HeapFree(GetProcessHeap(), 0, name
);
500 PRINTCAP_LoadPrinters(void) {
501 BOOL hadprinter
= FALSE
;
505 BOOL had_bash
= FALSE
;
507 f
= fopen("/etc/printcap","r");
511 while(fgets(buf
,sizeof(buf
),f
)) {
514 end
=strchr(buf
,'\n');
518 while(isspace(*start
)) start
++;
519 if(*start
== '#' || *start
== '\0')
522 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
523 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
524 HeapFree(GetProcessHeap(),0,pent
);
528 if (end
&& *--end
== '\\') {
535 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
538 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
544 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
545 HeapFree(GetProcessHeap(),0,pent
);
551 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
554 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
555 lstrlenW(value
) * sizeof(WCHAR
));
557 return ERROR_FILE_NOT_FOUND
;
560 void WINSPOOL_LoadSystemPrinters(void)
562 HKEY hkey
, hkeyPrinters
;
565 DWORD needed
, num
, i
;
566 WCHAR PrinterName
[256];
569 di3a
.cVersion
= 0x400;
570 di3a
.pName
= "PS Driver";
571 di3a
.pEnvironment
= NULL
; /* NULL means auto */
572 di3a
.pDriverPath
= "wineps16";
573 di3a
.pDataFile
= "<datafile?>";
574 di3a
.pConfigFile
= "wineps16";
575 di3a
.pHelpFile
= "<helpfile?>";
576 di3a
.pDependentFiles
= "<dependend files?>";
577 di3a
.pMonitorName
= "<monitor name?>";
578 di3a
.pDefaultDataType
= "RAW";
580 if (!AddPrinterDriverA(NULL
,3,(LPBYTE
)&di3a
)) {
581 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
585 /* This ensures that all printer entries have a valid Name value. If causes
586 problems later if they don't. If one is found to be missed we create one
587 and set it equal to the name of the key */
588 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
589 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
590 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
591 for(i
= 0; i
< num
; i
++) {
592 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
593 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
594 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
595 set_reg_szW(hkey
, NameW
, PrinterName
);
602 RegCloseKey(hkeyPrinters
);
605 /* We want to avoid calling AddPrinter on printers as much as
606 possible, because on cups printers this will (eventually) lead
607 to a call to cupsGetPPD which takes forever, even with non-cups
608 printers AddPrinter takes a while. So we'll tag all printers that
609 were automatically added last time around, if they still exist
610 we'll leave them be otherwise we'll delete them. */
611 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
613 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
614 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
615 for(i
= 0; i
< num
; i
++) {
616 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
617 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
618 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
620 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
628 HeapFree(GetProcessHeap(), 0, pi
);
632 #ifdef HAVE_CUPS_CUPS_H
633 done
= CUPS_LoadPrinters();
636 if(!done
) { /* If we have any CUPS based printers, skip looking for printcap printers */
637 /* Check for [ppd] section in config file before parsing /etc/printcap */
638 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
639 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Printing\\PPD Files",
640 &hkey
) == ERROR_SUCCESS
) {
642 PRINTCAP_LoadPrinters();
646 /* Now enumerate the list again and delete any printers that a still tagged */
647 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
649 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
650 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
651 for(i
= 0; i
< num
; i
++) {
652 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
653 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
654 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
655 DWORD dw
, type
, size
= sizeof(dw
);
656 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
657 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
667 HeapFree(GetProcessHeap(), 0, pi
);
675 /******************************************************************
676 * get_opened_printer_entry
677 * Get the first place empty in the opened printer table
679 static HANDLE
get_opened_printer_entry( LPCWSTR name
)
681 UINT_PTR handle
= nb_printer_handles
, i
;
682 jobqueue_t
*queue
= NULL
;
683 opened_printer_t
*printer
;
685 EnterCriticalSection(&printer_handles_cs
);
687 for (i
= 0; i
< nb_printer_handles
; i
++)
689 if (!printer_handles
[i
])
691 if(handle
== nb_printer_handles
)
694 else if(!queue
&& !strcmpW(name
, printer_handles
[i
]->name
))
695 queue
= printer_handles
[i
]->queue
;
698 if (handle
>= nb_printer_handles
)
700 opened_printer_t
**new_array
;
702 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
703 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
705 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
706 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
713 printer_handles
= new_array
;
714 nb_printer_handles
+= 16;
717 if (!(printer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
))))
723 printer
->name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(name
) + 1) * sizeof(WCHAR
));
724 strcpyW(printer
->name
, name
);
726 printer
->queue
= queue
;
729 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
730 list_init(&printer
->queue
->jobs
);
731 printer
->queue
->ref
= 0;
733 InterlockedIncrement(&printer
->queue
->ref
);
736 printer_handles
[handle
] = printer
;
739 LeaveCriticalSection(&printer_handles_cs
);
741 return (HANDLE
)handle
;
744 /******************************************************************
746 * Get the pointer to the opened printer referred by the handle
748 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
750 UINT_PTR idx
= (UINT_PTR
)hprn
;
751 opened_printer_t
*ret
= NULL
;
753 EnterCriticalSection(&printer_handles_cs
);
755 if ((idx
<= 0) || (idx
> nb_printer_handles
))
758 ret
= printer_handles
[idx
- 1];
760 LeaveCriticalSection(&printer_handles_cs
);
764 /******************************************************************
765 * get_opened_printer_name
766 * Get the pointer to the opened printer name referred by the handle
768 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
770 opened_printer_t
*printer
= get_opened_printer(hprn
);
771 if(!printer
) return NULL
;
772 return printer
->name
;
775 /******************************************************************
776 * WINSPOOL_GetOpenedPrinterRegKey
779 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
781 LPCWSTR name
= get_opened_printer_name(hPrinter
);
785 if(!name
) return ERROR_INVALID_HANDLE
;
787 if((ret
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
)) !=
791 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
793 ERR("Can't find opened printer %s in registry\n",
795 RegCloseKey(hkeyPrinters
);
796 return ERROR_INVALID_PRINTER_NAME
; /* ? */
798 RegCloseKey(hkeyPrinters
);
799 return ERROR_SUCCESS
;
802 /******************************************************************
805 * Get the pointer to the specified job.
806 * Should hold the printer_handles_cs before calling.
808 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
810 opened_printer_t
*printer
= get_opened_printer(hprn
);
813 if(!printer
) return NULL
;
814 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
816 if(job
->job_id
== JobId
)
822 /***********************************************************
825 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
828 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
831 Formname
= (dmA
->dmSize
> off_formname
);
832 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
833 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
834 dmW
->dmDeviceName
, CCHDEVICENAME
);
836 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
837 dmA
->dmSize
- CCHDEVICENAME
);
839 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
840 off_formname
- CCHDEVICENAME
);
841 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
842 dmW
->dmFormName
, CCHFORMNAME
);
843 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
844 (off_formname
+ CCHFORMNAME
));
847 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
852 /***********************************************************
854 * Creates an ascii copy of supplied devmode on heap
856 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
861 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
863 if(!dmW
) return NULL
;
864 Formname
= (dmW
->dmSize
> off_formname
);
865 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
866 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
867 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
868 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
870 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
871 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
873 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
874 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
875 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
876 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
877 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
878 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
881 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
886 /***********************************************************
888 * Creates a unicode copy of PRINTER_INFO_2A on heap
890 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
892 LPPRINTER_INFO_2W piW
;
893 UNICODE_STRING usBuffer
;
895 if(!piA
) return NULL
;
896 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
897 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
899 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
900 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
901 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
902 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
903 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
904 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
905 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
906 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
907 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
908 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
909 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
910 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
914 /***********************************************************
915 * FREE_PRINTER_INFO_2W
916 * Free PRINTER_INFO_2W and all strings
918 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
922 HeapFree(heap
,0,piW
->pServerName
);
923 HeapFree(heap
,0,piW
->pPrinterName
);
924 HeapFree(heap
,0,piW
->pShareName
);
925 HeapFree(heap
,0,piW
->pPortName
);
926 HeapFree(heap
,0,piW
->pDriverName
);
927 HeapFree(heap
,0,piW
->pComment
);
928 HeapFree(heap
,0,piW
->pLocation
);
929 HeapFree(heap
,0,piW
->pDevMode
);
930 HeapFree(heap
,0,piW
->pSepFile
);
931 HeapFree(heap
,0,piW
->pPrintProcessor
);
932 HeapFree(heap
,0,piW
->pDatatype
);
933 HeapFree(heap
,0,piW
->pParameters
);
934 HeapFree(heap
,0,piW
);
938 /******************************************************************
939 * DeviceCapabilities [WINSPOOL.@]
940 * DeviceCapabilitiesA [WINSPOOL.@]
943 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
944 LPSTR pOutput
, LPDEVMODEA lpdm
)
948 if (!GDI_CallDeviceCapabilities16
)
950 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
952 if (!GDI_CallDeviceCapabilities16
) return -1;
954 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
956 /* If DC_PAPERSIZE map POINT16s to POINTs */
957 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
958 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
959 POINT
*pt
= (POINT
*)pOutput
;
961 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
962 for(i
= 0; i
< ret
; i
++, pt
++)
967 HeapFree( GetProcessHeap(), 0, tmp
);
973 /*****************************************************************************
974 * DeviceCapabilitiesW [WINSPOOL.@]
976 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
979 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
980 WORD fwCapability
, LPWSTR pOutput
,
981 const DEVMODEW
*pDevMode
)
983 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
984 LPSTR pDeviceA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDevice
);
985 LPSTR pPortA
= HEAP_strdupWtoA(GetProcessHeap(),0,pPort
);
988 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
989 fwCapability
== DC_FILEDEPENDENCIES
||
990 fwCapability
== DC_PAPERNAMES
)) {
991 /* These need A -> W translation */
994 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
998 switch(fwCapability
) {
1003 case DC_FILEDEPENDENCIES
:
1007 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1008 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1010 for(i
= 0; i
< ret
; i
++)
1011 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1012 pOutput
+ (i
* size
), size
);
1013 HeapFree(GetProcessHeap(), 0, pOutputA
);
1015 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1016 (LPSTR
)pOutput
, dmA
);
1018 HeapFree(GetProcessHeap(),0,pPortA
);
1019 HeapFree(GetProcessHeap(),0,pDeviceA
);
1020 HeapFree(GetProcessHeap(),0,dmA
);
1024 /******************************************************************
1025 * DocumentPropertiesA [WINSPOOL.@]
1027 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1029 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1030 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1031 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1033 LPSTR lpName
= pDeviceName
;
1036 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1037 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1041 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1043 ERR("no name from hPrinter?\n");
1044 SetLastError(ERROR_INVALID_HANDLE
);
1047 lpName
= HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW
);
1050 if (!GDI_CallExtDeviceMode16
)
1052 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1054 if (!GDI_CallExtDeviceMode16
) {
1055 ERR("No CallExtDeviceMode16?\n");
1059 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, "LPT1:",
1060 pDevModeInput
, NULL
, fMode
);
1063 HeapFree(GetProcessHeap(),0,lpName
);
1068 /*****************************************************************************
1069 * DocumentPropertiesW (WINSPOOL.@)
1071 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1073 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1075 LPDEVMODEW pDevModeOutput
,
1076 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1079 LPSTR pDeviceNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName
);
1080 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1081 LPDEVMODEA pDevModeOutputA
= NULL
;
1084 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1085 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1087 if(pDevModeOutput
) {
1088 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1089 if(ret
< 0) return ret
;
1090 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1092 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1093 pDevModeInputA
, fMode
);
1094 if(pDevModeOutput
) {
1095 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1096 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1098 if(fMode
== 0 && ret
> 0)
1099 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1100 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1101 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1105 /******************************************************************
1106 * OpenPrinterA [WINSPOOL.@]
1111 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1112 LPPRINTER_DEFAULTSA pDefault
)
1114 UNICODE_STRING lpPrinterNameW
;
1115 UNICODE_STRING usBuffer
;
1116 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1117 PWSTR pwstrPrinterNameW
;
1120 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1123 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1124 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1125 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1126 pDefaultW
= &DefaultW
;
1128 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1130 RtlFreeUnicodeString(&usBuffer
);
1131 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1133 RtlFreeUnicodeString(&lpPrinterNameW
);
1137 /******************************************************************
1138 * OpenPrinterW [WINSPOOL.@]
1140 * Open a Printer / Printserver or a Printer-Object
1143 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1144 * phPrinter [O] The resulting Handle is stored here
1145 * pDefault [I] PTR to Default Printer Settings or NULL
1152 * lpPrinterName is one of:
1153 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1154 *| Printer: "PrinterName"
1155 *| Printer-Object: "PrinterName,Job xxx"
1156 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1157 *| XcvPort: "Servername,XcvPort PortName"
1160 *| Printserver not supported
1161 *| Printer-Object not supported
1162 *| XcvMonitor not supported
1163 *| XcvPort not supported
1164 *| pDefaults not supported
1167 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
,
1168 LPPRINTER_DEFAULTSW pDefault
)
1170 HKEY hkeyPrinters
, hkeyPrinter
;
1172 if (!lpPrinterName
) {
1173 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault
);
1174 SetLastError(ERROR_INVALID_PARAMETER
);
1178 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName
),
1181 /* Check Printer exists */
1182 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1184 ERR("Can't create Printers key\n");
1185 SetLastError(ERROR_FILE_NOT_FOUND
); /* ?? */
1189 if(lpPrinterName
[0] == '\0' || /* explicitly exclude "" */
1190 RegOpenKeyW(hkeyPrinters
, lpPrinterName
, &hkeyPrinter
)
1192 TRACE("Can't find printer %s in registry\n",
1193 debugstr_w(lpPrinterName
));
1194 RegCloseKey(hkeyPrinters
);
1195 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1198 RegCloseKey(hkeyPrinter
);
1199 RegCloseKey(hkeyPrinters
);
1201 if(!phPrinter
) /* This seems to be what win95 does anyway */
1204 /* Get the unique handle of the printer*/
1205 *phPrinter
= get_opened_printer_entry( lpPrinterName
);
1207 if (pDefault
!= NULL
)
1208 FIXME("Not handling pDefault\n");
1213 /******************************************************************
1214 * AddMonitorA [WINSPOOL.@]
1219 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1221 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName
), Level
, pMonitors
);
1222 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1226 /******************************************************************************
1227 * AddMonitorW [WINSPOOL.@]
1229 * Install a Printmonitor
1232 * pName [I] Servername or NULL (local Computer)
1233 * Level [I] Structure-Level (Must be 2)
1234 * pMonitors [I] PTR to MONITOR_INFO_2
1241 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1247 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1249 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName
), Level
, pMonitors
);
1250 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1254 /******************************************************************
1255 * DeletePrinterDriverA [WINSPOOL.@]
1259 DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
1261 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1262 debugstr_a(pDriverName
));
1263 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1267 /******************************************************************
1268 * DeletePrinterDriverW [WINSPOOL.@]
1272 DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
1274 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1275 debugstr_w(pDriverName
));
1276 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1280 /******************************************************************
1281 * DeleteMonitorA [WINSPOOL.@]
1283 * See DeleteMonitorW.
1287 DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
1289 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1290 debugstr_a(pMonitorName
));
1291 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1295 /******************************************************************
1296 * DeleteMonitorW [WINSPOOL.@]
1298 * Delete a specific Printmonitor from a Printing-Environment
1301 * pName [I] Servername or NULL (local Computer)
1302 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1303 * pMonitorName [I] Name of the Monitor, that should be deleted
1314 DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1316 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1317 debugstr_w(pMonitorName
));
1318 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1322 /******************************************************************
1323 * DeletePortA [WINSPOOL.@]
1329 DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
1331 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName
),hWnd
,
1332 debugstr_a(pPortName
));
1333 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1337 /******************************************************************
1338 * DeletePortW [WINSPOOL.@]
1340 * Delete a specific Port
1343 * pName [I] Servername or NULL (local Computer)
1344 * hWnd [I] Handle to parent Window for the Dialog-Box
1345 * pPortName [I] Name of the Port, that should be deleted
1356 DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1358 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName
),hWnd
,
1359 debugstr_w(pPortName
));
1360 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1364 /******************************************************************************
1365 * SetPrinterW [WINSPOOL.@]
1375 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1379 /******************************************************************************
1380 * WritePrinter [WINSPOOL.@]
1382 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
1384 opened_printer_t
*printer
;
1387 TRACE("(%p, %p, %ld, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
1389 EnterCriticalSection(&printer_handles_cs
);
1390 printer
= get_opened_printer(hPrinter
);
1393 SetLastError(ERROR_INVALID_HANDLE
);
1399 SetLastError(ERROR_SPL_NO_STARTDOC
);
1403 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
1405 LeaveCriticalSection(&printer_handles_cs
);
1409 /*****************************************************************************
1410 * AddFormA [WINSPOOL.@]
1412 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1414 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1418 /*****************************************************************************
1419 * AddFormW [WINSPOOL.@]
1421 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1423 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1427 /*****************************************************************************
1428 * AddJobA [WINSPOOL.@]
1430 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1433 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
1437 SetLastError(ERROR_INVALID_LEVEL
);
1441 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
1444 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
1445 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
1446 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
1447 if(*pcbNeeded
> cbBuf
) {
1448 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1451 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
1452 addjobA
->JobId
= addjobW
->JobId
;
1453 addjobA
->Path
= (char *)(addjobA
+ 1);
1454 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
1460 /*****************************************************************************
1461 * AddJobW [WINSPOOL.@]
1463 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1465 opened_printer_t
*printer
;
1468 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1469 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
1470 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
1472 ADDJOB_INFO_1W
*addjob
;
1474 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
1476 EnterCriticalSection(&printer_handles_cs
);
1478 printer
= get_opened_printer(hPrinter
);
1481 SetLastError(ERROR_INVALID_HANDLE
);
1486 SetLastError(ERROR_INVALID_LEVEL
);
1490 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
1494 job
->job_id
= InterlockedIncrement(&next_job_id
);
1496 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
1497 if(path
[len
- 1] != '\\')
1499 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
1500 sprintfW(filename
, fmtW
, path
, job
->job_id
);
1502 len
= strlenW(filename
);
1503 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1504 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
1505 job
->document_title
= strdupW(default_doc_title
);
1506 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
1508 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
1509 if(*pcbNeeded
<= cbBuf
) {
1510 addjob
= (ADDJOB_INFO_1W
*)pData
;
1511 addjob
->JobId
= job
->job_id
;
1512 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
1513 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
1516 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1519 LeaveCriticalSection(&printer_handles_cs
);
1523 /*****************************************************************************
1524 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1526 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
1527 DWORD level
, LPBYTE Info
,
1528 DWORD cbBuf
, LPDWORD needed
)
1530 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server
), debugstr_a(env
),
1531 level
, Info
, cbBuf
);
1535 /*****************************************************************************
1536 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1538 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
1539 DWORD level
, LPBYTE Info
,
1540 DWORD cbBuf
, LPDWORD needed
)
1542 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server
), debugstr_w(env
),
1543 level
, Info
, cbBuf
);
1547 /*****************************************************************************
1548 * WINSPOOL_OpenDriverReg [internal]
1550 * opens the registry for the printer drivers depending on the given input
1551 * variable pEnvironment
1554 * the opened hkey on success
1557 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
)
1559 static const WCHAR WinNTW
[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1560 static const WCHAR Win40W
[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1562 LPWSTR lpKey
, buffer
= NULL
;
1566 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
));
1570 pEnvW
= pEnvironment
;
1572 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
1573 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1574 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
1579 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
1581 if(!GetVersionExW( &ver
))
1584 switch (ver
.dwPlatformId
) {
1585 case VER_PLATFORM_WIN32s
:
1586 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1588 case VER_PLATFORM_WIN32_NT
:
1595 TRACE("set environment to %s\n", debugstr_w(pEnvW
));
1598 lpKey
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1599 (strlenW(pEnvW
) + strlenW(DriversW
) + 1) * sizeof(WCHAR
));
1600 wsprintfW( lpKey
, DriversW
, pEnvW
);
1602 TRACE("%s\n", debugstr_w(lpKey
));
1604 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, lpKey
, &retval
) != ERROR_SUCCESS
)
1607 HeapFree( GetProcessHeap(), 0, buffer
);
1608 HeapFree( GetProcessHeap(), 0, lpKey
);
1613 /*****************************************************************************
1614 * AddPrinterW [WINSPOOL.@]
1616 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1618 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
1622 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
1625 TRACE("(%s,%ld,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
1628 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
1629 SetLastError(ERROR_INVALID_PARAMETER
);
1633 ERR("Level = %ld, unsupported!\n", Level
);
1634 SetLastError(ERROR_INVALID_LEVEL
);
1637 if (strlenW(pi
->pPrinterName
) >= CCHDEVICENAME
) {
1638 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1639 debugstr_w(pi
->pPrinterName
)
1641 SetLastError(ERROR_INVALID_LEVEL
);
1645 SetLastError(ERROR_INVALID_PARAMETER
);
1648 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1650 ERR("Can't create Printers key\n");
1653 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
1654 if (!RegQueryValueA(hkeyPrinter
,"Attributes",NULL
,NULL
)) {
1655 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
1656 RegCloseKey(hkeyPrinter
);
1657 RegCloseKey(hkeyPrinters
);
1660 RegCloseKey(hkeyPrinter
);
1662 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
1664 ERR("Can't create Drivers key\n");
1665 RegCloseKey(hkeyPrinters
);
1668 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
1670 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
1671 RegCloseKey(hkeyPrinters
);
1672 RegCloseKey(hkeyDrivers
);
1673 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
1676 RegCloseKey(hkeyDriver
);
1677 RegCloseKey(hkeyDrivers
);
1679 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
1680 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
1681 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
1682 RegCloseKey(hkeyPrinters
);
1686 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
1688 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
1689 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1690 RegCloseKey(hkeyPrinters
);
1693 RegSetValueExA(hkeyPrinter
, "Attributes", 0, REG_DWORD
,
1694 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
1695 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
1697 /* See if we can load the driver. We may need the devmode structure anyway
1700 * Note that DocumentPropertiesW will briefly try to open the printer we
1701 * just create to find a DEVMODEA struct (it will use the WINEPS default
1702 * one in case it is not there, so we are ok).
1704 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
1707 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi
->pPrinterName
));
1708 size
= sizeof(DEVMODEW
);
1714 dmW
= HeapAlloc(GetProcessHeap(), 0, size
);
1715 ZeroMemory(dmW
,size
);
1717 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
1719 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi
->pPrinterName
));
1720 HeapFree(GetProcessHeap(),0,dmW
);
1725 /* set devmode to printer name */
1726 strcpyW(dmW
->dmDeviceName
,pi
->pPrinterName
);
1730 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1731 and we support these drivers. NT writes DEVMODEW so somehow
1732 we'll need to distinguish between these when we support NT
1736 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
1737 RegSetValueExA(hkeyPrinter
, "Default DevMode", 0, REG_BINARY
,
1738 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1739 HeapFree(GetProcessHeap(), 0, dmA
);
1741 HeapFree(GetProcessHeap(), 0, dmW
);
1743 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
1744 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
1745 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
1746 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
1748 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
1749 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
1750 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
1751 RegSetValueExA(hkeyPrinter
, "Priority", 0, REG_DWORD
,
1752 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
1753 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
1754 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
1755 RegSetValueExA(hkeyPrinter
, "StartTime", 0, REG_DWORD
,
1756 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
1757 RegSetValueExA(hkeyPrinter
, "Status", 0, REG_DWORD
,
1758 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
1759 RegSetValueExA(hkeyPrinter
, "UntilTime", 0, REG_DWORD
,
1760 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
1762 RegCloseKey(hkeyPrinter
);
1763 RegCloseKey(hkeyPrinters
);
1764 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
1765 ERR("OpenPrinter failing\n");
1771 /*****************************************************************************
1772 * AddPrinterA [WINSPOOL.@]
1774 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1776 UNICODE_STRING pNameW
;
1778 PRINTER_INFO_2W
*piW
;
1779 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
1782 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
1784 ERR("Level = %ld, unsupported!\n", Level
);
1785 SetLastError(ERROR_INVALID_LEVEL
);
1788 pwstrNameW
= asciitounicode(&pNameW
,pName
);
1789 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
1791 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
1793 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
1794 RtlFreeUnicodeString(&pNameW
);
1799 /*****************************************************************************
1800 * ClosePrinter [WINSPOOL.@]
1802 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
1804 UINT_PTR i
= (UINT_PTR
)hPrinter
;
1805 opened_printer_t
*printer
= NULL
;
1808 TRACE("Handle %p\n", hPrinter
);
1810 EnterCriticalSection(&printer_handles_cs
);
1812 if ((i
> 0) && (i
<= nb_printer_handles
))
1813 printer
= printer_handles
[i
- 1];
1817 struct list
*cursor
, *cursor2
;
1820 EndDocPrinter(hPrinter
);
1822 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
1824 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
1826 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
1827 ScheduleJob(hPrinter
, job
->job_id
);
1829 HeapFree(GetProcessHeap(), 0, printer
->queue
);
1831 HeapFree(GetProcessHeap(), 0, printer
->name
);
1832 HeapFree(GetProcessHeap(), 0, printer
);
1833 printer_handles
[i
- 1] = NULL
;
1836 LeaveCriticalSection(&printer_handles_cs
);
1840 /*****************************************************************************
1841 * DeleteFormA [WINSPOOL.@]
1843 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
1845 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
1849 /*****************************************************************************
1850 * DeleteFormW [WINSPOOL.@]
1852 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
1854 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
1858 /*****************************************************************************
1859 * WINSPOOL_SHRegDeleteKey
1861 * Recursively delete subkeys.
1862 * Cut & paste from shlwapi.
1865 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
)
1867 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1868 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1871 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1874 /* Find how many subkeys there are */
1875 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1876 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1880 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1881 /* Name too big: alloc a buffer for it */
1882 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
1885 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1888 /* Recursively delete all the subkeys */
1889 for(i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1891 dwSize
= dwMaxSubkeyLen
;
1892 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1894 dwRet
= WINSPOOL_SHDeleteKeyW(hSubKey
, lpszName
);
1897 if (lpszName
!= szNameBuf
)
1898 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
1902 RegCloseKey(hSubKey
);
1904 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1909 /*****************************************************************************
1910 * DeletePrinter [WINSPOOL.@]
1912 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
1914 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1915 HKEY hkeyPrinters
, hkey
;
1918 SetLastError(ERROR_INVALID_HANDLE
);
1921 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1922 WINSPOOL_SHDeleteKeyW(hkeyPrinters
, lpNameW
);
1923 RegCloseKey(hkeyPrinters
);
1925 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
1926 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1927 RegDeleteValueW(hkey
, lpNameW
);
1933 /*****************************************************************************
1934 * SetPrinterA [WINSPOOL.@]
1936 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
1939 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter
,Level
,pPrinter
,Command
);
1943 /*****************************************************************************
1944 * SetJobA [WINSPOOL.@]
1946 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1947 LPBYTE pJob
, DWORD Command
)
1951 UNICODE_STRING usBuffer
;
1953 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
1955 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1956 are all ignored by SetJob, so we don't bother copying them */
1964 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
1965 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
1967 JobW
= (LPBYTE
)info1W
;
1968 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
1969 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
1970 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
1971 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
1972 info1W
->Status
= info1A
->Status
;
1973 info1W
->Priority
= info1A
->Priority
;
1974 info1W
->Position
= info1A
->Position
;
1975 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
1980 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
1981 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
1983 JobW
= (LPBYTE
)info2W
;
1984 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
1985 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
1986 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
1987 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
1988 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
1989 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
1990 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
1991 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
1992 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
1993 info2W
->Status
= info2A
->Status
;
1994 info2W
->Priority
= info2A
->Priority
;
1995 info2W
->Position
= info2A
->Position
;
1996 info2W
->StartTime
= info2A
->StartTime
;
1997 info2W
->UntilTime
= info2A
->UntilTime
;
1998 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2002 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2003 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2006 SetLastError(ERROR_INVALID_LEVEL
);
2010 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2016 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2017 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2018 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2019 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2020 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2025 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2026 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2027 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2028 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2029 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2030 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2031 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2032 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2033 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2037 HeapFree(GetProcessHeap(), 0, JobW
);
2042 /*****************************************************************************
2043 * SetJobW [WINSPOOL.@]
2045 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2046 LPBYTE pJob
, DWORD Command
)
2051 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2052 FIXME("Ignoring everything other than document title\n");
2054 EnterCriticalSection(&printer_handles_cs
);
2055 job
= get_job(hPrinter
, JobId
);
2065 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2066 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2067 job
->document_title
= strdupW(info1
->pDocument
);
2072 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2073 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2074 job
->document_title
= strdupW(info2
->pDocument
);
2080 SetLastError(ERROR_INVALID_LEVEL
);
2085 LeaveCriticalSection(&printer_handles_cs
);
2089 /*****************************************************************************
2090 * EndDocPrinter [WINSPOOL.@]
2092 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2094 opened_printer_t
*printer
;
2096 TRACE("(%p)\n", hPrinter
);
2098 EnterCriticalSection(&printer_handles_cs
);
2100 printer
= get_opened_printer(hPrinter
);
2103 SetLastError(ERROR_INVALID_HANDLE
);
2109 SetLastError(ERROR_SPL_NO_STARTDOC
);
2113 CloseHandle(printer
->doc
->hf
);
2114 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2115 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2116 printer
->doc
= NULL
;
2119 LeaveCriticalSection(&printer_handles_cs
);
2123 /*****************************************************************************
2124 * EndPagePrinter [WINSPOOL.@]
2126 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2128 FIXME("(%p): stub\n", hPrinter
);
2132 /*****************************************************************************
2133 * StartDocPrinterA [WINSPOOL.@]
2135 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2137 UNICODE_STRING usBuffer
;
2139 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2142 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2143 or one (DOC_INFO_3) extra DWORDs */
2147 doc2W
.JobId
= doc2
->JobId
;
2150 doc2W
.dwMode
= doc2
->dwMode
;
2153 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2154 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2155 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
2159 SetLastError(ERROR_INVALID_LEVEL
);
2163 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
2165 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
2166 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
2167 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
2172 /*****************************************************************************
2173 * StartDocPrinterW [WINSPOOL.@]
2175 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2177 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
2178 opened_printer_t
*printer
;
2179 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2180 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
2181 JOB_INFO_1W job_info
;
2182 DWORD needed
, ret
= 0;
2186 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2187 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
2188 debugstr_w(doc
->pDatatype
));
2190 if(Level
< 1 || Level
> 3)
2192 SetLastError(ERROR_INVALID_LEVEL
);
2196 EnterCriticalSection(&printer_handles_cs
);
2197 printer
= get_opened_printer(hPrinter
);
2200 SetLastError(ERROR_INVALID_HANDLE
);
2206 SetLastError(ERROR_INVALID_PRINTER_STATE
);
2210 /* Even if we're printing to a file we still add a print job, we'll
2211 just ignore the spool file name */
2213 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
2215 ERR("AddJob failed gle %08lx\n", GetLastError());
2219 if(doc
->pOutputFile
)
2220 filename
= doc
->pOutputFile
;
2222 filename
= addjob
->Path
;
2224 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
2225 if(hf
== INVALID_HANDLE_VALUE
)
2228 memset(&job_info
, 0, sizeof(job_info
));
2229 job_info
.pDocument
= doc
->pDocName
;
2230 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
2232 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
2233 printer
->doc
->hf
= hf
;
2234 ret
= printer
->doc
->job_id
= addjob
->JobId
;
2236 LeaveCriticalSection(&printer_handles_cs
);
2241 /*****************************************************************************
2242 * StartPagePrinter [WINSPOOL.@]
2244 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
2246 FIXME("(%p): stub\n", hPrinter
);
2250 /*****************************************************************************
2251 * GetFormA [WINSPOOL.@]
2253 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2254 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2256 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,pFormName
,
2257 Level
,pForm
,cbBuf
,pcbNeeded
);
2261 /*****************************************************************************
2262 * GetFormW [WINSPOOL.@]
2264 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2265 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2267 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,
2268 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
2272 /*****************************************************************************
2273 * SetFormA [WINSPOOL.@]
2275 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2278 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2282 /*****************************************************************************
2283 * SetFormW [WINSPOOL.@]
2285 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2288 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2292 /*****************************************************************************
2293 * ReadPrinter [WINSPOOL.@]
2295 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
2296 LPDWORD pNoBytesRead
)
2298 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
2302 /*****************************************************************************
2303 * ResetPrinterA [WINSPOOL.@]
2305 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
2307 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2311 /*****************************************************************************
2312 * ResetPrinterW [WINSPOOL.@]
2314 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2316 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2320 /*****************************************************************************
2321 * WINSPOOL_GetDWORDFromReg
2323 * Return DWORD associated with ValueName from hkey.
2325 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
2327 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
2330 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
2332 if(ret
!= ERROR_SUCCESS
) {
2333 WARN("Got ret = %ld on name %s\n", ret
, ValueName
);
2336 if(type
!= REG_DWORD
) {
2337 ERR("Got type %ld\n", type
);
2343 /*****************************************************************************
2344 * WINSPOOL_GetStringFromReg
2346 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2347 * String is stored either as unicode or ascii.
2348 * Bit of a hack here to get the ValueName if we want ascii.
2350 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
2351 DWORD buflen
, DWORD
*needed
,
2354 DWORD sz
= buflen
, type
;
2358 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2360 LPSTR ValueNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,ValueName
);
2361 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
2362 HeapFree(GetProcessHeap(),0,ValueNameA
);
2364 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
2365 WARN("Got ret = %ld\n", ret
);
2373 /*****************************************************************************
2374 * WINSPOOL_GetDefaultDevMode
2376 * Get a default DevMode values for wineps.
2380 static void WINSPOOL_GetDefaultDevMode(
2382 DWORD buflen
, DWORD
*needed
,
2386 static const char szwps
[] = "wineps.drv";
2388 /* fill default DEVMODE - should be read from ppd... */
2389 ZeroMemory( &dm
, sizeof(dm
) );
2390 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
2391 dm
.dmSpecVersion
= DM_SPECVERSION
;
2392 dm
.dmDriverVersion
= 1;
2393 dm
.dmSize
= sizeof(DEVMODEA
);
2394 dm
.dmDriverExtra
= 0;
2396 DM_ORIENTATION
| DM_PAPERSIZE
|
2397 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
2400 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
2401 DM_YRESOLUTION
| DM_TTOPTION
;
2403 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
2404 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
2405 dm
.u1
.s1
.dmPaperLength
= 2970;
2406 dm
.u1
.s1
.dmPaperWidth
= 2100;
2410 dm
.dmDefaultSource
= DMBIN_AUTO
;
2411 dm
.dmPrintQuality
= DMRES_MEDIUM
;
2414 dm
.dmYResolution
= 300; /* 300dpi */
2415 dm
.dmTTOption
= DMTT_BITMAP
;
2418 /* dm.dmLogPixels */
2419 /* dm.dmBitsPerPel */
2420 /* dm.dmPelsWidth */
2421 /* dm.dmPelsHeight */
2422 /* dm.dmDisplayFlags */
2423 /* dm.dmDisplayFrequency */
2424 /* dm.dmICMMethod */
2425 /* dm.dmICMIntent */
2426 /* dm.dmMediaType */
2427 /* dm.dmDitherType */
2428 /* dm.dmReserved1 */
2429 /* dm.dmReserved2 */
2430 /* dm.dmPanningWidth */
2431 /* dm.dmPanningHeight */
2434 if(buflen
>= sizeof(DEVMODEW
)) {
2435 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
2436 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
2437 HeapFree(GetProcessHeap(),0,pdmW
);
2439 *needed
= sizeof(DEVMODEW
);
2443 if(buflen
>= sizeof(DEVMODEA
)) {
2444 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
2446 *needed
= sizeof(DEVMODEA
);
2450 /*****************************************************************************
2451 * WINSPOOL_GetDevModeFromReg
2453 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2454 * DevMode is stored either as unicode or ascii.
2456 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
2458 DWORD buflen
, DWORD
*needed
,
2461 DWORD sz
= buflen
, type
;
2464 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
2465 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2466 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
2467 if (sz
< sizeof(DEVMODEA
))
2469 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName
),sz
);
2472 /* ensures that dmSize is not erratically bogus if registry is invalid */
2473 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
2474 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
2476 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2478 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
2479 memcpy(ptr
, dmW
, sz
);
2480 HeapFree(GetProcessHeap(),0,dmW
);
2487 /*********************************************************************
2488 * WINSPOOL_GetPrinter_2
2490 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2491 * The strings are either stored as unicode or ascii.
2493 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
2494 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2497 DWORD size
, left
= cbBuf
;
2498 BOOL space
= (cbBuf
> 0);
2503 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2505 if(space
&& size
<= left
) {
2506 pi2
->pPrinterName
= (LPWSTR
)ptr
;
2513 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
2515 if(space
&& size
<= left
) {
2516 pi2
->pShareName
= (LPWSTR
)ptr
;
2523 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2525 if(space
&& size
<= left
) {
2526 pi2
->pPortName
= (LPWSTR
)ptr
;
2533 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
2535 if(space
&& size
<= left
) {
2536 pi2
->pDriverName
= (LPWSTR
)ptr
;
2543 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
2545 if(space
&& size
<= left
) {
2546 pi2
->pComment
= (LPWSTR
)ptr
;
2553 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
2555 if(space
&& size
<= left
) {
2556 pi2
->pLocation
= (LPWSTR
)ptr
;
2563 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
2565 if(space
&& size
<= left
) {
2566 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2575 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
2576 if(space
&& size
<= left
) {
2577 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2584 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
2586 if(space
&& size
<= left
) {
2587 pi2
->pSepFile
= (LPWSTR
)ptr
;
2594 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
2596 if(space
&& size
<= left
) {
2597 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
2604 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
2606 if(space
&& size
<= left
) {
2607 pi2
->pDatatype
= (LPWSTR
)ptr
;
2614 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
2616 if(space
&& size
<= left
) {
2617 pi2
->pParameters
= (LPWSTR
)ptr
;
2625 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2626 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
2627 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2628 "Default Priority");
2629 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
2630 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
2633 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
2634 memset(pi2
, 0, sizeof(*pi2
));
2639 /*********************************************************************
2640 * WINSPOOL_GetPrinter_4
2642 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2644 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
2645 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2648 DWORD size
, left
= cbBuf
;
2649 BOOL space
= (cbBuf
> 0);
2654 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2656 if(space
&& size
<= left
) {
2657 pi4
->pPrinterName
= (LPWSTR
)ptr
;
2665 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2668 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
2669 memset(pi4
, 0, sizeof(*pi4
));
2674 /*********************************************************************
2675 * WINSPOOL_GetPrinter_5
2677 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2679 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
2680 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2683 DWORD size
, left
= cbBuf
;
2684 BOOL space
= (cbBuf
> 0);
2689 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2691 if(space
&& size
<= left
) {
2692 pi5
->pPrinterName
= (LPWSTR
)ptr
;
2699 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2701 if(space
&& size
<= left
) {
2702 pi5
->pPortName
= (LPWSTR
)ptr
;
2710 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2711 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2713 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2717 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
2718 memset(pi5
, 0, sizeof(*pi5
));
2723 /*****************************************************************************
2724 * WINSPOOL_GetPrinter
2726 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2727 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2728 * just a collection of pointers to strings.
2730 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2731 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
2734 DWORD size
, needed
= 0;
2736 HKEY hkeyPrinter
, hkeyPrinters
;
2739 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
2741 if (!(name
= get_opened_printer_name(hPrinter
))) {
2742 SetLastError(ERROR_INVALID_HANDLE
);
2746 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2748 ERR("Can't create Printers key\n");
2751 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
2753 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
2754 RegCloseKey(hkeyPrinters
);
2755 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
2762 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
2764 size
= sizeof(PRINTER_INFO_2W
);
2766 ptr
= pPrinter
+ size
;
2768 memset(pPrinter
, 0, size
);
2773 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
2781 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
2783 size
= sizeof(PRINTER_INFO_4W
);
2785 ptr
= pPrinter
+ size
;
2787 memset(pPrinter
, 0, size
);
2792 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
2801 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
2803 size
= sizeof(PRINTER_INFO_5W
);
2805 ptr
= pPrinter
+ size
;
2807 memset(pPrinter
, 0, size
);
2813 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
2820 FIXME("Unimplemented level %ld\n", Level
);
2821 SetLastError(ERROR_INVALID_LEVEL
);
2822 RegCloseKey(hkeyPrinters
);
2823 RegCloseKey(hkeyPrinter
);
2827 RegCloseKey(hkeyPrinter
);
2828 RegCloseKey(hkeyPrinters
);
2830 TRACE("returning %d needed = %ld\n", ret
, needed
);
2831 if(pcbNeeded
) *pcbNeeded
= needed
;
2833 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2837 /*****************************************************************************
2838 * GetPrinterW [WINSPOOL.@]
2840 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2841 DWORD cbBuf
, LPDWORD pcbNeeded
)
2843 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2847 /*****************************************************************************
2848 * GetPrinterA [WINSPOOL.@]
2850 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2851 DWORD cbBuf
, LPDWORD pcbNeeded
)
2853 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2857 /*****************************************************************************
2858 * WINSPOOL_EnumPrinters
2860 * Implementation of EnumPrintersA|W
2862 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
2863 DWORD dwLevel
, LPBYTE lpbPrinters
,
2864 DWORD cbBuf
, LPDWORD lpdwNeeded
,
2865 LPDWORD lpdwReturned
, BOOL unicode
)
2868 HKEY hkeyPrinters
, hkeyPrinter
;
2869 WCHAR PrinterName
[255];
2870 DWORD needed
= 0, number
= 0;
2871 DWORD used
, i
, left
;
2875 memset(lpbPrinters
, 0, cbBuf
);
2881 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2882 if(dwType
== PRINTER_ENUM_DEFAULT
)
2885 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
2886 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2887 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
2888 if(!dwType
) return TRUE
;
2891 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
2892 FIXME("dwType = %08lx\n", dwType
);
2893 SetLastError(ERROR_INVALID_FLAGS
);
2897 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2899 ERR("Can't create Printers key\n");
2903 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
2904 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
2905 RegCloseKey(hkeyPrinters
);
2906 ERR("Can't query Printers key\n");
2909 TRACE("Found %ld printers\n", number
);
2913 RegCloseKey(hkeyPrinters
);
2915 *lpdwReturned
= number
;
2919 used
= number
* sizeof(PRINTER_INFO_2W
);
2922 used
= number
* sizeof(PRINTER_INFO_4W
);
2925 used
= number
* sizeof(PRINTER_INFO_5W
);
2929 SetLastError(ERROR_INVALID_LEVEL
);
2930 RegCloseKey(hkeyPrinters
);
2933 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
2935 for(i
= 0; i
< number
; i
++) {
2936 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
2938 ERR("Can't enum key number %ld\n", i
);
2939 RegCloseKey(hkeyPrinters
);
2942 TRACE("Printer %ld is %s\n", i
, debugstr_w(PrinterName
));
2943 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
2945 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
2946 RegCloseKey(hkeyPrinters
);
2951 buf
= lpbPrinters
+ used
;
2952 left
= cbBuf
- used
;
2960 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
2961 left
, &needed
, unicode
);
2963 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
2966 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
2967 left
, &needed
, unicode
);
2969 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
2972 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
2973 left
, &needed
, unicode
);
2975 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
2978 ERR("Shouldn't be here!\n");
2979 RegCloseKey(hkeyPrinter
);
2980 RegCloseKey(hkeyPrinters
);
2983 RegCloseKey(hkeyPrinter
);
2985 RegCloseKey(hkeyPrinters
);
2992 memset(lpbPrinters
, 0, cbBuf
);
2993 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2997 *lpdwReturned
= number
;
2998 SetLastError(ERROR_SUCCESS
);
3003 /******************************************************************
3004 * EnumPrintersW [WINSPOOL.@]
3006 * Enumerates the available printers, print servers and print
3007 * providers, depending on the specified flags, name and level.
3011 * If level is set to 1:
3012 * Not implemented yet!
3013 * Returns TRUE with an empty list.
3015 * If level is set to 2:
3016 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3017 * Returns an array of PRINTER_INFO_2 data structures in the
3018 * lpbPrinters buffer. Note that according to MSDN also an
3019 * OpenPrinter should be performed on every remote printer.
3021 * If level is set to 4 (officially WinNT only):
3022 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3023 * Fast: Only the registry is queried to retrieve printer names,
3024 * no connection to the driver is made.
3025 * Returns an array of PRINTER_INFO_4 data structures in the
3026 * lpbPrinters buffer.
3028 * If level is set to 5 (officially WinNT4/Win9x only):
3029 * Fast: Only the registry is queried to retrieve printer names,
3030 * no connection to the driver is made.
3031 * Returns an array of PRINTER_INFO_5 data structures in the
3032 * lpbPrinters buffer.
3034 * If level set to 3 or 6+:
3035 * returns zero (failure!)
3037 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3041 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3042 * - Only levels 2, 4 and 5 are implemented at the moment.
3043 * - 16-bit printer drivers are not enumerated.
3044 * - Returned amount of bytes used/needed does not match the real Windoze
3045 * implementation (as in this implementation, all strings are part
3046 * of the buffer, whereas Win32 keeps them somewhere else)
3047 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3050 * - In a regular Wine installation, no registry settings for printers
3051 * exist, which makes this function return an empty list.
3053 BOOL WINAPI
EnumPrintersW(
3054 DWORD dwType
, /* [in] Types of print objects to enumerate */
3055 LPWSTR lpszName
, /* [in] name of objects to enumerate */
3056 DWORD dwLevel
, /* [in] type of printer info structure */
3057 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
3058 DWORD cbBuf
, /* [in] max size of buffer in bytes */
3059 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
3060 LPDWORD lpdwReturned
/* [out] number of entries returned */
3063 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
3064 lpdwNeeded
, lpdwReturned
, TRUE
);
3067 /******************************************************************
3068 * EnumPrintersA [WINSPOOL.@]
3071 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
3072 DWORD dwLevel
, LPBYTE lpbPrinters
,
3073 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3074 LPDWORD lpdwReturned
)
3077 UNICODE_STRING lpszNameW
;
3080 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
3081 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
3082 lpdwNeeded
, lpdwReturned
, FALSE
);
3083 RtlFreeUnicodeString(&lpszNameW
);
3087 /*****************************************************************************
3088 * WINSPOOL_GetDriverInfoFromReg [internal]
3090 * Enters the information from the registry into the DRIVER_INFO struct
3093 * zero if the printer driver does not exist in the registry
3094 * (only if Level > 1) otherwise nonzero
3096 static BOOL
WINSPOOL_GetDriverInfoFromReg(
3099 LPWSTR pEnvironment
,
3101 LPBYTE ptr
, /* DRIVER_INFO */
3102 LPBYTE pDriverStrings
, /* strings buffer */
3103 DWORD cbBuf
, /* size of string buffer */
3104 LPDWORD pcbNeeded
, /* space needed for str. */
3105 BOOL unicode
) /* type of strings */
3106 { DWORD dw
, size
, tmp
, type
;
3108 LPBYTE strPtr
= pDriverStrings
;
3110 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3111 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
3112 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
3115 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
3116 if (*pcbNeeded
<= cbBuf
)
3117 strcpyW((LPWSTR
)strPtr
, DriverName
);
3119 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
3121 if(*pcbNeeded
<= cbBuf
)
3122 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1,
3123 (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
3127 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
3131 ((PDRIVER_INFO_3W
) ptr
)->pName
= (LPWSTR
) strPtr
;
3132 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3135 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
3136 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName
));
3137 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
3142 if(RegQueryValueExA(hkeyDriver
, "Version", 0, &type
, (PBYTE
)&dw
, &size
) !=
3144 WARN("Can't get Version\n");
3146 ((PDRIVER_INFO_3A
) ptr
)->cVersion
= dw
;
3149 pEnvironment
= (LPWSTR
)DefaultEnvironmentW
;
3151 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
3153 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
3156 if(*pcbNeeded
<= cbBuf
) {
3158 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
3160 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1,
3161 (LPSTR
)strPtr
, size
, NULL
, NULL
);
3163 ((PDRIVER_INFO_3W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
3164 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3167 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
3170 if(*pcbNeeded
<= cbBuf
)
3171 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
3174 ((PDRIVER_INFO_3W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
3175 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3178 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
3181 if(*pcbNeeded
<= cbBuf
)
3182 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
3185 ((PDRIVER_INFO_3W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
3186 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3189 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3190 0, &size
, unicode
)) {
3192 if(*pcbNeeded
<= cbBuf
)
3193 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3194 size
, &tmp
, unicode
);
3196 ((PDRIVER_INFO_3W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
3197 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3201 RegCloseKey(hkeyDriver
);
3202 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3206 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
3209 if(*pcbNeeded
<= cbBuf
)
3210 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
3211 size
, &tmp
, unicode
);
3213 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
3214 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3217 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
3220 if(*pcbNeeded
<= cbBuf
)
3221 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
3222 size
, &tmp
, unicode
);
3224 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
3225 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3228 if(WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
3231 if(*pcbNeeded
<= cbBuf
)
3232 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
3233 size
, &tmp
, unicode
);
3235 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
3236 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3239 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
3242 if(*pcbNeeded
<= cbBuf
)
3243 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
,
3244 size
, &tmp
, unicode
);
3246 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
3247 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3250 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3251 RegCloseKey(hkeyDriver
);
3255 /*****************************************************************************
3256 * WINSPOOL_GetPrinterDriver
3258 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
3259 DWORD Level
, LPBYTE pDriverInfo
,
3260 DWORD cbBuf
, LPDWORD pcbNeeded
,
3264 WCHAR DriverName
[100];
3265 DWORD ret
, type
, size
, needed
= 0;
3267 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
3269 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
3270 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
3272 ZeroMemory(pDriverInfo
, cbBuf
);
3274 if (!(name
= get_opened_printer_name(hPrinter
))) {
3275 SetLastError(ERROR_INVALID_HANDLE
);
3278 if(Level
< 1 || Level
> 3) {
3279 SetLastError(ERROR_INVALID_LEVEL
);
3282 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
3284 ERR("Can't create Printers key\n");
3287 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
3289 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3290 RegCloseKey(hkeyPrinters
);
3291 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3294 size
= sizeof(DriverName
);
3296 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
3297 (LPBYTE
)DriverName
, &size
);
3298 RegCloseKey(hkeyPrinter
);
3299 RegCloseKey(hkeyPrinters
);
3300 if(ret
!= ERROR_SUCCESS
) {
3301 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
3305 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
3307 ERR("Can't create Drivers key\n");
3313 size
= sizeof(DRIVER_INFO_1W
);
3316 size
= sizeof(DRIVER_INFO_2W
);
3319 size
= sizeof(DRIVER_INFO_3W
);
3322 ERR("Invalid level\n");
3327 ptr
= pDriverInfo
+ size
;
3329 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
3330 pEnvironment
, Level
, pDriverInfo
,
3331 (cbBuf
< size
) ? NULL
: ptr
,
3332 (cbBuf
< size
) ? 0 : cbBuf
- size
,
3333 &needed
, unicode
)) {
3334 RegCloseKey(hkeyDrivers
);
3338 RegCloseKey(hkeyDrivers
);
3340 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
3341 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3342 if(cbBuf
>= needed
) return TRUE
;
3343 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3347 /*****************************************************************************
3348 * GetPrinterDriverA [WINSPOOL.@]
3350 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
3351 DWORD Level
, LPBYTE pDriverInfo
,
3352 DWORD cbBuf
, LPDWORD pcbNeeded
)
3355 UNICODE_STRING pEnvW
;
3358 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
3359 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
3360 cbBuf
, pcbNeeded
, FALSE
);
3361 RtlFreeUnicodeString(&pEnvW
);
3364 /*****************************************************************************
3365 * GetPrinterDriverW [WINSPOOL.@]
3367 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
3368 DWORD Level
, LPBYTE pDriverInfo
,
3369 DWORD cbBuf
, LPDWORD pcbNeeded
)
3371 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
3372 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
3375 /*****************************************************************************
3376 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3378 * Return the PATH for the Printer-Drivers (UNICODE)
3381 * pName [I] Servername (NT only) or NULL (local Computer)
3382 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3383 * Level [I] Structure-Level (must be 1)
3384 * pDriverDirectory [O] PTR to Buffer that receives the Result
3385 * cbBuf [I] Size of Buffer at pDriverDirectory
3386 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3387 * required for pDriverDirectory
3390 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3391 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3392 * if cbBuf is too small
3394 * Native Values returned in pDriverDirectory on Success:
3395 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3396 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3397 *| win9x(Windows 4.0): "%winsysdir%"
3399 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3402 *- pName != NULL not supported
3403 *- pEnvironment != NULL not supported
3404 *- Current Implementation returns always "%winsysdir%"
3407 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
3408 DWORD Level
, LPBYTE pDriverDirectory
,
3409 DWORD cbBuf
, LPDWORD pcbNeeded
)
3412 const printenv_t
* env
;
3414 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
3415 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
3417 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
3418 SetLastError(ERROR_INVALID_PARAMETER
);
3422 env
= validate_envW(pEnvironment
);
3423 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
3426 WARN("(Level: %ld) is ignored in win9x\n", Level
);
3427 SetLastError(ERROR_INVALID_LEVEL
);
3431 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3432 needed
= GetSystemDirectoryW(NULL
, 0);
3433 /* add the Size for the Subdirectories */
3434 needed
+= lstrlenW(spooldriversW
);
3435 needed
+= lstrlenW(env
->subdir
);
3436 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
3439 *pcbNeeded
= needed
;
3440 TRACE("required: 0x%lx/%ld\n", needed
, needed
);
3441 if(needed
> cbBuf
) {
3442 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3445 if(pcbNeeded
== NULL
) {
3446 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3447 SetLastError(RPC_X_NULL_REF_POINTER
);
3450 if(pDriverDirectory
== NULL
) {
3451 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3452 SetLastError(ERROR_INVALID_USER_BUFFER
);
3456 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
3457 /* add the Subdirectories */
3458 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
3459 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
3460 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
3465 /*****************************************************************************
3466 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3468 * Return the PATH for the Printer-Drivers (ANSI)
3470 * See GetPrinterDriverDirectoryW.
3473 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3476 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
3477 DWORD Level
, LPBYTE pDriverDirectory
,
3478 DWORD cbBuf
, LPDWORD pcbNeeded
)
3480 UNICODE_STRING nameW
, environmentW
;
3483 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
3484 WCHAR
*driverDirectoryW
= NULL
;
3486 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName
),
3487 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
3489 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
3491 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
3492 else nameW
.Buffer
= NULL
;
3493 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
3494 else environmentW
.Buffer
= NULL
;
3496 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
3497 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
3500 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
3501 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
3503 *pcbNeeded
= needed
;
3504 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
3506 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
3508 TRACE("required: 0x%lx/%ld\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3510 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
3511 RtlFreeUnicodeString(&environmentW
);
3512 RtlFreeUnicodeString(&nameW
);
3517 /*****************************************************************************
3518 * AddPrinterDriverA [WINSPOOL.@]
3520 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
3523 HKEY hkeyDrivers
, hkeyName
;
3525 TRACE("(%s,%ld,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
3527 if(level
!= 2 && level
!= 3) {
3528 SetLastError(ERROR_INVALID_LEVEL
);
3532 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
3533 SetLastError(ERROR_INVALID_PARAMETER
);
3537 WARN("pDriverInfo == NULL\n");
3538 SetLastError(ERROR_INVALID_PARAMETER
);
3543 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
3545 memset(&di3
, 0, sizeof(di3
));
3546 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
3549 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
3551 SetLastError(ERROR_INVALID_PARAMETER
);
3554 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= "";
3555 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= "\0";
3556 if(!di3
.pHelpFile
) di3
.pHelpFile
= "";
3557 if(!di3
.pMonitorName
) di3
.pMonitorName
= "";
3559 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
3562 ERR("Can't create Drivers key\n");
3566 if(level
== 2) { /* apparently can't overwrite with level2 */
3567 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
3568 RegCloseKey(hkeyName
);
3569 RegCloseKey(hkeyDrivers
);
3570 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
3571 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
3575 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
3576 RegCloseKey(hkeyDrivers
);
3577 ERR("Can't create Name key\n");
3580 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
3582 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, 0);
3583 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, 0);
3584 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
3586 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, 0);
3587 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
3588 (LPBYTE
) di3
.pDependentFiles
, 0);
3589 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, 0);
3590 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, 0);
3591 RegCloseKey(hkeyName
);
3592 RegCloseKey(hkeyDrivers
);
3597 /*****************************************************************************
3598 * AddPrinterDriverW [WINSPOOL.@]
3600 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
3603 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName
),
3608 /*****************************************************************************
3609 * AddPrintProcessorA [WINSPOOL.@]
3611 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
3612 LPSTR pPrintProcessorName
)
3614 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
3615 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
3619 /*****************************************************************************
3620 * AddPrintProcessorW [WINSPOOL.@]
3622 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
3623 LPWSTR pPrintProcessorName
)
3625 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
3626 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
3630 /*****************************************************************************
3631 * AddPrintProvidorA [WINSPOOL.@]
3633 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3635 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
3639 /*****************************************************************************
3640 * AddPrintProvidorW [WINSPOOL.@]
3642 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3644 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
3648 /*****************************************************************************
3649 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3651 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
3652 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
3654 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
3655 pDevModeOutput
, pDevModeInput
);
3659 /*****************************************************************************
3660 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3662 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
3663 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
3665 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
3666 pDevModeOutput
, pDevModeInput
);
3670 /*****************************************************************************
3671 * PrinterProperties [WINSPOOL.@]
3673 * Displays a dialog to set the properties of the printer.
3676 * nonzero on success or zero on failure
3679 * implemented as stub only
3681 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
3682 HANDLE hPrinter
/* [in] handle to printer object */
3684 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
3685 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3689 /*****************************************************************************
3690 * EnumJobsA [WINSPOOL.@]
3693 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3694 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3697 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3698 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3700 if(pcbNeeded
) *pcbNeeded
= 0;
3701 if(pcReturned
) *pcReturned
= 0;
3706 /*****************************************************************************
3707 * EnumJobsW [WINSPOOL.@]
3710 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3711 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3714 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3715 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3717 if(pcbNeeded
) *pcbNeeded
= 0;
3718 if(pcReturned
) *pcReturned
= 0;
3722 /*****************************************************************************
3723 * WINSPOOL_EnumPrinterDrivers [internal]
3725 * Delivers information about all printer drivers installed on the
3726 * localhost or a given server
3729 * nonzero on success or zero on failure. If the buffer for the returned
3730 * information is too small the function will return an error
3733 * - only implemented for localhost, foreign hosts will return an error
3735 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPWSTR pEnvironment
,
3736 DWORD Level
, LPBYTE pDriverInfo
,
3737 DWORD cbBuf
, LPDWORD pcbNeeded
,
3738 LPDWORD pcReturned
, BOOL unicode
)
3741 DWORD i
, needed
, number
= 0, size
= 0;
3742 WCHAR DriverNameW
[255];
3745 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3746 debugstr_w(pName
), debugstr_w(pEnvironment
),
3747 Level
, pDriverInfo
, cbBuf
, unicode
);
3749 /* check for local drivers */
3751 ERR("remote drivers unsupported! Current remote host is %s\n",
3756 /* check input parameter */
3757 if((Level
< 1) || (Level
> 3)) {
3758 ERR("unsupported level %ld\n", Level
);
3759 SetLastError(ERROR_INVALID_LEVEL
);
3763 /* initialize return values */
3765 memset( pDriverInfo
, 0, cbBuf
);
3769 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
3771 ERR("Can't open Drivers key\n");
3775 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3776 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3777 RegCloseKey(hkeyDrivers
);
3778 ERR("Can't query Drivers key\n");
3781 TRACE("Found %ld Drivers\n", number
);
3783 /* get size of single struct
3784 * unicode and ascii structure have the same size
3788 size
= sizeof(DRIVER_INFO_1A
);
3791 size
= sizeof(DRIVER_INFO_2A
);
3794 size
= sizeof(DRIVER_INFO_3A
);
3798 /* calculate required buffer size */
3799 *pcbNeeded
= size
* number
;
3801 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
3803 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
3804 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
3806 ERR("Can't enum key number %ld\n", i
);
3807 RegCloseKey(hkeyDrivers
);
3810 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
3811 pEnvironment
, Level
, ptr
,
3812 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
3813 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
3814 &needed
, unicode
)) {
3815 RegCloseKey(hkeyDrivers
);
3818 (*pcbNeeded
) += needed
;
3821 RegCloseKey(hkeyDrivers
);
3823 if(cbBuf
< *pcbNeeded
){
3824 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3828 *pcReturned
= number
;
3832 /*****************************************************************************
3833 * EnumPrinterDriversW [WINSPOOL.@]
3835 * see function EnumPrinterDrivers for RETURNS, BUGS
3837 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
3838 LPBYTE pDriverInfo
, DWORD cbBuf
,
3839 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3841 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
3842 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
3845 /*****************************************************************************
3846 * EnumPrinterDriversA [WINSPOOL.@]
3848 * see function EnumPrinterDrivers for RETURNS, BUGS
3850 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
3851 LPBYTE pDriverInfo
, DWORD cbBuf
,
3852 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3854 UNICODE_STRING pNameW
, pEnvironmentW
;
3855 PWSTR pwstrNameW
, pwstrEnvironmentW
;
3857 pwstrNameW
= asciitounicode(&pNameW
, pName
);
3858 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
3860 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
3861 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
3863 RtlFreeUnicodeString(&pNameW
);
3864 RtlFreeUnicodeString(&pEnvironmentW
);
3869 static CHAR PortMonitor
[] = "Wine Port Monitor";
3870 static CHAR PortDescription
[] = "Wine Port";
3872 static BOOL
WINSPOOL_ComPortExists( LPCSTR name
)
3876 handle
= CreateFileA( name
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3877 NULL
, OPEN_EXISTING
, 0, NULL
);
3878 if (handle
== INVALID_HANDLE_VALUE
)
3880 TRACE("Checking %s exists\n", name
);
3881 CloseHandle( handle
);
3885 static DWORD
WINSPOOL_CountSerialPorts(void)
3892 strcpy( name
, "COMx:" );
3894 if (WINSPOOL_ComPortExists( name
))
3901 /******************************************************************************
3902 * EnumPortsA (WINSPOOL.@)
3907 * ANSI-Version did not call the UNICODE-Version
3910 BOOL WINAPI
EnumPortsA(LPSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
3911 LPDWORD bufneeded
,LPDWORD bufreturned
)
3914 DWORD info_size
, ofs
, i
, printer_count
, serial_count
, count
, n
, r
;
3915 const LPCSTR szPrinterPortKey
= "Software\\Wine\\Wine\\Config\\spooler";
3919 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3920 debugstr_a(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
3925 info_size
= sizeof (PORT_INFO_1A
);
3928 info_size
= sizeof (PORT_INFO_2A
);
3931 SetLastError(ERROR_INVALID_LEVEL
);
3935 /* see how many exist */
3938 serial_count
= WINSPOOL_CountSerialPorts();
3941 r
= RegOpenKeyA( HKEY_LOCAL_MACHINE
, szPrinterPortKey
, &hkey_printer
);
3942 if ( r
== ERROR_SUCCESS
)
3944 RegQueryInfoKeyA( hkey_printer
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3945 &printer_count
, NULL
, NULL
, NULL
, NULL
);
3947 count
= serial_count
+ printer_count
;
3949 /* then fill in the structure info structure once
3950 we know the offset to the first string */
3952 memset( buffer
, 0, bufsize
);
3954 ofs
= info_size
*count
;
3955 for ( i
=0; i
<count
; i
++)
3957 DWORD vallen
= sizeof(portname
) - 1;
3959 /* get the serial port values, then the printer values */
3960 if ( i
< serial_count
)
3962 strcpy( portname
, "COMx:" );
3963 portname
[3] = '1' + i
;
3964 if (!WINSPOOL_ComPortExists( portname
))
3967 TRACE("Found %s\n", portname
);
3968 vallen
= strlen( portname
);
3972 r
= RegEnumValueA( hkey_printer
, i
-serial_count
,
3973 portname
, &vallen
, NULL
, NULL
, NULL
, 0 );
3978 /* add a colon if necessary, and make it upper case */
3979 CharUpperBuffA(portname
,vallen
);
3980 if (strcasecmp(portname
,"nul")!=0)
3981 if (vallen
&& (portname
[vallen
-1] != ':') )
3982 lstrcatA(portname
,":");
3984 /* add the port info structure if we can fit it */
3985 if ( info_size
*(n
+1) < bufsize
)
3989 PORT_INFO_1A
*info
= (PORT_INFO_1A
*) &buffer
[info_size
*n
];
3990 info
->pName
= (LPSTR
) &buffer
[ofs
];
3992 else if ( level
== 2)
3994 PORT_INFO_2A
*info
= (PORT_INFO_2A
*) &buffer
[info_size
*n
];
3995 info
->pPortName
= (LPSTR
) &buffer
[ofs
];
3996 /* FIXME: fill in more stuff here */
3997 info
->pMonitorName
= PortMonitor
;
3998 info
->pDescription
= PortDescription
;
3999 info
->fPortType
= PORT_TYPE_WRITE
|PORT_TYPE_READ
;
4002 /* add the name of the port if we can fit it */
4003 if ( ofs
< bufsize
)
4004 lstrcpynA((LPSTR
)&buffer
[ofs
],portname
,bufsize
- ofs
);
4010 ofs
+= lstrlenA(portname
)+1;
4013 RegCloseKey(hkey_printer
);
4024 /******************************************************************************
4025 * EnumPortsW (WINSPOOL.@)
4027 * Enumerate available Ports
4030 * name [I] Servername or NULL (local Computer)
4031 * level [I] Structure-Level (1 or 2)
4032 * buffer [O] PTR to Buffer that receives the Result
4033 * bufsize [I] Size of Buffer at buffer
4034 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4035 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4039 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4042 * UNICODE-Version is a stub
4045 BOOL WINAPI
EnumPortsW(LPWSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
4046 LPDWORD bufneeded
,LPDWORD bufreturned
)
4048 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4049 debugstr_w(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
4053 /******************************************************************************
4054 * GetDefaultPrinterW (WINSPOOL.@)
4057 * This function must read the value from data 'device' of key
4058 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4060 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
4064 WCHAR
*buffer
, *ptr
;
4068 SetLastError(ERROR_INVALID_PARAMETER
);
4072 /* make the buffer big enough for the stuff from the profile/registry,
4073 * the content must fit into the local buffer to compute the correct
4074 * size even if the extern buffer is too small or not given.
4075 * (20 for ,driver,port) */
4077 len
= max(100, (insize
+ 20));
4078 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4080 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
4082 SetLastError (ERROR_FILE_NOT_FOUND
);
4086 TRACE("%s\n", debugstr_w(buffer
));
4088 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
4090 SetLastError(ERROR_INVALID_NAME
);
4096 *namesize
= strlenW(buffer
) + 1;
4097 if(!name
|| (*namesize
> insize
))
4099 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4103 strcpyW(name
, buffer
);
4106 HeapFree( GetProcessHeap(), 0, buffer
);
4111 /******************************************************************************
4112 * GetDefaultPrinterA (WINSPOOL.@)
4114 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
4118 WCHAR
*bufferW
= NULL
;
4122 SetLastError(ERROR_INVALID_PARAMETER
);
4126 if(name
&& *namesize
) {
4128 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
4131 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
4136 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
4140 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
4143 TRACE("0x%08lx/0x%08lx:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
4146 HeapFree( GetProcessHeap(), 0, bufferW
);
4151 /******************************************************************************
4152 * SetPrinterDataExA (WINSPOOL.@)
4154 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4155 LPCSTR pValueName
, DWORD Type
,
4156 LPBYTE pData
, DWORD cbData
)
4158 HKEY hkeyPrinter
, hkeySubkey
;
4161 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_a(pKeyName
),
4162 debugstr_a(pValueName
), Type
, pData
, cbData
);
4164 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4168 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4170 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
4171 RegCloseKey(hkeyPrinter
);
4174 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
4175 RegCloseKey(hkeySubkey
);
4176 RegCloseKey(hkeyPrinter
);
4180 /******************************************************************************
4181 * SetPrinterDataExW (WINSPOOL.@)
4183 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4184 LPCWSTR pValueName
, DWORD Type
,
4185 LPBYTE pData
, DWORD cbData
)
4187 HKEY hkeyPrinter
, hkeySubkey
;
4190 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_w(pKeyName
),
4191 debugstr_w(pValueName
), Type
, pData
, cbData
);
4193 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4197 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4199 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
4200 RegCloseKey(hkeyPrinter
);
4203 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
4204 RegCloseKey(hkeySubkey
);
4205 RegCloseKey(hkeyPrinter
);
4209 /******************************************************************************
4210 * SetPrinterDataA (WINSPOOL.@)
4212 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
4213 LPBYTE pData
, DWORD cbData
)
4215 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
4219 /******************************************************************************
4220 * SetPrinterDataW (WINSPOOL.@)
4222 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
4223 LPBYTE pData
, DWORD cbData
)
4225 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
4229 /******************************************************************************
4230 * GetPrinterDataExA (WINSPOOL.@)
4232 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4233 LPCSTR pValueName
, LPDWORD pType
,
4234 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4236 HKEY hkeyPrinter
, hkeySubkey
;
4239 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4240 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
4243 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4247 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4249 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
4250 RegCloseKey(hkeyPrinter
);
4254 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4255 RegCloseKey(hkeySubkey
);
4256 RegCloseKey(hkeyPrinter
);
4260 /******************************************************************************
4261 * GetPrinterDataExW (WINSPOOL.@)
4263 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4264 LPCWSTR pValueName
, LPDWORD pType
,
4265 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4267 HKEY hkeyPrinter
, hkeySubkey
;
4270 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4271 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
4274 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4278 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4280 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
4281 RegCloseKey(hkeyPrinter
);
4285 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4286 RegCloseKey(hkeySubkey
);
4287 RegCloseKey(hkeyPrinter
);
4291 /******************************************************************************
4292 * GetPrinterDataA (WINSPOOL.@)
4294 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
4295 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4297 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
4298 pData
, nSize
, pcbNeeded
);
4301 /******************************************************************************
4302 * GetPrinterDataW (WINSPOOL.@)
4304 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
4305 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4307 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
4308 pData
, nSize
, pcbNeeded
);
4311 /*******************************************************************************
4312 * EnumPrinterDataExW [WINSPOOL.@]
4314 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4315 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4316 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4318 HKEY hkPrinter
, hkSubKey
;
4319 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
4320 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
4325 PPRINTER_ENUM_VALUESW ppev
;
4327 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
4329 if (pKeyName
== NULL
|| *pKeyName
== 0)
4330 return ERROR_INVALID_PARAMETER
;
4332 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
4333 if (ret
!= ERROR_SUCCESS
)
4335 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4340 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
4341 if (ret
!= ERROR_SUCCESS
)
4343 r
= RegCloseKey (hkPrinter
);
4344 if (r
!= ERROR_SUCCESS
)
4345 WARN ("RegCloseKey returned %li\n", r
);
4346 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter
,
4347 debugstr_w (pKeyName
), ret
);
4351 ret
= RegCloseKey (hkPrinter
);
4352 if (ret
!= ERROR_SUCCESS
)
4354 ERR ("RegCloseKey returned %li\n", ret
);
4355 r
= RegCloseKey (hkSubKey
);
4356 if (r
!= ERROR_SUCCESS
)
4357 WARN ("RegCloseKey returned %li\n", r
);
4361 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4362 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
4363 if (ret
!= ERROR_SUCCESS
)
4365 r
= RegCloseKey (hkSubKey
);
4366 if (r
!= ERROR_SUCCESS
)
4367 WARN ("RegCloseKey returned %li\n", r
);
4368 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey
, ret
);
4372 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4373 "cbMaxValueLen = %li\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
4375 if (cValues
== 0) /* empty key */
4377 r
= RegCloseKey (hkSubKey
);
4378 if (r
!= ERROR_SUCCESS
)
4379 WARN ("RegCloseKey returned %li\n", r
);
4380 *pcbEnumValues
= *pnEnumValues
= 0;
4381 return ERROR_SUCCESS
;
4384 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
4386 hHeap
= GetProcessHeap ();
4389 ERR ("GetProcessHeap failed\n");
4390 r
= RegCloseKey (hkSubKey
);
4391 if (r
!= ERROR_SUCCESS
)
4392 WARN ("RegCloseKey returned %li\n", r
);
4393 return ERROR_OUTOFMEMORY
;
4396 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
4397 if (lpValueName
== NULL
)
4399 ERR ("Failed to allocate %li bytes from process heap\n",
4400 cbMaxValueNameLen
* sizeof (WCHAR
));
4401 r
= RegCloseKey (hkSubKey
);
4402 if (r
!= ERROR_SUCCESS
)
4403 WARN ("RegCloseKey returned %li\n", r
);
4404 return ERROR_OUTOFMEMORY
;
4407 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
4408 if (lpValue
== NULL
)
4410 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen
);
4411 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4412 WARN ("HeapFree failed with code %li\n", GetLastError ());
4413 r
= RegCloseKey (hkSubKey
);
4414 if (r
!= ERROR_SUCCESS
)
4415 WARN ("RegCloseKey returned %li\n", r
);
4416 return ERROR_OUTOFMEMORY
;
4419 TRACE ("pass 1: calculating buffer required for all names and values\n");
4421 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4423 TRACE ("%li bytes required for %li headers\n", cbBufSize
, cValues
);
4425 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4427 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4428 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4429 NULL
, NULL
, lpValue
, &cbValueLen
);
4430 if (ret
!= ERROR_SUCCESS
)
4432 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4433 WARN ("HeapFree failed with code %li\n", GetLastError ());
4434 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4435 WARN ("HeapFree failed with code %li\n", GetLastError ());
4436 r
= RegCloseKey (hkSubKey
);
4437 if (r
!= ERROR_SUCCESS
)
4438 WARN ("RegCloseKey returned %li\n", r
);
4439 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4443 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4444 debugstr_w (lpValueName
), dwIndex
,
4445 (cbValueNameLen
+ 1) * sizeof (WCHAR
), cbValueLen
);
4447 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4448 cbBufSize
+= cbValueLen
;
4451 TRACE ("%li bytes required for all %li values\n", cbBufSize
, cValues
);
4453 *pcbEnumValues
= cbBufSize
;
4454 *pnEnumValues
= cValues
;
4456 if (cbEnumValues
< cbBufSize
) /* buffer too small */
4458 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4459 WARN ("HeapFree failed with code %li\n", GetLastError ());
4460 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4461 WARN ("HeapFree failed with code %li\n", GetLastError ());
4462 r
= RegCloseKey (hkSubKey
);
4463 if (r
!= ERROR_SUCCESS
)
4464 WARN ("RegCloseKey returned %li\n", r
);
4465 TRACE ("%li byte buffer is not large enough\n", cbEnumValues
);
4466 return ERROR_MORE_DATA
;
4469 TRACE ("pass 2: copying all names and values to buffer\n");
4471 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
4472 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4474 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4476 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4477 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4478 NULL
, &dwType
, lpValue
, &cbValueLen
);
4479 if (ret
!= ERROR_SUCCESS
)
4481 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4482 WARN ("HeapFree failed with code %li\n", GetLastError ());
4483 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4484 WARN ("HeapFree failed with code %li\n", GetLastError ());
4485 r
= RegCloseKey (hkSubKey
);
4486 if (r
!= ERROR_SUCCESS
)
4487 WARN ("RegCloseKey returned %li\n", r
);
4488 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4492 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4493 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
4494 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
4495 pEnumValues
+= cbValueNameLen
;
4497 /* return # of *bytes* (including trailing \0), not # of chars */
4498 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
4500 ppev
[dwIndex
].dwType
= dwType
;
4502 memcpy (pEnumValues
, lpValue
, cbValueLen
);
4503 ppev
[dwIndex
].pData
= pEnumValues
;
4504 pEnumValues
+= cbValueLen
;
4506 ppev
[dwIndex
].cbData
= cbValueLen
;
4508 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4509 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
4512 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4514 ret
= GetLastError ();
4515 ERR ("HeapFree failed with code %li\n", ret
);
4516 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4517 WARN ("HeapFree failed with code %li\n", GetLastError ());
4518 r
= RegCloseKey (hkSubKey
);
4519 if (r
!= ERROR_SUCCESS
)
4520 WARN ("RegCloseKey returned %li\n", r
);
4524 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4526 ret
= GetLastError ();
4527 ERR ("HeapFree failed with code %li\n", ret
);
4528 r
= RegCloseKey (hkSubKey
);
4529 if (r
!= ERROR_SUCCESS
)
4530 WARN ("RegCloseKey returned %li\n", r
);
4534 ret
= RegCloseKey (hkSubKey
);
4535 if (ret
!= ERROR_SUCCESS
)
4537 ERR ("RegCloseKey returned %li\n", ret
);
4541 return ERROR_SUCCESS
;
4544 /*******************************************************************************
4545 * EnumPrinterDataExA [WINSPOOL.@]
4547 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4548 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4549 * what Windows 2000 SP1 does.
4552 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4553 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4554 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4558 DWORD ret
, dwIndex
, dwBufSize
;
4562 TRACE ("%p %s\n", hPrinter
, pKeyName
);
4564 if (pKeyName
== NULL
|| *pKeyName
== 0)
4565 return ERROR_INVALID_PARAMETER
;
4567 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
4570 ret
= GetLastError ();
4571 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4575 hHeap
= GetProcessHeap ();
4578 ERR ("GetProcessHeap failed\n");
4579 return ERROR_OUTOFMEMORY
;
4582 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
4583 if (pKeyNameW
== NULL
)
4585 ERR ("Failed to allocate %li bytes from process heap\n",
4586 (LONG
) len
* sizeof (WCHAR
));
4587 return ERROR_OUTOFMEMORY
;
4590 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
4592 ret
= GetLastError ();
4593 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4594 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4595 WARN ("HeapFree failed with code %li\n", GetLastError ());
4599 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
4600 pcbEnumValues
, pnEnumValues
);
4601 if (ret
!= ERROR_SUCCESS
)
4603 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4604 WARN ("HeapFree failed with code %li\n", GetLastError ());
4605 TRACE ("EnumPrinterDataExW returned %li\n", ret
);
4609 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4611 ret
= GetLastError ();
4612 ERR ("HeapFree failed with code %li\n", ret
);
4616 if (*pnEnumValues
== 0) /* empty key */
4617 return ERROR_SUCCESS
;
4620 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4622 PPRINTER_ENUM_VALUESW ppev
=
4623 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4625 if (dwBufSize
< ppev
->cbValueName
)
4626 dwBufSize
= ppev
->cbValueName
;
4628 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
4629 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
4630 dwBufSize
= ppev
->cbData
;
4633 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize
);
4635 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
4636 if (pBuffer
== NULL
)
4638 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize
);
4639 return ERROR_OUTOFMEMORY
;
4642 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4644 PPRINTER_ENUM_VALUESW ppev
=
4645 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4647 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
4648 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
4652 ret
= GetLastError ();
4653 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4654 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4655 WARN ("HeapFree failed with code %li\n", GetLastError ());
4659 memcpy (ppev
->pValueName
, pBuffer
, len
);
4661 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4663 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
4664 ppev
->dwType
!= REG_MULTI_SZ
)
4667 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
4668 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
4671 ret
= GetLastError ();
4672 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4673 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4674 WARN ("HeapFree failed with code %li\n", GetLastError ());
4678 memcpy (ppev
->pData
, pBuffer
, len
);
4680 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4681 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4684 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4686 ret
= GetLastError ();
4687 ERR ("HeapFree failed with code %li\n", ret
);
4691 return ERROR_SUCCESS
;
4694 /******************************************************************************
4695 * AbortPrinter (WINSPOOL.@)
4697 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
4699 FIXME("(%p), stub!\n", hPrinter
);
4703 /******************************************************************************
4704 * AddPortA (WINSPOOL.@)
4709 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
4711 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName
),hWnd
,debugstr_a(pMonitorName
));
4715 /******************************************************************************
4716 * AddPortW (WINSPOOL.@)
4718 * Add a Port for a specific Monitor
4721 * pName [I] Servername or NULL (local Computer)
4722 * hWnd [I] Handle to parent Window for the Dialog-Box
4723 * pMonitorName [I] Name of the Monitor that manage the Port
4733 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
4735 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName
),hWnd
,debugstr_w(pMonitorName
));
4739 /******************************************************************************
4740 * AddPortExA (WINSPOOL.@)
4745 BOOL WINAPI
AddPortExA(HANDLE hMonitor
, LPSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPSTR lpMonitorName
)
4747 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor
, debugstr_a(pName
), Level
,
4748 lpBuffer
, debugstr_a(lpMonitorName
));
4752 /******************************************************************************
4753 * AddPortExW (WINSPOOL.@)
4755 * Add a Port for a specific Monitor, without presenting a user interface
4758 * hMonitor [I] Handle from InitializePrintMonitor2()
4759 * pName [I] Servername or NULL (local Computer)
4760 * Level [I] Structure-Level (1 or 2) for lpBuffer
4761 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
4762 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
4772 BOOL WINAPI
AddPortExW(HANDLE hMonitor
, LPWSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPWSTR lpMonitorName
)
4774 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor
, debugstr_w(pName
), Level
,
4775 lpBuffer
, debugstr_w(lpMonitorName
));
4779 /******************************************************************************
4780 * AddPrinterConnectionA (WINSPOOL.@)
4782 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
4784 FIXME("%s\n", debugstr_a(pName
));
4788 /******************************************************************************
4789 * AddPrinterConnectionW (WINSPOOL.@)
4791 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
4793 FIXME("%s\n", debugstr_w(pName
));
4797 /******************************************************************************
4798 * AddPrinterDriverExW (WINSPOOL.@)
4800 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
4801 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4803 FIXME("%s %ld %p %ld\n", debugstr_w(pName
),
4804 Level
, pDriverInfo
, dwFileCopyFlags
);
4805 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4809 /******************************************************************************
4810 * AddPrinterDriverExA (WINSPOOL.@)
4812 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
4813 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4815 FIXME("%s %ld %p %ld\n", debugstr_a(pName
),
4816 Level
, pDriverInfo
, dwFileCopyFlags
);
4817 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4821 /******************************************************************************
4822 * ConfigurePortA (WINSPOOL.@)
4824 * See ConfigurePortW.
4827 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
4829 FIXME("%s %p %s\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
4833 /******************************************************************************
4834 * ConfigurePortW (WINSPOOL.@)
4836 * Display the Configuration-Dialog for a specific Port
4839 * pName [I] Servername or NULL (local Computer)
4840 * hWnd [I] Handle to parent Window for the Dialog-Box
4841 * pPortName [I] Name of the Port, that should be configured
4851 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
4853 FIXME("%s %p %s\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
4857 /******************************************************************************
4858 * ConnectToPrinterDlg (WINSPOOL.@)
4860 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
4862 FIXME("%p %lx\n", hWnd
, Flags
);
4866 /******************************************************************************
4867 * DeletePrinterConnectionA (WINSPOOL.@)
4869 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
4871 FIXME("%s\n", debugstr_a(pName
));
4875 /******************************************************************************
4876 * DeletePrinterConnectionW (WINSPOOL.@)
4878 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
4880 FIXME("%s\n", debugstr_w(pName
));
4884 /******************************************************************************
4885 * DeletePrinterDriverExW (WINSPOOL.@)
4887 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
4888 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4890 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4891 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4895 /******************************************************************************
4896 * DeletePrinterDriverExA (WINSPOOL.@)
4898 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
4899 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4901 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4902 debugstr_a(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4906 /******************************************************************************
4907 * DeletePrinterDataExW (WINSPOOL.@)
4909 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
4912 FIXME("%p %s %s\n", hPrinter
,
4913 debugstr_w(pKeyName
), debugstr_w(pValueName
));
4914 return ERROR_INVALID_PARAMETER
;
4917 /******************************************************************************
4918 * DeletePrinterDataExA (WINSPOOL.@)
4920 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
4923 FIXME("%p %s %s\n", hPrinter
,
4924 debugstr_a(pKeyName
), debugstr_a(pValueName
));
4925 return ERROR_INVALID_PARAMETER
;
4928 /******************************************************************************
4929 * DeletePrintProcessorA (WINSPOOL.@)
4931 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
4933 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4934 debugstr_a(pPrintProcessorName
));
4938 /******************************************************************************
4939 * DeletePrintProcessorW (WINSPOOL.@)
4941 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
4943 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4944 debugstr_w(pPrintProcessorName
));
4948 /******************************************************************************
4949 * DeletePrintProvidorA (WINSPOOL.@)
4951 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
4953 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4954 debugstr_a(pPrintProviderName
));
4958 /******************************************************************************
4959 * DeletePrintProvidorW (WINSPOOL.@)
4961 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
4963 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4964 debugstr_w(pPrintProviderName
));
4968 /******************************************************************************
4969 * EnumFormsA (WINSPOOL.@)
4971 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
4972 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4974 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
4978 /******************************************************************************
4979 * EnumFormsW (WINSPOOL.@)
4981 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
4982 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4984 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
4988 /*****************************************************************************
4989 * EnumMonitorsA [WINSPOOL.@]
4991 * See EnumMonitorsW.
4994 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
4995 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4997 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName
), Level
, pMonitors
,
4998 cbBuf
, pcbNeeded
, pcReturned
);
4999 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5003 /*****************************************************************************
5004 * EnumMonitorsW [WINSPOOL.@]
5006 * Enumerate available Monitors
5009 * pName [I] Servername or NULL (local Computer)
5010 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5011 * pMonitors [O] PTR to Buffer that receives the Result
5012 * cbBuf [I] Size of Buffer at pMonitors
5013 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5014 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5018 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5024 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
5025 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5027 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName
), Level
, pMonitors
,
5028 cbBuf
, pcbNeeded
, pcReturned
);
5029 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5033 /******************************************************************************
5034 * XcvDataW (WINSPOOL.@)
5037 * There doesn't seem to be an A version...
5039 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
5040 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
5041 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
5043 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv
, debugstr_w(pszDataName
),
5044 pInputData
, cbInputData
, pOutputData
,
5045 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
5049 /*****************************************************************************
5050 * EnumPrinterDataA [WINSPOOL.@]
5053 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
5054 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
5055 DWORD cbData
, LPDWORD pcbData
)
5057 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
5058 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
5059 return ERROR_NO_MORE_ITEMS
;
5062 /*****************************************************************************
5063 * EnumPrinterDataW [WINSPOOL.@]
5066 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
5067 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
5068 DWORD cbData
, LPDWORD pcbData
)
5070 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
5071 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
5072 return ERROR_NO_MORE_ITEMS
;
5075 /*****************************************************************************
5076 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5079 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
5080 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
5081 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5083 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName
),
5084 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
5085 pcbNeeded
, pcReturned
);
5089 /*****************************************************************************
5090 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5093 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
5094 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
5095 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5097 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
5098 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
5099 pcbNeeded
, pcReturned
);
5103 /*****************************************************************************
5104 * EnumPrintProcessorsA [WINSPOOL.@]
5107 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5108 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
5110 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName
, pEnvironment
, Level
,
5111 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
5115 /*****************************************************************************
5116 * EnumPrintProcessorsW [WINSPOOL.@]
5119 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5120 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
5122 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
5123 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
5124 cbBuf
, pcbNeeded
, pcbReturned
);
5128 /*****************************************************************************
5129 * ExtDeviceMode [WINSPOOL.@]
5132 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
5133 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
5136 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd
, hInst
, pDevModeOutput
,
5137 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
5138 debugstr_a(pProfile
), fMode
);
5142 /*****************************************************************************
5143 * FindClosePrinterChangeNotification [WINSPOOL.@]
5146 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
5148 FIXME("Stub: %p\n", hChange
);
5152 /*****************************************************************************
5153 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5156 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
5157 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
5159 FIXME("Stub: %p %lx %lx %p\n",
5160 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
5161 return INVALID_HANDLE_VALUE
;
5164 /*****************************************************************************
5165 * FindNextPrinterChangeNotification [WINSPOOL.@]
5168 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
5169 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
5171 FIXME("Stub: %p %p %p %p\n",
5172 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
5176 /*****************************************************************************
5177 * FreePrinterNotifyInfo [WINSPOOL.@]
5180 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
5182 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
5186 /*****************************************************************************
5189 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5190 * ansi depending on the unicode parameter.
5192 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
5202 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
5205 memcpy(ptr
, str
, *size
);
5212 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
5215 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
5222 /*****************************************************************************
5225 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
5226 LPDWORD pcbNeeded
, BOOL unicode
)
5228 DWORD size
, left
= cbBuf
;
5229 BOOL space
= (cbBuf
> 0);
5236 ji1
->JobId
= job
->job_id
;
5239 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
5240 if(space
&& size
<= left
)
5242 ji1
->pDocument
= (LPWSTR
)ptr
;
5253 /*****************************************************************************
5256 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
5257 LPDWORD pcbNeeded
, BOOL unicode
)
5259 DWORD size
, left
= cbBuf
;
5260 BOOL space
= (cbBuf
> 0);
5267 ji2
->JobId
= job
->job_id
;
5270 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
5271 if(space
&& size
<= left
)
5273 ji2
->pDocument
= (LPWSTR
)ptr
;
5284 /*****************************************************************************
5287 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5288 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
5291 DWORD needed
= 0, size
;
5295 TRACE("%p %ld %ld %p %ld %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
5297 EnterCriticalSection(&printer_handles_cs
);
5298 job
= get_job(hPrinter
, JobId
);
5305 size
= sizeof(JOB_INFO_1W
);
5310 memset(pJob
, 0, size
);
5314 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5319 size
= sizeof(JOB_INFO_2W
);
5324 memset(pJob
, 0, size
);
5328 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5333 size
= sizeof(JOB_INFO_3
);
5337 memset(pJob
, 0, size
);
5346 SetLastError(ERROR_INVALID_LEVEL
);
5350 *pcbNeeded
= needed
;
5352 LeaveCriticalSection(&printer_handles_cs
);
5356 /*****************************************************************************
5357 * GetJobA [WINSPOOL.@]
5360 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5361 DWORD cbBuf
, LPDWORD pcbNeeded
)
5363 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
5366 /*****************************************************************************
5367 * GetJobW [WINSPOOL.@]
5370 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5371 DWORD cbBuf
, LPDWORD pcbNeeded
)
5373 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
5376 /*****************************************************************************
5379 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
5381 char *unixname
, *queue
, *cmd
;
5382 char fmt
[] = "lpr -P%s %s";
5385 if(!(unixname
= wine_get_unix_file_name(filename
)))
5388 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5389 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5390 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5392 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
5393 sprintf(cmd
, fmt
, queue
, unixname
);
5395 TRACE("printing with: %s\n", cmd
);
5398 HeapFree(GetProcessHeap(), 0, cmd
);
5399 HeapFree(GetProcessHeap(), 0, queue
);
5400 HeapFree(GetProcessHeap(), 0, unixname
);
5404 /*****************************************************************************
5407 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
5409 #if HAVE_CUPS_CUPS_H
5412 char *unixname
, *queue
, *doc_titleA
;
5416 if(!(unixname
= wine_get_unix_file_name(filename
)))
5419 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5420 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5421 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5423 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
5424 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
5425 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
5427 TRACE("printing via cups\n");
5428 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
5429 HeapFree(GetProcessHeap(), 0, doc_titleA
);
5430 HeapFree(GetProcessHeap(), 0, queue
);
5431 HeapFree(GetProcessHeap(), 0, unixname
);
5437 return schedule_lpr(printer_name
, filename
);
5441 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
5448 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
5452 if(HIWORD(wparam
) == BN_CLICKED
)
5454 if(LOWORD(wparam
) == IDOK
)
5457 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
5460 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
5461 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
5463 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
5465 WCHAR caption
[200], message
[200];
5468 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5469 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
5470 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
5471 if(mb_ret
== IDCANCEL
)
5473 HeapFree(GetProcessHeap(), 0, filename
);
5477 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5478 if(hf
== INVALID_HANDLE_VALUE
)
5480 WCHAR caption
[200], message
[200];
5482 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5483 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
5484 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
5485 HeapFree(GetProcessHeap(), 0, filename
);
5489 DeleteFileW(filename
);
5490 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5492 EndDialog(hwnd
, IDOK
);
5495 if(LOWORD(wparam
) == IDCANCEL
)
5497 EndDialog(hwnd
, IDCANCEL
);
5506 /*****************************************************************************
5509 static BOOL
get_filename(LPWSTR
*filename
)
5511 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
5512 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
5515 /*****************************************************************************
5518 static BOOL
schedule_file(LPCWSTR filename
)
5520 LPWSTR output
= NULL
;
5522 if(get_filename(&output
))
5524 TRACE("copy to %s\n", debugstr_w(output
));
5525 CopyFileW(filename
, output
, FALSE
);
5526 HeapFree(GetProcessHeap(), 0, output
);
5532 /*****************************************************************************
5535 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
5538 char *unixname
, *cmdA
;
5540 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
5544 if(!(unixname
= wine_get_unix_file_name(filename
)))
5547 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
5548 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
5549 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
5551 TRACE("printing with: %s\n", cmdA
);
5553 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
5558 ERR("pipe() failed!\n");
5568 /* reset signals that we previously set to SIG_IGN */
5569 signal(SIGPIPE
, SIG_DFL
);
5570 signal(SIGCHLD
, SIG_DFL
);
5576 while((no_read
= read(file_fd
, buf
, sizeof(buf
))))
5577 write(fds
[1], buf
, no_read
);
5582 if(file_fd
!= -1) close(file_fd
);
5583 if(fds
[0] != -1) close(fds
[0]);
5584 if(fds
[1] != -1) close(fds
[1]);
5586 HeapFree(GetProcessHeap(), 0, cmdA
);
5587 HeapFree(GetProcessHeap(), 0, unixname
);
5594 /*****************************************************************************
5597 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
5599 int in_fd
, out_fd
, no_read
;
5602 char *unixname
, *outputA
;
5605 if(!(unixname
= wine_get_unix_file_name(filename
)))
5608 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
5609 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
5610 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
5612 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
5613 in_fd
= open(unixname
, O_RDONLY
);
5614 if(out_fd
== -1 || in_fd
== -1)
5617 while((no_read
= read(in_fd
, buf
, sizeof(buf
))))
5618 write(out_fd
, buf
, no_read
);
5622 if(in_fd
!= -1) close(in_fd
);
5623 if(out_fd
!= -1) close(out_fd
);
5624 HeapFree(GetProcessHeap(), 0, outputA
);
5625 HeapFree(GetProcessHeap(), 0, unixname
);
5629 /*****************************************************************************
5630 * ScheduleJob [WINSPOOL.@]
5633 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
5635 opened_printer_t
*printer
;
5637 struct list
*cursor
, *cursor2
;
5639 TRACE("(%p, %lx)\n", hPrinter
, dwJobID
);
5640 EnterCriticalSection(&printer_handles_cs
);
5641 printer
= get_opened_printer(hPrinter
);
5645 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
5647 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
5650 if(job
->job_id
!= dwJobID
) continue;
5652 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
5653 if(hf
!= INVALID_HANDLE_VALUE
)
5655 PRINTER_INFO_5W
*pi5
;
5659 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5660 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5662 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
5663 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
5664 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
5665 TRACE("need to schedule job %ld filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
5666 debugstr_w(pi5
->pPortName
));
5670 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5671 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
5673 DWORD type
, count
= sizeof(output
);
5674 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
5677 if(output
[0] == '|')
5679 schedule_pipe(output
+ 1, job
->filename
);
5683 schedule_unixfile(output
, job
->filename
);
5685 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
5687 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
5689 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
5691 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
5693 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
5695 schedule_file(job
->filename
);
5699 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
5701 HeapFree(GetProcessHeap(), 0, pi5
);
5703 DeleteFileW(job
->filename
);
5705 list_remove(cursor
);
5706 HeapFree(GetProcessHeap(), 0, job
->document_title
);
5707 HeapFree(GetProcessHeap(), 0, job
->filename
);
5708 HeapFree(GetProcessHeap(), 0, job
);
5713 LeaveCriticalSection(&printer_handles_cs
);
5717 /*****************************************************************************
5718 * StartDocDlgA [WINSPOOL.@]
5720 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
5722 UNICODE_STRING usBuffer
;
5727 docW
.cbSize
= sizeof(docW
);
5728 docW
.lpszDocName
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
5729 docW
.lpszOutput
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
5730 docW
.lpszDatatype
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
5731 docW
.fwType
= doc
->fwType
;
5733 retW
= StartDocDlgW(hPrinter
, &docW
);
5737 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
5738 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
5739 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
5740 HeapFree(GetProcessHeap(), 0, retW
);
5743 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDatatype
);
5744 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszOutput
);
5745 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDocName
);
5750 /*****************************************************************************
5751 * StartDocDlgW [WINSPOOL.@]
5753 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5754 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5755 * port is "FILE:". Also returns the full path if passed a relative path.
5757 * The caller should free the returned string from the process heap.
5759 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
5764 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
5766 PRINTER_INFO_5W
*pi5
;
5767 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
5768 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
5770 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
5771 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
5772 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
5774 HeapFree(GetProcessHeap(), 0, pi5
);
5777 HeapFree(GetProcessHeap(), 0, pi5
);
5780 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
5783 get_filename(&name
);
5786 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
5788 HeapFree(GetProcessHeap(), 0, name
);
5791 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5792 GetFullPathNameW(name
, len
, ret
, NULL
);
5793 HeapFree(GetProcessHeap(), 0, name
);
5798 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
5801 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5802 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
5804 attr
= GetFileAttributesW(ret
);
5805 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
5807 HeapFree(GetProcessHeap(), 0, ret
);