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 * An empty string is handled the same way as NULL.
208 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
212 static const printenv_t
* validate_envW(LPCWSTR env
)
214 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
};
215 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
};
216 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
218 const printenv_t
*result
= NULL
;
221 TRACE("testing %s\n", debugstr_w(env
));
224 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
226 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
228 result
= all_printenv
[i
];
233 if (result
== NULL
) {
234 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
235 SetLastError(ERROR_INVALID_ENVIRONMENT
);
237 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
241 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
243 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
249 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
250 if passed a NULL string. This returns NULLs to the result.
252 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
256 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
257 return usBufferPtr
->Buffer
;
259 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
263 static LPWSTR
strdupW(LPCWSTR p
)
269 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
270 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
276 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
,BOOL force
) {
279 /* If forcing, or no profile string entry for device yet, set the entry
281 * The always change entry if not WINEPS yet is discussable.
284 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
286 !strstr(qbuf
,"WINEPS.DRV")
288 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
291 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
292 WriteProfileStringA("windows","device",buf
);
293 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
294 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
297 HeapFree(GetProcessHeap(),0,buf
);
301 #ifdef HAVE_CUPS_CUPS_H
302 static typeof(cupsGetDests
) *pcupsGetDests
;
303 static typeof(cupsGetPPD
) *pcupsGetPPD
;
304 static typeof(cupsPrintFile
) *pcupsPrintFile
;
305 static void *cupshandle
;
307 static BOOL
CUPS_LoadPrinters(void)
310 BOOL hadprinter
= FALSE
;
312 PRINTER_INFO_2A pinfo2a
;
314 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
316 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
319 TRACE("loaded %s\n", SONAME_LIBCUPS
);
322 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
323 if (!p##x) return FALSE;
326 DYNCUPS(cupsGetDests
);
327 DYNCUPS(cupsPrintFile
);
330 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
332 ERR("Can't create Printers key\n");
336 nrofdests
= pcupsGetDests(&dests
);
337 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
338 for (i
=0;i
<nrofdests
;i
++) {
339 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
340 sprintf(port
,"LPR:%s",dests
[i
].name
);
341 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
342 sprintf(devline
,"WINEPS.DRV,%s",port
);
343 WriteProfileStringA("devices",dests
[i
].name
,devline
);
344 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
345 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
348 HeapFree(GetProcessHeap(),0,devline
);
350 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
351 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
352 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
354 TRACE("Printer already exists\n");
355 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
356 RegCloseKey(hkeyPrinter
);
358 memset(&pinfo2a
,0,sizeof(pinfo2a
));
359 pinfo2a
.pPrinterName
= dests
[i
].name
;
360 pinfo2a
.pDatatype
= "RAW";
361 pinfo2a
.pPrintProcessor
= "WinPrint";
362 pinfo2a
.pDriverName
= "PS Driver";
363 pinfo2a
.pComment
= "WINEPS Printer using CUPS";
364 pinfo2a
.pLocation
= "<physical location of printer>";
365 pinfo2a
.pPortName
= port
;
366 pinfo2a
.pParameters
= "<parameters?>";
367 pinfo2a
.pShareName
= "<share name?>";
368 pinfo2a
.pSepFile
= "<sep file?>";
370 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
371 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
372 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests
[i
].name
,GetLastError());
375 HeapFree(GetProcessHeap(),0,port
);
378 if (dests
[i
].is_default
)
379 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
381 RegCloseKey(hkeyPrinters
);
387 PRINTCAP_ParseEntry(char *pent
,BOOL isfirst
) {
388 PRINTER_INFO_2A pinfo2a
;
389 char *e
,*s
,*name
,*prettyname
,*devname
;
390 BOOL ret
= FALSE
, set_default
= FALSE
;
391 char *port
,*devline
,*env_default
;
392 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
394 while (isspace(*pent
)) pent
++;
395 s
= strchr(pent
,':');
397 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
405 TRACE("name=%s entry=%s\n",name
, pent
);
407 if(ispunct(*name
)) { /* a tc entry, not a real printer */
408 TRACE("skipping tc entry\n");
412 if(strstr(pent
,":server")) { /* server only version so skip */
413 TRACE("skipping server entry\n");
417 /* Determine whether this is a postscript printer. */
420 env_default
= getenv("PRINTER");
422 /* Get longest name, usually the one at the right for later display. */
423 while((s
=strchr(prettyname
,'|'))) {
426 while(isspace(*--e
)) *e
= '\0';
427 TRACE("\t%s\n", debugstr_a(prettyname
));
428 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
429 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
432 e
= prettyname
+ strlen(prettyname
);
433 while(isspace(*--e
)) *e
= '\0';
434 TRACE("\t%s\n", debugstr_a(prettyname
));
435 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
437 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
438 * if it is too long, we use it as comment below. */
439 devname
= prettyname
;
440 if (strlen(devname
)>=CCHDEVICENAME
-1)
442 if (strlen(devname
)>=CCHDEVICENAME
-1) {
447 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
448 sprintf(port
,"LPR:%s",name
);
450 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
451 sprintf(devline
,"WINEPS.DRV,%s",port
);
452 WriteProfileStringA("devices",devname
,devline
);
453 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
454 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
457 HeapFree(GetProcessHeap(),0,devline
);
459 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
461 ERR("Can't create Printers key\n");
465 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
466 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
468 TRACE("Printer already exists\n");
469 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
470 RegCloseKey(hkeyPrinter
);
472 memset(&pinfo2a
,0,sizeof(pinfo2a
));
473 pinfo2a
.pPrinterName
= devname
;
474 pinfo2a
.pDatatype
= "RAW";
475 pinfo2a
.pPrintProcessor
= "WinPrint";
476 pinfo2a
.pDriverName
= "PS Driver";
477 pinfo2a
.pComment
= "WINEPS Printer using LPR";
478 pinfo2a
.pLocation
= prettyname
;
479 pinfo2a
.pPortName
= port
;
480 pinfo2a
.pParameters
= "<parameters?>";
481 pinfo2a
.pShareName
= "<share name?>";
482 pinfo2a
.pSepFile
= "<sep file?>";
484 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
485 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
486 ERR("%s not added by AddPrinterA (%ld)\n",name
,GetLastError());
489 RegCloseKey(hkeyPrinters
);
491 if (isfirst
|| set_default
)
492 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
494 HeapFree(GetProcessHeap(), 0, port
);
496 HeapFree(GetProcessHeap(), 0, name
);
501 PRINTCAP_LoadPrinters(void) {
502 BOOL hadprinter
= FALSE
;
506 BOOL had_bash
= FALSE
;
508 f
= fopen("/etc/printcap","r");
512 while(fgets(buf
,sizeof(buf
),f
)) {
515 end
=strchr(buf
,'\n');
519 while(isspace(*start
)) start
++;
520 if(*start
== '#' || *start
== '\0')
523 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
524 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
525 HeapFree(GetProcessHeap(),0,pent
);
529 if (end
&& *--end
== '\\') {
536 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
539 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
545 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
546 HeapFree(GetProcessHeap(),0,pent
);
552 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
555 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
556 lstrlenW(value
) * sizeof(WCHAR
));
558 return ERROR_FILE_NOT_FOUND
;
561 void WINSPOOL_LoadSystemPrinters(void)
563 HKEY hkey
, hkeyPrinters
;
566 DWORD needed
, num
, i
;
567 WCHAR PrinterName
[256];
570 di3a
.cVersion
= 0x400;
571 di3a
.pName
= "PS Driver";
572 di3a
.pEnvironment
= NULL
; /* NULL means auto */
573 di3a
.pDriverPath
= "wineps16";
574 di3a
.pDataFile
= "<datafile?>";
575 di3a
.pConfigFile
= "wineps16";
576 di3a
.pHelpFile
= "<helpfile?>";
577 di3a
.pDependentFiles
= "<dependend files?>";
578 di3a
.pMonitorName
= "<monitor name?>";
579 di3a
.pDefaultDataType
= "RAW";
581 if (!AddPrinterDriverA(NULL
,3,(LPBYTE
)&di3a
)) {
582 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
586 /* This ensures that all printer entries have a valid Name value. If causes
587 problems later if they don't. If one is found to be missed we create one
588 and set it equal to the name of the key */
589 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
590 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
591 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
592 for(i
= 0; i
< num
; i
++) {
593 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
594 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
595 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
596 set_reg_szW(hkey
, NameW
, PrinterName
);
603 RegCloseKey(hkeyPrinters
);
606 /* We want to avoid calling AddPrinter on printers as much as
607 possible, because on cups printers this will (eventually) lead
608 to a call to cupsGetPPD which takes forever, even with non-cups
609 printers AddPrinter takes a while. So we'll tag all printers that
610 were automatically added last time around, if they still exist
611 we'll leave them be otherwise we'll delete them. */
612 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
614 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
615 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
616 for(i
= 0; i
< num
; i
++) {
617 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
618 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
619 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
621 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
629 HeapFree(GetProcessHeap(), 0, pi
);
633 #ifdef HAVE_CUPS_CUPS_H
634 done
= CUPS_LoadPrinters();
637 if(!done
) { /* If we have any CUPS based printers, skip looking for printcap printers */
638 /* Check for [ppd] section in config file before parsing /etc/printcap */
639 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
640 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Printing\\PPD Files",
641 &hkey
) == ERROR_SUCCESS
) {
643 PRINTCAP_LoadPrinters();
647 /* Now enumerate the list again and delete any printers that a still tagged */
648 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
650 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
651 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
652 for(i
= 0; i
< num
; i
++) {
653 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
654 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
655 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
656 DWORD dw
, type
, size
= sizeof(dw
);
657 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
658 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
668 HeapFree(GetProcessHeap(), 0, pi
);
676 /******************************************************************
677 * get_opened_printer_entry
678 * Get the first place empty in the opened printer table
680 static HANDLE
get_opened_printer_entry( LPCWSTR name
)
682 UINT_PTR handle
= nb_printer_handles
, i
;
683 jobqueue_t
*queue
= NULL
;
684 opened_printer_t
*printer
;
686 EnterCriticalSection(&printer_handles_cs
);
688 for (i
= 0; i
< nb_printer_handles
; i
++)
690 if (!printer_handles
[i
])
692 if(handle
== nb_printer_handles
)
695 else if(!queue
&& !strcmpW(name
, printer_handles
[i
]->name
))
696 queue
= printer_handles
[i
]->queue
;
699 if (handle
>= nb_printer_handles
)
701 opened_printer_t
**new_array
;
703 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
704 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
706 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
707 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
714 printer_handles
= new_array
;
715 nb_printer_handles
+= 16;
718 if (!(printer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
))))
724 printer
->name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(name
) + 1) * sizeof(WCHAR
));
725 strcpyW(printer
->name
, name
);
727 printer
->queue
= queue
;
730 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
731 list_init(&printer
->queue
->jobs
);
732 printer
->queue
->ref
= 0;
734 InterlockedIncrement(&printer
->queue
->ref
);
737 printer_handles
[handle
] = printer
;
740 LeaveCriticalSection(&printer_handles_cs
);
742 return (HANDLE
)handle
;
745 /******************************************************************
747 * Get the pointer to the opened printer referred by the handle
749 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
751 UINT_PTR idx
= (UINT_PTR
)hprn
;
752 opened_printer_t
*ret
= NULL
;
754 EnterCriticalSection(&printer_handles_cs
);
756 if ((idx
<= 0) || (idx
> nb_printer_handles
))
759 ret
= printer_handles
[idx
- 1];
761 LeaveCriticalSection(&printer_handles_cs
);
765 /******************************************************************
766 * get_opened_printer_name
767 * Get the pointer to the opened printer name referred by the handle
769 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
771 opened_printer_t
*printer
= get_opened_printer(hprn
);
772 if(!printer
) return NULL
;
773 return printer
->name
;
776 /******************************************************************
777 * WINSPOOL_GetOpenedPrinterRegKey
780 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
782 LPCWSTR name
= get_opened_printer_name(hPrinter
);
786 if(!name
) return ERROR_INVALID_HANDLE
;
788 if((ret
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
)) !=
792 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
794 ERR("Can't find opened printer %s in registry\n",
796 RegCloseKey(hkeyPrinters
);
797 return ERROR_INVALID_PRINTER_NAME
; /* ? */
799 RegCloseKey(hkeyPrinters
);
800 return ERROR_SUCCESS
;
803 /******************************************************************
806 * Get the pointer to the specified job.
807 * Should hold the printer_handles_cs before calling.
809 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
811 opened_printer_t
*printer
= get_opened_printer(hprn
);
814 if(!printer
) return NULL
;
815 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
817 if(job
->job_id
== JobId
)
823 /***********************************************************
826 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
829 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
832 Formname
= (dmA
->dmSize
> off_formname
);
833 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
834 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
835 dmW
->dmDeviceName
, CCHDEVICENAME
);
837 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
838 dmA
->dmSize
- CCHDEVICENAME
);
840 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
841 off_formname
- CCHDEVICENAME
);
842 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
843 dmW
->dmFormName
, CCHFORMNAME
);
844 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
845 (off_formname
+ CCHFORMNAME
));
848 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
853 /***********************************************************
855 * Creates an ascii copy of supplied devmode on heap
857 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
862 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
864 if(!dmW
) return NULL
;
865 Formname
= (dmW
->dmSize
> off_formname
);
866 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
867 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
868 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
869 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
871 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
872 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
874 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
875 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
876 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
877 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
878 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
879 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
882 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
887 /***********************************************************
889 * Creates a unicode copy of PRINTER_INFO_2A on heap
891 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
893 LPPRINTER_INFO_2W piW
;
894 UNICODE_STRING usBuffer
;
896 if(!piA
) return NULL
;
897 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
898 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
900 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
901 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
902 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
903 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
904 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
905 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
906 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
907 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
908 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
909 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
910 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
911 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
915 /***********************************************************
916 * FREE_PRINTER_INFO_2W
917 * Free PRINTER_INFO_2W and all strings
919 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
923 HeapFree(heap
,0,piW
->pServerName
);
924 HeapFree(heap
,0,piW
->pPrinterName
);
925 HeapFree(heap
,0,piW
->pShareName
);
926 HeapFree(heap
,0,piW
->pPortName
);
927 HeapFree(heap
,0,piW
->pDriverName
);
928 HeapFree(heap
,0,piW
->pComment
);
929 HeapFree(heap
,0,piW
->pLocation
);
930 HeapFree(heap
,0,piW
->pDevMode
);
931 HeapFree(heap
,0,piW
->pSepFile
);
932 HeapFree(heap
,0,piW
->pPrintProcessor
);
933 HeapFree(heap
,0,piW
->pDatatype
);
934 HeapFree(heap
,0,piW
->pParameters
);
935 HeapFree(heap
,0,piW
);
939 /******************************************************************
940 * DeviceCapabilities [WINSPOOL.@]
941 * DeviceCapabilitiesA [WINSPOOL.@]
944 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
945 LPSTR pOutput
, LPDEVMODEA lpdm
)
949 if (!GDI_CallDeviceCapabilities16
)
951 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
953 if (!GDI_CallDeviceCapabilities16
) return -1;
955 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
957 /* If DC_PAPERSIZE map POINT16s to POINTs */
958 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
959 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
960 POINT
*pt
= (POINT
*)pOutput
;
962 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
963 for(i
= 0; i
< ret
; i
++, pt
++)
968 HeapFree( GetProcessHeap(), 0, tmp
);
974 /*****************************************************************************
975 * DeviceCapabilitiesW [WINSPOOL.@]
977 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
980 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
981 WORD fwCapability
, LPWSTR pOutput
,
982 const DEVMODEW
*pDevMode
)
984 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
985 LPSTR pDeviceA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDevice
);
986 LPSTR pPortA
= HEAP_strdupWtoA(GetProcessHeap(),0,pPort
);
989 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
990 fwCapability
== DC_FILEDEPENDENCIES
||
991 fwCapability
== DC_PAPERNAMES
)) {
992 /* These need A -> W translation */
995 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
999 switch(fwCapability
) {
1004 case DC_FILEDEPENDENCIES
:
1008 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1009 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1011 for(i
= 0; i
< ret
; i
++)
1012 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1013 pOutput
+ (i
* size
), size
);
1014 HeapFree(GetProcessHeap(), 0, pOutputA
);
1016 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1017 (LPSTR
)pOutput
, dmA
);
1019 HeapFree(GetProcessHeap(),0,pPortA
);
1020 HeapFree(GetProcessHeap(),0,pDeviceA
);
1021 HeapFree(GetProcessHeap(),0,dmA
);
1025 /******************************************************************
1026 * DocumentPropertiesA [WINSPOOL.@]
1028 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1030 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1031 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1032 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1034 LPSTR lpName
= pDeviceName
;
1037 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1038 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1042 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1044 ERR("no name from hPrinter?\n");
1045 SetLastError(ERROR_INVALID_HANDLE
);
1048 lpName
= HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW
);
1051 if (!GDI_CallExtDeviceMode16
)
1053 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1055 if (!GDI_CallExtDeviceMode16
) {
1056 ERR("No CallExtDeviceMode16?\n");
1060 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, "LPT1:",
1061 pDevModeInput
, NULL
, fMode
);
1064 HeapFree(GetProcessHeap(),0,lpName
);
1069 /*****************************************************************************
1070 * DocumentPropertiesW (WINSPOOL.@)
1072 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1074 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1076 LPDEVMODEW pDevModeOutput
,
1077 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1080 LPSTR pDeviceNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName
);
1081 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1082 LPDEVMODEA pDevModeOutputA
= NULL
;
1085 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1086 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1088 if(pDevModeOutput
) {
1089 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1090 if(ret
< 0) return ret
;
1091 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1093 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1094 pDevModeInputA
, fMode
);
1095 if(pDevModeOutput
) {
1096 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1097 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1099 if(fMode
== 0 && ret
> 0)
1100 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1101 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1102 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1106 /******************************************************************
1107 * OpenPrinterA [WINSPOOL.@]
1112 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1113 LPPRINTER_DEFAULTSA pDefault
)
1115 UNICODE_STRING lpPrinterNameW
;
1116 UNICODE_STRING usBuffer
;
1117 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1118 PWSTR pwstrPrinterNameW
;
1121 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1124 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1125 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1126 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1127 pDefaultW
= &DefaultW
;
1129 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1131 RtlFreeUnicodeString(&usBuffer
);
1132 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1134 RtlFreeUnicodeString(&lpPrinterNameW
);
1138 /******************************************************************
1139 * OpenPrinterW [WINSPOOL.@]
1141 * Open a Printer / Printserver or a Printer-Object
1144 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1145 * phPrinter [O] The resulting Handle is stored here
1146 * pDefault [I] PTR to Default Printer Settings or NULL
1153 * lpPrinterName is one of:
1154 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1155 *| Printer: "PrinterName"
1156 *| Printer-Object: "PrinterName,Job xxx"
1157 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1158 *| XcvPort: "Servername,XcvPort PortName"
1161 *| Printserver not supported
1162 *| Printer-Object not supported
1163 *| XcvMonitor not supported
1164 *| XcvPort not supported
1165 *| pDefaults not supported
1168 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
,
1169 LPPRINTER_DEFAULTSW pDefault
)
1171 HKEY hkeyPrinters
, hkeyPrinter
;
1173 if (!lpPrinterName
) {
1174 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault
);
1175 SetLastError(ERROR_INVALID_PARAMETER
);
1179 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName
),
1182 /* Check Printer exists */
1183 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1185 ERR("Can't create Printers key\n");
1186 SetLastError(ERROR_FILE_NOT_FOUND
); /* ?? */
1190 if(lpPrinterName
[0] == '\0' || /* explicitly exclude "" */
1191 RegOpenKeyW(hkeyPrinters
, lpPrinterName
, &hkeyPrinter
)
1193 TRACE("Can't find printer %s in registry\n",
1194 debugstr_w(lpPrinterName
));
1195 RegCloseKey(hkeyPrinters
);
1196 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1199 RegCloseKey(hkeyPrinter
);
1200 RegCloseKey(hkeyPrinters
);
1202 if(!phPrinter
) /* This seems to be what win95 does anyway */
1205 /* Get the unique handle of the printer*/
1206 *phPrinter
= get_opened_printer_entry( lpPrinterName
);
1208 if (pDefault
!= NULL
)
1209 FIXME("Not handling pDefault\n");
1214 /******************************************************************
1215 * AddMonitorA [WINSPOOL.@]
1220 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1222 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName
), Level
, pMonitors
);
1223 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1227 /******************************************************************************
1228 * AddMonitorW [WINSPOOL.@]
1230 * Install a Printmonitor
1233 * pName [I] Servername or NULL (local Computer)
1234 * Level [I] Structure-Level (Must be 2)
1235 * pMonitors [I] PTR to MONITOR_INFO_2
1242 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1248 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1250 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName
), Level
, pMonitors
);
1251 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1255 /******************************************************************
1256 * DeletePrinterDriverA [WINSPOOL.@]
1260 DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
1262 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1263 debugstr_a(pDriverName
));
1264 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1268 /******************************************************************
1269 * DeletePrinterDriverW [WINSPOOL.@]
1273 DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
1275 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1276 debugstr_w(pDriverName
));
1277 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1281 /******************************************************************
1282 * DeleteMonitorA [WINSPOOL.@]
1284 * See DeleteMonitorW.
1288 DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
1290 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1291 debugstr_a(pMonitorName
));
1292 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1296 /******************************************************************
1297 * DeleteMonitorW [WINSPOOL.@]
1299 * Delete a specific Printmonitor from a Printing-Environment
1302 * pName [I] Servername or NULL (local Computer)
1303 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1304 * pMonitorName [I] Name of the Monitor, that should be deleted
1315 DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1317 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1318 debugstr_w(pMonitorName
));
1319 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1323 /******************************************************************
1324 * DeletePortA [WINSPOOL.@]
1330 DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
1332 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName
),hWnd
,
1333 debugstr_a(pPortName
));
1334 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1338 /******************************************************************
1339 * DeletePortW [WINSPOOL.@]
1341 * Delete a specific Port
1344 * pName [I] Servername or NULL (local Computer)
1345 * hWnd [I] Handle to parent Window for the Dialog-Box
1346 * pPortName [I] Name of the Port, that should be deleted
1357 DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1359 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName
),hWnd
,
1360 debugstr_w(pPortName
));
1361 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1365 /******************************************************************************
1366 * SetPrinterW [WINSPOOL.@]
1376 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1380 /******************************************************************************
1381 * WritePrinter [WINSPOOL.@]
1383 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
1385 opened_printer_t
*printer
;
1388 TRACE("(%p, %p, %ld, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
1390 EnterCriticalSection(&printer_handles_cs
);
1391 printer
= get_opened_printer(hPrinter
);
1394 SetLastError(ERROR_INVALID_HANDLE
);
1400 SetLastError(ERROR_SPL_NO_STARTDOC
);
1404 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
1406 LeaveCriticalSection(&printer_handles_cs
);
1410 /*****************************************************************************
1411 * AddFormA [WINSPOOL.@]
1413 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1415 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1419 /*****************************************************************************
1420 * AddFormW [WINSPOOL.@]
1422 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1424 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1428 /*****************************************************************************
1429 * AddJobA [WINSPOOL.@]
1431 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1434 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
1438 SetLastError(ERROR_INVALID_LEVEL
);
1442 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
1445 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
1446 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
1447 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
1448 if(*pcbNeeded
> cbBuf
) {
1449 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1452 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
1453 addjobA
->JobId
= addjobW
->JobId
;
1454 addjobA
->Path
= (char *)(addjobA
+ 1);
1455 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
1461 /*****************************************************************************
1462 * AddJobW [WINSPOOL.@]
1464 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1466 opened_printer_t
*printer
;
1469 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1470 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
1471 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
1473 ADDJOB_INFO_1W
*addjob
;
1475 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
1477 EnterCriticalSection(&printer_handles_cs
);
1479 printer
= get_opened_printer(hPrinter
);
1482 SetLastError(ERROR_INVALID_HANDLE
);
1487 SetLastError(ERROR_INVALID_LEVEL
);
1491 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
1495 job
->job_id
= InterlockedIncrement(&next_job_id
);
1497 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
1498 if(path
[len
- 1] != '\\')
1500 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
1501 sprintfW(filename
, fmtW
, path
, job
->job_id
);
1503 len
= strlenW(filename
);
1504 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1505 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
1506 job
->document_title
= strdupW(default_doc_title
);
1507 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
1509 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
1510 if(*pcbNeeded
<= cbBuf
) {
1511 addjob
= (ADDJOB_INFO_1W
*)pData
;
1512 addjob
->JobId
= job
->job_id
;
1513 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
1514 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
1517 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1520 LeaveCriticalSection(&printer_handles_cs
);
1524 /*****************************************************************************
1525 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1527 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
1528 DWORD level
, LPBYTE Info
,
1529 DWORD cbBuf
, LPDWORD needed
)
1531 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server
), debugstr_a(env
),
1532 level
, Info
, cbBuf
);
1536 /*****************************************************************************
1537 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1539 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
1540 DWORD level
, LPBYTE Info
,
1541 DWORD cbBuf
, LPDWORD needed
)
1543 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server
), debugstr_w(env
),
1544 level
, Info
, cbBuf
);
1548 /*****************************************************************************
1549 * WINSPOOL_OpenDriverReg [internal]
1551 * opens the registry for the printer drivers depending on the given input
1552 * variable pEnvironment
1555 * the opened hkey on success
1558 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
)
1560 static const WCHAR WinNTW
[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1561 static const WCHAR Win40W
[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1563 LPWSTR lpKey
, buffer
= NULL
;
1567 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
));
1571 pEnvW
= pEnvironment
;
1573 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
1574 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1575 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
1580 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
1582 if(!GetVersionExW( &ver
))
1585 switch (ver
.dwPlatformId
) {
1586 case VER_PLATFORM_WIN32s
:
1587 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1589 case VER_PLATFORM_WIN32_NT
:
1596 TRACE("set environment to %s\n", debugstr_w(pEnvW
));
1599 lpKey
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1600 (strlenW(pEnvW
) + strlenW(DriversW
) + 1) * sizeof(WCHAR
));
1601 wsprintfW( lpKey
, DriversW
, pEnvW
);
1603 TRACE("%s\n", debugstr_w(lpKey
));
1605 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, lpKey
, &retval
) != ERROR_SUCCESS
)
1608 HeapFree( GetProcessHeap(), 0, buffer
);
1609 HeapFree( GetProcessHeap(), 0, lpKey
);
1614 /*****************************************************************************
1615 * AddPrinterW [WINSPOOL.@]
1617 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1619 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
1623 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
1626 TRACE("(%s,%ld,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
1629 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
1630 SetLastError(ERROR_INVALID_PARAMETER
);
1634 ERR("Level = %ld, unsupported!\n", Level
);
1635 SetLastError(ERROR_INVALID_LEVEL
);
1638 if (strlenW(pi
->pPrinterName
) >= CCHDEVICENAME
) {
1639 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1640 debugstr_w(pi
->pPrinterName
)
1642 SetLastError(ERROR_INVALID_LEVEL
);
1646 SetLastError(ERROR_INVALID_PARAMETER
);
1649 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1651 ERR("Can't create Printers key\n");
1654 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
1655 if (!RegQueryValueA(hkeyPrinter
,"Attributes",NULL
,NULL
)) {
1656 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
1657 RegCloseKey(hkeyPrinter
);
1658 RegCloseKey(hkeyPrinters
);
1661 RegCloseKey(hkeyPrinter
);
1663 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
1665 ERR("Can't create Drivers key\n");
1666 RegCloseKey(hkeyPrinters
);
1669 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
1671 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
1672 RegCloseKey(hkeyPrinters
);
1673 RegCloseKey(hkeyDrivers
);
1674 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
1677 RegCloseKey(hkeyDriver
);
1678 RegCloseKey(hkeyDrivers
);
1680 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
1681 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
1682 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
1683 RegCloseKey(hkeyPrinters
);
1687 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
1689 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
1690 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1691 RegCloseKey(hkeyPrinters
);
1694 RegSetValueExA(hkeyPrinter
, "Attributes", 0, REG_DWORD
,
1695 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
1696 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
1698 /* See if we can load the driver. We may need the devmode structure anyway
1701 * Note that DocumentPropertiesW will briefly try to open the printer we
1702 * just create to find a DEVMODEA struct (it will use the WINEPS default
1703 * one in case it is not there, so we are ok).
1705 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
1708 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi
->pPrinterName
));
1709 size
= sizeof(DEVMODEW
);
1715 dmW
= HeapAlloc(GetProcessHeap(), 0, size
);
1716 ZeroMemory(dmW
,size
);
1718 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
1720 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi
->pPrinterName
));
1721 HeapFree(GetProcessHeap(),0,dmW
);
1726 /* set devmode to printer name */
1727 strcpyW(dmW
->dmDeviceName
,pi
->pPrinterName
);
1731 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1732 and we support these drivers. NT writes DEVMODEW so somehow
1733 we'll need to distinguish between these when we support NT
1737 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
1738 RegSetValueExA(hkeyPrinter
, "Default DevMode", 0, REG_BINARY
,
1739 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1740 HeapFree(GetProcessHeap(), 0, dmA
);
1742 HeapFree(GetProcessHeap(), 0, dmW
);
1744 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
1745 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
1746 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
1747 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
1749 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
1750 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
1751 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
1752 RegSetValueExA(hkeyPrinter
, "Priority", 0, REG_DWORD
,
1753 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
1754 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
1755 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
1756 RegSetValueExA(hkeyPrinter
, "StartTime", 0, REG_DWORD
,
1757 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
1758 RegSetValueExA(hkeyPrinter
, "Status", 0, REG_DWORD
,
1759 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
1760 RegSetValueExA(hkeyPrinter
, "UntilTime", 0, REG_DWORD
,
1761 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
1763 RegCloseKey(hkeyPrinter
);
1764 RegCloseKey(hkeyPrinters
);
1765 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
1766 ERR("OpenPrinter failing\n");
1772 /*****************************************************************************
1773 * AddPrinterA [WINSPOOL.@]
1775 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1777 UNICODE_STRING pNameW
;
1779 PRINTER_INFO_2W
*piW
;
1780 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
1783 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
1785 ERR("Level = %ld, unsupported!\n", Level
);
1786 SetLastError(ERROR_INVALID_LEVEL
);
1789 pwstrNameW
= asciitounicode(&pNameW
,pName
);
1790 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
1792 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
1794 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
1795 RtlFreeUnicodeString(&pNameW
);
1800 /*****************************************************************************
1801 * ClosePrinter [WINSPOOL.@]
1803 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
1805 UINT_PTR i
= (UINT_PTR
)hPrinter
;
1806 opened_printer_t
*printer
= NULL
;
1809 TRACE("Handle %p\n", hPrinter
);
1811 EnterCriticalSection(&printer_handles_cs
);
1813 if ((i
> 0) && (i
<= nb_printer_handles
))
1814 printer
= printer_handles
[i
- 1];
1818 struct list
*cursor
, *cursor2
;
1821 EndDocPrinter(hPrinter
);
1823 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
1825 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
1827 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
1828 ScheduleJob(hPrinter
, job
->job_id
);
1830 HeapFree(GetProcessHeap(), 0, printer
->queue
);
1832 HeapFree(GetProcessHeap(), 0, printer
->name
);
1833 HeapFree(GetProcessHeap(), 0, printer
);
1834 printer_handles
[i
- 1] = NULL
;
1837 LeaveCriticalSection(&printer_handles_cs
);
1841 /*****************************************************************************
1842 * DeleteFormA [WINSPOOL.@]
1844 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
1846 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
1850 /*****************************************************************************
1851 * DeleteFormW [WINSPOOL.@]
1853 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
1855 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
1859 /*****************************************************************************
1860 * WINSPOOL_SHRegDeleteKey
1862 * Recursively delete subkeys.
1863 * Cut & paste from shlwapi.
1866 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
)
1868 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1869 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1872 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1875 /* Find how many subkeys there are */
1876 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1877 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1881 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1882 /* Name too big: alloc a buffer for it */
1883 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
1886 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1889 /* Recursively delete all the subkeys */
1890 for(i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1892 dwSize
= dwMaxSubkeyLen
;
1893 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1895 dwRet
= WINSPOOL_SHDeleteKeyW(hSubKey
, lpszName
);
1898 if (lpszName
!= szNameBuf
)
1899 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
1903 RegCloseKey(hSubKey
);
1905 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1910 /*****************************************************************************
1911 * DeletePrinter [WINSPOOL.@]
1913 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
1915 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1916 HKEY hkeyPrinters
, hkey
;
1919 SetLastError(ERROR_INVALID_HANDLE
);
1922 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1923 WINSPOOL_SHDeleteKeyW(hkeyPrinters
, lpNameW
);
1924 RegCloseKey(hkeyPrinters
);
1926 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
1927 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1928 RegDeleteValueW(hkey
, lpNameW
);
1934 /*****************************************************************************
1935 * SetPrinterA [WINSPOOL.@]
1937 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
1940 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter
,Level
,pPrinter
,Command
);
1944 /*****************************************************************************
1945 * SetJobA [WINSPOOL.@]
1947 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1948 LPBYTE pJob
, DWORD Command
)
1952 UNICODE_STRING usBuffer
;
1954 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
1956 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1957 are all ignored by SetJob, so we don't bother copying them */
1965 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
1966 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
1968 JobW
= (LPBYTE
)info1W
;
1969 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
1970 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
1971 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
1972 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
1973 info1W
->Status
= info1A
->Status
;
1974 info1W
->Priority
= info1A
->Priority
;
1975 info1W
->Position
= info1A
->Position
;
1976 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
1981 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
1982 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
1984 JobW
= (LPBYTE
)info2W
;
1985 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
1986 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
1987 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
1988 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
1989 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
1990 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
1991 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
1992 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
1993 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
1994 info2W
->Status
= info2A
->Status
;
1995 info2W
->Priority
= info2A
->Priority
;
1996 info2W
->Position
= info2A
->Position
;
1997 info2W
->StartTime
= info2A
->StartTime
;
1998 info2W
->UntilTime
= info2A
->UntilTime
;
1999 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2003 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2004 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2007 SetLastError(ERROR_INVALID_LEVEL
);
2011 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2017 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2018 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2019 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2020 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2021 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2026 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2027 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2028 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2029 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2030 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2031 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2032 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2033 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2034 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2038 HeapFree(GetProcessHeap(), 0, JobW
);
2043 /*****************************************************************************
2044 * SetJobW [WINSPOOL.@]
2046 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2047 LPBYTE pJob
, DWORD Command
)
2052 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2053 FIXME("Ignoring everything other than document title\n");
2055 EnterCriticalSection(&printer_handles_cs
);
2056 job
= get_job(hPrinter
, JobId
);
2066 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2067 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2068 job
->document_title
= strdupW(info1
->pDocument
);
2073 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2074 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2075 job
->document_title
= strdupW(info2
->pDocument
);
2081 SetLastError(ERROR_INVALID_LEVEL
);
2086 LeaveCriticalSection(&printer_handles_cs
);
2090 /*****************************************************************************
2091 * EndDocPrinter [WINSPOOL.@]
2093 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2095 opened_printer_t
*printer
;
2097 TRACE("(%p)\n", hPrinter
);
2099 EnterCriticalSection(&printer_handles_cs
);
2101 printer
= get_opened_printer(hPrinter
);
2104 SetLastError(ERROR_INVALID_HANDLE
);
2110 SetLastError(ERROR_SPL_NO_STARTDOC
);
2114 CloseHandle(printer
->doc
->hf
);
2115 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2116 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2117 printer
->doc
= NULL
;
2120 LeaveCriticalSection(&printer_handles_cs
);
2124 /*****************************************************************************
2125 * EndPagePrinter [WINSPOOL.@]
2127 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2129 FIXME("(%p): stub\n", hPrinter
);
2133 /*****************************************************************************
2134 * StartDocPrinterA [WINSPOOL.@]
2136 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2138 UNICODE_STRING usBuffer
;
2140 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2143 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2144 or one (DOC_INFO_3) extra DWORDs */
2148 doc2W
.JobId
= doc2
->JobId
;
2151 doc2W
.dwMode
= doc2
->dwMode
;
2154 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2155 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2156 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
2160 SetLastError(ERROR_INVALID_LEVEL
);
2164 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
2166 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
2167 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
2168 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
2173 /*****************************************************************************
2174 * StartDocPrinterW [WINSPOOL.@]
2176 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2178 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
2179 opened_printer_t
*printer
;
2180 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2181 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
2182 JOB_INFO_1W job_info
;
2183 DWORD needed
, ret
= 0;
2187 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2188 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
2189 debugstr_w(doc
->pDatatype
));
2191 if(Level
< 1 || Level
> 3)
2193 SetLastError(ERROR_INVALID_LEVEL
);
2197 EnterCriticalSection(&printer_handles_cs
);
2198 printer
= get_opened_printer(hPrinter
);
2201 SetLastError(ERROR_INVALID_HANDLE
);
2207 SetLastError(ERROR_INVALID_PRINTER_STATE
);
2211 /* Even if we're printing to a file we still add a print job, we'll
2212 just ignore the spool file name */
2214 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
2216 ERR("AddJob failed gle %08lx\n", GetLastError());
2220 if(doc
->pOutputFile
)
2221 filename
= doc
->pOutputFile
;
2223 filename
= addjob
->Path
;
2225 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
2226 if(hf
== INVALID_HANDLE_VALUE
)
2229 memset(&job_info
, 0, sizeof(job_info
));
2230 job_info
.pDocument
= doc
->pDocName
;
2231 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
2233 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
2234 printer
->doc
->hf
= hf
;
2235 ret
= printer
->doc
->job_id
= addjob
->JobId
;
2237 LeaveCriticalSection(&printer_handles_cs
);
2242 /*****************************************************************************
2243 * StartPagePrinter [WINSPOOL.@]
2245 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
2247 FIXME("(%p): stub\n", hPrinter
);
2251 /*****************************************************************************
2252 * GetFormA [WINSPOOL.@]
2254 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2255 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2257 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,pFormName
,
2258 Level
,pForm
,cbBuf
,pcbNeeded
);
2262 /*****************************************************************************
2263 * GetFormW [WINSPOOL.@]
2265 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2266 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2268 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,
2269 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
2273 /*****************************************************************************
2274 * SetFormA [WINSPOOL.@]
2276 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2279 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2283 /*****************************************************************************
2284 * SetFormW [WINSPOOL.@]
2286 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2289 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2293 /*****************************************************************************
2294 * ReadPrinter [WINSPOOL.@]
2296 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
2297 LPDWORD pNoBytesRead
)
2299 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
2303 /*****************************************************************************
2304 * ResetPrinterA [WINSPOOL.@]
2306 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
2308 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2312 /*****************************************************************************
2313 * ResetPrinterW [WINSPOOL.@]
2315 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2317 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2321 /*****************************************************************************
2322 * WINSPOOL_GetDWORDFromReg
2324 * Return DWORD associated with ValueName from hkey.
2326 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
2328 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
2331 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
2333 if(ret
!= ERROR_SUCCESS
) {
2334 WARN("Got ret = %ld on name %s\n", ret
, ValueName
);
2337 if(type
!= REG_DWORD
) {
2338 ERR("Got type %ld\n", type
);
2344 /*****************************************************************************
2345 * WINSPOOL_GetStringFromReg
2347 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2348 * String is stored either as unicode or ascii.
2349 * Bit of a hack here to get the ValueName if we want ascii.
2351 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
2352 DWORD buflen
, DWORD
*needed
,
2355 DWORD sz
= buflen
, type
;
2359 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2361 LPSTR ValueNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,ValueName
);
2362 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
2363 HeapFree(GetProcessHeap(),0,ValueNameA
);
2365 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
2366 WARN("Got ret = %ld\n", ret
);
2374 /*****************************************************************************
2375 * WINSPOOL_GetDefaultDevMode
2377 * Get a default DevMode values for wineps.
2381 static void WINSPOOL_GetDefaultDevMode(
2383 DWORD buflen
, DWORD
*needed
,
2387 static const char szwps
[] = "wineps.drv";
2389 /* fill default DEVMODE - should be read from ppd... */
2390 ZeroMemory( &dm
, sizeof(dm
) );
2391 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
2392 dm
.dmSpecVersion
= DM_SPECVERSION
;
2393 dm
.dmDriverVersion
= 1;
2394 dm
.dmSize
= sizeof(DEVMODEA
);
2395 dm
.dmDriverExtra
= 0;
2397 DM_ORIENTATION
| DM_PAPERSIZE
|
2398 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
2401 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
2402 DM_YRESOLUTION
| DM_TTOPTION
;
2404 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
2405 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
2406 dm
.u1
.s1
.dmPaperLength
= 2970;
2407 dm
.u1
.s1
.dmPaperWidth
= 2100;
2411 dm
.dmDefaultSource
= DMBIN_AUTO
;
2412 dm
.dmPrintQuality
= DMRES_MEDIUM
;
2415 dm
.dmYResolution
= 300; /* 300dpi */
2416 dm
.dmTTOption
= DMTT_BITMAP
;
2419 /* dm.dmLogPixels */
2420 /* dm.dmBitsPerPel */
2421 /* dm.dmPelsWidth */
2422 /* dm.dmPelsHeight */
2423 /* dm.dmDisplayFlags */
2424 /* dm.dmDisplayFrequency */
2425 /* dm.dmICMMethod */
2426 /* dm.dmICMIntent */
2427 /* dm.dmMediaType */
2428 /* dm.dmDitherType */
2429 /* dm.dmReserved1 */
2430 /* dm.dmReserved2 */
2431 /* dm.dmPanningWidth */
2432 /* dm.dmPanningHeight */
2435 if(buflen
>= sizeof(DEVMODEW
)) {
2436 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
2437 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
2438 HeapFree(GetProcessHeap(),0,pdmW
);
2440 *needed
= sizeof(DEVMODEW
);
2444 if(buflen
>= sizeof(DEVMODEA
)) {
2445 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
2447 *needed
= sizeof(DEVMODEA
);
2451 /*****************************************************************************
2452 * WINSPOOL_GetDevModeFromReg
2454 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2455 * DevMode is stored either as unicode or ascii.
2457 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
2459 DWORD buflen
, DWORD
*needed
,
2462 DWORD sz
= buflen
, type
;
2465 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
2466 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2467 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
2468 if (sz
< sizeof(DEVMODEA
))
2470 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName
),sz
);
2473 /* ensures that dmSize is not erratically bogus if registry is invalid */
2474 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
2475 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
2477 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2479 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
2480 memcpy(ptr
, dmW
, sz
);
2481 HeapFree(GetProcessHeap(),0,dmW
);
2488 /*********************************************************************
2489 * WINSPOOL_GetPrinter_2
2491 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2492 * The strings are either stored as unicode or ascii.
2494 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
2495 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2498 DWORD size
, left
= cbBuf
;
2499 BOOL space
= (cbBuf
> 0);
2504 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2506 if(space
&& size
<= left
) {
2507 pi2
->pPrinterName
= (LPWSTR
)ptr
;
2514 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
2516 if(space
&& size
<= left
) {
2517 pi2
->pShareName
= (LPWSTR
)ptr
;
2524 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2526 if(space
&& size
<= left
) {
2527 pi2
->pPortName
= (LPWSTR
)ptr
;
2534 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
2536 if(space
&& size
<= left
) {
2537 pi2
->pDriverName
= (LPWSTR
)ptr
;
2544 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
2546 if(space
&& size
<= left
) {
2547 pi2
->pComment
= (LPWSTR
)ptr
;
2554 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
2556 if(space
&& size
<= left
) {
2557 pi2
->pLocation
= (LPWSTR
)ptr
;
2564 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
2566 if(space
&& size
<= left
) {
2567 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2576 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
2577 if(space
&& size
<= left
) {
2578 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2585 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
2587 if(space
&& size
<= left
) {
2588 pi2
->pSepFile
= (LPWSTR
)ptr
;
2595 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
2597 if(space
&& size
<= left
) {
2598 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
2605 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
2607 if(space
&& size
<= left
) {
2608 pi2
->pDatatype
= (LPWSTR
)ptr
;
2615 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
2617 if(space
&& size
<= left
) {
2618 pi2
->pParameters
= (LPWSTR
)ptr
;
2626 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2627 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
2628 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2629 "Default Priority");
2630 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
2631 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
2634 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
2635 memset(pi2
, 0, sizeof(*pi2
));
2640 /*********************************************************************
2641 * WINSPOOL_GetPrinter_4
2643 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2645 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
2646 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2649 DWORD size
, left
= cbBuf
;
2650 BOOL space
= (cbBuf
> 0);
2655 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2657 if(space
&& size
<= left
) {
2658 pi4
->pPrinterName
= (LPWSTR
)ptr
;
2666 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2669 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
2670 memset(pi4
, 0, sizeof(*pi4
));
2675 /*********************************************************************
2676 * WINSPOOL_GetPrinter_5
2678 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2680 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
2681 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2684 DWORD size
, left
= cbBuf
;
2685 BOOL space
= (cbBuf
> 0);
2690 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2692 if(space
&& size
<= left
) {
2693 pi5
->pPrinterName
= (LPWSTR
)ptr
;
2700 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2702 if(space
&& size
<= left
) {
2703 pi5
->pPortName
= (LPWSTR
)ptr
;
2711 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2712 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2714 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2718 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
2719 memset(pi5
, 0, sizeof(*pi5
));
2724 /*****************************************************************************
2725 * WINSPOOL_GetPrinter
2727 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2728 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2729 * just a collection of pointers to strings.
2731 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2732 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
2735 DWORD size
, needed
= 0;
2737 HKEY hkeyPrinter
, hkeyPrinters
;
2740 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
2742 if (!(name
= get_opened_printer_name(hPrinter
))) {
2743 SetLastError(ERROR_INVALID_HANDLE
);
2747 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2749 ERR("Can't create Printers key\n");
2752 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
2754 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
2755 RegCloseKey(hkeyPrinters
);
2756 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
2763 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
2765 size
= sizeof(PRINTER_INFO_2W
);
2767 ptr
= pPrinter
+ size
;
2769 memset(pPrinter
, 0, size
);
2774 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
2782 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
2784 size
= sizeof(PRINTER_INFO_4W
);
2786 ptr
= pPrinter
+ size
;
2788 memset(pPrinter
, 0, size
);
2793 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
2802 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
2804 size
= sizeof(PRINTER_INFO_5W
);
2806 ptr
= pPrinter
+ size
;
2808 memset(pPrinter
, 0, size
);
2814 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
2821 FIXME("Unimplemented level %ld\n", Level
);
2822 SetLastError(ERROR_INVALID_LEVEL
);
2823 RegCloseKey(hkeyPrinters
);
2824 RegCloseKey(hkeyPrinter
);
2828 RegCloseKey(hkeyPrinter
);
2829 RegCloseKey(hkeyPrinters
);
2831 TRACE("returning %d needed = %ld\n", ret
, needed
);
2832 if(pcbNeeded
) *pcbNeeded
= needed
;
2834 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2838 /*****************************************************************************
2839 * GetPrinterW [WINSPOOL.@]
2841 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2842 DWORD cbBuf
, LPDWORD pcbNeeded
)
2844 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2848 /*****************************************************************************
2849 * GetPrinterA [WINSPOOL.@]
2851 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2852 DWORD cbBuf
, LPDWORD pcbNeeded
)
2854 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2858 /*****************************************************************************
2859 * WINSPOOL_EnumPrinters
2861 * Implementation of EnumPrintersA|W
2863 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
2864 DWORD dwLevel
, LPBYTE lpbPrinters
,
2865 DWORD cbBuf
, LPDWORD lpdwNeeded
,
2866 LPDWORD lpdwReturned
, BOOL unicode
)
2869 HKEY hkeyPrinters
, hkeyPrinter
;
2870 WCHAR PrinterName
[255];
2871 DWORD needed
= 0, number
= 0;
2872 DWORD used
, i
, left
;
2876 memset(lpbPrinters
, 0, cbBuf
);
2882 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2883 if(dwType
== PRINTER_ENUM_DEFAULT
)
2886 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
2887 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2888 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
2889 if(!dwType
) return TRUE
;
2892 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
2893 FIXME("dwType = %08lx\n", dwType
);
2894 SetLastError(ERROR_INVALID_FLAGS
);
2898 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2900 ERR("Can't create Printers key\n");
2904 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
2905 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
2906 RegCloseKey(hkeyPrinters
);
2907 ERR("Can't query Printers key\n");
2910 TRACE("Found %ld printers\n", number
);
2914 RegCloseKey(hkeyPrinters
);
2916 *lpdwReturned
= number
;
2920 used
= number
* sizeof(PRINTER_INFO_2W
);
2923 used
= number
* sizeof(PRINTER_INFO_4W
);
2926 used
= number
* sizeof(PRINTER_INFO_5W
);
2930 SetLastError(ERROR_INVALID_LEVEL
);
2931 RegCloseKey(hkeyPrinters
);
2934 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
2936 for(i
= 0; i
< number
; i
++) {
2937 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
2939 ERR("Can't enum key number %ld\n", i
);
2940 RegCloseKey(hkeyPrinters
);
2943 TRACE("Printer %ld is %s\n", i
, debugstr_w(PrinterName
));
2944 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
2946 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
2947 RegCloseKey(hkeyPrinters
);
2952 buf
= lpbPrinters
+ used
;
2953 left
= cbBuf
- used
;
2961 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
2962 left
, &needed
, unicode
);
2964 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
2967 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
2968 left
, &needed
, unicode
);
2970 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
2973 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
2974 left
, &needed
, unicode
);
2976 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
2979 ERR("Shouldn't be here!\n");
2980 RegCloseKey(hkeyPrinter
);
2981 RegCloseKey(hkeyPrinters
);
2984 RegCloseKey(hkeyPrinter
);
2986 RegCloseKey(hkeyPrinters
);
2993 memset(lpbPrinters
, 0, cbBuf
);
2994 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2998 *lpdwReturned
= number
;
2999 SetLastError(ERROR_SUCCESS
);
3004 /******************************************************************
3005 * EnumPrintersW [WINSPOOL.@]
3007 * Enumerates the available printers, print servers and print
3008 * providers, depending on the specified flags, name and level.
3012 * If level is set to 1:
3013 * Not implemented yet!
3014 * Returns TRUE with an empty list.
3016 * If level is set to 2:
3017 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3018 * Returns an array of PRINTER_INFO_2 data structures in the
3019 * lpbPrinters buffer. Note that according to MSDN also an
3020 * OpenPrinter should be performed on every remote printer.
3022 * If level is set to 4 (officially WinNT only):
3023 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3024 * Fast: Only the registry is queried to retrieve printer names,
3025 * no connection to the driver is made.
3026 * Returns an array of PRINTER_INFO_4 data structures in the
3027 * lpbPrinters buffer.
3029 * If level is set to 5 (officially WinNT4/Win9x only):
3030 * Fast: Only the registry is queried to retrieve printer names,
3031 * no connection to the driver is made.
3032 * Returns an array of PRINTER_INFO_5 data structures in the
3033 * lpbPrinters buffer.
3035 * If level set to 3 or 6+:
3036 * returns zero (failure!)
3038 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3042 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3043 * - Only levels 2, 4 and 5 are implemented at the moment.
3044 * - 16-bit printer drivers are not enumerated.
3045 * - Returned amount of bytes used/needed does not match the real Windoze
3046 * implementation (as in this implementation, all strings are part
3047 * of the buffer, whereas Win32 keeps them somewhere else)
3048 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3051 * - In a regular Wine installation, no registry settings for printers
3052 * exist, which makes this function return an empty list.
3054 BOOL WINAPI
EnumPrintersW(
3055 DWORD dwType
, /* [in] Types of print objects to enumerate */
3056 LPWSTR lpszName
, /* [in] name of objects to enumerate */
3057 DWORD dwLevel
, /* [in] type of printer info structure */
3058 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
3059 DWORD cbBuf
, /* [in] max size of buffer in bytes */
3060 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
3061 LPDWORD lpdwReturned
/* [out] number of entries returned */
3064 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
3065 lpdwNeeded
, lpdwReturned
, TRUE
);
3068 /******************************************************************
3069 * EnumPrintersA [WINSPOOL.@]
3072 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
3073 DWORD dwLevel
, LPBYTE lpbPrinters
,
3074 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3075 LPDWORD lpdwReturned
)
3078 UNICODE_STRING lpszNameW
;
3081 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
3082 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
3083 lpdwNeeded
, lpdwReturned
, FALSE
);
3084 RtlFreeUnicodeString(&lpszNameW
);
3088 /*****************************************************************************
3089 * WINSPOOL_GetDriverInfoFromReg [internal]
3091 * Enters the information from the registry into the DRIVER_INFO struct
3094 * zero if the printer driver does not exist in the registry
3095 * (only if Level > 1) otherwise nonzero
3097 static BOOL
WINSPOOL_GetDriverInfoFromReg(
3100 LPWSTR pEnvironment
,
3102 LPBYTE ptr
, /* DRIVER_INFO */
3103 LPBYTE pDriverStrings
, /* strings buffer */
3104 DWORD cbBuf
, /* size of string buffer */
3105 LPDWORD pcbNeeded
, /* space needed for str. */
3106 BOOL unicode
) /* type of strings */
3107 { DWORD dw
, size
, tmp
, type
;
3109 LPBYTE strPtr
= pDriverStrings
;
3111 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3112 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
3113 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
3116 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
3117 if (*pcbNeeded
<= cbBuf
)
3118 strcpyW((LPWSTR
)strPtr
, DriverName
);
3120 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
3122 if(*pcbNeeded
<= cbBuf
)
3123 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1,
3124 (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
3128 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
3132 ((PDRIVER_INFO_3W
) ptr
)->pName
= (LPWSTR
) strPtr
;
3133 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3136 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
3137 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName
));
3138 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
3143 if(RegQueryValueExA(hkeyDriver
, "Version", 0, &type
, (PBYTE
)&dw
, &size
) !=
3145 WARN("Can't get Version\n");
3147 ((PDRIVER_INFO_3A
) ptr
)->cVersion
= dw
;
3150 pEnvironment
= (LPWSTR
)DefaultEnvironmentW
;
3152 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
3154 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
3157 if(*pcbNeeded
<= cbBuf
) {
3159 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
3161 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1,
3162 (LPSTR
)strPtr
, size
, NULL
, NULL
);
3164 ((PDRIVER_INFO_3W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
3165 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3168 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
3171 if(*pcbNeeded
<= cbBuf
)
3172 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
3175 ((PDRIVER_INFO_3W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
3176 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3179 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
3182 if(*pcbNeeded
<= cbBuf
)
3183 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
3186 ((PDRIVER_INFO_3W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
3187 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3190 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3191 0, &size
, unicode
)) {
3193 if(*pcbNeeded
<= cbBuf
)
3194 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3195 size
, &tmp
, unicode
);
3197 ((PDRIVER_INFO_3W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
3198 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3202 RegCloseKey(hkeyDriver
);
3203 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3207 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
3210 if(*pcbNeeded
<= cbBuf
)
3211 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
3212 size
, &tmp
, unicode
);
3214 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
3215 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3218 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
3221 if(*pcbNeeded
<= cbBuf
)
3222 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
3223 size
, &tmp
, unicode
);
3225 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
3226 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3229 if(WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
3232 if(*pcbNeeded
<= cbBuf
)
3233 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
3234 size
, &tmp
, unicode
);
3236 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
3237 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3240 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
3243 if(*pcbNeeded
<= cbBuf
)
3244 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
,
3245 size
, &tmp
, unicode
);
3247 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
3248 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3251 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3252 RegCloseKey(hkeyDriver
);
3256 /*****************************************************************************
3257 * WINSPOOL_GetPrinterDriver
3259 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
3260 DWORD Level
, LPBYTE pDriverInfo
,
3261 DWORD cbBuf
, LPDWORD pcbNeeded
,
3265 WCHAR DriverName
[100];
3266 DWORD ret
, type
, size
, needed
= 0;
3268 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
3270 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
3271 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
3273 ZeroMemory(pDriverInfo
, cbBuf
);
3275 if (!(name
= get_opened_printer_name(hPrinter
))) {
3276 SetLastError(ERROR_INVALID_HANDLE
);
3279 if(Level
< 1 || Level
> 3) {
3280 SetLastError(ERROR_INVALID_LEVEL
);
3283 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
3285 ERR("Can't create Printers key\n");
3288 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
3290 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3291 RegCloseKey(hkeyPrinters
);
3292 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3295 size
= sizeof(DriverName
);
3297 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
3298 (LPBYTE
)DriverName
, &size
);
3299 RegCloseKey(hkeyPrinter
);
3300 RegCloseKey(hkeyPrinters
);
3301 if(ret
!= ERROR_SUCCESS
) {
3302 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
3306 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
3308 ERR("Can't create Drivers key\n");
3314 size
= sizeof(DRIVER_INFO_1W
);
3317 size
= sizeof(DRIVER_INFO_2W
);
3320 size
= sizeof(DRIVER_INFO_3W
);
3323 ERR("Invalid level\n");
3328 ptr
= pDriverInfo
+ size
;
3330 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
3331 pEnvironment
, Level
, pDriverInfo
,
3332 (cbBuf
< size
) ? NULL
: ptr
,
3333 (cbBuf
< size
) ? 0 : cbBuf
- size
,
3334 &needed
, unicode
)) {
3335 RegCloseKey(hkeyDrivers
);
3339 RegCloseKey(hkeyDrivers
);
3341 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
3342 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3343 if(cbBuf
>= needed
) return TRUE
;
3344 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3348 /*****************************************************************************
3349 * GetPrinterDriverA [WINSPOOL.@]
3351 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
3352 DWORD Level
, LPBYTE pDriverInfo
,
3353 DWORD cbBuf
, LPDWORD pcbNeeded
)
3356 UNICODE_STRING pEnvW
;
3359 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
3360 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
3361 cbBuf
, pcbNeeded
, FALSE
);
3362 RtlFreeUnicodeString(&pEnvW
);
3365 /*****************************************************************************
3366 * GetPrinterDriverW [WINSPOOL.@]
3368 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
3369 DWORD Level
, LPBYTE pDriverInfo
,
3370 DWORD cbBuf
, LPDWORD pcbNeeded
)
3372 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
3373 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
3376 /*****************************************************************************
3377 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3379 * Return the PATH for the Printer-Drivers (UNICODE)
3382 * pName [I] Servername (NT only) or NULL (local Computer)
3383 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3384 * Level [I] Structure-Level (must be 1)
3385 * pDriverDirectory [O] PTR to Buffer that receives the Result
3386 * cbBuf [I] Size of Buffer at pDriverDirectory
3387 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3388 * required for pDriverDirectory
3391 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3392 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3393 * if cbBuf is too small
3395 * Native Values returned in pDriverDirectory on Success:
3396 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3397 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3398 *| win9x(Windows 4.0): "%winsysdir%"
3400 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3403 *- Only NULL or "" is supported for pName
3406 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
3407 DWORD Level
, LPBYTE pDriverDirectory
,
3408 DWORD cbBuf
, LPDWORD pcbNeeded
)
3411 const printenv_t
* env
;
3413 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
3414 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
3415 if(pName
!= NULL
&& pName
[0]) {
3416 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
3417 SetLastError(ERROR_INVALID_PARAMETER
);
3421 env
= validate_envW(pEnvironment
);
3422 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
3425 WARN("(Level: %ld) is ignored in win9x\n", Level
);
3426 SetLastError(ERROR_INVALID_LEVEL
);
3430 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3431 needed
= GetSystemDirectoryW(NULL
, 0);
3432 /* add the Size for the Subdirectories */
3433 needed
+= lstrlenW(spooldriversW
);
3434 needed
+= lstrlenW(env
->subdir
);
3435 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
3438 *pcbNeeded
= needed
;
3439 TRACE("required: 0x%lx/%ld\n", needed
, needed
);
3440 if(needed
> cbBuf
) {
3441 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3444 if(pcbNeeded
== NULL
) {
3445 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3446 SetLastError(RPC_X_NULL_REF_POINTER
);
3449 if(pDriverDirectory
== NULL
) {
3450 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3451 SetLastError(ERROR_INVALID_USER_BUFFER
);
3455 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
3456 /* add the Subdirectories */
3457 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
3458 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
3459 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
3464 /*****************************************************************************
3465 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3467 * Return the PATH for the Printer-Drivers (ANSI)
3469 * See GetPrinterDriverDirectoryW.
3472 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3475 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
3476 DWORD Level
, LPBYTE pDriverDirectory
,
3477 DWORD cbBuf
, LPDWORD pcbNeeded
)
3479 UNICODE_STRING nameW
, environmentW
;
3482 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
3483 WCHAR
*driverDirectoryW
= NULL
;
3485 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName
),
3486 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
3488 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
3490 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
3491 else nameW
.Buffer
= NULL
;
3492 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
3493 else environmentW
.Buffer
= NULL
;
3495 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
3496 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
3499 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
3500 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
3502 *pcbNeeded
= needed
;
3503 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
3505 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
3507 TRACE("required: 0x%lx/%ld\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3509 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
3510 RtlFreeUnicodeString(&environmentW
);
3511 RtlFreeUnicodeString(&nameW
);
3516 /*****************************************************************************
3517 * AddPrinterDriverA [WINSPOOL.@]
3519 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
3522 HKEY hkeyDrivers
, hkeyName
;
3524 TRACE("(%s,%ld,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
3526 if(level
!= 2 && level
!= 3) {
3527 SetLastError(ERROR_INVALID_LEVEL
);
3531 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
3532 SetLastError(ERROR_INVALID_PARAMETER
);
3536 WARN("pDriverInfo == NULL\n");
3537 SetLastError(ERROR_INVALID_PARAMETER
);
3542 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
3544 memset(&di3
, 0, sizeof(di3
));
3545 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
3548 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
3550 SetLastError(ERROR_INVALID_PARAMETER
);
3553 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= "";
3554 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= "\0";
3555 if(!di3
.pHelpFile
) di3
.pHelpFile
= "";
3556 if(!di3
.pMonitorName
) di3
.pMonitorName
= "";
3558 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
3561 ERR("Can't create Drivers key\n");
3565 if(level
== 2) { /* apparently can't overwrite with level2 */
3566 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
3567 RegCloseKey(hkeyName
);
3568 RegCloseKey(hkeyDrivers
);
3569 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
3570 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
3574 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
3575 RegCloseKey(hkeyDrivers
);
3576 ERR("Can't create Name key\n");
3579 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
3581 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, 0);
3582 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, 0);
3583 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
3585 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, 0);
3586 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
3587 (LPBYTE
) di3
.pDependentFiles
, 0);
3588 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, 0);
3589 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, 0);
3590 RegCloseKey(hkeyName
);
3591 RegCloseKey(hkeyDrivers
);
3596 /*****************************************************************************
3597 * AddPrinterDriverW [WINSPOOL.@]
3599 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
3602 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName
),
3607 /*****************************************************************************
3608 * AddPrintProcessorA [WINSPOOL.@]
3610 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
3611 LPSTR pPrintProcessorName
)
3613 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
3614 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
3618 /*****************************************************************************
3619 * AddPrintProcessorW [WINSPOOL.@]
3621 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
3622 LPWSTR pPrintProcessorName
)
3624 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
3625 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
3629 /*****************************************************************************
3630 * AddPrintProvidorA [WINSPOOL.@]
3632 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3634 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
3638 /*****************************************************************************
3639 * AddPrintProvidorW [WINSPOOL.@]
3641 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3643 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
3647 /*****************************************************************************
3648 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3650 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
3651 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
3653 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
3654 pDevModeOutput
, pDevModeInput
);
3658 /*****************************************************************************
3659 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3661 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
3662 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
3664 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
3665 pDevModeOutput
, pDevModeInput
);
3669 /*****************************************************************************
3670 * PrinterProperties [WINSPOOL.@]
3672 * Displays a dialog to set the properties of the printer.
3675 * nonzero on success or zero on failure
3678 * implemented as stub only
3680 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
3681 HANDLE hPrinter
/* [in] handle to printer object */
3683 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
3684 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3688 /*****************************************************************************
3689 * EnumJobsA [WINSPOOL.@]
3692 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3693 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3696 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3697 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3699 if(pcbNeeded
) *pcbNeeded
= 0;
3700 if(pcReturned
) *pcReturned
= 0;
3705 /*****************************************************************************
3706 * EnumJobsW [WINSPOOL.@]
3709 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3710 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3713 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3714 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3716 if(pcbNeeded
) *pcbNeeded
= 0;
3717 if(pcReturned
) *pcReturned
= 0;
3721 /*****************************************************************************
3722 * WINSPOOL_EnumPrinterDrivers [internal]
3724 * Delivers information about all printer drivers installed on the
3725 * localhost or a given server
3728 * nonzero on success or zero on failure. If the buffer for the returned
3729 * information is too small the function will return an error
3732 * - only implemented for localhost, foreign hosts will return an error
3734 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPWSTR pEnvironment
,
3735 DWORD Level
, LPBYTE pDriverInfo
,
3736 DWORD cbBuf
, LPDWORD pcbNeeded
,
3737 LPDWORD pcReturned
, BOOL unicode
)
3740 DWORD i
, needed
, number
= 0, size
= 0;
3741 WCHAR DriverNameW
[255];
3744 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3745 debugstr_w(pName
), debugstr_w(pEnvironment
),
3746 Level
, pDriverInfo
, cbBuf
, unicode
);
3748 /* check for local drivers */
3750 ERR("remote drivers unsupported! Current remote host is %s\n",
3755 /* check input parameter */
3756 if((Level
< 1) || (Level
> 3)) {
3757 ERR("unsupported level %ld\n", Level
);
3758 SetLastError(ERROR_INVALID_LEVEL
);
3762 /* initialize return values */
3764 memset( pDriverInfo
, 0, cbBuf
);
3768 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
3770 ERR("Can't open Drivers key\n");
3774 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3775 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3776 RegCloseKey(hkeyDrivers
);
3777 ERR("Can't query Drivers key\n");
3780 TRACE("Found %ld Drivers\n", number
);
3782 /* get size of single struct
3783 * unicode and ascii structure have the same size
3787 size
= sizeof(DRIVER_INFO_1A
);
3790 size
= sizeof(DRIVER_INFO_2A
);
3793 size
= sizeof(DRIVER_INFO_3A
);
3797 /* calculate required buffer size */
3798 *pcbNeeded
= size
* number
;
3800 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
3802 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
3803 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
3805 ERR("Can't enum key number %ld\n", i
);
3806 RegCloseKey(hkeyDrivers
);
3809 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
3810 pEnvironment
, Level
, ptr
,
3811 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
3812 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
3813 &needed
, unicode
)) {
3814 RegCloseKey(hkeyDrivers
);
3817 (*pcbNeeded
) += needed
;
3820 RegCloseKey(hkeyDrivers
);
3822 if(cbBuf
< *pcbNeeded
){
3823 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3827 *pcReturned
= number
;
3831 /*****************************************************************************
3832 * EnumPrinterDriversW [WINSPOOL.@]
3834 * see function EnumPrinterDrivers for RETURNS, BUGS
3836 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
3837 LPBYTE pDriverInfo
, DWORD cbBuf
,
3838 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3840 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
3841 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
3844 /*****************************************************************************
3845 * EnumPrinterDriversA [WINSPOOL.@]
3847 * see function EnumPrinterDrivers for RETURNS, BUGS
3849 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
3850 LPBYTE pDriverInfo
, DWORD cbBuf
,
3851 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3853 UNICODE_STRING pNameW
, pEnvironmentW
;
3854 PWSTR pwstrNameW
, pwstrEnvironmentW
;
3856 pwstrNameW
= asciitounicode(&pNameW
, pName
);
3857 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
3859 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
3860 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
3862 RtlFreeUnicodeString(&pNameW
);
3863 RtlFreeUnicodeString(&pEnvironmentW
);
3868 static CHAR PortMonitor
[] = "Wine Port Monitor";
3869 static CHAR PortDescription
[] = "Wine Port";
3871 static BOOL
WINSPOOL_ComPortExists( LPCSTR name
)
3875 handle
= CreateFileA( name
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3876 NULL
, OPEN_EXISTING
, 0, NULL
);
3877 if (handle
== INVALID_HANDLE_VALUE
)
3879 TRACE("Checking %s exists\n", name
);
3880 CloseHandle( handle
);
3884 static DWORD
WINSPOOL_CountSerialPorts(void)
3891 strcpy( name
, "COMx:" );
3893 if (WINSPOOL_ComPortExists( name
))
3900 /******************************************************************************
3901 * EnumPortsA (WINSPOOL.@)
3906 * ANSI-Version did not call the UNICODE-Version
3909 BOOL WINAPI
EnumPortsA(LPSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
3910 LPDWORD bufneeded
,LPDWORD bufreturned
)
3913 DWORD info_size
, ofs
, i
, printer_count
, serial_count
, count
, n
, r
;
3914 const LPCSTR szPrinterPortKey
= "Software\\Wine\\Wine\\Config\\spooler";
3918 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3919 debugstr_a(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
3924 info_size
= sizeof (PORT_INFO_1A
);
3927 info_size
= sizeof (PORT_INFO_2A
);
3930 SetLastError(ERROR_INVALID_LEVEL
);
3934 /* see how many exist */
3937 serial_count
= WINSPOOL_CountSerialPorts();
3940 r
= RegOpenKeyA( HKEY_LOCAL_MACHINE
, szPrinterPortKey
, &hkey_printer
);
3941 if ( r
== ERROR_SUCCESS
)
3943 RegQueryInfoKeyA( hkey_printer
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3944 &printer_count
, NULL
, NULL
, NULL
, NULL
);
3946 count
= serial_count
+ printer_count
;
3948 /* then fill in the structure info structure once
3949 we know the offset to the first string */
3951 memset( buffer
, 0, bufsize
);
3953 ofs
= info_size
*count
;
3954 for ( i
=0; i
<count
; i
++)
3956 DWORD vallen
= sizeof(portname
) - 1;
3958 /* get the serial port values, then the printer values */
3959 if ( i
< serial_count
)
3961 strcpy( portname
, "COMx:" );
3962 portname
[3] = '1' + i
;
3963 if (!WINSPOOL_ComPortExists( portname
))
3966 TRACE("Found %s\n", portname
);
3967 vallen
= strlen( portname
);
3971 r
= RegEnumValueA( hkey_printer
, i
-serial_count
,
3972 portname
, &vallen
, NULL
, NULL
, NULL
, 0 );
3977 /* add a colon if necessary, and make it upper case */
3978 CharUpperBuffA(portname
,vallen
);
3979 if (strcasecmp(portname
,"nul")!=0)
3980 if (vallen
&& (portname
[vallen
-1] != ':') )
3981 lstrcatA(portname
,":");
3983 /* add the port info structure if we can fit it */
3984 if ( info_size
*(n
+1) < bufsize
)
3988 PORT_INFO_1A
*info
= (PORT_INFO_1A
*) &buffer
[info_size
*n
];
3989 info
->pName
= (LPSTR
) &buffer
[ofs
];
3991 else if ( level
== 2)
3993 PORT_INFO_2A
*info
= (PORT_INFO_2A
*) &buffer
[info_size
*n
];
3994 info
->pPortName
= (LPSTR
) &buffer
[ofs
];
3995 /* FIXME: fill in more stuff here */
3996 info
->pMonitorName
= PortMonitor
;
3997 info
->pDescription
= PortDescription
;
3998 info
->fPortType
= PORT_TYPE_WRITE
|PORT_TYPE_READ
;
4001 /* add the name of the port if we can fit it */
4002 if ( ofs
< bufsize
)
4003 lstrcpynA((LPSTR
)&buffer
[ofs
],portname
,bufsize
- ofs
);
4009 ofs
+= lstrlenA(portname
)+1;
4012 RegCloseKey(hkey_printer
);
4023 /******************************************************************************
4024 * EnumPortsW (WINSPOOL.@)
4026 * Enumerate available Ports
4029 * name [I] Servername or NULL (local Computer)
4030 * level [I] Structure-Level (1 or 2)
4031 * buffer [O] PTR to Buffer that receives the Result
4032 * bufsize [I] Size of Buffer at buffer
4033 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4034 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4038 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4041 * UNICODE-Version is a stub
4044 BOOL WINAPI
EnumPortsW(LPWSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
4045 LPDWORD bufneeded
,LPDWORD bufreturned
)
4047 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4048 debugstr_w(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
4052 /******************************************************************************
4053 * GetDefaultPrinterW (WINSPOOL.@)
4056 * This function must read the value from data 'device' of key
4057 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4059 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
4063 WCHAR
*buffer
, *ptr
;
4067 SetLastError(ERROR_INVALID_PARAMETER
);
4071 /* make the buffer big enough for the stuff from the profile/registry,
4072 * the content must fit into the local buffer to compute the correct
4073 * size even if the extern buffer is too small or not given.
4074 * (20 for ,driver,port) */
4076 len
= max(100, (insize
+ 20));
4077 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4079 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
4081 SetLastError (ERROR_FILE_NOT_FOUND
);
4085 TRACE("%s\n", debugstr_w(buffer
));
4087 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
4089 SetLastError(ERROR_INVALID_NAME
);
4095 *namesize
= strlenW(buffer
) + 1;
4096 if(!name
|| (*namesize
> insize
))
4098 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4102 strcpyW(name
, buffer
);
4105 HeapFree( GetProcessHeap(), 0, buffer
);
4110 /******************************************************************************
4111 * GetDefaultPrinterA (WINSPOOL.@)
4113 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
4117 WCHAR
*bufferW
= NULL
;
4121 SetLastError(ERROR_INVALID_PARAMETER
);
4125 if(name
&& *namesize
) {
4127 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
4130 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
4135 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
4139 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
4142 TRACE("0x%08lx/0x%08lx:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
4145 HeapFree( GetProcessHeap(), 0, bufferW
);
4150 /******************************************************************************
4151 * SetDefaultPrinterW (WINSPOOL.204)
4153 * Set the Name of the Default Printer
4156 * pszPrinter [I] Name of the Printer or NULL
4163 * When the Parameter is NULL or points to an Empty String and
4164 * a Default Printer was already present, then this Function changes nothing.
4165 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4166 * the First enumerated local Printer is used.
4169 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
4172 TRACE("(%s)\n", debugstr_w(pszPrinter
));
4174 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4178 /******************************************************************************
4179 * SetDefaultPrinterA (WINSPOOL.202)
4181 * See SetDefaultPrinterW.
4184 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
4187 TRACE("(%s)\n", debugstr_a(pszPrinter
));
4189 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4194 /******************************************************************************
4195 * SetPrinterDataExA (WINSPOOL.@)
4197 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4198 LPCSTR pValueName
, DWORD Type
,
4199 LPBYTE pData
, DWORD cbData
)
4201 HKEY hkeyPrinter
, hkeySubkey
;
4204 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_a(pKeyName
),
4205 debugstr_a(pValueName
), Type
, pData
, cbData
);
4207 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4211 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4213 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
4214 RegCloseKey(hkeyPrinter
);
4217 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
4218 RegCloseKey(hkeySubkey
);
4219 RegCloseKey(hkeyPrinter
);
4223 /******************************************************************************
4224 * SetPrinterDataExW (WINSPOOL.@)
4226 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4227 LPCWSTR pValueName
, DWORD Type
,
4228 LPBYTE pData
, DWORD cbData
)
4230 HKEY hkeyPrinter
, hkeySubkey
;
4233 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_w(pKeyName
),
4234 debugstr_w(pValueName
), Type
, pData
, cbData
);
4236 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4240 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4242 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
4243 RegCloseKey(hkeyPrinter
);
4246 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
4247 RegCloseKey(hkeySubkey
);
4248 RegCloseKey(hkeyPrinter
);
4252 /******************************************************************************
4253 * SetPrinterDataA (WINSPOOL.@)
4255 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
4256 LPBYTE pData
, DWORD cbData
)
4258 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
4262 /******************************************************************************
4263 * SetPrinterDataW (WINSPOOL.@)
4265 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
4266 LPBYTE pData
, DWORD cbData
)
4268 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
4272 /******************************************************************************
4273 * GetPrinterDataExA (WINSPOOL.@)
4275 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4276 LPCSTR pValueName
, LPDWORD pType
,
4277 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4279 HKEY hkeyPrinter
, hkeySubkey
;
4282 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4283 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
4286 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4290 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4292 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
4293 RegCloseKey(hkeyPrinter
);
4297 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4298 RegCloseKey(hkeySubkey
);
4299 RegCloseKey(hkeyPrinter
);
4303 /******************************************************************************
4304 * GetPrinterDataExW (WINSPOOL.@)
4306 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4307 LPCWSTR pValueName
, LPDWORD pType
,
4308 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4310 HKEY hkeyPrinter
, hkeySubkey
;
4313 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4314 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
4317 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4321 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4323 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
4324 RegCloseKey(hkeyPrinter
);
4328 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4329 RegCloseKey(hkeySubkey
);
4330 RegCloseKey(hkeyPrinter
);
4334 /******************************************************************************
4335 * GetPrinterDataA (WINSPOOL.@)
4337 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
4338 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4340 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
4341 pData
, nSize
, pcbNeeded
);
4344 /******************************************************************************
4345 * GetPrinterDataW (WINSPOOL.@)
4347 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
4348 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4350 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
4351 pData
, nSize
, pcbNeeded
);
4354 /*******************************************************************************
4355 * EnumPrinterDataExW [WINSPOOL.@]
4357 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4358 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4359 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4361 HKEY hkPrinter
, hkSubKey
;
4362 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
4363 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
4368 PPRINTER_ENUM_VALUESW ppev
;
4370 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
4372 if (pKeyName
== NULL
|| *pKeyName
== 0)
4373 return ERROR_INVALID_PARAMETER
;
4375 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
4376 if (ret
!= ERROR_SUCCESS
)
4378 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4383 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
4384 if (ret
!= ERROR_SUCCESS
)
4386 r
= RegCloseKey (hkPrinter
);
4387 if (r
!= ERROR_SUCCESS
)
4388 WARN ("RegCloseKey returned %li\n", r
);
4389 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter
,
4390 debugstr_w (pKeyName
), ret
);
4394 ret
= RegCloseKey (hkPrinter
);
4395 if (ret
!= ERROR_SUCCESS
)
4397 ERR ("RegCloseKey returned %li\n", ret
);
4398 r
= RegCloseKey (hkSubKey
);
4399 if (r
!= ERROR_SUCCESS
)
4400 WARN ("RegCloseKey returned %li\n", r
);
4404 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4405 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
4406 if (ret
!= ERROR_SUCCESS
)
4408 r
= RegCloseKey (hkSubKey
);
4409 if (r
!= ERROR_SUCCESS
)
4410 WARN ("RegCloseKey returned %li\n", r
);
4411 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey
, ret
);
4415 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4416 "cbMaxValueLen = %li\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
4418 if (cValues
== 0) /* empty key */
4420 r
= RegCloseKey (hkSubKey
);
4421 if (r
!= ERROR_SUCCESS
)
4422 WARN ("RegCloseKey returned %li\n", r
);
4423 *pcbEnumValues
= *pnEnumValues
= 0;
4424 return ERROR_SUCCESS
;
4427 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
4429 hHeap
= GetProcessHeap ();
4432 ERR ("GetProcessHeap failed\n");
4433 r
= RegCloseKey (hkSubKey
);
4434 if (r
!= ERROR_SUCCESS
)
4435 WARN ("RegCloseKey returned %li\n", r
);
4436 return ERROR_OUTOFMEMORY
;
4439 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
4440 if (lpValueName
== NULL
)
4442 ERR ("Failed to allocate %li bytes from process heap\n",
4443 cbMaxValueNameLen
* sizeof (WCHAR
));
4444 r
= RegCloseKey (hkSubKey
);
4445 if (r
!= ERROR_SUCCESS
)
4446 WARN ("RegCloseKey returned %li\n", r
);
4447 return ERROR_OUTOFMEMORY
;
4450 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
4451 if (lpValue
== NULL
)
4453 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen
);
4454 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4455 WARN ("HeapFree failed with code %li\n", GetLastError ());
4456 r
= RegCloseKey (hkSubKey
);
4457 if (r
!= ERROR_SUCCESS
)
4458 WARN ("RegCloseKey returned %li\n", r
);
4459 return ERROR_OUTOFMEMORY
;
4462 TRACE ("pass 1: calculating buffer required for all names and values\n");
4464 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4466 TRACE ("%li bytes required for %li headers\n", cbBufSize
, cValues
);
4468 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4470 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4471 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4472 NULL
, NULL
, lpValue
, &cbValueLen
);
4473 if (ret
!= ERROR_SUCCESS
)
4475 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4476 WARN ("HeapFree failed with code %li\n", GetLastError ());
4477 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4478 WARN ("HeapFree failed with code %li\n", GetLastError ());
4479 r
= RegCloseKey (hkSubKey
);
4480 if (r
!= ERROR_SUCCESS
)
4481 WARN ("RegCloseKey returned %li\n", r
);
4482 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4486 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4487 debugstr_w (lpValueName
), dwIndex
,
4488 (cbValueNameLen
+ 1) * sizeof (WCHAR
), cbValueLen
);
4490 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4491 cbBufSize
+= cbValueLen
;
4494 TRACE ("%li bytes required for all %li values\n", cbBufSize
, cValues
);
4496 *pcbEnumValues
= cbBufSize
;
4497 *pnEnumValues
= cValues
;
4499 if (cbEnumValues
< cbBufSize
) /* buffer too small */
4501 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4502 WARN ("HeapFree failed with code %li\n", GetLastError ());
4503 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4504 WARN ("HeapFree failed with code %li\n", GetLastError ());
4505 r
= RegCloseKey (hkSubKey
);
4506 if (r
!= ERROR_SUCCESS
)
4507 WARN ("RegCloseKey returned %li\n", r
);
4508 TRACE ("%li byte buffer is not large enough\n", cbEnumValues
);
4509 return ERROR_MORE_DATA
;
4512 TRACE ("pass 2: copying all names and values to buffer\n");
4514 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
4515 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4517 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4519 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4520 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4521 NULL
, &dwType
, lpValue
, &cbValueLen
);
4522 if (ret
!= ERROR_SUCCESS
)
4524 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4525 WARN ("HeapFree failed with code %li\n", GetLastError ());
4526 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4527 WARN ("HeapFree failed with code %li\n", GetLastError ());
4528 r
= RegCloseKey (hkSubKey
);
4529 if (r
!= ERROR_SUCCESS
)
4530 WARN ("RegCloseKey returned %li\n", r
);
4531 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4535 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4536 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
4537 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
4538 pEnumValues
+= cbValueNameLen
;
4540 /* return # of *bytes* (including trailing \0), not # of chars */
4541 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
4543 ppev
[dwIndex
].dwType
= dwType
;
4545 memcpy (pEnumValues
, lpValue
, cbValueLen
);
4546 ppev
[dwIndex
].pData
= pEnumValues
;
4547 pEnumValues
+= cbValueLen
;
4549 ppev
[dwIndex
].cbData
= cbValueLen
;
4551 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4552 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
4555 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4557 ret
= GetLastError ();
4558 ERR ("HeapFree failed with code %li\n", ret
);
4559 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4560 WARN ("HeapFree failed with code %li\n", GetLastError ());
4561 r
= RegCloseKey (hkSubKey
);
4562 if (r
!= ERROR_SUCCESS
)
4563 WARN ("RegCloseKey returned %li\n", r
);
4567 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4569 ret
= GetLastError ();
4570 ERR ("HeapFree failed with code %li\n", ret
);
4571 r
= RegCloseKey (hkSubKey
);
4572 if (r
!= ERROR_SUCCESS
)
4573 WARN ("RegCloseKey returned %li\n", r
);
4577 ret
= RegCloseKey (hkSubKey
);
4578 if (ret
!= ERROR_SUCCESS
)
4580 ERR ("RegCloseKey returned %li\n", ret
);
4584 return ERROR_SUCCESS
;
4587 /*******************************************************************************
4588 * EnumPrinterDataExA [WINSPOOL.@]
4590 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4591 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4592 * what Windows 2000 SP1 does.
4595 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4596 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4597 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4601 DWORD ret
, dwIndex
, dwBufSize
;
4605 TRACE ("%p %s\n", hPrinter
, pKeyName
);
4607 if (pKeyName
== NULL
|| *pKeyName
== 0)
4608 return ERROR_INVALID_PARAMETER
;
4610 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
4613 ret
= GetLastError ();
4614 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4618 hHeap
= GetProcessHeap ();
4621 ERR ("GetProcessHeap failed\n");
4622 return ERROR_OUTOFMEMORY
;
4625 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
4626 if (pKeyNameW
== NULL
)
4628 ERR ("Failed to allocate %li bytes from process heap\n",
4629 (LONG
) len
* sizeof (WCHAR
));
4630 return ERROR_OUTOFMEMORY
;
4633 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
4635 ret
= GetLastError ();
4636 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4637 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4638 WARN ("HeapFree failed with code %li\n", GetLastError ());
4642 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
4643 pcbEnumValues
, pnEnumValues
);
4644 if (ret
!= ERROR_SUCCESS
)
4646 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4647 WARN ("HeapFree failed with code %li\n", GetLastError ());
4648 TRACE ("EnumPrinterDataExW returned %li\n", ret
);
4652 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4654 ret
= GetLastError ();
4655 ERR ("HeapFree failed with code %li\n", ret
);
4659 if (*pnEnumValues
== 0) /* empty key */
4660 return ERROR_SUCCESS
;
4663 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4665 PPRINTER_ENUM_VALUESW ppev
=
4666 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4668 if (dwBufSize
< ppev
->cbValueName
)
4669 dwBufSize
= ppev
->cbValueName
;
4671 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
4672 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
4673 dwBufSize
= ppev
->cbData
;
4676 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize
);
4678 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
4679 if (pBuffer
== NULL
)
4681 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize
);
4682 return ERROR_OUTOFMEMORY
;
4685 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4687 PPRINTER_ENUM_VALUESW ppev
=
4688 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4690 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
4691 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
4695 ret
= GetLastError ();
4696 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4697 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4698 WARN ("HeapFree failed with code %li\n", GetLastError ());
4702 memcpy (ppev
->pValueName
, pBuffer
, len
);
4704 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4706 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
4707 ppev
->dwType
!= REG_MULTI_SZ
)
4710 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
4711 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
4714 ret
= GetLastError ();
4715 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4716 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4717 WARN ("HeapFree failed with code %li\n", GetLastError ());
4721 memcpy (ppev
->pData
, pBuffer
, len
);
4723 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4724 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4727 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4729 ret
= GetLastError ();
4730 ERR ("HeapFree failed with code %li\n", ret
);
4734 return ERROR_SUCCESS
;
4737 /******************************************************************************
4738 * AbortPrinter (WINSPOOL.@)
4740 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
4742 FIXME("(%p), stub!\n", hPrinter
);
4746 /******************************************************************************
4747 * AddPortA (WINSPOOL.@)
4752 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
4754 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName
),hWnd
,debugstr_a(pMonitorName
));
4758 /******************************************************************************
4759 * AddPortW (WINSPOOL.@)
4761 * Add a Port for a specific Monitor
4764 * pName [I] Servername or NULL (local Computer)
4765 * hWnd [I] Handle to parent Window for the Dialog-Box
4766 * pMonitorName [I] Name of the Monitor that manage the Port
4776 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
4778 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName
),hWnd
,debugstr_w(pMonitorName
));
4782 /******************************************************************************
4783 * AddPortExA (WINSPOOL.@)
4788 BOOL WINAPI
AddPortExA(HANDLE hMonitor
, LPSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPSTR lpMonitorName
)
4790 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor
, debugstr_a(pName
), Level
,
4791 lpBuffer
, debugstr_a(lpMonitorName
));
4795 /******************************************************************************
4796 * AddPortExW (WINSPOOL.@)
4798 * Add a Port for a specific Monitor, without presenting a user interface
4801 * hMonitor [I] Handle from InitializePrintMonitor2()
4802 * pName [I] Servername or NULL (local Computer)
4803 * Level [I] Structure-Level (1 or 2) for lpBuffer
4804 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
4805 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
4815 BOOL WINAPI
AddPortExW(HANDLE hMonitor
, LPWSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPWSTR lpMonitorName
)
4817 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor
, debugstr_w(pName
), Level
,
4818 lpBuffer
, debugstr_w(lpMonitorName
));
4822 /******************************************************************************
4823 * AddPrinterConnectionA (WINSPOOL.@)
4825 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
4827 FIXME("%s\n", debugstr_a(pName
));
4831 /******************************************************************************
4832 * AddPrinterConnectionW (WINSPOOL.@)
4834 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
4836 FIXME("%s\n", debugstr_w(pName
));
4840 /******************************************************************************
4841 * AddPrinterDriverExW (WINSPOOL.@)
4843 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
4844 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4846 FIXME("%s %ld %p %ld\n", debugstr_w(pName
),
4847 Level
, pDriverInfo
, dwFileCopyFlags
);
4848 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4852 /******************************************************************************
4853 * AddPrinterDriverExA (WINSPOOL.@)
4855 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
4856 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4858 FIXME("%s %ld %p %ld\n", debugstr_a(pName
),
4859 Level
, pDriverInfo
, dwFileCopyFlags
);
4860 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4864 /******************************************************************************
4865 * ConfigurePortA (WINSPOOL.@)
4867 * See ConfigurePortW.
4870 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
4872 FIXME("%s %p %s\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
4876 /******************************************************************************
4877 * ConfigurePortW (WINSPOOL.@)
4879 * Display the Configuration-Dialog for a specific Port
4882 * pName [I] Servername or NULL (local Computer)
4883 * hWnd [I] Handle to parent Window for the Dialog-Box
4884 * pPortName [I] Name of the Port, that should be configured
4894 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
4896 FIXME("%s %p %s\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
4900 /******************************************************************************
4901 * ConnectToPrinterDlg (WINSPOOL.@)
4903 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
4905 FIXME("%p %lx\n", hWnd
, Flags
);
4909 /******************************************************************************
4910 * DeletePrinterConnectionA (WINSPOOL.@)
4912 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
4914 FIXME("%s\n", debugstr_a(pName
));
4918 /******************************************************************************
4919 * DeletePrinterConnectionW (WINSPOOL.@)
4921 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
4923 FIXME("%s\n", debugstr_w(pName
));
4927 /******************************************************************************
4928 * DeletePrinterDriverExW (WINSPOOL.@)
4930 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
4931 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4933 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4934 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4938 /******************************************************************************
4939 * DeletePrinterDriverExA (WINSPOOL.@)
4941 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
4942 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4944 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4945 debugstr_a(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4949 /******************************************************************************
4950 * DeletePrinterDataExW (WINSPOOL.@)
4952 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
4955 FIXME("%p %s %s\n", hPrinter
,
4956 debugstr_w(pKeyName
), debugstr_w(pValueName
));
4957 return ERROR_INVALID_PARAMETER
;
4960 /******************************************************************************
4961 * DeletePrinterDataExA (WINSPOOL.@)
4963 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
4966 FIXME("%p %s %s\n", hPrinter
,
4967 debugstr_a(pKeyName
), debugstr_a(pValueName
));
4968 return ERROR_INVALID_PARAMETER
;
4971 /******************************************************************************
4972 * DeletePrintProcessorA (WINSPOOL.@)
4974 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
4976 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4977 debugstr_a(pPrintProcessorName
));
4981 /******************************************************************************
4982 * DeletePrintProcessorW (WINSPOOL.@)
4984 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
4986 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4987 debugstr_w(pPrintProcessorName
));
4991 /******************************************************************************
4992 * DeletePrintProvidorA (WINSPOOL.@)
4994 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
4996 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4997 debugstr_a(pPrintProviderName
));
5001 /******************************************************************************
5002 * DeletePrintProvidorW (WINSPOOL.@)
5004 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
5006 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5007 debugstr_w(pPrintProviderName
));
5011 /******************************************************************************
5012 * EnumFormsA (WINSPOOL.@)
5014 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
5015 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5017 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
5021 /******************************************************************************
5022 * EnumFormsW (WINSPOOL.@)
5024 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
5025 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5027 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
5031 /*****************************************************************************
5032 * EnumMonitorsA [WINSPOOL.@]
5034 * See EnumMonitorsW.
5037 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
5038 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5040 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName
), Level
, pMonitors
,
5041 cbBuf
, pcbNeeded
, pcReturned
);
5042 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5046 /*****************************************************************************
5047 * EnumMonitorsW [WINSPOOL.@]
5049 * Enumerate available Monitors
5052 * pName [I] Servername or NULL (local Computer)
5053 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5054 * pMonitors [O] PTR to Buffer that receives the Result
5055 * cbBuf [I] Size of Buffer at pMonitors
5056 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5057 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5061 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5067 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
5068 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5070 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName
), Level
, pMonitors
,
5071 cbBuf
, pcbNeeded
, pcReturned
);
5072 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5076 /******************************************************************************
5077 * XcvDataW (WINSPOOL.@)
5080 * There doesn't seem to be an A version...
5082 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
5083 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
5084 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
5086 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv
, debugstr_w(pszDataName
),
5087 pInputData
, cbInputData
, pOutputData
,
5088 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
5092 /*****************************************************************************
5093 * EnumPrinterDataA [WINSPOOL.@]
5096 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
5097 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
5098 DWORD cbData
, LPDWORD pcbData
)
5100 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
5101 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
5102 return ERROR_NO_MORE_ITEMS
;
5105 /*****************************************************************************
5106 * EnumPrinterDataW [WINSPOOL.@]
5109 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
5110 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
5111 DWORD cbData
, LPDWORD pcbData
)
5113 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
5114 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
5115 return ERROR_NO_MORE_ITEMS
;
5118 /*****************************************************************************
5119 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5122 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
5123 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
5124 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5126 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName
),
5127 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
5128 pcbNeeded
, pcReturned
);
5132 /*****************************************************************************
5133 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5136 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
5137 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
5138 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5140 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
5141 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
5142 pcbNeeded
, pcReturned
);
5146 /*****************************************************************************
5147 * EnumPrintProcessorsA [WINSPOOL.@]
5150 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5151 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
5153 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName
, pEnvironment
, Level
,
5154 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
5158 /*****************************************************************************
5159 * EnumPrintProcessorsW [WINSPOOL.@]
5162 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5163 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
5165 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
5166 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
5167 cbBuf
, pcbNeeded
, pcbReturned
);
5171 /*****************************************************************************
5172 * ExtDeviceMode [WINSPOOL.@]
5175 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
5176 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
5179 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd
, hInst
, pDevModeOutput
,
5180 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
5181 debugstr_a(pProfile
), fMode
);
5185 /*****************************************************************************
5186 * FindClosePrinterChangeNotification [WINSPOOL.@]
5189 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
5191 FIXME("Stub: %p\n", hChange
);
5195 /*****************************************************************************
5196 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5199 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
5200 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
5202 FIXME("Stub: %p %lx %lx %p\n",
5203 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
5204 return INVALID_HANDLE_VALUE
;
5207 /*****************************************************************************
5208 * FindNextPrinterChangeNotification [WINSPOOL.@]
5211 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
5212 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
5214 FIXME("Stub: %p %p %p %p\n",
5215 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
5219 /*****************************************************************************
5220 * FreePrinterNotifyInfo [WINSPOOL.@]
5223 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
5225 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
5229 /*****************************************************************************
5232 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5233 * ansi depending on the unicode parameter.
5235 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
5245 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
5248 memcpy(ptr
, str
, *size
);
5255 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
5258 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
5265 /*****************************************************************************
5268 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
5269 LPDWORD pcbNeeded
, BOOL unicode
)
5271 DWORD size
, left
= cbBuf
;
5272 BOOL space
= (cbBuf
> 0);
5279 ji1
->JobId
= job
->job_id
;
5282 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
5283 if(space
&& size
<= left
)
5285 ji1
->pDocument
= (LPWSTR
)ptr
;
5296 /*****************************************************************************
5299 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
5300 LPDWORD pcbNeeded
, BOOL unicode
)
5302 DWORD size
, left
= cbBuf
;
5303 BOOL space
= (cbBuf
> 0);
5310 ji2
->JobId
= job
->job_id
;
5313 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
5314 if(space
&& size
<= left
)
5316 ji2
->pDocument
= (LPWSTR
)ptr
;
5327 /*****************************************************************************
5330 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5331 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
5334 DWORD needed
= 0, size
;
5338 TRACE("%p %ld %ld %p %ld %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
5340 EnterCriticalSection(&printer_handles_cs
);
5341 job
= get_job(hPrinter
, JobId
);
5348 size
= sizeof(JOB_INFO_1W
);
5353 memset(pJob
, 0, size
);
5357 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5362 size
= sizeof(JOB_INFO_2W
);
5367 memset(pJob
, 0, size
);
5371 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5376 size
= sizeof(JOB_INFO_3
);
5380 memset(pJob
, 0, size
);
5389 SetLastError(ERROR_INVALID_LEVEL
);
5393 *pcbNeeded
= needed
;
5395 LeaveCriticalSection(&printer_handles_cs
);
5399 /*****************************************************************************
5400 * GetJobA [WINSPOOL.@]
5403 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5404 DWORD cbBuf
, LPDWORD pcbNeeded
)
5406 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
5409 /*****************************************************************************
5410 * GetJobW [WINSPOOL.@]
5413 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5414 DWORD cbBuf
, LPDWORD pcbNeeded
)
5416 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
5419 /*****************************************************************************
5422 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
5424 char *unixname
, *queue
, *cmd
;
5425 char fmt
[] = "lpr -P%s %s";
5428 if(!(unixname
= wine_get_unix_file_name(filename
)))
5431 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5432 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5433 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5435 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
5436 sprintf(cmd
, fmt
, queue
, unixname
);
5438 TRACE("printing with: %s\n", cmd
);
5441 HeapFree(GetProcessHeap(), 0, cmd
);
5442 HeapFree(GetProcessHeap(), 0, queue
);
5443 HeapFree(GetProcessHeap(), 0, unixname
);
5447 /*****************************************************************************
5450 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
5452 #if HAVE_CUPS_CUPS_H
5455 char *unixname
, *queue
, *doc_titleA
;
5459 if(!(unixname
= wine_get_unix_file_name(filename
)))
5462 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5463 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5464 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5466 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
5467 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
5468 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
5470 TRACE("printing via cups\n");
5471 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
5472 HeapFree(GetProcessHeap(), 0, doc_titleA
);
5473 HeapFree(GetProcessHeap(), 0, queue
);
5474 HeapFree(GetProcessHeap(), 0, unixname
);
5480 return schedule_lpr(printer_name
, filename
);
5484 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
5491 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
5495 if(HIWORD(wparam
) == BN_CLICKED
)
5497 if(LOWORD(wparam
) == IDOK
)
5500 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
5503 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
5504 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
5506 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
5508 WCHAR caption
[200], message
[200];
5511 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5512 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
5513 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
5514 if(mb_ret
== IDCANCEL
)
5516 HeapFree(GetProcessHeap(), 0, filename
);
5520 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5521 if(hf
== INVALID_HANDLE_VALUE
)
5523 WCHAR caption
[200], message
[200];
5525 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5526 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
5527 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
5528 HeapFree(GetProcessHeap(), 0, filename
);
5532 DeleteFileW(filename
);
5533 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5535 EndDialog(hwnd
, IDOK
);
5538 if(LOWORD(wparam
) == IDCANCEL
)
5540 EndDialog(hwnd
, IDCANCEL
);
5549 /*****************************************************************************
5552 static BOOL
get_filename(LPWSTR
*filename
)
5554 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
5555 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
5558 /*****************************************************************************
5561 static BOOL
schedule_file(LPCWSTR filename
)
5563 LPWSTR output
= NULL
;
5565 if(get_filename(&output
))
5567 TRACE("copy to %s\n", debugstr_w(output
));
5568 CopyFileW(filename
, output
, FALSE
);
5569 HeapFree(GetProcessHeap(), 0, output
);
5575 /*****************************************************************************
5578 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
5581 char *unixname
, *cmdA
;
5583 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
5587 if(!(unixname
= wine_get_unix_file_name(filename
)))
5590 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
5591 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
5592 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
5594 TRACE("printing with: %s\n", cmdA
);
5596 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
5601 ERR("pipe() failed!\n");
5611 /* reset signals that we previously set to SIG_IGN */
5612 signal(SIGPIPE
, SIG_DFL
);
5613 signal(SIGCHLD
, SIG_DFL
);
5619 while((no_read
= read(file_fd
, buf
, sizeof(buf
))))
5620 write(fds
[1], buf
, no_read
);
5625 if(file_fd
!= -1) close(file_fd
);
5626 if(fds
[0] != -1) close(fds
[0]);
5627 if(fds
[1] != -1) close(fds
[1]);
5629 HeapFree(GetProcessHeap(), 0, cmdA
);
5630 HeapFree(GetProcessHeap(), 0, unixname
);
5637 /*****************************************************************************
5640 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
5642 int in_fd
, out_fd
, no_read
;
5645 char *unixname
, *outputA
;
5648 if(!(unixname
= wine_get_unix_file_name(filename
)))
5651 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
5652 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
5653 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
5655 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
5656 in_fd
= open(unixname
, O_RDONLY
);
5657 if(out_fd
== -1 || in_fd
== -1)
5660 while((no_read
= read(in_fd
, buf
, sizeof(buf
))))
5661 write(out_fd
, buf
, no_read
);
5665 if(in_fd
!= -1) close(in_fd
);
5666 if(out_fd
!= -1) close(out_fd
);
5667 HeapFree(GetProcessHeap(), 0, outputA
);
5668 HeapFree(GetProcessHeap(), 0, unixname
);
5672 /*****************************************************************************
5673 * ScheduleJob [WINSPOOL.@]
5676 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
5678 opened_printer_t
*printer
;
5680 struct list
*cursor
, *cursor2
;
5682 TRACE("(%p, %lx)\n", hPrinter
, dwJobID
);
5683 EnterCriticalSection(&printer_handles_cs
);
5684 printer
= get_opened_printer(hPrinter
);
5688 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
5690 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
5693 if(job
->job_id
!= dwJobID
) continue;
5695 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
5696 if(hf
!= INVALID_HANDLE_VALUE
)
5698 PRINTER_INFO_5W
*pi5
;
5702 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5703 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5705 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
5706 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
5707 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
5708 TRACE("need to schedule job %ld filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
5709 debugstr_w(pi5
->pPortName
));
5713 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5714 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
5716 DWORD type
, count
= sizeof(output
);
5717 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
5720 if(output
[0] == '|')
5722 schedule_pipe(output
+ 1, job
->filename
);
5726 schedule_unixfile(output
, job
->filename
);
5728 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
5730 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
5732 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
5734 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
5736 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
5738 schedule_file(job
->filename
);
5742 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
5744 HeapFree(GetProcessHeap(), 0, pi5
);
5746 DeleteFileW(job
->filename
);
5748 list_remove(cursor
);
5749 HeapFree(GetProcessHeap(), 0, job
->document_title
);
5750 HeapFree(GetProcessHeap(), 0, job
->filename
);
5751 HeapFree(GetProcessHeap(), 0, job
);
5756 LeaveCriticalSection(&printer_handles_cs
);
5760 /*****************************************************************************
5761 * StartDocDlgA [WINSPOOL.@]
5763 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
5765 UNICODE_STRING usBuffer
;
5770 docW
.cbSize
= sizeof(docW
);
5771 docW
.lpszDocName
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
5772 docW
.lpszOutput
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
5773 docW
.lpszDatatype
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
5774 docW
.fwType
= doc
->fwType
;
5776 retW
= StartDocDlgW(hPrinter
, &docW
);
5780 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
5781 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
5782 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
5783 HeapFree(GetProcessHeap(), 0, retW
);
5786 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDatatype
);
5787 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszOutput
);
5788 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDocName
);
5793 /*****************************************************************************
5794 * StartDocDlgW [WINSPOOL.@]
5796 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5797 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5798 * port is "FILE:". Also returns the full path if passed a relative path.
5800 * The caller should free the returned string from the process heap.
5802 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
5807 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
5809 PRINTER_INFO_5W
*pi5
;
5810 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
5811 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
5813 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
5814 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
5815 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
5817 HeapFree(GetProcessHeap(), 0, pi5
);
5820 HeapFree(GetProcessHeap(), 0, pi5
);
5823 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
5826 get_filename(&name
);
5829 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
5831 HeapFree(GetProcessHeap(), 0, name
);
5834 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5835 GetFullPathNameW(name
, len
, ret
, NULL
);
5836 HeapFree(GetProcessHeap(), 0, name
);
5841 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
5844 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5845 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
5847 attr
= GetFileAttributesW(ret
);
5848 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
5850 HeapFree(GetProcessHeap(), 0, ret
);