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 MonitorsW
[] = { 'S','y','s','t','e','m','\\',
130 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'C','o','n','t','r','o','l','\\',
132 'P','r','i','n','t','\\',
133 'M','o','n','i','t','o','r','s',0};
135 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
137 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
138 'M','i','c','r','o','s','o','f','t','\\',
139 'W','i','n','d','o','w','s',' ','N','T','\\',
140 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
141 'W','i','n','d','o','w','s',0};
143 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s',' ','N','T','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'D','e','v','i','c','e','s',0};
149 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
150 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
151 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
152 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
153 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
155 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
157 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
158 'i','o','n',' ','F','i','l','e',0};
159 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
160 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
161 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v',
163 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F',
165 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
166 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
167 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
168 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
169 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
170 static const WCHAR NameW
[] = {'N','a','m','e',0};
171 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
172 static const WCHAR PortW
[] = {'P','o','r','t',0};
173 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e',
175 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i',
177 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i',
178 'v','e','r','D','a','t','a',0};
179 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F',
181 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
182 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
183 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
184 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
185 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
186 static const WCHAR emptyStringW
[] = {0};
188 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
190 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
191 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
192 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
194 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
195 'D','o','c','u','m','e','n','t',0};
197 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
);
198 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
199 DWORD Level
, LPBYTE pDriverInfo
,
200 DWORD cbBuf
, LPDWORD pcbNeeded
,
202 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
);
204 /******************************************************************
205 * validate the user-supplied printing-environment [internal]
208 * env [I] PTR to Environment-String or NULL
212 * Success: PTR to printenv_t
215 * An empty string is handled the same way as NULL.
216 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
220 static const printenv_t
* validate_envW(LPCWSTR env
)
222 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
};
223 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
};
224 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
226 const printenv_t
*result
= NULL
;
229 TRACE("testing %s\n", debugstr_w(env
));
232 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
234 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
236 result
= all_printenv
[i
];
241 if (result
== NULL
) {
242 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
243 SetLastError(ERROR_INVALID_ENVIRONMENT
);
245 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
249 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
251 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
257 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
258 if passed a NULL string. This returns NULLs to the result.
260 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
264 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
265 return usBufferPtr
->Buffer
;
267 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
271 static LPWSTR
strdupW(LPCWSTR p
)
277 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
278 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
284 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
,BOOL force
) {
287 /* If forcing, or no profile string entry for device yet, set the entry
289 * The always change entry if not WINEPS yet is discussable.
292 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
294 !strstr(qbuf
,"WINEPS.DRV")
296 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
299 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
300 WriteProfileStringA("windows","device",buf
);
301 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
302 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
305 HeapFree(GetProcessHeap(),0,buf
);
309 #ifdef HAVE_CUPS_CUPS_H
310 static typeof(cupsGetDests
) *pcupsGetDests
;
311 static typeof(cupsGetPPD
) *pcupsGetPPD
;
312 static typeof(cupsPrintFile
) *pcupsPrintFile
;
313 static void *cupshandle
;
315 static BOOL
CUPS_LoadPrinters(void)
318 BOOL hadprinter
= FALSE
;
320 PRINTER_INFO_2A pinfo2a
;
322 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
324 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
327 TRACE("loaded %s\n", SONAME_LIBCUPS
);
330 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
331 if (!p##x) return FALSE;
334 DYNCUPS(cupsGetDests
);
335 DYNCUPS(cupsPrintFile
);
338 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
340 ERR("Can't create Printers key\n");
344 nrofdests
= pcupsGetDests(&dests
);
345 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
346 for (i
=0;i
<nrofdests
;i
++) {
347 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
348 sprintf(port
,"LPR:%s",dests
[i
].name
);
349 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
350 sprintf(devline
,"WINEPS.DRV,%s",port
);
351 WriteProfileStringA("devices",dests
[i
].name
,devline
);
352 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
353 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
356 HeapFree(GetProcessHeap(),0,devline
);
358 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
359 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
360 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
362 TRACE("Printer already exists\n");
363 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
364 RegCloseKey(hkeyPrinter
);
366 memset(&pinfo2a
,0,sizeof(pinfo2a
));
367 pinfo2a
.pPrinterName
= dests
[i
].name
;
368 pinfo2a
.pDatatype
= "RAW";
369 pinfo2a
.pPrintProcessor
= "WinPrint";
370 pinfo2a
.pDriverName
= "PS Driver";
371 pinfo2a
.pComment
= "WINEPS Printer using CUPS";
372 pinfo2a
.pLocation
= "<physical location of printer>";
373 pinfo2a
.pPortName
= port
;
374 pinfo2a
.pParameters
= "<parameters?>";
375 pinfo2a
.pShareName
= "<share name?>";
376 pinfo2a
.pSepFile
= "<sep file?>";
378 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
379 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
380 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests
[i
].name
,GetLastError());
383 HeapFree(GetProcessHeap(),0,port
);
386 if (dests
[i
].is_default
)
387 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
389 RegCloseKey(hkeyPrinters
);
395 PRINTCAP_ParseEntry(char *pent
,BOOL isfirst
) {
396 PRINTER_INFO_2A pinfo2a
;
397 char *e
,*s
,*name
,*prettyname
,*devname
;
398 BOOL ret
= FALSE
, set_default
= FALSE
;
399 char *port
,*devline
,*env_default
;
400 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
402 while (isspace(*pent
)) pent
++;
403 s
= strchr(pent
,':');
405 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
413 TRACE("name=%s entry=%s\n",name
, pent
);
415 if(ispunct(*name
)) { /* a tc entry, not a real printer */
416 TRACE("skipping tc entry\n");
420 if(strstr(pent
,":server")) { /* server only version so skip */
421 TRACE("skipping server entry\n");
425 /* Determine whether this is a postscript printer. */
428 env_default
= getenv("PRINTER");
430 /* Get longest name, usually the one at the right for later display. */
431 while((s
=strchr(prettyname
,'|'))) {
434 while(isspace(*--e
)) *e
= '\0';
435 TRACE("\t%s\n", debugstr_a(prettyname
));
436 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
437 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
440 e
= prettyname
+ strlen(prettyname
);
441 while(isspace(*--e
)) *e
= '\0';
442 TRACE("\t%s\n", debugstr_a(prettyname
));
443 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
445 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
446 * if it is too long, we use it as comment below. */
447 devname
= prettyname
;
448 if (strlen(devname
)>=CCHDEVICENAME
-1)
450 if (strlen(devname
)>=CCHDEVICENAME
-1) {
455 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
456 sprintf(port
,"LPR:%s",name
);
458 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
459 sprintf(devline
,"WINEPS.DRV,%s",port
);
460 WriteProfileStringA("devices",devname
,devline
);
461 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
462 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
465 HeapFree(GetProcessHeap(),0,devline
);
467 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
469 ERR("Can't create Printers key\n");
473 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
474 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
476 TRACE("Printer already exists\n");
477 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
478 RegCloseKey(hkeyPrinter
);
480 memset(&pinfo2a
,0,sizeof(pinfo2a
));
481 pinfo2a
.pPrinterName
= devname
;
482 pinfo2a
.pDatatype
= "RAW";
483 pinfo2a
.pPrintProcessor
= "WinPrint";
484 pinfo2a
.pDriverName
= "PS Driver";
485 pinfo2a
.pComment
= "WINEPS Printer using LPR";
486 pinfo2a
.pLocation
= prettyname
;
487 pinfo2a
.pPortName
= port
;
488 pinfo2a
.pParameters
= "<parameters?>";
489 pinfo2a
.pShareName
= "<share name?>";
490 pinfo2a
.pSepFile
= "<sep file?>";
492 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
493 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
494 ERR("%s not added by AddPrinterA (%ld)\n",name
,GetLastError());
497 RegCloseKey(hkeyPrinters
);
499 if (isfirst
|| set_default
)
500 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
502 HeapFree(GetProcessHeap(), 0, port
);
504 HeapFree(GetProcessHeap(), 0, name
);
509 PRINTCAP_LoadPrinters(void) {
510 BOOL hadprinter
= FALSE
;
514 BOOL had_bash
= FALSE
;
516 f
= fopen("/etc/printcap","r");
520 while(fgets(buf
,sizeof(buf
),f
)) {
523 end
=strchr(buf
,'\n');
527 while(isspace(*start
)) start
++;
528 if(*start
== '#' || *start
== '\0')
531 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
532 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
533 HeapFree(GetProcessHeap(),0,pent
);
537 if (end
&& *--end
== '\\') {
544 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
547 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
553 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
554 HeapFree(GetProcessHeap(),0,pent
);
560 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
563 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
564 lstrlenW(value
) * sizeof(WCHAR
));
566 return ERROR_FILE_NOT_FOUND
;
569 void WINSPOOL_LoadSystemPrinters(void)
571 HKEY hkey
, hkeyPrinters
;
574 DWORD needed
, num
, i
;
575 WCHAR PrinterName
[256];
578 di3a
.cVersion
= 0x400;
579 di3a
.pName
= "PS Driver";
580 di3a
.pEnvironment
= NULL
; /* NULL means auto */
581 di3a
.pDriverPath
= "wineps16";
582 di3a
.pDataFile
= "<datafile?>";
583 di3a
.pConfigFile
= "wineps16";
584 di3a
.pHelpFile
= "<helpfile?>";
585 di3a
.pDependentFiles
= "<dependend files?>";
586 di3a
.pMonitorName
= "<monitor name?>";
587 di3a
.pDefaultDataType
= "RAW";
589 if (!AddPrinterDriverA(NULL
,3,(LPBYTE
)&di3a
)) {
590 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
594 /* This ensures that all printer entries have a valid Name value. If causes
595 problems later if they don't. If one is found to be missed we create one
596 and set it equal to the name of the key */
597 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
598 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
599 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
600 for(i
= 0; i
< num
; i
++) {
601 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
602 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
603 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
604 set_reg_szW(hkey
, NameW
, PrinterName
);
611 RegCloseKey(hkeyPrinters
);
614 /* We want to avoid calling AddPrinter on printers as much as
615 possible, because on cups printers this will (eventually) lead
616 to a call to cupsGetPPD which takes forever, even with non-cups
617 printers AddPrinter takes a while. So we'll tag all printers that
618 were automatically added last time around, if they still exist
619 we'll leave them be otherwise we'll delete them. */
620 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
622 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
623 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
624 for(i
= 0; i
< num
; i
++) {
625 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
626 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
627 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
629 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
637 HeapFree(GetProcessHeap(), 0, pi
);
641 #ifdef HAVE_CUPS_CUPS_H
642 done
= CUPS_LoadPrinters();
645 if(!done
) { /* If we have any CUPS based printers, skip looking for printcap printers */
646 /* Check for [ppd] section in config file before parsing /etc/printcap */
647 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
648 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Printing\\PPD Files",
649 &hkey
) == ERROR_SUCCESS
) {
651 PRINTCAP_LoadPrinters();
655 /* Now enumerate the list again and delete any printers that a still tagged */
656 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
658 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
659 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
660 for(i
= 0; i
< num
; i
++) {
661 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
662 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
663 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
664 DWORD dw
, type
, size
= sizeof(dw
);
665 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
666 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
676 HeapFree(GetProcessHeap(), 0, pi
);
683 /*****************************************************************************
684 * enumerate the local monitors (INTERNAL)
686 * returns the needed size (in bytes) for pMonitors
687 * and *lpreturned is set to number of entries returned in pMonitors
690 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
695 LPMONITOR_INFO_2W mi
;
696 WCHAR buffer
[MAX_PATH
];
697 WCHAR dllname
[MAX_PATH
];
705 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
707 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
708 len
= entrysize
* numentries
;
709 ptr
= (LPWSTR
) &pMonitors
[len
];
712 len
= sizeof(buffer
);
715 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
716 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
717 /* Scan all Monitor-Registry-Keys */
718 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
719 TRACE("Monitor_%ld: %s\n", numentries
, debugstr_w(buffer
));
720 dllsize
= sizeof(dllname
);
723 /* The Monitor must have a Driver-DLL */
724 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
725 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
726 /* We found a valid DLL for this Monitor. */
727 TRACE("using Driver: %s\n", debugstr_w(dllname
));
732 /* Windows returns only Port-Monitors here, but to simplify our code,
733 we do no filtering for Language-Monitors */
737 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
739 /* we install and return only monitors for "Windows NT x86" */
740 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
744 /* required size is calculated. Now fill the user-buffer */
745 if (pMonitors
&& (cbBuf
>= needed
)){
746 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
747 pMonitors
+= entrysize
;
749 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi
, level
, numentries
);
751 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
752 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
754 mi
->pEnvironment
= ptr
;
755 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
756 ptr
+= (lstrlenW(envname_x86W
)+1);
759 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
760 ptr
+= (dllsize
/ sizeof(WCHAR
));
765 len
= sizeof(buffer
);
770 *lpreturned
= numentries
;
771 TRACE("need %ld byte for %ld entries\n", needed
, numentries
);
775 /******************************************************************
776 * get_opened_printer_entry
777 * Get the first place empty in the opened printer table
779 static HANDLE
get_opened_printer_entry( LPCWSTR name
)
781 UINT_PTR handle
= nb_printer_handles
, i
;
782 jobqueue_t
*queue
= NULL
;
783 opened_printer_t
*printer
;
785 EnterCriticalSection(&printer_handles_cs
);
787 for (i
= 0; i
< nb_printer_handles
; i
++)
789 if (!printer_handles
[i
])
791 if(handle
== nb_printer_handles
)
794 else if(!queue
&& !strcmpW(name
, printer_handles
[i
]->name
))
795 queue
= printer_handles
[i
]->queue
;
798 if (handle
>= nb_printer_handles
)
800 opened_printer_t
**new_array
;
802 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
803 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
805 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
806 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
813 printer_handles
= new_array
;
814 nb_printer_handles
+= 16;
817 if (!(printer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
))))
823 printer
->name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(name
) + 1) * sizeof(WCHAR
));
824 strcpyW(printer
->name
, name
);
826 printer
->queue
= queue
;
829 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
830 list_init(&printer
->queue
->jobs
);
831 printer
->queue
->ref
= 0;
833 InterlockedIncrement(&printer
->queue
->ref
);
836 printer_handles
[handle
] = printer
;
839 LeaveCriticalSection(&printer_handles_cs
);
841 return (HANDLE
)handle
;
844 /******************************************************************
846 * Get the pointer to the opened printer referred by the handle
848 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
850 UINT_PTR idx
= (UINT_PTR
)hprn
;
851 opened_printer_t
*ret
= NULL
;
853 EnterCriticalSection(&printer_handles_cs
);
855 if ((idx
<= 0) || (idx
> nb_printer_handles
))
858 ret
= printer_handles
[idx
- 1];
860 LeaveCriticalSection(&printer_handles_cs
);
864 /******************************************************************
865 * get_opened_printer_name
866 * Get the pointer to the opened printer name referred by the handle
868 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
870 opened_printer_t
*printer
= get_opened_printer(hprn
);
871 if(!printer
) return NULL
;
872 return printer
->name
;
875 /******************************************************************
876 * WINSPOOL_GetOpenedPrinterRegKey
879 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
881 LPCWSTR name
= get_opened_printer_name(hPrinter
);
885 if(!name
) return ERROR_INVALID_HANDLE
;
887 if((ret
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
)) !=
891 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
893 ERR("Can't find opened printer %s in registry\n",
895 RegCloseKey(hkeyPrinters
);
896 return ERROR_INVALID_PRINTER_NAME
; /* ? */
898 RegCloseKey(hkeyPrinters
);
899 return ERROR_SUCCESS
;
902 /******************************************************************
905 * Get the pointer to the specified job.
906 * Should hold the printer_handles_cs before calling.
908 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
910 opened_printer_t
*printer
= get_opened_printer(hprn
);
913 if(!printer
) return NULL
;
914 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
916 if(job
->job_id
== JobId
)
922 /***********************************************************
925 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
928 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
931 Formname
= (dmA
->dmSize
> off_formname
);
932 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
933 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
934 dmW
->dmDeviceName
, CCHDEVICENAME
);
936 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
937 dmA
->dmSize
- CCHDEVICENAME
);
939 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
940 off_formname
- CCHDEVICENAME
);
941 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
942 dmW
->dmFormName
, CCHFORMNAME
);
943 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
944 (off_formname
+ CCHFORMNAME
));
947 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
952 /***********************************************************
954 * Creates an ascii copy of supplied devmode on heap
956 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
961 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
963 if(!dmW
) return NULL
;
964 Formname
= (dmW
->dmSize
> off_formname
);
965 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
966 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
967 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
968 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
970 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
971 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
973 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
974 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
975 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
976 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
977 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
978 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
981 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
986 /***********************************************************
988 * Creates a unicode copy of PRINTER_INFO_2A on heap
990 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
992 LPPRINTER_INFO_2W piW
;
993 UNICODE_STRING usBuffer
;
995 if(!piA
) return NULL
;
996 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
997 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
999 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1000 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1001 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1002 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1003 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1004 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1005 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1006 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1007 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1008 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1009 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1010 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1014 /***********************************************************
1015 * FREE_PRINTER_INFO_2W
1016 * Free PRINTER_INFO_2W and all strings
1018 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1022 HeapFree(heap
,0,piW
->pServerName
);
1023 HeapFree(heap
,0,piW
->pPrinterName
);
1024 HeapFree(heap
,0,piW
->pShareName
);
1025 HeapFree(heap
,0,piW
->pPortName
);
1026 HeapFree(heap
,0,piW
->pDriverName
);
1027 HeapFree(heap
,0,piW
->pComment
);
1028 HeapFree(heap
,0,piW
->pLocation
);
1029 HeapFree(heap
,0,piW
->pDevMode
);
1030 HeapFree(heap
,0,piW
->pSepFile
);
1031 HeapFree(heap
,0,piW
->pPrintProcessor
);
1032 HeapFree(heap
,0,piW
->pDatatype
);
1033 HeapFree(heap
,0,piW
->pParameters
);
1034 HeapFree(heap
,0,piW
);
1038 /******************************************************************
1039 * DeviceCapabilities [WINSPOOL.@]
1040 * DeviceCapabilitiesA [WINSPOOL.@]
1043 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1044 LPSTR pOutput
, LPDEVMODEA lpdm
)
1048 if (!GDI_CallDeviceCapabilities16
)
1050 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1052 if (!GDI_CallDeviceCapabilities16
) return -1;
1054 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1056 /* If DC_PAPERSIZE map POINT16s to POINTs */
1057 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1058 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1059 POINT
*pt
= (POINT
*)pOutput
;
1061 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1062 for(i
= 0; i
< ret
; i
++, pt
++)
1067 HeapFree( GetProcessHeap(), 0, tmp
);
1073 /*****************************************************************************
1074 * DeviceCapabilitiesW [WINSPOOL.@]
1076 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1079 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1080 WORD fwCapability
, LPWSTR pOutput
,
1081 const DEVMODEW
*pDevMode
)
1083 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1084 LPSTR pDeviceA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDevice
);
1085 LPSTR pPortA
= HEAP_strdupWtoA(GetProcessHeap(),0,pPort
);
1088 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1089 fwCapability
== DC_FILEDEPENDENCIES
||
1090 fwCapability
== DC_PAPERNAMES
)) {
1091 /* These need A -> W translation */
1094 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1098 switch(fwCapability
) {
1103 case DC_FILEDEPENDENCIES
:
1107 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1108 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1110 for(i
= 0; i
< ret
; i
++)
1111 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1112 pOutput
+ (i
* size
), size
);
1113 HeapFree(GetProcessHeap(), 0, pOutputA
);
1115 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1116 (LPSTR
)pOutput
, dmA
);
1118 HeapFree(GetProcessHeap(),0,pPortA
);
1119 HeapFree(GetProcessHeap(),0,pDeviceA
);
1120 HeapFree(GetProcessHeap(),0,dmA
);
1124 /******************************************************************
1125 * DocumentPropertiesA [WINSPOOL.@]
1127 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1129 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1130 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1131 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1133 LPSTR lpName
= pDeviceName
;
1136 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1137 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1141 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1143 ERR("no name from hPrinter?\n");
1144 SetLastError(ERROR_INVALID_HANDLE
);
1147 lpName
= HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW
);
1150 if (!GDI_CallExtDeviceMode16
)
1152 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1154 if (!GDI_CallExtDeviceMode16
) {
1155 ERR("No CallExtDeviceMode16?\n");
1159 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, "LPT1:",
1160 pDevModeInput
, NULL
, fMode
);
1163 HeapFree(GetProcessHeap(),0,lpName
);
1168 /*****************************************************************************
1169 * DocumentPropertiesW (WINSPOOL.@)
1171 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1173 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1175 LPDEVMODEW pDevModeOutput
,
1176 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1179 LPSTR pDeviceNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName
);
1180 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1181 LPDEVMODEA pDevModeOutputA
= NULL
;
1184 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1185 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1187 if(pDevModeOutput
) {
1188 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1189 if(ret
< 0) return ret
;
1190 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1192 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1193 pDevModeInputA
, fMode
);
1194 if(pDevModeOutput
) {
1195 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1196 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1198 if(fMode
== 0 && ret
> 0)
1199 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1200 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1201 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1205 /******************************************************************
1206 * OpenPrinterA [WINSPOOL.@]
1211 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1212 LPPRINTER_DEFAULTSA pDefault
)
1214 UNICODE_STRING lpPrinterNameW
;
1215 UNICODE_STRING usBuffer
;
1216 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1217 PWSTR pwstrPrinterNameW
;
1220 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1223 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1224 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1225 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1226 pDefaultW
= &DefaultW
;
1228 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1230 RtlFreeUnicodeString(&usBuffer
);
1231 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1233 RtlFreeUnicodeString(&lpPrinterNameW
);
1237 /******************************************************************
1238 * OpenPrinterW [WINSPOOL.@]
1240 * Open a Printer / Printserver or a Printer-Object
1243 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1244 * phPrinter [O] The resulting Handle is stored here
1245 * pDefault [I] PTR to Default Printer Settings or NULL
1252 * lpPrinterName is one of:
1253 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1254 *| Printer: "PrinterName"
1255 *| Printer-Object: "PrinterName,Job xxx"
1256 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1257 *| XcvPort: "Servername,XcvPort PortName"
1260 *| Printserver not supported
1261 *| Printer-Object not supported
1262 *| XcvMonitor not supported
1263 *| XcvPort not supported
1264 *| pDefaults not supported
1267 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
,
1268 LPPRINTER_DEFAULTSW pDefault
)
1270 HKEY hkeyPrinters
, hkeyPrinter
;
1272 if (!lpPrinterName
) {
1273 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault
);
1274 SetLastError(ERROR_INVALID_PARAMETER
);
1278 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName
),
1281 /* Check Printer exists */
1282 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1284 ERR("Can't create Printers key\n");
1285 SetLastError(ERROR_FILE_NOT_FOUND
); /* ?? */
1289 if(lpPrinterName
[0] == '\0' || /* explicitly exclude "" */
1290 RegOpenKeyW(hkeyPrinters
, lpPrinterName
, &hkeyPrinter
)
1292 TRACE("Can't find printer %s in registry\n",
1293 debugstr_w(lpPrinterName
));
1294 RegCloseKey(hkeyPrinters
);
1295 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1298 RegCloseKey(hkeyPrinter
);
1299 RegCloseKey(hkeyPrinters
);
1301 if(!phPrinter
) /* This seems to be what win95 does anyway */
1304 /* Get the unique handle of the printer*/
1305 *phPrinter
= get_opened_printer_entry( lpPrinterName
);
1307 if (pDefault
!= NULL
)
1308 FIXME("Not handling pDefault\n");
1313 /******************************************************************
1314 * AddMonitorA [WINSPOOL.@]
1319 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1321 LPWSTR nameW
= NULL
;
1324 LPMONITOR_INFO_2A mi2a
;
1325 MONITOR_INFO_2W mi2w
;
1327 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1328 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1329 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
1330 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
1331 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
1334 SetLastError(ERROR_INVALID_LEVEL
);
1338 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1344 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1345 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1346 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1349 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1351 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1352 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1353 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1355 if (mi2a
->pEnvironment
) {
1356 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1357 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1358 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1360 if (mi2a
->pDLLName
) {
1361 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1362 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1363 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1366 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1368 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1369 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1370 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1372 HeapFree(GetProcessHeap(), 0, nameW
);
1376 /******************************************************************************
1377 * AddMonitorW [WINSPOOL.@]
1379 * Install a Printmonitor
1382 * pName [I] Servername or NULL (local Computer)
1383 * Level [I] Structure-Level (Must be 2)
1384 * pMonitors [I] PTR to MONITOR_INFO_2
1391 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1394 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1396 LPMONITOR_INFO_2W mi2w
;
1399 HMODULE hdll
= NULL
;
1403 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1404 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1405 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
1406 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
1407 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
1410 SetLastError(ERROR_INVALID_LEVEL
);
1414 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1419 if (pName
&& (pName
[0])) {
1420 FIXME("for server %s not implemented\n", debugstr_w(pName
));
1421 SetLastError(ERROR_ACCESS_DENIED
);
1426 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1427 WARN("pName not valid : %s \n", debugstr_w(mi2w
->pName
));
1428 SetLastError(ERROR_INVALID_PARAMETER
);
1431 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
1432 WARN("Environment %s requested (we support only %s)\n",
1433 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
1434 SetLastError(ERROR_INVALID_ENVIRONMENT
);
1438 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1439 WARN("pDLLName not valid : %s \n", debugstr_w(mi2w
->pDLLName
));
1440 SetLastError(ERROR_INVALID_PARAMETER
);
1444 if ((hdll
= LoadLibraryW(mi2w
->pDLLName
)) == NULL
) {
1449 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
1450 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
1454 if(RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1455 KEY_WRITE
, NULL
, &hentry
, &disposition
) == ERROR_SUCCESS
) {
1457 if (disposition
== REG_OPENED_EXISTING_KEY
) {
1458 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1459 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1460 9x: ERROR_ALREADY_EXISTS (183) */
1461 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1466 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1467 res
= (RegSetValueExW(hentry
, DriverW
, 0,
1468 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1470 RegCloseKey(hentry
);
1477 /******************************************************************
1478 * DeletePrinterDriverA [WINSPOOL.@]
1482 DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
1484 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1485 debugstr_a(pDriverName
));
1486 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1490 /******************************************************************
1491 * DeletePrinterDriverW [WINSPOOL.@]
1495 DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
1497 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1498 debugstr_w(pDriverName
));
1499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1503 /******************************************************************
1504 * DeleteMonitorA [WINSPOOL.@]
1506 * See DeleteMonitorW.
1510 DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
1512 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1513 debugstr_a(pMonitorName
));
1514 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1518 /******************************************************************
1519 * DeleteMonitorW [WINSPOOL.@]
1521 * Delete a specific Printmonitor from a Printing-Environment
1524 * pName [I] Servername or NULL (local Computer)
1525 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1526 * pMonitorName [I] Name of the Monitor, that should be deleted
1537 DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1539 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1540 debugstr_w(pMonitorName
));
1541 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1545 /******************************************************************
1546 * DeletePortA [WINSPOOL.@]
1552 DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
1554 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName
),hWnd
,
1555 debugstr_a(pPortName
));
1556 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1560 /******************************************************************
1561 * DeletePortW [WINSPOOL.@]
1563 * Delete a specific Port
1566 * pName [I] Servername or NULL (local Computer)
1567 * hWnd [I] Handle to parent Window for the Dialog-Box
1568 * pPortName [I] Name of the Port, that should be deleted
1579 DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1581 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName
),hWnd
,
1582 debugstr_w(pPortName
));
1583 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1587 /******************************************************************************
1588 * SetPrinterW [WINSPOOL.@]
1598 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1602 /******************************************************************************
1603 * WritePrinter [WINSPOOL.@]
1605 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
1607 opened_printer_t
*printer
;
1610 TRACE("(%p, %p, %ld, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
1612 EnterCriticalSection(&printer_handles_cs
);
1613 printer
= get_opened_printer(hPrinter
);
1616 SetLastError(ERROR_INVALID_HANDLE
);
1622 SetLastError(ERROR_SPL_NO_STARTDOC
);
1626 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
1628 LeaveCriticalSection(&printer_handles_cs
);
1632 /*****************************************************************************
1633 * AddFormA [WINSPOOL.@]
1635 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1637 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1641 /*****************************************************************************
1642 * AddFormW [WINSPOOL.@]
1644 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1646 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1650 /*****************************************************************************
1651 * AddJobA [WINSPOOL.@]
1653 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1656 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
1660 SetLastError(ERROR_INVALID_LEVEL
);
1664 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
1667 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
1668 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
1669 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
1670 if(*pcbNeeded
> cbBuf
) {
1671 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1674 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
1675 addjobA
->JobId
= addjobW
->JobId
;
1676 addjobA
->Path
= (char *)(addjobA
+ 1);
1677 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
1683 /*****************************************************************************
1684 * AddJobW [WINSPOOL.@]
1686 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1688 opened_printer_t
*printer
;
1691 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1692 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
1693 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
1695 ADDJOB_INFO_1W
*addjob
;
1697 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
1699 EnterCriticalSection(&printer_handles_cs
);
1701 printer
= get_opened_printer(hPrinter
);
1704 SetLastError(ERROR_INVALID_HANDLE
);
1709 SetLastError(ERROR_INVALID_LEVEL
);
1713 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
1717 job
->job_id
= InterlockedIncrement(&next_job_id
);
1719 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
1720 if(path
[len
- 1] != '\\')
1722 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
1723 sprintfW(filename
, fmtW
, path
, job
->job_id
);
1725 len
= strlenW(filename
);
1726 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1727 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
1728 job
->document_title
= strdupW(default_doc_title
);
1729 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
1731 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
1732 if(*pcbNeeded
<= cbBuf
) {
1733 addjob
= (ADDJOB_INFO_1W
*)pData
;
1734 addjob
->JobId
= job
->job_id
;
1735 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
1736 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
1739 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1742 LeaveCriticalSection(&printer_handles_cs
);
1746 /*****************************************************************************
1747 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1749 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
1750 DWORD level
, LPBYTE Info
,
1751 DWORD cbBuf
, LPDWORD needed
)
1753 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server
), debugstr_a(env
),
1754 level
, Info
, cbBuf
);
1758 /*****************************************************************************
1759 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1761 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
1762 DWORD level
, LPBYTE Info
,
1763 DWORD cbBuf
, LPDWORD needed
)
1765 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server
), debugstr_w(env
),
1766 level
, Info
, cbBuf
);
1770 /*****************************************************************************
1771 * WINSPOOL_OpenDriverReg [internal]
1773 * opens the registry for the printer drivers depending on the given input
1774 * variable pEnvironment
1777 * the opened hkey on success
1780 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
)
1782 static const WCHAR WinNTW
[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1783 static const WCHAR Win40W
[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1785 LPWSTR lpKey
, buffer
= NULL
;
1789 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
));
1793 pEnvW
= pEnvironment
;
1795 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
1796 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1797 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
1802 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
1804 if(!GetVersionExW( &ver
))
1807 switch (ver
.dwPlatformId
) {
1808 case VER_PLATFORM_WIN32s
:
1809 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1811 case VER_PLATFORM_WIN32_NT
:
1818 TRACE("set environment to %s\n", debugstr_w(pEnvW
));
1821 lpKey
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1822 (strlenW(pEnvW
) + strlenW(DriversW
) + 1) * sizeof(WCHAR
));
1823 wsprintfW( lpKey
, DriversW
, pEnvW
);
1825 TRACE("%s\n", debugstr_w(lpKey
));
1827 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, lpKey
, &retval
) != ERROR_SUCCESS
)
1830 HeapFree( GetProcessHeap(), 0, buffer
);
1831 HeapFree( GetProcessHeap(), 0, lpKey
);
1836 /*****************************************************************************
1837 * AddPrinterW [WINSPOOL.@]
1839 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1841 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
1845 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
1848 TRACE("(%s,%ld,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
1851 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
1852 SetLastError(ERROR_INVALID_PARAMETER
);
1856 ERR("Level = %ld, unsupported!\n", Level
);
1857 SetLastError(ERROR_INVALID_LEVEL
);
1860 if (strlenW(pi
->pPrinterName
) >= CCHDEVICENAME
) {
1861 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1862 debugstr_w(pi
->pPrinterName
)
1864 SetLastError(ERROR_INVALID_LEVEL
);
1868 SetLastError(ERROR_INVALID_PARAMETER
);
1871 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1873 ERR("Can't create Printers key\n");
1876 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
1877 if (!RegQueryValueA(hkeyPrinter
,"Attributes",NULL
,NULL
)) {
1878 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
1879 RegCloseKey(hkeyPrinter
);
1880 RegCloseKey(hkeyPrinters
);
1883 RegCloseKey(hkeyPrinter
);
1885 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
1887 ERR("Can't create Drivers key\n");
1888 RegCloseKey(hkeyPrinters
);
1891 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
1893 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
1894 RegCloseKey(hkeyPrinters
);
1895 RegCloseKey(hkeyDrivers
);
1896 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
1899 RegCloseKey(hkeyDriver
);
1900 RegCloseKey(hkeyDrivers
);
1902 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
1903 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
1904 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
1905 RegCloseKey(hkeyPrinters
);
1909 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
1911 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
1912 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1913 RegCloseKey(hkeyPrinters
);
1916 RegSetValueExA(hkeyPrinter
, "Attributes", 0, REG_DWORD
,
1917 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
1918 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
1920 /* See if we can load the driver. We may need the devmode structure anyway
1923 * Note that DocumentPropertiesW will briefly try to open the printer we
1924 * just create to find a DEVMODEA struct (it will use the WINEPS default
1925 * one in case it is not there, so we are ok).
1927 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
1930 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi
->pPrinterName
));
1931 size
= sizeof(DEVMODEW
);
1937 dmW
= HeapAlloc(GetProcessHeap(), 0, size
);
1938 ZeroMemory(dmW
,size
);
1940 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
1942 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi
->pPrinterName
));
1943 HeapFree(GetProcessHeap(),0,dmW
);
1948 /* set devmode to printer name */
1949 strcpyW(dmW
->dmDeviceName
,pi
->pPrinterName
);
1953 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1954 and we support these drivers. NT writes DEVMODEW so somehow
1955 we'll need to distinguish between these when we support NT
1959 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
1960 RegSetValueExA(hkeyPrinter
, "Default DevMode", 0, REG_BINARY
,
1961 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1962 HeapFree(GetProcessHeap(), 0, dmA
);
1964 HeapFree(GetProcessHeap(), 0, dmW
);
1966 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
1967 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
1968 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
1969 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
1971 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
1972 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
1973 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
1974 RegSetValueExA(hkeyPrinter
, "Priority", 0, REG_DWORD
,
1975 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
1976 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
1977 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
1978 RegSetValueExA(hkeyPrinter
, "StartTime", 0, REG_DWORD
,
1979 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
1980 RegSetValueExA(hkeyPrinter
, "Status", 0, REG_DWORD
,
1981 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
1982 RegSetValueExA(hkeyPrinter
, "UntilTime", 0, REG_DWORD
,
1983 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
1985 RegCloseKey(hkeyPrinter
);
1986 RegCloseKey(hkeyPrinters
);
1987 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
1988 ERR("OpenPrinter failing\n");
1994 /*****************************************************************************
1995 * AddPrinterA [WINSPOOL.@]
1997 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1999 UNICODE_STRING pNameW
;
2001 PRINTER_INFO_2W
*piW
;
2002 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2005 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2007 ERR("Level = %ld, unsupported!\n", Level
);
2008 SetLastError(ERROR_INVALID_LEVEL
);
2011 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2012 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2014 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2016 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2017 RtlFreeUnicodeString(&pNameW
);
2022 /*****************************************************************************
2023 * ClosePrinter [WINSPOOL.@]
2025 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2027 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2028 opened_printer_t
*printer
= NULL
;
2031 TRACE("Handle %p\n", hPrinter
);
2033 EnterCriticalSection(&printer_handles_cs
);
2035 if ((i
> 0) && (i
<= nb_printer_handles
))
2036 printer
= printer_handles
[i
- 1];
2040 struct list
*cursor
, *cursor2
;
2043 EndDocPrinter(hPrinter
);
2045 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2047 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2049 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2050 ScheduleJob(hPrinter
, job
->job_id
);
2052 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2054 HeapFree(GetProcessHeap(), 0, printer
->name
);
2055 HeapFree(GetProcessHeap(), 0, printer
);
2056 printer_handles
[i
- 1] = NULL
;
2059 LeaveCriticalSection(&printer_handles_cs
);
2063 /*****************************************************************************
2064 * DeleteFormA [WINSPOOL.@]
2066 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2068 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2072 /*****************************************************************************
2073 * DeleteFormW [WINSPOOL.@]
2075 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2077 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2081 /*****************************************************************************
2082 * WINSPOOL_SHRegDeleteKey
2084 * Recursively delete subkeys.
2085 * Cut & paste from shlwapi.
2088 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
)
2090 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
2091 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
2094 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
2097 /* Find how many subkeys there are */
2098 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
2099 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
2103 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
2104 /* Name too big: alloc a buffer for it */
2105 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
2108 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
2111 /* Recursively delete all the subkeys */
2112 for(i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
2114 dwSize
= dwMaxSubkeyLen
;
2115 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
2117 dwRet
= WINSPOOL_SHDeleteKeyW(hSubKey
, lpszName
);
2120 if (lpszName
!= szNameBuf
)
2121 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
2125 RegCloseKey(hSubKey
);
2127 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
2132 /*****************************************************************************
2133 * DeletePrinter [WINSPOOL.@]
2135 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2137 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2138 HKEY hkeyPrinters
, hkey
;
2141 SetLastError(ERROR_INVALID_HANDLE
);
2144 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2145 WINSPOOL_SHDeleteKeyW(hkeyPrinters
, lpNameW
);
2146 RegCloseKey(hkeyPrinters
);
2148 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2149 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2150 RegDeleteValueW(hkey
, lpNameW
);
2156 /*****************************************************************************
2157 * SetPrinterA [WINSPOOL.@]
2159 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2162 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2166 /*****************************************************************************
2167 * SetJobA [WINSPOOL.@]
2169 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2170 LPBYTE pJob
, DWORD Command
)
2174 UNICODE_STRING usBuffer
;
2176 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2178 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2179 are all ignored by SetJob, so we don't bother copying them */
2187 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2188 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2190 JobW
= (LPBYTE
)info1W
;
2191 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2192 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2193 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2194 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2195 info1W
->Status
= info1A
->Status
;
2196 info1W
->Priority
= info1A
->Priority
;
2197 info1W
->Position
= info1A
->Position
;
2198 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2203 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2204 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2206 JobW
= (LPBYTE
)info2W
;
2207 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2208 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2209 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2210 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2211 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2212 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2213 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2214 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2215 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2216 info2W
->Status
= info2A
->Status
;
2217 info2W
->Priority
= info2A
->Priority
;
2218 info2W
->Position
= info2A
->Position
;
2219 info2W
->StartTime
= info2A
->StartTime
;
2220 info2W
->UntilTime
= info2A
->UntilTime
;
2221 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2225 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2226 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2229 SetLastError(ERROR_INVALID_LEVEL
);
2233 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2239 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2240 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2241 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2242 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2243 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2248 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2249 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2250 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2251 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2252 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2253 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2254 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2255 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2256 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2260 HeapFree(GetProcessHeap(), 0, JobW
);
2265 /*****************************************************************************
2266 * SetJobW [WINSPOOL.@]
2268 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2269 LPBYTE pJob
, DWORD Command
)
2274 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2275 FIXME("Ignoring everything other than document title\n");
2277 EnterCriticalSection(&printer_handles_cs
);
2278 job
= get_job(hPrinter
, JobId
);
2288 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2289 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2290 job
->document_title
= strdupW(info1
->pDocument
);
2295 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2296 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2297 job
->document_title
= strdupW(info2
->pDocument
);
2303 SetLastError(ERROR_INVALID_LEVEL
);
2308 LeaveCriticalSection(&printer_handles_cs
);
2312 /*****************************************************************************
2313 * EndDocPrinter [WINSPOOL.@]
2315 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2317 opened_printer_t
*printer
;
2319 TRACE("(%p)\n", hPrinter
);
2321 EnterCriticalSection(&printer_handles_cs
);
2323 printer
= get_opened_printer(hPrinter
);
2326 SetLastError(ERROR_INVALID_HANDLE
);
2332 SetLastError(ERROR_SPL_NO_STARTDOC
);
2336 CloseHandle(printer
->doc
->hf
);
2337 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2338 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2339 printer
->doc
= NULL
;
2342 LeaveCriticalSection(&printer_handles_cs
);
2346 /*****************************************************************************
2347 * EndPagePrinter [WINSPOOL.@]
2349 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2351 FIXME("(%p): stub\n", hPrinter
);
2355 /*****************************************************************************
2356 * StartDocPrinterA [WINSPOOL.@]
2358 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2360 UNICODE_STRING usBuffer
;
2362 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2365 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2366 or one (DOC_INFO_3) extra DWORDs */
2370 doc2W
.JobId
= doc2
->JobId
;
2373 doc2W
.dwMode
= doc2
->dwMode
;
2376 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2377 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2378 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
2382 SetLastError(ERROR_INVALID_LEVEL
);
2386 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
2388 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
2389 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
2390 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
2395 /*****************************************************************************
2396 * StartDocPrinterW [WINSPOOL.@]
2398 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2400 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
2401 opened_printer_t
*printer
;
2402 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2403 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
2404 JOB_INFO_1W job_info
;
2405 DWORD needed
, ret
= 0;
2409 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2410 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
2411 debugstr_w(doc
->pDatatype
));
2413 if(Level
< 1 || Level
> 3)
2415 SetLastError(ERROR_INVALID_LEVEL
);
2419 EnterCriticalSection(&printer_handles_cs
);
2420 printer
= get_opened_printer(hPrinter
);
2423 SetLastError(ERROR_INVALID_HANDLE
);
2429 SetLastError(ERROR_INVALID_PRINTER_STATE
);
2433 /* Even if we're printing to a file we still add a print job, we'll
2434 just ignore the spool file name */
2436 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
2438 ERR("AddJob failed gle %08lx\n", GetLastError());
2442 if(doc
->pOutputFile
)
2443 filename
= doc
->pOutputFile
;
2445 filename
= addjob
->Path
;
2447 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
2448 if(hf
== INVALID_HANDLE_VALUE
)
2451 memset(&job_info
, 0, sizeof(job_info
));
2452 job_info
.pDocument
= doc
->pDocName
;
2453 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
2455 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
2456 printer
->doc
->hf
= hf
;
2457 ret
= printer
->doc
->job_id
= addjob
->JobId
;
2459 LeaveCriticalSection(&printer_handles_cs
);
2464 /*****************************************************************************
2465 * StartPagePrinter [WINSPOOL.@]
2467 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
2469 FIXME("(%p): stub\n", hPrinter
);
2473 /*****************************************************************************
2474 * GetFormA [WINSPOOL.@]
2476 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2477 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2479 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,pFormName
,
2480 Level
,pForm
,cbBuf
,pcbNeeded
);
2484 /*****************************************************************************
2485 * GetFormW [WINSPOOL.@]
2487 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2488 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2490 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,
2491 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
2495 /*****************************************************************************
2496 * SetFormA [WINSPOOL.@]
2498 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2501 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2505 /*****************************************************************************
2506 * SetFormW [WINSPOOL.@]
2508 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2511 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2515 /*****************************************************************************
2516 * ReadPrinter [WINSPOOL.@]
2518 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
2519 LPDWORD pNoBytesRead
)
2521 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
2525 /*****************************************************************************
2526 * ResetPrinterA [WINSPOOL.@]
2528 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
2530 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2534 /*****************************************************************************
2535 * ResetPrinterW [WINSPOOL.@]
2537 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2539 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2543 /*****************************************************************************
2544 * WINSPOOL_GetDWORDFromReg
2546 * Return DWORD associated with ValueName from hkey.
2548 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
2550 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
2553 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
2555 if(ret
!= ERROR_SUCCESS
) {
2556 WARN("Got ret = %ld on name %s\n", ret
, ValueName
);
2559 if(type
!= REG_DWORD
) {
2560 ERR("Got type %ld\n", type
);
2566 /*****************************************************************************
2567 * WINSPOOL_GetStringFromReg
2569 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2570 * String is stored either as unicode or ascii.
2571 * Bit of a hack here to get the ValueName if we want ascii.
2573 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
2574 DWORD buflen
, DWORD
*needed
,
2577 DWORD sz
= buflen
, type
;
2581 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2583 LPSTR ValueNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,ValueName
);
2584 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
2585 HeapFree(GetProcessHeap(),0,ValueNameA
);
2587 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
2588 WARN("Got ret = %ld\n", ret
);
2596 /*****************************************************************************
2597 * WINSPOOL_GetDefaultDevMode
2599 * Get a default DevMode values for wineps.
2603 static void WINSPOOL_GetDefaultDevMode(
2605 DWORD buflen
, DWORD
*needed
,
2609 static const char szwps
[] = "wineps.drv";
2611 /* fill default DEVMODE - should be read from ppd... */
2612 ZeroMemory( &dm
, sizeof(dm
) );
2613 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
2614 dm
.dmSpecVersion
= DM_SPECVERSION
;
2615 dm
.dmDriverVersion
= 1;
2616 dm
.dmSize
= sizeof(DEVMODEA
);
2617 dm
.dmDriverExtra
= 0;
2619 DM_ORIENTATION
| DM_PAPERSIZE
|
2620 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
2623 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
2624 DM_YRESOLUTION
| DM_TTOPTION
;
2626 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
2627 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
2628 dm
.u1
.s1
.dmPaperLength
= 2970;
2629 dm
.u1
.s1
.dmPaperWidth
= 2100;
2633 dm
.dmDefaultSource
= DMBIN_AUTO
;
2634 dm
.dmPrintQuality
= DMRES_MEDIUM
;
2637 dm
.dmYResolution
= 300; /* 300dpi */
2638 dm
.dmTTOption
= DMTT_BITMAP
;
2641 /* dm.dmLogPixels */
2642 /* dm.dmBitsPerPel */
2643 /* dm.dmPelsWidth */
2644 /* dm.dmPelsHeight */
2645 /* dm.dmDisplayFlags */
2646 /* dm.dmDisplayFrequency */
2647 /* dm.dmICMMethod */
2648 /* dm.dmICMIntent */
2649 /* dm.dmMediaType */
2650 /* dm.dmDitherType */
2651 /* dm.dmReserved1 */
2652 /* dm.dmReserved2 */
2653 /* dm.dmPanningWidth */
2654 /* dm.dmPanningHeight */
2657 if(buflen
>= sizeof(DEVMODEW
)) {
2658 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
2659 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
2660 HeapFree(GetProcessHeap(),0,pdmW
);
2662 *needed
= sizeof(DEVMODEW
);
2666 if(buflen
>= sizeof(DEVMODEA
)) {
2667 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
2669 *needed
= sizeof(DEVMODEA
);
2673 /*****************************************************************************
2674 * WINSPOOL_GetDevModeFromReg
2676 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2677 * DevMode is stored either as unicode or ascii.
2679 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
2681 DWORD buflen
, DWORD
*needed
,
2684 DWORD sz
= buflen
, type
;
2687 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
2688 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2689 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
2690 if (sz
< sizeof(DEVMODEA
))
2692 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName
),sz
);
2695 /* ensures that dmSize is not erratically bogus if registry is invalid */
2696 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
2697 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
2699 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2701 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
2702 memcpy(ptr
, dmW
, sz
);
2703 HeapFree(GetProcessHeap(),0,dmW
);
2710 /*********************************************************************
2711 * WINSPOOL_GetPrinter_2
2713 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2714 * The strings are either stored as unicode or ascii.
2716 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
2717 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2720 DWORD size
, left
= cbBuf
;
2721 BOOL space
= (cbBuf
> 0);
2726 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2728 if(space
&& size
<= left
) {
2729 pi2
->pPrinterName
= (LPWSTR
)ptr
;
2736 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
2738 if(space
&& size
<= left
) {
2739 pi2
->pShareName
= (LPWSTR
)ptr
;
2746 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2748 if(space
&& size
<= left
) {
2749 pi2
->pPortName
= (LPWSTR
)ptr
;
2756 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
2758 if(space
&& size
<= left
) {
2759 pi2
->pDriverName
= (LPWSTR
)ptr
;
2766 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
2768 if(space
&& size
<= left
) {
2769 pi2
->pComment
= (LPWSTR
)ptr
;
2776 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
2778 if(space
&& size
<= left
) {
2779 pi2
->pLocation
= (LPWSTR
)ptr
;
2786 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
2788 if(space
&& size
<= left
) {
2789 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2798 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
2799 if(space
&& size
<= left
) {
2800 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2807 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
2809 if(space
&& size
<= left
) {
2810 pi2
->pSepFile
= (LPWSTR
)ptr
;
2817 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
2819 if(space
&& size
<= left
) {
2820 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
2827 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
2829 if(space
&& size
<= left
) {
2830 pi2
->pDatatype
= (LPWSTR
)ptr
;
2837 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
2839 if(space
&& size
<= left
) {
2840 pi2
->pParameters
= (LPWSTR
)ptr
;
2848 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2849 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
2850 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2851 "Default Priority");
2852 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
2853 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
2856 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
2857 memset(pi2
, 0, sizeof(*pi2
));
2862 /*********************************************************************
2863 * WINSPOOL_GetPrinter_4
2865 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2867 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
2868 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2871 DWORD size
, left
= cbBuf
;
2872 BOOL space
= (cbBuf
> 0);
2877 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2879 if(space
&& size
<= left
) {
2880 pi4
->pPrinterName
= (LPWSTR
)ptr
;
2888 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2891 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
2892 memset(pi4
, 0, sizeof(*pi4
));
2897 /*********************************************************************
2898 * WINSPOOL_GetPrinter_5
2900 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2902 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
2903 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2906 DWORD size
, left
= cbBuf
;
2907 BOOL space
= (cbBuf
> 0);
2912 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2914 if(space
&& size
<= left
) {
2915 pi5
->pPrinterName
= (LPWSTR
)ptr
;
2922 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2924 if(space
&& size
<= left
) {
2925 pi5
->pPortName
= (LPWSTR
)ptr
;
2933 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2934 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2936 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2940 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
2941 memset(pi5
, 0, sizeof(*pi5
));
2946 /*****************************************************************************
2947 * WINSPOOL_GetPrinter
2949 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2950 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2951 * just a collection of pointers to strings.
2953 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2954 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
2957 DWORD size
, needed
= 0;
2959 HKEY hkeyPrinter
, hkeyPrinters
;
2962 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
2964 if (!(name
= get_opened_printer_name(hPrinter
))) {
2965 SetLastError(ERROR_INVALID_HANDLE
);
2969 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2971 ERR("Can't create Printers key\n");
2974 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
2976 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
2977 RegCloseKey(hkeyPrinters
);
2978 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
2985 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
2987 size
= sizeof(PRINTER_INFO_2W
);
2989 ptr
= pPrinter
+ size
;
2991 memset(pPrinter
, 0, size
);
2996 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
3004 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3006 size
= sizeof(PRINTER_INFO_4W
);
3008 ptr
= pPrinter
+ size
;
3010 memset(pPrinter
, 0, size
);
3015 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
3024 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3026 size
= sizeof(PRINTER_INFO_5W
);
3028 ptr
= pPrinter
+ size
;
3030 memset(pPrinter
, 0, size
);
3036 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
3043 FIXME("Unimplemented level %ld\n", Level
);
3044 SetLastError(ERROR_INVALID_LEVEL
);
3045 RegCloseKey(hkeyPrinters
);
3046 RegCloseKey(hkeyPrinter
);
3050 RegCloseKey(hkeyPrinter
);
3051 RegCloseKey(hkeyPrinters
);
3053 TRACE("returning %d needed = %ld\n", ret
, needed
);
3054 if(pcbNeeded
) *pcbNeeded
= needed
;
3056 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3060 /*****************************************************************************
3061 * GetPrinterW [WINSPOOL.@]
3063 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3064 DWORD cbBuf
, LPDWORD pcbNeeded
)
3066 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3070 /*****************************************************************************
3071 * GetPrinterA [WINSPOOL.@]
3073 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3074 DWORD cbBuf
, LPDWORD pcbNeeded
)
3076 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3080 /*****************************************************************************
3081 * WINSPOOL_EnumPrinters
3083 * Implementation of EnumPrintersA|W
3085 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
3086 DWORD dwLevel
, LPBYTE lpbPrinters
,
3087 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3088 LPDWORD lpdwReturned
, BOOL unicode
)
3091 HKEY hkeyPrinters
, hkeyPrinter
;
3092 WCHAR PrinterName
[255];
3093 DWORD needed
= 0, number
= 0;
3094 DWORD used
, i
, left
;
3098 memset(lpbPrinters
, 0, cbBuf
);
3104 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3105 if(dwType
== PRINTER_ENUM_DEFAULT
)
3108 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
3109 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3110 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
3111 if(!dwType
) return TRUE
;
3114 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
3115 FIXME("dwType = %08lx\n", dwType
);
3116 SetLastError(ERROR_INVALID_FLAGS
);
3120 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
3122 ERR("Can't create Printers key\n");
3126 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3127 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3128 RegCloseKey(hkeyPrinters
);
3129 ERR("Can't query Printers key\n");
3132 TRACE("Found %ld printers\n", number
);
3136 RegCloseKey(hkeyPrinters
);
3138 *lpdwReturned
= number
;
3142 used
= number
* sizeof(PRINTER_INFO_2W
);
3145 used
= number
* sizeof(PRINTER_INFO_4W
);
3148 used
= number
* sizeof(PRINTER_INFO_5W
);
3152 SetLastError(ERROR_INVALID_LEVEL
);
3153 RegCloseKey(hkeyPrinters
);
3156 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
3158 for(i
= 0; i
< number
; i
++) {
3159 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
3161 ERR("Can't enum key number %ld\n", i
);
3162 RegCloseKey(hkeyPrinters
);
3165 TRACE("Printer %ld is %s\n", i
, debugstr_w(PrinterName
));
3166 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
3168 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
3169 RegCloseKey(hkeyPrinters
);
3174 buf
= lpbPrinters
+ used
;
3175 left
= cbBuf
- used
;
3183 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
3184 left
, &needed
, unicode
);
3186 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
3189 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
3190 left
, &needed
, unicode
);
3192 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
3195 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
3196 left
, &needed
, unicode
);
3198 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
3201 ERR("Shouldn't be here!\n");
3202 RegCloseKey(hkeyPrinter
);
3203 RegCloseKey(hkeyPrinters
);
3206 RegCloseKey(hkeyPrinter
);
3208 RegCloseKey(hkeyPrinters
);
3215 memset(lpbPrinters
, 0, cbBuf
);
3216 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3220 *lpdwReturned
= number
;
3221 SetLastError(ERROR_SUCCESS
);
3226 /******************************************************************
3227 * EnumPrintersW [WINSPOOL.@]
3229 * Enumerates the available printers, print servers and print
3230 * providers, depending on the specified flags, name and level.
3234 * If level is set to 1:
3235 * Not implemented yet!
3236 * Returns TRUE with an empty list.
3238 * If level is set to 2:
3239 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3240 * Returns an array of PRINTER_INFO_2 data structures in the
3241 * lpbPrinters buffer. Note that according to MSDN also an
3242 * OpenPrinter should be performed on every remote printer.
3244 * If level is set to 4 (officially WinNT only):
3245 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3246 * Fast: Only the registry is queried to retrieve printer names,
3247 * no connection to the driver is made.
3248 * Returns an array of PRINTER_INFO_4 data structures in the
3249 * lpbPrinters buffer.
3251 * If level is set to 5 (officially WinNT4/Win9x only):
3252 * Fast: Only the registry is queried to retrieve printer names,
3253 * no connection to the driver is made.
3254 * Returns an array of PRINTER_INFO_5 data structures in the
3255 * lpbPrinters buffer.
3257 * If level set to 3 or 6+:
3258 * returns zero (failure!)
3260 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3264 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3265 * - Only levels 2, 4 and 5 are implemented at the moment.
3266 * - 16-bit printer drivers are not enumerated.
3267 * - Returned amount of bytes used/needed does not match the real Windoze
3268 * implementation (as in this implementation, all strings are part
3269 * of the buffer, whereas Win32 keeps them somewhere else)
3270 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3273 * - In a regular Wine installation, no registry settings for printers
3274 * exist, which makes this function return an empty list.
3276 BOOL WINAPI
EnumPrintersW(
3277 DWORD dwType
, /* [in] Types of print objects to enumerate */
3278 LPWSTR lpszName
, /* [in] name of objects to enumerate */
3279 DWORD dwLevel
, /* [in] type of printer info structure */
3280 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
3281 DWORD cbBuf
, /* [in] max size of buffer in bytes */
3282 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
3283 LPDWORD lpdwReturned
/* [out] number of entries returned */
3286 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
3287 lpdwNeeded
, lpdwReturned
, TRUE
);
3290 /******************************************************************
3291 * EnumPrintersA [WINSPOOL.@]
3294 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
3295 DWORD dwLevel
, LPBYTE lpbPrinters
,
3296 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3297 LPDWORD lpdwReturned
)
3300 UNICODE_STRING lpszNameW
;
3303 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
3304 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
3305 lpdwNeeded
, lpdwReturned
, FALSE
);
3306 RtlFreeUnicodeString(&lpszNameW
);
3310 /*****************************************************************************
3311 * WINSPOOL_GetDriverInfoFromReg [internal]
3313 * Enters the information from the registry into the DRIVER_INFO struct
3316 * zero if the printer driver does not exist in the registry
3317 * (only if Level > 1) otherwise nonzero
3319 static BOOL
WINSPOOL_GetDriverInfoFromReg(
3322 LPWSTR pEnvironment
,
3324 LPBYTE ptr
, /* DRIVER_INFO */
3325 LPBYTE pDriverStrings
, /* strings buffer */
3326 DWORD cbBuf
, /* size of string buffer */
3327 LPDWORD pcbNeeded
, /* space needed for str. */
3328 BOOL unicode
) /* type of strings */
3329 { DWORD dw
, size
, tmp
, type
;
3331 LPBYTE strPtr
= pDriverStrings
;
3333 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3334 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
3335 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
3338 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
3339 if (*pcbNeeded
<= cbBuf
)
3340 strcpyW((LPWSTR
)strPtr
, DriverName
);
3342 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
3344 if(*pcbNeeded
<= cbBuf
)
3345 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1,
3346 (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
3350 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
3354 ((PDRIVER_INFO_3W
) ptr
)->pName
= (LPWSTR
) strPtr
;
3355 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3358 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
3359 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName
));
3360 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
3365 if(RegQueryValueExA(hkeyDriver
, "Version", 0, &type
, (PBYTE
)&dw
, &size
) !=
3367 WARN("Can't get Version\n");
3369 ((PDRIVER_INFO_3A
) ptr
)->cVersion
= dw
;
3372 pEnvironment
= (LPWSTR
)DefaultEnvironmentW
;
3374 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
3376 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
3379 if(*pcbNeeded
<= cbBuf
) {
3381 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
3383 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1,
3384 (LPSTR
)strPtr
, size
, NULL
, NULL
);
3386 ((PDRIVER_INFO_3W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
3387 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3390 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
3393 if(*pcbNeeded
<= cbBuf
)
3394 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
3397 ((PDRIVER_INFO_3W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
3398 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
3401 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
3404 if(*pcbNeeded
<= cbBuf
)
3405 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
3408 ((PDRIVER_INFO_3W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
3409 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3412 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3413 0, &size
, unicode
)) {
3415 if(*pcbNeeded
<= cbBuf
)
3416 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
3417 size
, &tmp
, unicode
);
3419 ((PDRIVER_INFO_3W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
3420 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3424 RegCloseKey(hkeyDriver
);
3425 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3429 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
3432 if(*pcbNeeded
<= cbBuf
)
3433 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
3434 size
, &tmp
, unicode
);
3436 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
3437 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3440 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
3443 if(*pcbNeeded
<= cbBuf
)
3444 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
3445 size
, &tmp
, unicode
);
3447 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
3448 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3451 if(WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
3454 if(*pcbNeeded
<= cbBuf
)
3455 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
3456 size
, &tmp
, unicode
);
3458 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
3459 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3462 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
3465 if(*pcbNeeded
<= cbBuf
)
3466 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
,
3467 size
, &tmp
, unicode
);
3469 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
3470 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
3473 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
3474 RegCloseKey(hkeyDriver
);
3478 /*****************************************************************************
3479 * WINSPOOL_GetPrinterDriver
3481 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
3482 DWORD Level
, LPBYTE pDriverInfo
,
3483 DWORD cbBuf
, LPDWORD pcbNeeded
,
3487 WCHAR DriverName
[100];
3488 DWORD ret
, type
, size
, needed
= 0;
3490 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
3492 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
3493 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
3495 ZeroMemory(pDriverInfo
, cbBuf
);
3497 if (!(name
= get_opened_printer_name(hPrinter
))) {
3498 SetLastError(ERROR_INVALID_HANDLE
);
3501 if(Level
< 1 || Level
> 3) {
3502 SetLastError(ERROR_INVALID_LEVEL
);
3505 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
3507 ERR("Can't create Printers key\n");
3510 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
3512 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3513 RegCloseKey(hkeyPrinters
);
3514 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3517 size
= sizeof(DriverName
);
3519 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
3520 (LPBYTE
)DriverName
, &size
);
3521 RegCloseKey(hkeyPrinter
);
3522 RegCloseKey(hkeyPrinters
);
3523 if(ret
!= ERROR_SUCCESS
) {
3524 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
3528 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
3530 ERR("Can't create Drivers key\n");
3536 size
= sizeof(DRIVER_INFO_1W
);
3539 size
= sizeof(DRIVER_INFO_2W
);
3542 size
= sizeof(DRIVER_INFO_3W
);
3545 ERR("Invalid level\n");
3550 ptr
= pDriverInfo
+ size
;
3552 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
3553 pEnvironment
, Level
, pDriverInfo
,
3554 (cbBuf
< size
) ? NULL
: ptr
,
3555 (cbBuf
< size
) ? 0 : cbBuf
- size
,
3556 &needed
, unicode
)) {
3557 RegCloseKey(hkeyDrivers
);
3561 RegCloseKey(hkeyDrivers
);
3563 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
3564 TRACE("buffer space %ld required %ld\n", cbBuf
, size
+ needed
);
3565 if(cbBuf
>= needed
) return TRUE
;
3566 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3570 /*****************************************************************************
3571 * GetPrinterDriverA [WINSPOOL.@]
3573 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
3574 DWORD Level
, LPBYTE pDriverInfo
,
3575 DWORD cbBuf
, LPDWORD pcbNeeded
)
3578 UNICODE_STRING pEnvW
;
3581 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
3582 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
3583 cbBuf
, pcbNeeded
, FALSE
);
3584 RtlFreeUnicodeString(&pEnvW
);
3587 /*****************************************************************************
3588 * GetPrinterDriverW [WINSPOOL.@]
3590 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
3591 DWORD Level
, LPBYTE pDriverInfo
,
3592 DWORD cbBuf
, LPDWORD pcbNeeded
)
3594 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
3595 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
3598 /*****************************************************************************
3599 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3601 * Return the PATH for the Printer-Drivers (UNICODE)
3604 * pName [I] Servername (NT only) or NULL (local Computer)
3605 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3606 * Level [I] Structure-Level (must be 1)
3607 * pDriverDirectory [O] PTR to Buffer that receives the Result
3608 * cbBuf [I] Size of Buffer at pDriverDirectory
3609 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3610 * required for pDriverDirectory
3613 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3614 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3615 * if cbBuf is too small
3617 * Native Values returned in pDriverDirectory on Success:
3618 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3619 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3620 *| win9x(Windows 4.0): "%winsysdir%"
3622 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3625 *- Only NULL or "" is supported for pName
3628 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
3629 DWORD Level
, LPBYTE pDriverDirectory
,
3630 DWORD cbBuf
, LPDWORD pcbNeeded
)
3633 const printenv_t
* env
;
3635 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
3636 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
3637 if(pName
!= NULL
&& pName
[0]) {
3638 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
3639 SetLastError(ERROR_INVALID_PARAMETER
);
3643 env
= validate_envW(pEnvironment
);
3644 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
3647 WARN("(Level: %ld) is ignored in win9x\n", Level
);
3648 SetLastError(ERROR_INVALID_LEVEL
);
3652 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3653 needed
= GetSystemDirectoryW(NULL
, 0);
3654 /* add the Size for the Subdirectories */
3655 needed
+= lstrlenW(spooldriversW
);
3656 needed
+= lstrlenW(env
->subdir
);
3657 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
3660 *pcbNeeded
= needed
;
3661 TRACE("required: 0x%lx/%ld\n", needed
, needed
);
3662 if(needed
> cbBuf
) {
3663 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3666 if(pcbNeeded
== NULL
) {
3667 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3668 SetLastError(RPC_X_NULL_REF_POINTER
);
3671 if(pDriverDirectory
== NULL
) {
3672 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3673 SetLastError(ERROR_INVALID_USER_BUFFER
);
3677 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
3678 /* add the Subdirectories */
3679 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
3680 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
3681 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
3686 /*****************************************************************************
3687 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3689 * Return the PATH for the Printer-Drivers (ANSI)
3691 * See GetPrinterDriverDirectoryW.
3694 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3697 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
3698 DWORD Level
, LPBYTE pDriverDirectory
,
3699 DWORD cbBuf
, LPDWORD pcbNeeded
)
3701 UNICODE_STRING nameW
, environmentW
;
3704 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
3705 WCHAR
*driverDirectoryW
= NULL
;
3707 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName
),
3708 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
3710 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
3712 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
3713 else nameW
.Buffer
= NULL
;
3714 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
3715 else environmentW
.Buffer
= NULL
;
3717 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
3718 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
3721 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
3722 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
3724 *pcbNeeded
= needed
;
3725 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
3727 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
3729 TRACE("required: 0x%lx/%ld\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3731 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
3732 RtlFreeUnicodeString(&environmentW
);
3733 RtlFreeUnicodeString(&nameW
);
3738 /*****************************************************************************
3739 * AddPrinterDriverA [WINSPOOL.@]
3741 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
3744 HKEY hkeyDrivers
, hkeyName
;
3746 TRACE("(%s,%ld,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
3748 if(level
!= 2 && level
!= 3) {
3749 SetLastError(ERROR_INVALID_LEVEL
);
3753 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
3754 SetLastError(ERROR_INVALID_PARAMETER
);
3758 WARN("pDriverInfo == NULL\n");
3759 SetLastError(ERROR_INVALID_PARAMETER
);
3764 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
3766 memset(&di3
, 0, sizeof(di3
));
3767 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
3770 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
3772 SetLastError(ERROR_INVALID_PARAMETER
);
3775 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= "";
3776 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= "\0";
3777 if(!di3
.pHelpFile
) di3
.pHelpFile
= "";
3778 if(!di3
.pMonitorName
) di3
.pMonitorName
= "";
3780 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
3783 ERR("Can't create Drivers key\n");
3787 if(level
== 2) { /* apparently can't overwrite with level2 */
3788 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
3789 RegCloseKey(hkeyName
);
3790 RegCloseKey(hkeyDrivers
);
3791 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
3792 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
3796 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
3797 RegCloseKey(hkeyDrivers
);
3798 ERR("Can't create Name key\n");
3801 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
3803 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, 0);
3804 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, 0);
3805 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
3807 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, 0);
3808 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
3809 (LPBYTE
) di3
.pDependentFiles
, 0);
3810 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, 0);
3811 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, 0);
3812 RegCloseKey(hkeyName
);
3813 RegCloseKey(hkeyDrivers
);
3818 /*****************************************************************************
3819 * AddPrinterDriverW [WINSPOOL.@]
3821 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
3824 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName
),
3829 /*****************************************************************************
3830 * AddPrintProcessorA [WINSPOOL.@]
3832 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
3833 LPSTR pPrintProcessorName
)
3835 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
3836 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
3840 /*****************************************************************************
3841 * AddPrintProcessorW [WINSPOOL.@]
3843 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
3844 LPWSTR pPrintProcessorName
)
3846 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
3847 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
3851 /*****************************************************************************
3852 * AddPrintProvidorA [WINSPOOL.@]
3854 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3856 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
3860 /*****************************************************************************
3861 * AddPrintProvidorW [WINSPOOL.@]
3863 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3865 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
3869 /*****************************************************************************
3870 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3872 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
3873 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
3875 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
3876 pDevModeOutput
, pDevModeInput
);
3880 /*****************************************************************************
3881 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3883 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
3884 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
3886 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
3887 pDevModeOutput
, pDevModeInput
);
3891 /*****************************************************************************
3892 * PrinterProperties [WINSPOOL.@]
3894 * Displays a dialog to set the properties of the printer.
3897 * nonzero on success or zero on failure
3900 * implemented as stub only
3902 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
3903 HANDLE hPrinter
/* [in] handle to printer object */
3905 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
3906 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3910 /*****************************************************************************
3911 * EnumJobsA [WINSPOOL.@]
3914 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3915 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3918 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3919 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3921 if(pcbNeeded
) *pcbNeeded
= 0;
3922 if(pcReturned
) *pcReturned
= 0;
3927 /*****************************************************************************
3928 * EnumJobsW [WINSPOOL.@]
3931 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3932 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3935 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3936 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3938 if(pcbNeeded
) *pcbNeeded
= 0;
3939 if(pcReturned
) *pcReturned
= 0;
3943 /*****************************************************************************
3944 * WINSPOOL_EnumPrinterDrivers [internal]
3946 * Delivers information about all printer drivers installed on the
3947 * localhost or a given server
3950 * nonzero on success or zero on failure. If the buffer for the returned
3951 * information is too small the function will return an error
3954 * - only implemented for localhost, foreign hosts will return an error
3956 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPWSTR pEnvironment
,
3957 DWORD Level
, LPBYTE pDriverInfo
,
3958 DWORD cbBuf
, LPDWORD pcbNeeded
,
3959 LPDWORD pcReturned
, BOOL unicode
)
3962 DWORD i
, needed
, number
= 0, size
= 0;
3963 WCHAR DriverNameW
[255];
3966 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3967 debugstr_w(pName
), debugstr_w(pEnvironment
),
3968 Level
, pDriverInfo
, cbBuf
, unicode
);
3970 /* check for local drivers */
3972 ERR("remote drivers unsupported! Current remote host is %s\n",
3977 /* check input parameter */
3978 if((Level
< 1) || (Level
> 3)) {
3979 ERR("unsupported level %ld\n", Level
);
3980 SetLastError(ERROR_INVALID_LEVEL
);
3984 /* initialize return values */
3986 memset( pDriverInfo
, 0, cbBuf
);
3990 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
3992 ERR("Can't open Drivers key\n");
3996 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3997 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3998 RegCloseKey(hkeyDrivers
);
3999 ERR("Can't query Drivers key\n");
4002 TRACE("Found %ld Drivers\n", number
);
4004 /* get size of single struct
4005 * unicode and ascii structure have the same size
4009 size
= sizeof(DRIVER_INFO_1A
);
4012 size
= sizeof(DRIVER_INFO_2A
);
4015 size
= sizeof(DRIVER_INFO_3A
);
4019 /* calculate required buffer size */
4020 *pcbNeeded
= size
* number
;
4022 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
4024 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
4025 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
4027 ERR("Can't enum key number %ld\n", i
);
4028 RegCloseKey(hkeyDrivers
);
4031 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4032 pEnvironment
, Level
, ptr
,
4033 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
4034 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4035 &needed
, unicode
)) {
4036 RegCloseKey(hkeyDrivers
);
4039 (*pcbNeeded
) += needed
;
4042 RegCloseKey(hkeyDrivers
);
4044 if(cbBuf
< *pcbNeeded
){
4045 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4049 *pcReturned
= number
;
4053 /*****************************************************************************
4054 * EnumPrinterDriversW [WINSPOOL.@]
4056 * see function EnumPrinterDrivers for RETURNS, BUGS
4058 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4059 LPBYTE pDriverInfo
, DWORD cbBuf
,
4060 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4062 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4063 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
4066 /*****************************************************************************
4067 * EnumPrinterDriversA [WINSPOOL.@]
4069 * see function EnumPrinterDrivers for RETURNS, BUGS
4071 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4072 LPBYTE pDriverInfo
, DWORD cbBuf
,
4073 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4075 UNICODE_STRING pNameW
, pEnvironmentW
;
4076 PWSTR pwstrNameW
, pwstrEnvironmentW
;
4078 pwstrNameW
= asciitounicode(&pNameW
, pName
);
4079 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
4081 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
4082 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
4084 RtlFreeUnicodeString(&pNameW
);
4085 RtlFreeUnicodeString(&pEnvironmentW
);
4090 static CHAR PortMonitor
[] = "Wine Port Monitor";
4091 static CHAR PortDescription
[] = "Wine Port";
4093 static BOOL
WINSPOOL_ComPortExists( LPCSTR name
)
4097 handle
= CreateFileA( name
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
4098 NULL
, OPEN_EXISTING
, 0, NULL
);
4099 if (handle
== INVALID_HANDLE_VALUE
)
4101 TRACE("Checking %s exists\n", name
);
4102 CloseHandle( handle
);
4106 static DWORD
WINSPOOL_CountSerialPorts(void)
4113 strcpy( name
, "COMx:" );
4115 if (WINSPOOL_ComPortExists( name
))
4122 /******************************************************************************
4123 * EnumPortsA (WINSPOOL.@)
4128 * ANSI-Version did not call the UNICODE-Version
4131 BOOL WINAPI
EnumPortsA(LPSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
4132 LPDWORD bufneeded
,LPDWORD bufreturned
)
4135 DWORD info_size
, ofs
, i
, printer_count
, serial_count
, count
, n
, r
;
4136 const LPCSTR szPrinterPortKey
= "Software\\Wine\\Wine\\Config\\spooler";
4140 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4141 debugstr_a(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
4146 info_size
= sizeof (PORT_INFO_1A
);
4149 info_size
= sizeof (PORT_INFO_2A
);
4152 SetLastError(ERROR_INVALID_LEVEL
);
4156 /* see how many exist */
4159 serial_count
= WINSPOOL_CountSerialPorts();
4162 r
= RegOpenKeyA( HKEY_LOCAL_MACHINE
, szPrinterPortKey
, &hkey_printer
);
4163 if ( r
== ERROR_SUCCESS
)
4165 RegQueryInfoKeyA( hkey_printer
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4166 &printer_count
, NULL
, NULL
, NULL
, NULL
);
4168 count
= serial_count
+ printer_count
;
4170 /* then fill in the structure info structure once
4171 we know the offset to the first string */
4173 memset( buffer
, 0, bufsize
);
4175 ofs
= info_size
*count
;
4176 for ( i
=0; i
<count
; i
++)
4178 DWORD vallen
= sizeof(portname
) - 1;
4180 /* get the serial port values, then the printer values */
4181 if ( i
< serial_count
)
4183 strcpy( portname
, "COMx:" );
4184 portname
[3] = '1' + i
;
4185 if (!WINSPOOL_ComPortExists( portname
))
4188 TRACE("Found %s\n", portname
);
4189 vallen
= strlen( portname
);
4193 r
= RegEnumValueA( hkey_printer
, i
-serial_count
,
4194 portname
, &vallen
, NULL
, NULL
, NULL
, 0 );
4199 /* add a colon if necessary, and make it upper case */
4200 CharUpperBuffA(portname
,vallen
);
4201 if (strcasecmp(portname
,"nul")!=0)
4202 if (vallen
&& (portname
[vallen
-1] != ':') )
4203 lstrcatA(portname
,":");
4205 /* add the port info structure if we can fit it */
4206 if ( info_size
*(n
+1) < bufsize
)
4210 PORT_INFO_1A
*info
= (PORT_INFO_1A
*) &buffer
[info_size
*n
];
4211 info
->pName
= (LPSTR
) &buffer
[ofs
];
4213 else if ( level
== 2)
4215 PORT_INFO_2A
*info
= (PORT_INFO_2A
*) &buffer
[info_size
*n
];
4216 info
->pPortName
= (LPSTR
) &buffer
[ofs
];
4217 /* FIXME: fill in more stuff here */
4218 info
->pMonitorName
= PortMonitor
;
4219 info
->pDescription
= PortDescription
;
4220 info
->fPortType
= PORT_TYPE_WRITE
|PORT_TYPE_READ
;
4223 /* add the name of the port if we can fit it */
4224 if ( ofs
< bufsize
)
4225 lstrcpynA((LPSTR
)&buffer
[ofs
],portname
,bufsize
- ofs
);
4231 ofs
+= lstrlenA(portname
)+1;
4234 RegCloseKey(hkey_printer
);
4245 /******************************************************************************
4246 * EnumPortsW (WINSPOOL.@)
4248 * Enumerate available Ports
4251 * name [I] Servername or NULL (local Computer)
4252 * level [I] Structure-Level (1 or 2)
4253 * buffer [O] PTR to Buffer that receives the Result
4254 * bufsize [I] Size of Buffer at buffer
4255 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4256 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4260 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4263 * UNICODE-Version is a stub
4266 BOOL WINAPI
EnumPortsW(LPWSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
4267 LPDWORD bufneeded
,LPDWORD bufreturned
)
4269 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4270 debugstr_w(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
4274 /******************************************************************************
4275 * GetDefaultPrinterW (WINSPOOL.@)
4278 * This function must read the value from data 'device' of key
4279 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4281 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
4285 WCHAR
*buffer
, *ptr
;
4289 SetLastError(ERROR_INVALID_PARAMETER
);
4293 /* make the buffer big enough for the stuff from the profile/registry,
4294 * the content must fit into the local buffer to compute the correct
4295 * size even if the extern buffer is too small or not given.
4296 * (20 for ,driver,port) */
4298 len
= max(100, (insize
+ 20));
4299 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4301 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
4303 SetLastError (ERROR_FILE_NOT_FOUND
);
4307 TRACE("%s\n", debugstr_w(buffer
));
4309 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
4311 SetLastError(ERROR_INVALID_NAME
);
4317 *namesize
= strlenW(buffer
) + 1;
4318 if(!name
|| (*namesize
> insize
))
4320 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4324 strcpyW(name
, buffer
);
4327 HeapFree( GetProcessHeap(), 0, buffer
);
4332 /******************************************************************************
4333 * GetDefaultPrinterA (WINSPOOL.@)
4335 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
4339 WCHAR
*bufferW
= NULL
;
4343 SetLastError(ERROR_INVALID_PARAMETER
);
4347 if(name
&& *namesize
) {
4349 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
4352 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
4357 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
4361 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
4364 TRACE("0x%08lx/0x%08lx:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
4367 HeapFree( GetProcessHeap(), 0, bufferW
);
4372 /******************************************************************************
4373 * SetDefaultPrinterW (WINSPOOL.204)
4375 * Set the Name of the Default Printer
4378 * pszPrinter [I] Name of the Printer or NULL
4385 * When the Parameter is NULL or points to an Empty String and
4386 * a Default Printer was already present, then this Function changes nothing.
4387 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4388 * the First enumerated local Printer is used.
4391 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
4394 TRACE("(%s)\n", debugstr_w(pszPrinter
));
4396 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4400 /******************************************************************************
4401 * SetDefaultPrinterA (WINSPOOL.202)
4403 * See SetDefaultPrinterW.
4406 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
4409 TRACE("(%s)\n", debugstr_a(pszPrinter
));
4411 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4416 /******************************************************************************
4417 * SetPrinterDataExA (WINSPOOL.@)
4419 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4420 LPCSTR pValueName
, DWORD Type
,
4421 LPBYTE pData
, DWORD cbData
)
4423 HKEY hkeyPrinter
, hkeySubkey
;
4426 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_a(pKeyName
),
4427 debugstr_a(pValueName
), Type
, pData
, cbData
);
4429 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4433 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4435 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
4436 RegCloseKey(hkeyPrinter
);
4439 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
4440 RegCloseKey(hkeySubkey
);
4441 RegCloseKey(hkeyPrinter
);
4445 /******************************************************************************
4446 * SetPrinterDataExW (WINSPOOL.@)
4448 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4449 LPCWSTR pValueName
, DWORD Type
,
4450 LPBYTE pData
, DWORD cbData
)
4452 HKEY hkeyPrinter
, hkeySubkey
;
4455 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_w(pKeyName
),
4456 debugstr_w(pValueName
), Type
, pData
, cbData
);
4458 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4462 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4464 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
4465 RegCloseKey(hkeyPrinter
);
4468 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
4469 RegCloseKey(hkeySubkey
);
4470 RegCloseKey(hkeyPrinter
);
4474 /******************************************************************************
4475 * SetPrinterDataA (WINSPOOL.@)
4477 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
4478 LPBYTE pData
, DWORD cbData
)
4480 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
4484 /******************************************************************************
4485 * SetPrinterDataW (WINSPOOL.@)
4487 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
4488 LPBYTE pData
, DWORD cbData
)
4490 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
4494 /******************************************************************************
4495 * GetPrinterDataExA (WINSPOOL.@)
4497 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4498 LPCSTR pValueName
, LPDWORD pType
,
4499 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4501 HKEY hkeyPrinter
, hkeySubkey
;
4504 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4505 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
4508 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4512 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4514 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
4515 RegCloseKey(hkeyPrinter
);
4519 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4520 RegCloseKey(hkeySubkey
);
4521 RegCloseKey(hkeyPrinter
);
4525 /******************************************************************************
4526 * GetPrinterDataExW (WINSPOOL.@)
4528 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4529 LPCWSTR pValueName
, LPDWORD pType
,
4530 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4532 HKEY hkeyPrinter
, hkeySubkey
;
4535 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
4536 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
4539 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
4543 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
4545 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
4546 RegCloseKey(hkeyPrinter
);
4550 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
4551 RegCloseKey(hkeySubkey
);
4552 RegCloseKey(hkeyPrinter
);
4556 /******************************************************************************
4557 * GetPrinterDataA (WINSPOOL.@)
4559 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
4560 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4562 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
4563 pData
, nSize
, pcbNeeded
);
4566 /******************************************************************************
4567 * GetPrinterDataW (WINSPOOL.@)
4569 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
4570 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
4572 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
4573 pData
, nSize
, pcbNeeded
);
4576 /*******************************************************************************
4577 * EnumPrinterDataExW [WINSPOOL.@]
4579 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
4580 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4581 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4583 HKEY hkPrinter
, hkSubKey
;
4584 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
4585 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
4590 PPRINTER_ENUM_VALUESW ppev
;
4592 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
4594 if (pKeyName
== NULL
|| *pKeyName
== 0)
4595 return ERROR_INVALID_PARAMETER
;
4597 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
4598 if (ret
!= ERROR_SUCCESS
)
4600 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4605 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
4606 if (ret
!= ERROR_SUCCESS
)
4608 r
= RegCloseKey (hkPrinter
);
4609 if (r
!= ERROR_SUCCESS
)
4610 WARN ("RegCloseKey returned %li\n", r
);
4611 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter
,
4612 debugstr_w (pKeyName
), ret
);
4616 ret
= RegCloseKey (hkPrinter
);
4617 if (ret
!= ERROR_SUCCESS
)
4619 ERR ("RegCloseKey returned %li\n", ret
);
4620 r
= RegCloseKey (hkSubKey
);
4621 if (r
!= ERROR_SUCCESS
)
4622 WARN ("RegCloseKey returned %li\n", r
);
4626 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4627 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
4628 if (ret
!= ERROR_SUCCESS
)
4630 r
= RegCloseKey (hkSubKey
);
4631 if (r
!= ERROR_SUCCESS
)
4632 WARN ("RegCloseKey returned %li\n", r
);
4633 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey
, ret
);
4637 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4638 "cbMaxValueLen = %li\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
4640 if (cValues
== 0) /* empty key */
4642 r
= RegCloseKey (hkSubKey
);
4643 if (r
!= ERROR_SUCCESS
)
4644 WARN ("RegCloseKey returned %li\n", r
);
4645 *pcbEnumValues
= *pnEnumValues
= 0;
4646 return ERROR_SUCCESS
;
4649 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
4651 hHeap
= GetProcessHeap ();
4654 ERR ("GetProcessHeap failed\n");
4655 r
= RegCloseKey (hkSubKey
);
4656 if (r
!= ERROR_SUCCESS
)
4657 WARN ("RegCloseKey returned %li\n", r
);
4658 return ERROR_OUTOFMEMORY
;
4661 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
4662 if (lpValueName
== NULL
)
4664 ERR ("Failed to allocate %li bytes from process heap\n",
4665 cbMaxValueNameLen
* sizeof (WCHAR
));
4666 r
= RegCloseKey (hkSubKey
);
4667 if (r
!= ERROR_SUCCESS
)
4668 WARN ("RegCloseKey returned %li\n", r
);
4669 return ERROR_OUTOFMEMORY
;
4672 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
4673 if (lpValue
== NULL
)
4675 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen
);
4676 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4677 WARN ("HeapFree failed with code %li\n", GetLastError ());
4678 r
= RegCloseKey (hkSubKey
);
4679 if (r
!= ERROR_SUCCESS
)
4680 WARN ("RegCloseKey returned %li\n", r
);
4681 return ERROR_OUTOFMEMORY
;
4684 TRACE ("pass 1: calculating buffer required for all names and values\n");
4686 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4688 TRACE ("%li bytes required for %li headers\n", cbBufSize
, cValues
);
4690 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4692 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4693 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4694 NULL
, NULL
, lpValue
, &cbValueLen
);
4695 if (ret
!= ERROR_SUCCESS
)
4697 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4698 WARN ("HeapFree failed with code %li\n", GetLastError ());
4699 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4700 WARN ("HeapFree failed with code %li\n", GetLastError ());
4701 r
= RegCloseKey (hkSubKey
);
4702 if (r
!= ERROR_SUCCESS
)
4703 WARN ("RegCloseKey returned %li\n", r
);
4704 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4708 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4709 debugstr_w (lpValueName
), dwIndex
,
4710 (cbValueNameLen
+ 1) * sizeof (WCHAR
), cbValueLen
);
4712 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4713 cbBufSize
+= cbValueLen
;
4716 TRACE ("%li bytes required for all %li values\n", cbBufSize
, cValues
);
4718 *pcbEnumValues
= cbBufSize
;
4719 *pnEnumValues
= cValues
;
4721 if (cbEnumValues
< cbBufSize
) /* buffer too small */
4723 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4724 WARN ("HeapFree failed with code %li\n", GetLastError ());
4725 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4726 WARN ("HeapFree failed with code %li\n", GetLastError ());
4727 r
= RegCloseKey (hkSubKey
);
4728 if (r
!= ERROR_SUCCESS
)
4729 WARN ("RegCloseKey returned %li\n", r
);
4730 TRACE ("%li byte buffer is not large enough\n", cbEnumValues
);
4731 return ERROR_MORE_DATA
;
4734 TRACE ("pass 2: copying all names and values to buffer\n");
4736 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
4737 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
4739 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
4741 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
4742 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
4743 NULL
, &dwType
, lpValue
, &cbValueLen
);
4744 if (ret
!= ERROR_SUCCESS
)
4746 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4747 WARN ("HeapFree failed with code %li\n", GetLastError ());
4748 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4749 WARN ("HeapFree failed with code %li\n", GetLastError ());
4750 r
= RegCloseKey (hkSubKey
);
4751 if (r
!= ERROR_SUCCESS
)
4752 WARN ("RegCloseKey returned %li\n", r
);
4753 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
4757 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
4758 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
4759 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
4760 pEnumValues
+= cbValueNameLen
;
4762 /* return # of *bytes* (including trailing \0), not # of chars */
4763 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
4765 ppev
[dwIndex
].dwType
= dwType
;
4767 memcpy (pEnumValues
, lpValue
, cbValueLen
);
4768 ppev
[dwIndex
].pData
= pEnumValues
;
4769 pEnumValues
+= cbValueLen
;
4771 ppev
[dwIndex
].cbData
= cbValueLen
;
4773 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4774 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
4777 if (HeapFree (hHeap
, 0, lpValue
) == 0)
4779 ret
= GetLastError ();
4780 ERR ("HeapFree failed with code %li\n", ret
);
4781 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4782 WARN ("HeapFree failed with code %li\n", GetLastError ());
4783 r
= RegCloseKey (hkSubKey
);
4784 if (r
!= ERROR_SUCCESS
)
4785 WARN ("RegCloseKey returned %li\n", r
);
4789 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
4791 ret
= GetLastError ();
4792 ERR ("HeapFree failed with code %li\n", ret
);
4793 r
= RegCloseKey (hkSubKey
);
4794 if (r
!= ERROR_SUCCESS
)
4795 WARN ("RegCloseKey returned %li\n", r
);
4799 ret
= RegCloseKey (hkSubKey
);
4800 if (ret
!= ERROR_SUCCESS
)
4802 ERR ("RegCloseKey returned %li\n", ret
);
4806 return ERROR_SUCCESS
;
4809 /*******************************************************************************
4810 * EnumPrinterDataExA [WINSPOOL.@]
4812 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4813 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4814 * what Windows 2000 SP1 does.
4817 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4818 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4819 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4823 DWORD ret
, dwIndex
, dwBufSize
;
4827 TRACE ("%p %s\n", hPrinter
, pKeyName
);
4829 if (pKeyName
== NULL
|| *pKeyName
== 0)
4830 return ERROR_INVALID_PARAMETER
;
4832 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
4835 ret
= GetLastError ();
4836 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4840 hHeap
= GetProcessHeap ();
4843 ERR ("GetProcessHeap failed\n");
4844 return ERROR_OUTOFMEMORY
;
4847 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
4848 if (pKeyNameW
== NULL
)
4850 ERR ("Failed to allocate %li bytes from process heap\n",
4851 (LONG
) len
* sizeof (WCHAR
));
4852 return ERROR_OUTOFMEMORY
;
4855 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
4857 ret
= GetLastError ();
4858 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4859 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4860 WARN ("HeapFree failed with code %li\n", GetLastError ());
4864 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
4865 pcbEnumValues
, pnEnumValues
);
4866 if (ret
!= ERROR_SUCCESS
)
4868 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4869 WARN ("HeapFree failed with code %li\n", GetLastError ());
4870 TRACE ("EnumPrinterDataExW returned %li\n", ret
);
4874 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4876 ret
= GetLastError ();
4877 ERR ("HeapFree failed with code %li\n", ret
);
4881 if (*pnEnumValues
== 0) /* empty key */
4882 return ERROR_SUCCESS
;
4885 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4887 PPRINTER_ENUM_VALUESW ppev
=
4888 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4890 if (dwBufSize
< ppev
->cbValueName
)
4891 dwBufSize
= ppev
->cbValueName
;
4893 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
4894 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
4895 dwBufSize
= ppev
->cbData
;
4898 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize
);
4900 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
4901 if (pBuffer
== NULL
)
4903 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize
);
4904 return ERROR_OUTOFMEMORY
;
4907 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4909 PPRINTER_ENUM_VALUESW ppev
=
4910 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4912 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
4913 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
4917 ret
= GetLastError ();
4918 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4919 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4920 WARN ("HeapFree failed with code %li\n", GetLastError ());
4924 memcpy (ppev
->pValueName
, pBuffer
, len
);
4926 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4928 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
4929 ppev
->dwType
!= REG_MULTI_SZ
)
4932 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
4933 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
4936 ret
= GetLastError ();
4937 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4938 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4939 WARN ("HeapFree failed with code %li\n", GetLastError ());
4943 memcpy (ppev
->pData
, pBuffer
, len
);
4945 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4946 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4949 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4951 ret
= GetLastError ();
4952 ERR ("HeapFree failed with code %li\n", ret
);
4956 return ERROR_SUCCESS
;
4959 /******************************************************************************
4960 * AbortPrinter (WINSPOOL.@)
4962 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
4964 FIXME("(%p), stub!\n", hPrinter
);
4968 /******************************************************************************
4969 * AddPortA (WINSPOOL.@)
4974 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
4976 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName
),hWnd
,debugstr_a(pMonitorName
));
4980 /******************************************************************************
4981 * AddPortW (WINSPOOL.@)
4983 * Add a Port for a specific Monitor
4986 * pName [I] Servername or NULL (local Computer)
4987 * hWnd [I] Handle to parent Window for the Dialog-Box
4988 * pMonitorName [I] Name of the Monitor that manage the Port
4998 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
5000 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName
),hWnd
,debugstr_w(pMonitorName
));
5004 /******************************************************************************
5005 * AddPortExA (WINSPOOL.@)
5010 BOOL WINAPI
AddPortExA(HANDLE hMonitor
, LPSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPSTR lpMonitorName
)
5012 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor
, debugstr_a(pName
), Level
,
5013 lpBuffer
, debugstr_a(lpMonitorName
));
5017 /******************************************************************************
5018 * AddPortExW (WINSPOOL.@)
5020 * Add a Port for a specific Monitor, without presenting a user interface
5023 * hMonitor [I] Handle from InitializePrintMonitor2()
5024 * pName [I] Servername or NULL (local Computer)
5025 * Level [I] Structure-Level (1 or 2) for lpBuffer
5026 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5027 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5037 BOOL WINAPI
AddPortExW(HANDLE hMonitor
, LPWSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPWSTR lpMonitorName
)
5039 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor
, debugstr_w(pName
), Level
,
5040 lpBuffer
, debugstr_w(lpMonitorName
));
5044 /******************************************************************************
5045 * AddPrinterConnectionA (WINSPOOL.@)
5047 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
5049 FIXME("%s\n", debugstr_a(pName
));
5053 /******************************************************************************
5054 * AddPrinterConnectionW (WINSPOOL.@)
5056 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
5058 FIXME("%s\n", debugstr_w(pName
));
5062 /******************************************************************************
5063 * AddPrinterDriverExW (WINSPOOL.@)
5065 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
5066 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
5068 FIXME("%s %ld %p %ld\n", debugstr_w(pName
),
5069 Level
, pDriverInfo
, dwFileCopyFlags
);
5070 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
5074 /******************************************************************************
5075 * AddPrinterDriverExA (WINSPOOL.@)
5077 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
5078 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
5080 FIXME("%s %ld %p %ld\n", debugstr_a(pName
),
5081 Level
, pDriverInfo
, dwFileCopyFlags
);
5082 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
5086 /******************************************************************************
5087 * ConfigurePortA (WINSPOOL.@)
5089 * See ConfigurePortW.
5092 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
5094 FIXME("%s %p %s\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
5098 /******************************************************************************
5099 * ConfigurePortW (WINSPOOL.@)
5101 * Display the Configuration-Dialog for a specific Port
5104 * pName [I] Servername or NULL (local Computer)
5105 * hWnd [I] Handle to parent Window for the Dialog-Box
5106 * pPortName [I] Name of the Port, that should be configured
5116 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
5118 FIXME("%s %p %s\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
5122 /******************************************************************************
5123 * ConnectToPrinterDlg (WINSPOOL.@)
5125 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
5127 FIXME("%p %lx\n", hWnd
, Flags
);
5131 /******************************************************************************
5132 * DeletePrinterConnectionA (WINSPOOL.@)
5134 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
5136 FIXME("%s\n", debugstr_a(pName
));
5140 /******************************************************************************
5141 * DeletePrinterConnectionW (WINSPOOL.@)
5143 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
5145 FIXME("%s\n", debugstr_w(pName
));
5149 /******************************************************************************
5150 * DeletePrinterDriverExW (WINSPOOL.@)
5152 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
5153 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
5155 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5156 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
5160 /******************************************************************************
5161 * DeletePrinterDriverExA (WINSPOOL.@)
5163 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
5164 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
5166 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5167 debugstr_a(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
5171 /******************************************************************************
5172 * DeletePrinterDataExW (WINSPOOL.@)
5174 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
5177 FIXME("%p %s %s\n", hPrinter
,
5178 debugstr_w(pKeyName
), debugstr_w(pValueName
));
5179 return ERROR_INVALID_PARAMETER
;
5182 /******************************************************************************
5183 * DeletePrinterDataExA (WINSPOOL.@)
5185 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
5188 FIXME("%p %s %s\n", hPrinter
,
5189 debugstr_a(pKeyName
), debugstr_a(pValueName
));
5190 return ERROR_INVALID_PARAMETER
;
5193 /******************************************************************************
5194 * DeletePrintProcessorA (WINSPOOL.@)
5196 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
5198 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5199 debugstr_a(pPrintProcessorName
));
5203 /******************************************************************************
5204 * DeletePrintProcessorW (WINSPOOL.@)
5206 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
5208 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5209 debugstr_w(pPrintProcessorName
));
5213 /******************************************************************************
5214 * DeletePrintProvidorA (WINSPOOL.@)
5216 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
5218 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5219 debugstr_a(pPrintProviderName
));
5223 /******************************************************************************
5224 * DeletePrintProvidorW (WINSPOOL.@)
5226 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
5228 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5229 debugstr_w(pPrintProviderName
));
5233 /******************************************************************************
5234 * EnumFormsA (WINSPOOL.@)
5236 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
5237 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5239 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
5243 /******************************************************************************
5244 * EnumFormsW (WINSPOOL.@)
5246 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
5247 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5249 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
5253 /*****************************************************************************
5254 * EnumMonitorsA [WINSPOOL.@]
5256 * See EnumMonitorsW.
5259 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
5260 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5263 LPBYTE bufferW
= NULL
;
5264 LPWSTR nameW
= NULL
;
5266 DWORD numentries
= 0;
5269 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
5270 cbBuf
, pcbNeeded
, pcReturned
);
5272 /* convert servername to unicode */
5274 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5275 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5276 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5278 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5279 needed
= cbBuf
* sizeof(WCHAR
);
5280 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5281 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5283 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5284 if (pcbNeeded
) needed
= *pcbNeeded
;
5285 /* HeapReAlloc return NULL, when bufferW was NULL */
5286 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5287 HeapAlloc(GetProcessHeap(), 0, needed
);
5289 /* Try again with the large Buffer */
5290 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5292 numentries
= pcReturned
? *pcReturned
: 0;
5295 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5296 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5299 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5300 DWORD entrysize
= 0;
5303 LPMONITOR_INFO_2W mi2w
;
5304 LPMONITOR_INFO_2A mi2a
;
5306 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5307 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
5309 /* First pass: calculate the size for all Entries */
5310 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
5311 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
5313 while (index
< numentries
) {
5315 needed
+= entrysize
; /* MONITOR_INFO_?A */
5316 TRACE("%p: parsing #%ld (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
5318 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
5319 NULL
, 0, NULL
, NULL
);
5321 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
5322 NULL
, 0, NULL
, NULL
);
5323 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
5324 NULL
, 0, NULL
, NULL
);
5326 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5327 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
5328 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
5331 /* check for errors and quit on failure */
5332 if (cbBuf
< needed
) {
5333 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5337 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
5338 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
5339 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5340 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
5341 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
5343 /* Second Pass: Fill the User Buffer (if we have one) */
5344 while ((index
< numentries
) && pMonitors
) {
5346 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a
, Level
, index
);
5348 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
5349 ptr
, cbBuf
, NULL
, NULL
);
5353 mi2a
->pEnvironment
= ptr
;
5354 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
5355 ptr
, cbBuf
, NULL
, NULL
);
5359 mi2a
->pDLLName
= ptr
;
5360 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
5361 ptr
, cbBuf
, NULL
, NULL
);
5365 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5366 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
5367 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
5371 if (pcbNeeded
) *pcbNeeded
= needed
;
5372 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5374 HeapFree(GetProcessHeap(), 0, nameW
);
5375 HeapFree(GetProcessHeap(), 0, bufferW
);
5377 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5378 (res
), GetLastError(), needed
, numentries
);
5384 /*****************************************************************************
5385 * EnumMonitorsW [WINSPOOL.@]
5387 * Enumerate available Port-Monitors
5390 * pName [I] Servername or NULL (local Computer)
5391 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5392 * pMonitors [O] PTR to Buffer that receives the Result
5393 * cbBuf [I] Size of Buffer at pMonitors
5394 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5395 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5399 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5402 * Windows reads the Registry once and cache the Results.
5404 *| Language-Monitors are also installed in the same Registry-Location but
5405 *| they are filtered in Windows (not returned by EnumMonitors).
5406 *| We do no filtering to simplify our Code.
5409 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
5410 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5413 DWORD numentries
= 0;
5416 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
5417 cbBuf
, pcbNeeded
, pcReturned
);
5419 if (pName
&& (lstrlenW(pName
))) {
5420 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
5421 SetLastError(ERROR_ACCESS_DENIED
);
5425 /* Level is not checked in win9x */
5426 if (!Level
|| (Level
> 2)) {
5427 WARN("level (%ld) is ignored in win9x\n", Level
);
5428 SetLastError(ERROR_INVALID_LEVEL
);
5432 SetLastError(RPC_X_NULL_REF_POINTER
);
5436 /* Scan all Monitor-Keys */
5438 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
5440 /* we calculated the needed buffersize. now do the error-checks */
5441 if (cbBuf
< needed
) {
5442 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5445 else if (!pMonitors
|| !pcReturned
) {
5446 SetLastError(RPC_X_NULL_REF_POINTER
);
5450 /* fill the Buffer with the Monitor-Keys */
5451 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
5455 if (pcbNeeded
) *pcbNeeded
= needed
;
5456 if (pcReturned
) *pcReturned
= numentries
;
5458 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5459 res
, GetLastError(), needed
, numentries
);
5464 /******************************************************************************
5465 * XcvDataW (WINSPOOL.@)
5468 * There doesn't seem to be an A version...
5470 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
5471 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
5472 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
5474 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv
, debugstr_w(pszDataName
),
5475 pInputData
, cbInputData
, pOutputData
,
5476 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
5480 /*****************************************************************************
5481 * EnumPrinterDataA [WINSPOOL.@]
5484 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
5485 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
5486 DWORD cbData
, LPDWORD pcbData
)
5488 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
5489 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
5490 return ERROR_NO_MORE_ITEMS
;
5493 /*****************************************************************************
5494 * EnumPrinterDataW [WINSPOOL.@]
5497 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
5498 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
5499 DWORD cbData
, LPDWORD pcbData
)
5501 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
5502 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
5503 return ERROR_NO_MORE_ITEMS
;
5506 /*****************************************************************************
5507 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5510 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
5511 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
5512 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5514 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName
),
5515 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
5516 pcbNeeded
, pcReturned
);
5520 /*****************************************************************************
5521 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5524 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
5525 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
5526 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5528 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
5529 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
5530 pcbNeeded
, pcReturned
);
5534 /*****************************************************************************
5535 * EnumPrintProcessorsA [WINSPOOL.@]
5538 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5539 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
5541 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName
, pEnvironment
, Level
,
5542 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
5546 /*****************************************************************************
5547 * EnumPrintProcessorsW [WINSPOOL.@]
5550 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5551 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
5553 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
5554 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
5555 cbBuf
, pcbNeeded
, pcbReturned
);
5559 /*****************************************************************************
5560 * ExtDeviceMode [WINSPOOL.@]
5563 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
5564 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
5567 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd
, hInst
, pDevModeOutput
,
5568 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
5569 debugstr_a(pProfile
), fMode
);
5573 /*****************************************************************************
5574 * FindClosePrinterChangeNotification [WINSPOOL.@]
5577 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
5579 FIXME("Stub: %p\n", hChange
);
5583 /*****************************************************************************
5584 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5587 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
5588 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
5590 FIXME("Stub: %p %lx %lx %p\n",
5591 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
5592 return INVALID_HANDLE_VALUE
;
5595 /*****************************************************************************
5596 * FindNextPrinterChangeNotification [WINSPOOL.@]
5599 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
5600 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
5602 FIXME("Stub: %p %p %p %p\n",
5603 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
5607 /*****************************************************************************
5608 * FreePrinterNotifyInfo [WINSPOOL.@]
5611 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
5613 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
5617 /*****************************************************************************
5620 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5621 * ansi depending on the unicode parameter.
5623 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
5633 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
5636 memcpy(ptr
, str
, *size
);
5643 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
5646 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
5653 /*****************************************************************************
5656 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
5657 LPDWORD pcbNeeded
, BOOL unicode
)
5659 DWORD size
, left
= cbBuf
;
5660 BOOL space
= (cbBuf
> 0);
5667 ji1
->JobId
= job
->job_id
;
5670 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
5671 if(space
&& size
<= left
)
5673 ji1
->pDocument
= (LPWSTR
)ptr
;
5684 /*****************************************************************************
5687 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
5688 LPDWORD pcbNeeded
, BOOL unicode
)
5690 DWORD size
, left
= cbBuf
;
5691 BOOL space
= (cbBuf
> 0);
5698 ji2
->JobId
= job
->job_id
;
5701 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
5702 if(space
&& size
<= left
)
5704 ji2
->pDocument
= (LPWSTR
)ptr
;
5715 /*****************************************************************************
5718 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5719 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
5722 DWORD needed
= 0, size
;
5726 TRACE("%p %ld %ld %p %ld %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
5728 EnterCriticalSection(&printer_handles_cs
);
5729 job
= get_job(hPrinter
, JobId
);
5736 size
= sizeof(JOB_INFO_1W
);
5741 memset(pJob
, 0, size
);
5745 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5750 size
= sizeof(JOB_INFO_2W
);
5755 memset(pJob
, 0, size
);
5759 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
5764 size
= sizeof(JOB_INFO_3
);
5768 memset(pJob
, 0, size
);
5777 SetLastError(ERROR_INVALID_LEVEL
);
5781 *pcbNeeded
= needed
;
5783 LeaveCriticalSection(&printer_handles_cs
);
5787 /*****************************************************************************
5788 * GetJobA [WINSPOOL.@]
5791 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5792 DWORD cbBuf
, LPDWORD pcbNeeded
)
5794 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
5797 /*****************************************************************************
5798 * GetJobW [WINSPOOL.@]
5801 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
5802 DWORD cbBuf
, LPDWORD pcbNeeded
)
5804 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
5807 /*****************************************************************************
5810 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
5812 char *unixname
, *queue
, *cmd
;
5813 char fmt
[] = "lpr -P%s %s";
5816 if(!(unixname
= wine_get_unix_file_name(filename
)))
5819 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5820 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5821 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5823 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
5824 sprintf(cmd
, fmt
, queue
, unixname
);
5826 TRACE("printing with: %s\n", cmd
);
5829 HeapFree(GetProcessHeap(), 0, cmd
);
5830 HeapFree(GetProcessHeap(), 0, queue
);
5831 HeapFree(GetProcessHeap(), 0, unixname
);
5835 /*****************************************************************************
5838 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
5840 #if HAVE_CUPS_CUPS_H
5843 char *unixname
, *queue
, *doc_titleA
;
5847 if(!(unixname
= wine_get_unix_file_name(filename
)))
5850 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
5851 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
5852 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
5854 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
5855 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
5856 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
5858 TRACE("printing via cups\n");
5859 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
5860 HeapFree(GetProcessHeap(), 0, doc_titleA
);
5861 HeapFree(GetProcessHeap(), 0, queue
);
5862 HeapFree(GetProcessHeap(), 0, unixname
);
5868 return schedule_lpr(printer_name
, filename
);
5872 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
5879 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
5883 if(HIWORD(wparam
) == BN_CLICKED
)
5885 if(LOWORD(wparam
) == IDOK
)
5888 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
5891 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
5892 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
5894 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
5896 WCHAR caption
[200], message
[200];
5899 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5900 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
5901 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
5902 if(mb_ret
== IDCANCEL
)
5904 HeapFree(GetProcessHeap(), 0, filename
);
5908 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5909 if(hf
== INVALID_HANDLE_VALUE
)
5911 WCHAR caption
[200], message
[200];
5913 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
5914 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
5915 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
5916 HeapFree(GetProcessHeap(), 0, filename
);
5920 DeleteFileW(filename
);
5921 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5923 EndDialog(hwnd
, IDOK
);
5926 if(LOWORD(wparam
) == IDCANCEL
)
5928 EndDialog(hwnd
, IDCANCEL
);
5937 /*****************************************************************************
5940 static BOOL
get_filename(LPWSTR
*filename
)
5942 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
5943 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
5946 /*****************************************************************************
5949 static BOOL
schedule_file(LPCWSTR filename
)
5951 LPWSTR output
= NULL
;
5953 if(get_filename(&output
))
5955 TRACE("copy to %s\n", debugstr_w(output
));
5956 CopyFileW(filename
, output
, FALSE
);
5957 HeapFree(GetProcessHeap(), 0, output
);
5963 /*****************************************************************************
5966 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
5969 char *unixname
, *cmdA
;
5971 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
5975 if(!(unixname
= wine_get_unix_file_name(filename
)))
5978 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
5979 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
5980 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
5982 TRACE("printing with: %s\n", cmdA
);
5984 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
5989 ERR("pipe() failed!\n");
5999 /* reset signals that we previously set to SIG_IGN */
6000 signal(SIGPIPE
, SIG_DFL
);
6001 signal(SIGCHLD
, SIG_DFL
);
6007 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
6008 write(fds
[1], buf
, no_read
);
6013 if(file_fd
!= -1) close(file_fd
);
6014 if(fds
[0] != -1) close(fds
[0]);
6015 if(fds
[1] != -1) close(fds
[1]);
6017 HeapFree(GetProcessHeap(), 0, cmdA
);
6018 HeapFree(GetProcessHeap(), 0, unixname
);
6025 /*****************************************************************************
6028 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
6030 int in_fd
, out_fd
, no_read
;
6033 char *unixname
, *outputA
;
6036 if(!(unixname
= wine_get_unix_file_name(filename
)))
6039 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
6040 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
6041 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
6043 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
6044 in_fd
= open(unixname
, O_RDONLY
);
6045 if(out_fd
== -1 || in_fd
== -1)
6048 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
6049 write(out_fd
, buf
, no_read
);
6053 if(in_fd
!= -1) close(in_fd
);
6054 if(out_fd
!= -1) close(out_fd
);
6055 HeapFree(GetProcessHeap(), 0, outputA
);
6056 HeapFree(GetProcessHeap(), 0, unixname
);
6060 /*****************************************************************************
6061 * ScheduleJob [WINSPOOL.@]
6064 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
6066 opened_printer_t
*printer
;
6068 struct list
*cursor
, *cursor2
;
6070 TRACE("(%p, %lx)\n", hPrinter
, dwJobID
);
6071 EnterCriticalSection(&printer_handles_cs
);
6072 printer
= get_opened_printer(hPrinter
);
6076 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
6078 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
6081 if(job
->job_id
!= dwJobID
) continue;
6083 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
6084 if(hf
!= INVALID_HANDLE_VALUE
)
6086 PRINTER_INFO_5W
*pi5
;
6090 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6091 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6093 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
6094 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
6095 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
6096 TRACE("need to schedule job %ld filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
6097 debugstr_w(pi5
->pPortName
));
6101 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6102 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
6104 DWORD type
, count
= sizeof(output
);
6105 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
6108 if(output
[0] == '|')
6110 schedule_pipe(output
+ 1, job
->filename
);
6114 schedule_unixfile(output
, job
->filename
);
6116 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
6118 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
6120 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
6122 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
6124 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
6126 schedule_file(job
->filename
);
6130 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
6132 HeapFree(GetProcessHeap(), 0, pi5
);
6134 DeleteFileW(job
->filename
);
6136 list_remove(cursor
);
6137 HeapFree(GetProcessHeap(), 0, job
->document_title
);
6138 HeapFree(GetProcessHeap(), 0, job
->filename
);
6139 HeapFree(GetProcessHeap(), 0, job
);
6144 LeaveCriticalSection(&printer_handles_cs
);
6148 /*****************************************************************************
6149 * StartDocDlgA [WINSPOOL.@]
6151 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
6153 UNICODE_STRING usBuffer
;
6158 docW
.cbSize
= sizeof(docW
);
6159 docW
.lpszDocName
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
6160 docW
.lpszOutput
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
6161 docW
.lpszDatatype
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
6162 docW
.fwType
= doc
->fwType
;
6164 retW
= StartDocDlgW(hPrinter
, &docW
);
6168 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
6169 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
6170 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
6171 HeapFree(GetProcessHeap(), 0, retW
);
6174 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDatatype
);
6175 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszOutput
);
6176 HeapFree(GetProcessHeap(), 0, (LPWSTR
)docW
.lpszDocName
);
6181 /*****************************************************************************
6182 * StartDocDlgW [WINSPOOL.@]
6184 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6185 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6186 * port is "FILE:". Also returns the full path if passed a relative path.
6188 * The caller should free the returned string from the process heap.
6190 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
6195 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
6197 PRINTER_INFO_5W
*pi5
;
6198 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
6199 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
6201 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
6202 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
6203 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
6205 HeapFree(GetProcessHeap(), 0, pi5
);
6208 HeapFree(GetProcessHeap(), 0, pi5
);
6211 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
6214 get_filename(&name
);
6217 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
6219 HeapFree(GetProcessHeap(), 0, name
);
6222 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6223 GetFullPathNameW(name
, len
, ret
, NULL
);
6224 HeapFree(GetProcessHeap(), 0, name
);
6229 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
6232 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6233 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
6235 attr
= GetFileAttributesW(ret
);
6236 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
6238 HeapFree(GetProcessHeap(), 0, ret
);