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
9 * Copyright 2005-2008 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs
;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
70 0, 0, &monitor_handles_cs
,
71 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
72 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs
;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
80 0, 0, &printer_handles_cs
,
81 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
82 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
86 /* ############################### */
122 WCHAR
*document_title
;
130 LPCWSTR versionregpath
;
131 LPCWSTR versionsubdir
;
134 /* ############################### */
136 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
137 static monitor_t
* pm_localport
;
139 static opened_printer_t
**printer_handles
;
140 static UINT nb_printer_handles
;
141 static LONG next_job_id
= 1;
143 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
144 WORD fwCapability
, LPSTR lpszOutput
,
146 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
147 LPSTR lpszDevice
, LPSTR lpszPort
,
148 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
151 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW
[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
191 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
192 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
193 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
194 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
195 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
196 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
197 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
198 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
200 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
201 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
203 static const WCHAR backslashW
[] = {'\\',0};
204 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
205 'i','o','n',' ','F','i','l','e',0};
206 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
207 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
208 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
209 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
210 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
211 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
212 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
213 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
214 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
215 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
216 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
217 static const WCHAR MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
218 static const WCHAR NameW
[] = {'N','a','m','e',0};
219 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
220 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
221 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
222 static const WCHAR PortW
[] = {'P','o','r','t',0};
223 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
224 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
225 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
226 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
227 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
228 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
229 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
230 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
232 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
233 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
234 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
235 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
236 static const WCHAR emptyStringW
[] = {0};
237 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
238 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
240 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
242 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
243 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
244 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
246 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
247 'D','o','c','u','m','e','n','t',0};
249 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
250 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
251 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
252 0, sizeof(DRIVER_INFO_8W
)};
254 /******************************************************************
255 * validate the user-supplied printing-environment [internal]
258 * env [I] PTR to Environment-String or NULL
262 * Success: PTR to printenv_t
265 * An empty string is handled the same way as NULL.
266 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
270 static const printenv_t
* validate_envW(LPCWSTR env
)
272 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
273 3, Version3_RegPathW
, Version3_SubdirW
};
274 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
275 0, Version0_RegPathW
, Version0_SubdirW
};
277 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
279 const printenv_t
*result
= NULL
;
282 TRACE("testing %s\n", debugstr_w(env
));
285 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
287 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
289 result
= all_printenv
[i
];
294 if (result
== NULL
) {
295 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
296 SetLastError(ERROR_INVALID_ENVIRONMENT
);
298 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
302 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
304 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
310 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
311 if passed a NULL string. This returns NULLs to the result.
313 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
317 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
318 return usBufferPtr
->Buffer
;
320 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
324 static LPWSTR
strdupW(LPCWSTR p
)
330 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
331 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
336 static LPSTR
strdupWtoA( LPCWSTR str
)
341 if (!str
) return NULL
;
342 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
343 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
344 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
348 /******************************************************************
349 * Return the number of bytes for an multi_sz string.
350 * The result includes all \0s
351 * (specifically the extra \0, that is needed as multi_sz terminator).
354 static int multi_sz_lenW(const WCHAR
*str
)
356 const WCHAR
*ptr
= str
;
360 ptr
+= lstrlenW(ptr
) + 1;
363 return (ptr
- str
+ 1) * sizeof(WCHAR
);
366 /* ################################ */
368 static int multi_sz_lenA(const char *str
)
370 const char *ptr
= str
;
374 ptr
+= lstrlenA(ptr
) + 1;
377 return ptr
- str
+ 1;
381 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
384 /* If forcing, or no profile string entry for device yet, set the entry
386 * The always change entry if not WINEPS yet is discussable.
389 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
391 !strstr(qbuf
,"WINEPS.DRV")
393 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
396 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
397 WriteProfileStringA("windows","device",buf
);
398 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
399 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
402 HeapFree(GetProcessHeap(),0,buf
);
406 static BOOL
add_printer_driver(const char *name
)
410 static char driver_9x
[] = "wineps16.drv",
411 driver_nt
[] = "wineps.drv",
412 env_9x
[] = "Windows 4.0",
413 env_nt
[] = "Windows NT x86",
414 data_file
[] = "generic.ppd",
415 default_data_type
[] = "RAW";
417 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
419 di3a
.pName
= (char *)name
;
420 di3a
.pEnvironment
= env_nt
;
421 di3a
.pDriverPath
= driver_nt
;
422 di3a
.pDataFile
= data_file
;
423 di3a
.pConfigFile
= driver_nt
;
424 di3a
.pDefaultDataType
= default_data_type
;
426 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
427 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
430 di3a
.pEnvironment
= env_9x
;
431 di3a
.pDriverPath
= driver_9x
;
432 di3a
.pConfigFile
= driver_9x
;
433 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
434 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
439 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
440 debugstr_a(di3a
.pEnvironment
), GetLastError());
444 #ifdef SONAME_LIBCUPS
445 static typeof(cupsGetDests
) *pcupsGetDests
;
446 static typeof(cupsGetPPD
) *pcupsGetPPD
;
447 static typeof(cupsPrintFile
) *pcupsPrintFile
;
448 static void *cupshandle
;
450 static BOOL
CUPS_LoadPrinters(void)
453 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
455 PRINTER_INFO_2A pinfo2a
;
457 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
460 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
462 TRACE("%s\n", loaderror
);
465 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
468 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
469 if (!p##x) return FALSE;
472 DYNCUPS(cupsGetDests
);
473 DYNCUPS(cupsPrintFile
);
476 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
478 ERR("Can't create Printers key\n");
482 nrofdests
= pcupsGetDests(&dests
);
483 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
484 for (i
=0;i
<nrofdests
;i
++) {
485 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
486 sprintf(port
,"LPR:%s",dests
[i
].name
);
487 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
488 sprintf(devline
,"WINEPS.DRV,%s",port
);
489 WriteProfileStringA("devices",dests
[i
].name
,devline
);
490 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
491 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
494 HeapFree(GetProcessHeap(),0,devline
);
496 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
497 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
498 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
500 TRACE("Printer already exists\n");
501 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
502 RegCloseKey(hkeyPrinter
);
504 static CHAR data_type
[] = "RAW",
505 print_proc
[] = "WinPrint",
506 comment
[] = "WINEPS Printer using CUPS",
507 location
[] = "<physical location of printer>",
508 params
[] = "<parameters?>",
509 share_name
[] = "<share name?>",
510 sep_file
[] = "<sep file?>";
512 add_printer_driver(dests
[i
].name
);
514 memset(&pinfo2a
,0,sizeof(pinfo2a
));
515 pinfo2a
.pPrinterName
= dests
[i
].name
;
516 pinfo2a
.pDatatype
= data_type
;
517 pinfo2a
.pPrintProcessor
= print_proc
;
518 pinfo2a
.pDriverName
= dests
[i
].name
;
519 pinfo2a
.pComment
= comment
;
520 pinfo2a
.pLocation
= location
;
521 pinfo2a
.pPortName
= port
;
522 pinfo2a
.pParameters
= params
;
523 pinfo2a
.pShareName
= share_name
;
524 pinfo2a
.pSepFile
= sep_file
;
526 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
527 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
528 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
531 HeapFree(GetProcessHeap(),0,port
);
534 if (dests
[i
].is_default
) {
535 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
539 if (hadprinter
& !haddefault
)
540 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
541 RegCloseKey(hkeyPrinters
);
547 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
548 PRINTER_INFO_2A pinfo2a
;
549 char *e
,*s
,*name
,*prettyname
,*devname
;
550 BOOL ret
= FALSE
, set_default
= FALSE
;
551 char *port
= NULL
, *devline
,*env_default
;
552 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
554 while (isspace(*pent
)) pent
++;
555 s
= strchr(pent
,':');
557 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
565 TRACE("name=%s entry=%s\n",name
, pent
);
567 if(ispunct(*name
)) { /* a tc entry, not a real printer */
568 TRACE("skipping tc entry\n");
572 if(strstr(pent
,":server")) { /* server only version so skip */
573 TRACE("skipping server entry\n");
577 /* Determine whether this is a postscript printer. */
580 env_default
= getenv("PRINTER");
582 /* Get longest name, usually the one at the right for later display. */
583 while((s
=strchr(prettyname
,'|'))) {
586 while(isspace(*--e
)) *e
= '\0';
587 TRACE("\t%s\n", debugstr_a(prettyname
));
588 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
589 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
592 e
= prettyname
+ strlen(prettyname
);
593 while(isspace(*--e
)) *e
= '\0';
594 TRACE("\t%s\n", debugstr_a(prettyname
));
595 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
597 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
598 * if it is too long, we use it as comment below. */
599 devname
= prettyname
;
600 if (strlen(devname
)>=CCHDEVICENAME
-1)
602 if (strlen(devname
)>=CCHDEVICENAME
-1) {
607 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
608 sprintf(port
,"LPR:%s",name
);
610 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
611 sprintf(devline
,"WINEPS.DRV,%s",port
);
612 WriteProfileStringA("devices",devname
,devline
);
613 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
614 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
617 HeapFree(GetProcessHeap(),0,devline
);
619 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
621 ERR("Can't create Printers key\n");
625 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
626 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
628 TRACE("Printer already exists\n");
629 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
630 RegCloseKey(hkeyPrinter
);
632 static CHAR data_type
[] = "RAW",
633 print_proc
[] = "WinPrint",
634 comment
[] = "WINEPS Printer using LPR",
635 params
[] = "<parameters?>",
636 share_name
[] = "<share name?>",
637 sep_file
[] = "<sep file?>";
639 add_printer_driver(devname
);
641 memset(&pinfo2a
,0,sizeof(pinfo2a
));
642 pinfo2a
.pPrinterName
= devname
;
643 pinfo2a
.pDatatype
= data_type
;
644 pinfo2a
.pPrintProcessor
= print_proc
;
645 pinfo2a
.pDriverName
= devname
;
646 pinfo2a
.pComment
= comment
;
647 pinfo2a
.pLocation
= prettyname
;
648 pinfo2a
.pPortName
= port
;
649 pinfo2a
.pParameters
= params
;
650 pinfo2a
.pShareName
= share_name
;
651 pinfo2a
.pSepFile
= sep_file
;
653 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
654 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
655 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
658 RegCloseKey(hkeyPrinters
);
660 if (isfirst
|| set_default
)
661 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
664 HeapFree(GetProcessHeap(), 0, port
);
665 HeapFree(GetProcessHeap(), 0, name
);
670 PRINTCAP_LoadPrinters(void) {
671 BOOL hadprinter
= FALSE
;
675 BOOL had_bash
= FALSE
;
677 f
= fopen("/etc/printcap","r");
681 while(fgets(buf
,sizeof(buf
),f
)) {
684 end
=strchr(buf
,'\n');
688 while(isspace(*start
)) start
++;
689 if(*start
== '#' || *start
== '\0')
692 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
693 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
694 HeapFree(GetProcessHeap(),0,pent
);
698 if (end
&& *--end
== '\\') {
705 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
708 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
714 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
715 HeapFree(GetProcessHeap(),0,pent
);
721 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
724 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
725 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
727 return ERROR_FILE_NOT_FOUND
;
730 /*****************************************************************************
731 * enumerate the local monitors (INTERNAL)
733 * returns the needed size (in bytes) for pMonitors
734 * and *lpreturned is set to number of entries returned in pMonitors
737 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
742 LPMONITOR_INFO_2W mi
;
743 WCHAR buffer
[MAX_PATH
];
744 WCHAR dllname
[MAX_PATH
];
752 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
754 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
755 len
= entrysize
* numentries
;
756 ptr
= (LPWSTR
) &pMonitors
[len
];
759 len
= sizeof(buffer
)/sizeof(buffer
[0]);
762 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
763 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
764 /* Scan all Monitor-Registry-Keys */
765 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
766 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
767 dllsize
= sizeof(dllname
);
770 /* The Monitor must have a Driver-DLL */
771 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
772 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
773 /* We found a valid DLL for this Monitor. */
774 TRACE("using Driver: %s\n", debugstr_w(dllname
));
779 /* Windows returns only Port-Monitors here, but to simplify our code,
780 we do no filtering for Language-Monitors */
784 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
786 /* we install and return only monitors for "Windows NT x86" */
787 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
791 /* required size is calculated. Now fill the user-buffer */
792 if (pMonitors
&& (cbBuf
>= needed
)){
793 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
794 pMonitors
+= entrysize
;
796 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
798 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
799 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
801 mi
->pEnvironment
= ptr
;
802 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
803 ptr
+= (lstrlenW(envname_x86W
)+1);
806 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
807 ptr
+= (dllsize
/ sizeof(WCHAR
));
812 len
= sizeof(buffer
)/sizeof(buffer
[0]);
817 *lpreturned
= numentries
;
818 TRACE("need %d byte for %d entries\n", needed
, numentries
);
822 /******************************************************************
823 * monitor_unload [internal]
825 * release a printmonitor and unload it from memory, when needed
828 static void monitor_unload(monitor_t
* pm
)
830 if (pm
== NULL
) return;
831 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
833 EnterCriticalSection(&monitor_handles_cs
);
835 if (pm
->refcount
) pm
->refcount
--;
837 if (pm
->refcount
== 0) {
838 list_remove(&pm
->entry
);
839 FreeLibrary(pm
->hdll
);
840 HeapFree(GetProcessHeap(), 0, pm
->name
);
841 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
842 HeapFree(GetProcessHeap(), 0, pm
);
844 LeaveCriticalSection(&monitor_handles_cs
);
847 /******************************************************************
848 * monitor_unloadall [internal]
850 * release all printmonitors and unload them from memory, when needed
853 static void monitor_unloadall(void)
858 EnterCriticalSection(&monitor_handles_cs
);
859 /* iterate through the list, with safety against removal */
860 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
864 LeaveCriticalSection(&monitor_handles_cs
);
867 /******************************************************************
868 * monitor_load [internal]
870 * load a printmonitor, get the dllname from the registry, when needed
871 * initialize the monitor and dump found function-pointers
873 * On failure, SetLastError() is called and NULL is returned
876 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
878 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
879 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
880 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
881 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
882 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
884 monitor_t
* pm
= NULL
;
886 LPWSTR regroot
= NULL
;
887 LPWSTR driver
= dllname
;
889 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
890 /* Is the Monitor already loaded? */
891 EnterCriticalSection(&monitor_handles_cs
);
894 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
896 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
904 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
905 if (pm
== NULL
) goto cleanup
;
906 list_add_tail(&monitor_handles
, &pm
->entry
);
910 if (pm
->name
== NULL
) {
911 /* Load the monitor */
912 LPMONITOREX pmonitorEx
;
916 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
917 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
921 lstrcpyW(regroot
, MonitorsW
);
922 lstrcatW(regroot
, name
);
923 /* Get the Driver from the Registry */
924 if (driver
== NULL
) {
927 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
928 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
929 &namesize
) == ERROR_SUCCESS
) {
930 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
931 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
938 pm
->name
= strdupW(name
);
939 pm
->dllname
= strdupW(driver
);
941 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
943 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
948 pm
->hdll
= LoadLibraryW(driver
);
949 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
951 if (pm
->hdll
== NULL
) {
953 SetLastError(ERROR_MOD_NOT_FOUND
);
958 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
959 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
960 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
961 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
962 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
965 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
966 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
967 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
968 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
969 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
971 if (pInitializePrintMonitorUI
!= NULL
) {
972 pm
->monitorUI
= pInitializePrintMonitorUI();
973 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
975 TRACE( "0x%08x: dwMonitorSize (%d)\n",
976 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
981 if (pInitializePrintMonitor
&& regroot
) {
982 pmonitorEx
= pInitializePrintMonitor(regroot
);
983 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
984 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
987 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
988 pm
->monitor
= &(pmonitorEx
->Monitor
);
993 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
997 if (!pm
->monitor
&& regroot
) {
998 if (pInitializePrintMonitor2
!= NULL
) {
999 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
1001 if (pInitializeMonitorEx
!= NULL
) {
1002 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
1004 if (pInitializeMonitor
!= NULL
) {
1005 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
1008 if (!pm
->monitor
&& !pm
->monitorUI
) {
1010 SetLastError(ERROR_PROC_NOT_FOUND
);
1015 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
1019 LeaveCriticalSection(&monitor_handles_cs
);
1020 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
1021 HeapFree(GetProcessHeap(), 0, regroot
);
1022 TRACE("=> %p\n", pm
);
1026 /******************************************************************
1027 * monitor_loadall [internal]
1029 * Load all registered monitors
1032 static DWORD
monitor_loadall(void)
1035 DWORD registered
= 0;
1038 WCHAR buffer
[MAX_PATH
];
1041 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1042 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1043 NULL
, NULL
, NULL
, NULL
, NULL
);
1045 TRACE("%d monitors registered\n", registered
);
1047 EnterCriticalSection(&monitor_handles_cs
);
1048 while (id
< registered
) {
1050 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1051 pm
= monitor_load(buffer
, NULL
);
1055 LeaveCriticalSection(&monitor_handles_cs
);
1056 RegCloseKey(hmonitors
);
1058 TRACE("%d monitors loaded\n", loaded
);
1062 /******************************************************************
1063 * monitor_loadui [internal]
1065 * load the userinterface-dll for a given portmonitor
1067 * On failure, NULL is returned
1070 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1072 monitor_t
* pui
= NULL
;
1073 LPWSTR buffer
[MAX_PATH
];
1078 if (pm
== NULL
) return NULL
;
1079 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1081 /* Try the Portmonitor first; works for many monitors */
1082 if (pm
->monitorUI
) {
1083 EnterCriticalSection(&monitor_handles_cs
);
1085 LeaveCriticalSection(&monitor_handles_cs
);
1089 /* query the userinterface-dllname from the Portmonitor */
1090 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1091 /* building (",XcvMonitor %s",pm->name) not needed yet */
1092 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1093 TRACE("got %u with %p\n", res
, hXcv
);
1095 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1096 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1097 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1098 pm
->monitor
->pfnXcvClosePort(hXcv
);
1105 /******************************************************************
1106 * monitor_load_by_port [internal]
1108 * load a printmonitor for a given port
1110 * On failure, NULL is returned
1113 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1118 monitor_t
* pm
= NULL
;
1119 DWORD registered
= 0;
1123 TRACE("(%s)\n", debugstr_w(portname
));
1125 /* Try the Local Monitor first */
1126 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1127 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1128 /* found the portname */
1130 return monitor_load(LocalPortW
, NULL
);
1135 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1136 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1137 if (buffer
== NULL
) return NULL
;
1139 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1140 EnterCriticalSection(&monitor_handles_cs
);
1141 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1143 while ((pm
== NULL
) && (id
< registered
)) {
1145 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1146 TRACE("testing %s\n", debugstr_w(buffer
));
1147 len
= lstrlenW(buffer
);
1148 lstrcatW(buffer
, bs_Ports_bsW
);
1149 lstrcatW(buffer
, portname
);
1150 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1152 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1153 pm
= monitor_load(buffer
, NULL
);
1157 LeaveCriticalSection(&monitor_handles_cs
);
1160 HeapFree(GetProcessHeap(), 0, buffer
);
1164 /******************************************************************
1165 * enumerate the local Ports from all loaded monitors (internal)
1167 * returns the needed size (in bytes) for pPorts
1168 * and *lpreturned is set to number of entries returned in pPorts
1171 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1175 LPPORT_INFO_2W cache
;
1177 LPBYTE pi_buffer
= NULL
;
1178 DWORD pi_allocated
= 0;
1189 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1190 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1192 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1193 needed
= entrysize
* numentries
;
1194 ptr
= (LPWSTR
) &pPorts
[needed
];
1199 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1201 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1204 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1205 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1206 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1207 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1208 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1209 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1210 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1212 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1213 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1215 numentries
+= pi_returned
;
1216 needed
+= pi_needed
;
1218 /* fill the output-buffer (pPorts), if we have one */
1219 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1221 while (pi_returned
> pi_index
) {
1222 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1223 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1224 out
->pPortName
= ptr
;
1225 lstrcpyW(ptr
, cache
->pPortName
);
1226 ptr
+= (lstrlenW(ptr
)+1);
1228 out
->pMonitorName
= ptr
;
1229 lstrcpyW(ptr
, cache
->pMonitorName
);
1230 ptr
+= (lstrlenW(ptr
)+1);
1232 out
->pDescription
= ptr
;
1233 lstrcpyW(ptr
, cache
->pDescription
);
1234 ptr
+= (lstrlenW(ptr
)+1);
1235 out
->fPortType
= cache
->fPortType
;
1236 out
->Reserved
= cache
->Reserved
;
1244 /* the temporary portinfo-buffer is no longer needed */
1245 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1247 *lpreturned
= numentries
;
1248 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1252 /******************************************************************
1253 * get_servername_from_name (internal)
1255 * for an external server, a copy of the serverpart from the full name is returned
1258 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1262 WCHAR buffer
[MAX_PATH
];
1265 if (name
== NULL
) return NULL
;
1266 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1268 server
= strdupW(&name
[2]); /* skip over both backslash */
1269 if (server
== NULL
) return NULL
;
1271 /* strip '\' and the printername */
1272 ptr
= strchrW(server
, '\\');
1273 if (ptr
) ptr
[0] = '\0';
1275 TRACE("found %s\n", debugstr_w(server
));
1277 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1278 if (GetComputerNameW(buffer
, &len
)) {
1279 if (lstrcmpW(buffer
, server
) == 0) {
1280 /* The requested Servername is our computername */
1281 HeapFree(GetProcessHeap(), 0, server
);
1288 /******************************************************************
1289 * get_basename_from_name (internal)
1291 * skip over the serverpart from the full name
1294 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1296 if (name
== NULL
) return NULL
;
1297 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1298 /* skip over the servername and search for the following '\' */
1299 name
= strchrW(&name
[2], '\\');
1300 if ((name
) && (name
[1])) {
1301 /* found a separator ('\') followed by a name:
1302 skip over the separator and return the rest */
1307 /* no basename present (we found only a servername) */
1314 /******************************************************************
1315 * get_opened_printer_entry
1316 * Get the first place empty in the opened printer table
1319 * - pDefault is ignored
1321 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1323 UINT_PTR handle
= nb_printer_handles
, i
;
1324 jobqueue_t
*queue
= NULL
;
1325 opened_printer_t
*printer
= NULL
;
1327 LPCWSTR printername
;
1332 servername
= get_servername_from_name(name
);
1334 FIXME("server %s not supported\n", debugstr_w(servername
));
1335 HeapFree(GetProcessHeap(), 0, servername
);
1336 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1340 printername
= get_basename_from_name(name
);
1341 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1343 /* an empty printername is invalid */
1344 if (printername
&& (!printername
[0])) {
1345 SetLastError(ERROR_INVALID_PARAMETER
);
1349 EnterCriticalSection(&printer_handles_cs
);
1351 for (i
= 0; i
< nb_printer_handles
; i
++)
1353 if (!printer_handles
[i
])
1355 if(handle
== nb_printer_handles
)
1360 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1361 queue
= printer_handles
[i
]->queue
;
1365 if (handle
>= nb_printer_handles
)
1367 opened_printer_t
**new_array
;
1368 if (printer_handles
)
1369 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1370 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1372 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1373 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1380 printer_handles
= new_array
;
1381 nb_printer_handles
+= 16;
1384 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1391 /* clone the base name. This is NULL for the printserver */
1392 printer
->printername
= strdupW(printername
);
1394 /* clone the full name */
1395 printer
->name
= strdupW(name
);
1396 if (name
&& (!printer
->name
)) {
1402 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1403 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1404 /* OpenPrinter(",XcvMonitor " detected */
1405 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1406 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1407 if (printer
->pm
== NULL
) {
1408 SetLastError(ERROR_UNKNOWN_PORT
);
1415 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1416 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1417 /* OpenPrinter(",XcvPort " detected */
1418 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1419 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1420 if (printer
->pm
== NULL
) {
1421 SetLastError(ERROR_UNKNOWN_PORT
);
1429 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1430 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1431 pDefault
? pDefault
->DesiredAccess
: 0,
1434 if (printer
->hXcv
== NULL
) {
1435 SetLastError(ERROR_INVALID_PARAMETER
);
1442 /* Does the Printer exist? */
1443 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1444 ERR("Can't create Printers key\n");
1448 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1449 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1450 RegCloseKey(hkeyPrinters
);
1451 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1455 RegCloseKey(hkeyPrinter
);
1456 RegCloseKey(hkeyPrinters
);
1461 TRACE("using the local printserver\n");
1465 printer
->queue
= queue
;
1468 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1469 if (!printer
->queue
) {
1473 list_init(&printer
->queue
->jobs
);
1474 printer
->queue
->ref
= 0;
1476 InterlockedIncrement(&printer
->queue
->ref
);
1478 printer_handles
[handle
] = printer
;
1481 LeaveCriticalSection(&printer_handles_cs
);
1482 if (!handle
&& printer
) {
1483 /* Something failed: Free all resources */
1484 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1485 monitor_unload(printer
->pm
);
1486 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1487 HeapFree(GetProcessHeap(), 0, printer
->name
);
1488 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1489 HeapFree(GetProcessHeap(), 0, printer
);
1492 return (HANDLE
)handle
;
1495 /******************************************************************
1496 * get_opened_printer
1497 * Get the pointer to the opened printer referred by the handle
1499 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1501 UINT_PTR idx
= (UINT_PTR
)hprn
;
1502 opened_printer_t
*ret
= NULL
;
1504 EnterCriticalSection(&printer_handles_cs
);
1506 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
1507 ret
= printer_handles
[idx
- 1];
1509 LeaveCriticalSection(&printer_handles_cs
);
1513 /******************************************************************
1514 * get_opened_printer_name
1515 * Get the pointer to the opened printer name referred by the handle
1517 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1519 opened_printer_t
*printer
= get_opened_printer(hprn
);
1520 if(!printer
) return NULL
;
1521 return printer
->name
;
1524 /******************************************************************
1525 * WINSPOOL_GetOpenedPrinterRegKey
1528 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1530 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1534 if(!name
) return ERROR_INVALID_HANDLE
;
1536 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1540 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1542 ERR("Can't find opened printer %s in registry\n",
1544 RegCloseKey(hkeyPrinters
);
1545 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1547 RegCloseKey(hkeyPrinters
);
1548 return ERROR_SUCCESS
;
1551 void WINSPOOL_LoadSystemPrinters(void)
1553 HKEY hkey
, hkeyPrinters
;
1555 DWORD needed
, num
, i
;
1556 WCHAR PrinterName
[256];
1559 /* This ensures that all printer entries have a valid Name value. If causes
1560 problems later if they don't. If one is found to be missed we create one
1561 and set it equal to the name of the key */
1562 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1563 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1564 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1565 for(i
= 0; i
< num
; i
++) {
1566 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1567 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1568 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1569 set_reg_szW(hkey
, NameW
, PrinterName
);
1576 RegCloseKey(hkeyPrinters
);
1579 /* We want to avoid calling AddPrinter on printers as much as
1580 possible, because on cups printers this will (eventually) lead
1581 to a call to cupsGetPPD which takes forever, even with non-cups
1582 printers AddPrinter takes a while. So we'll tag all printers that
1583 were automatically added last time around, if they still exist
1584 we'll leave them be otherwise we'll delete them. */
1585 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1587 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1588 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1589 for(i
= 0; i
< num
; i
++) {
1590 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1591 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1592 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1594 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1602 HeapFree(GetProcessHeap(), 0, pi
);
1606 #ifdef SONAME_LIBCUPS
1607 done
= CUPS_LoadPrinters();
1610 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1611 PRINTCAP_LoadPrinters();
1613 /* Now enumerate the list again and delete any printers that are still tagged */
1614 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1616 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1617 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1618 for(i
= 0; i
< num
; i
++) {
1619 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1620 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1621 BOOL delete_driver
= FALSE
;
1622 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1623 DWORD dw
, type
, size
= sizeof(dw
);
1624 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1625 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1626 DeletePrinter(hprn
);
1627 delete_driver
= TRUE
;
1633 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1638 HeapFree(GetProcessHeap(), 0, pi
);
1645 /******************************************************************
1648 * Get the pointer to the specified job.
1649 * Should hold the printer_handles_cs before calling.
1651 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1653 opened_printer_t
*printer
= get_opened_printer(hprn
);
1656 if(!printer
) return NULL
;
1657 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1659 if(job
->job_id
== JobId
)
1665 /***********************************************************
1668 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1671 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1674 Formname
= (dmA
->dmSize
> off_formname
);
1675 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1676 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1677 dmW
->dmDeviceName
, CCHDEVICENAME
);
1679 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1680 dmA
->dmSize
- CCHDEVICENAME
);
1682 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1683 off_formname
- CCHDEVICENAME
);
1684 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1685 dmW
->dmFormName
, CCHFORMNAME
);
1686 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1687 (off_formname
+ CCHFORMNAME
));
1690 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1691 dmA
->dmDriverExtra
);
1695 /***********************************************************
1697 * Creates an ascii copy of supplied devmode on heap
1699 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
1704 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
1706 if(!dmW
) return NULL
;
1707 Formname
= (dmW
->dmSize
> off_formname
);
1708 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
1709 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1710 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1711 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1713 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1714 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
1716 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1717 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
1718 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1719 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1720 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
1721 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
1724 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
1725 dmW
->dmDriverExtra
);
1729 /***********************************************************
1730 * PRINTER_INFO_2AtoW
1731 * Creates a unicode copy of PRINTER_INFO_2A on heap
1733 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1735 LPPRINTER_INFO_2W piW
;
1736 UNICODE_STRING usBuffer
;
1738 if(!piA
) return NULL
;
1739 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1740 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1742 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1743 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1744 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1745 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1746 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1747 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1748 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1749 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1750 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1751 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1752 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1753 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1757 /***********************************************************
1758 * FREE_PRINTER_INFO_2W
1759 * Free PRINTER_INFO_2W and all strings
1761 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1765 HeapFree(heap
,0,piW
->pServerName
);
1766 HeapFree(heap
,0,piW
->pPrinterName
);
1767 HeapFree(heap
,0,piW
->pShareName
);
1768 HeapFree(heap
,0,piW
->pPortName
);
1769 HeapFree(heap
,0,piW
->pDriverName
);
1770 HeapFree(heap
,0,piW
->pComment
);
1771 HeapFree(heap
,0,piW
->pLocation
);
1772 HeapFree(heap
,0,piW
->pDevMode
);
1773 HeapFree(heap
,0,piW
->pSepFile
);
1774 HeapFree(heap
,0,piW
->pPrintProcessor
);
1775 HeapFree(heap
,0,piW
->pDatatype
);
1776 HeapFree(heap
,0,piW
->pParameters
);
1777 HeapFree(heap
,0,piW
);
1781 /******************************************************************
1782 * DeviceCapabilities [WINSPOOL.@]
1783 * DeviceCapabilitiesA [WINSPOOL.@]
1786 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1787 LPSTR pOutput
, LPDEVMODEA lpdm
)
1791 if (!GDI_CallDeviceCapabilities16
)
1793 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1795 if (!GDI_CallDeviceCapabilities16
) return -1;
1797 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1799 /* If DC_PAPERSIZE map POINT16s to POINTs */
1800 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1801 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1802 POINT
*pt
= (POINT
*)pOutput
;
1804 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1805 for(i
= 0; i
< ret
; i
++, pt
++)
1810 HeapFree( GetProcessHeap(), 0, tmp
);
1816 /*****************************************************************************
1817 * DeviceCapabilitiesW [WINSPOOL.@]
1819 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1822 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1823 WORD fwCapability
, LPWSTR pOutput
,
1824 const DEVMODEW
*pDevMode
)
1826 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1827 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1828 LPSTR pPortA
= strdupWtoA(pPort
);
1831 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1832 fwCapability
== DC_FILEDEPENDENCIES
||
1833 fwCapability
== DC_PAPERNAMES
)) {
1834 /* These need A -> W translation */
1837 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1841 switch(fwCapability
) {
1846 case DC_FILEDEPENDENCIES
:
1850 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1851 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1853 for(i
= 0; i
< ret
; i
++)
1854 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1855 pOutput
+ (i
* size
), size
);
1856 HeapFree(GetProcessHeap(), 0, pOutputA
);
1858 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1859 (LPSTR
)pOutput
, dmA
);
1861 HeapFree(GetProcessHeap(),0,pPortA
);
1862 HeapFree(GetProcessHeap(),0,pDeviceA
);
1863 HeapFree(GetProcessHeap(),0,dmA
);
1867 /******************************************************************
1868 * DocumentPropertiesA [WINSPOOL.@]
1870 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1872 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1873 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1874 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1876 LPSTR lpName
= pDeviceName
;
1877 static CHAR port
[] = "LPT1:";
1880 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1881 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1885 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1887 ERR("no name from hPrinter?\n");
1888 SetLastError(ERROR_INVALID_HANDLE
);
1891 lpName
= strdupWtoA(lpNameW
);
1894 if (!GDI_CallExtDeviceMode16
)
1896 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1898 if (!GDI_CallExtDeviceMode16
) {
1899 ERR("No CallExtDeviceMode16?\n");
1903 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1904 pDevModeInput
, NULL
, fMode
);
1907 HeapFree(GetProcessHeap(),0,lpName
);
1912 /*****************************************************************************
1913 * DocumentPropertiesW (WINSPOOL.@)
1915 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1917 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1919 LPDEVMODEW pDevModeOutput
,
1920 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1923 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1924 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1925 LPDEVMODEA pDevModeOutputA
= NULL
;
1928 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1929 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1931 if(pDevModeOutput
) {
1932 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1933 if(ret
< 0) return ret
;
1934 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1936 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1937 pDevModeInputA
, fMode
);
1938 if(pDevModeOutput
) {
1939 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1940 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1942 if(fMode
== 0 && ret
> 0)
1943 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1944 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1945 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1949 /******************************************************************
1950 * OpenPrinterA [WINSPOOL.@]
1955 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1956 LPPRINTER_DEFAULTSA pDefault
)
1958 UNICODE_STRING lpPrinterNameW
;
1959 UNICODE_STRING usBuffer
;
1960 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1961 PWSTR pwstrPrinterNameW
;
1964 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1967 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1968 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1969 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1970 pDefaultW
= &DefaultW
;
1972 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1974 RtlFreeUnicodeString(&usBuffer
);
1975 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1977 RtlFreeUnicodeString(&lpPrinterNameW
);
1981 /******************************************************************
1982 * OpenPrinterW [WINSPOOL.@]
1984 * Open a Printer / Printserver or a Printer-Object
1987 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1988 * phPrinter [O] The resulting Handle is stored here
1989 * pDefault [I] PTR to Default Printer Settings or NULL
1996 * lpPrinterName is one of:
1997 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1998 *| Printer: "PrinterName"
1999 *| Printer-Object: "PrinterName,Job xxx"
2000 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2001 *| XcvPort: "Servername,XcvPort PortName"
2004 *| Printer-Object not supported
2005 *| pDefaults is ignored
2008 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2011 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2013 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2014 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2018 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2019 SetLastError(ERROR_INVALID_PARAMETER
);
2023 /* Get the unique handle of the printer or Printserver */
2024 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2025 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2026 return (*phPrinter
!= 0);
2029 /******************************************************************
2030 * AddMonitorA [WINSPOOL.@]
2035 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2037 LPWSTR nameW
= NULL
;
2040 LPMONITOR_INFO_2A mi2a
;
2041 MONITOR_INFO_2W mi2w
;
2043 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2044 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2045 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
2046 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
2047 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
2050 SetLastError(ERROR_INVALID_LEVEL
);
2054 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2060 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2061 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2062 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2065 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2067 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2068 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2069 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2071 if (mi2a
->pEnvironment
) {
2072 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2073 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2074 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2076 if (mi2a
->pDLLName
) {
2077 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2078 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2079 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2082 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2084 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2085 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2086 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2088 HeapFree(GetProcessHeap(), 0, nameW
);
2092 /******************************************************************************
2093 * AddMonitorW [WINSPOOL.@]
2095 * Install a Printmonitor
2098 * pName [I] Servername or NULL (local Computer)
2099 * Level [I] Structure-Level (Must be 2)
2100 * pMonitors [I] PTR to MONITOR_INFO_2
2107 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2110 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2112 monitor_t
* pm
= NULL
;
2113 LPMONITOR_INFO_2W mi2w
;
2119 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2120 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2121 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
2122 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
2123 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
2126 SetLastError(ERROR_INVALID_LEVEL
);
2130 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2135 if (pName
&& (pName
[0])) {
2136 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2137 SetLastError(ERROR_ACCESS_DENIED
);
2142 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2143 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2144 SetLastError(ERROR_INVALID_PARAMETER
);
2147 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2148 WARN("Environment %s requested (we support only %s)\n",
2149 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2150 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2154 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2155 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2156 SetLastError(ERROR_INVALID_PARAMETER
);
2160 /* Load and initialize the monitor. SetLastError() is called on failure */
2161 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2166 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2167 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2171 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2172 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2173 &disposition
) == ERROR_SUCCESS
) {
2175 /* Some installers set options for the port before calling AddMonitor.
2176 We query the "Driver" entry to verify that the monitor is installed,
2177 before we return an error.
2178 When a user installs two print monitors at the same time with the
2179 same name but with a different driver DLL and a task switch comes
2180 between RegQueryValueExW and RegSetValueExW, a race condition
2181 is possible but silently ignored. */
2185 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2186 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2187 &namesize
) == ERROR_SUCCESS
)) {
2188 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2189 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2190 9x: ERROR_ALREADY_EXISTS (183) */
2191 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2196 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2197 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2198 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2200 RegCloseKey(hentry
);
2207 /******************************************************************
2208 * DeletePrinterDriverA [WINSPOOL.@]
2211 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2213 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2216 /******************************************************************
2217 * DeletePrinterDriverW [WINSPOOL.@]
2220 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2222 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2225 /******************************************************************
2226 * DeleteMonitorA [WINSPOOL.@]
2228 * See DeleteMonitorW.
2231 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2233 LPWSTR nameW
= NULL
;
2234 LPWSTR EnvironmentW
= NULL
;
2235 LPWSTR MonitorNameW
= NULL
;
2240 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2241 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2242 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2246 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2247 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2248 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2251 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2252 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2253 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2256 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2258 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2259 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2260 HeapFree(GetProcessHeap(), 0, nameW
);
2264 /******************************************************************
2265 * DeleteMonitorW [WINSPOOL.@]
2267 * Delete a specific Printmonitor from a Printing-Environment
2270 * pName [I] Servername or NULL (local Computer)
2271 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2272 * pMonitorName [I] Name of the Monitor, that should be deleted
2279 * pEnvironment is ignored in Windows for the local Computer.
2283 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2287 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2288 debugstr_w(pMonitorName
));
2290 if (pName
&& (pName
[0])) {
2291 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2292 SetLastError(ERROR_ACCESS_DENIED
);
2296 /* pEnvironment is ignored in Windows for the local Computer */
2298 if (!pMonitorName
|| !pMonitorName
[0]) {
2299 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2300 SetLastError(ERROR_INVALID_PARAMETER
);
2304 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2305 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2309 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2310 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2315 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2318 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2319 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2323 /******************************************************************
2324 * DeletePortA [WINSPOOL.@]
2329 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2331 LPWSTR nameW
= NULL
;
2332 LPWSTR portW
= NULL
;
2336 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2338 /* convert servername to unicode */
2340 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2341 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2342 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2345 /* convert portname to unicode */
2347 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2348 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2349 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2352 res
= DeletePortW(nameW
, hWnd
, portW
);
2353 HeapFree(GetProcessHeap(), 0, nameW
);
2354 HeapFree(GetProcessHeap(), 0, portW
);
2358 /******************************************************************
2359 * DeletePortW [WINSPOOL.@]
2361 * Delete a specific Port
2364 * pName [I] Servername or NULL (local Computer)
2365 * hWnd [I] Handle to parent Window for the Dialog-Box
2366 * pPortName [I] Name of the Port, that should be deleted
2373 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2379 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2381 if (pName
&& pName
[0]) {
2382 SetLastError(ERROR_INVALID_PARAMETER
);
2387 SetLastError(RPC_X_NULL_REF_POINTER
);
2391 /* an empty Portname is Invalid */
2392 if (!pPortName
[0]) {
2393 SetLastError(ERROR_NOT_SUPPORTED
);
2397 pm
= monitor_load_by_port(pPortName
);
2398 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2399 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2400 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2401 TRACE("got %d with %u\n", res
, GetLastError());
2405 pui
= monitor_loadui(pm
);
2406 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2407 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2408 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2409 TRACE("got %d with %u\n", res
, GetLastError());
2413 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2414 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2416 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2417 SetLastError(ERROR_NOT_SUPPORTED
);
2420 monitor_unload(pui
);
2424 TRACE("returning %d with %u\n", res
, GetLastError());
2428 /******************************************************************************
2429 * SetPrinterW [WINSPOOL.@]
2431 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2433 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2434 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2438 /******************************************************************************
2439 * WritePrinter [WINSPOOL.@]
2441 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2443 opened_printer_t
*printer
;
2446 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2448 EnterCriticalSection(&printer_handles_cs
);
2449 printer
= get_opened_printer(hPrinter
);
2452 SetLastError(ERROR_INVALID_HANDLE
);
2458 SetLastError(ERROR_SPL_NO_STARTDOC
);
2462 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2464 LeaveCriticalSection(&printer_handles_cs
);
2468 /*****************************************************************************
2469 * AddFormA [WINSPOOL.@]
2471 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2473 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2477 /*****************************************************************************
2478 * AddFormW [WINSPOOL.@]
2480 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2482 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2486 /*****************************************************************************
2487 * AddJobA [WINSPOOL.@]
2489 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2492 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2496 SetLastError(ERROR_INVALID_LEVEL
);
2500 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2503 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2504 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2505 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2506 if(*pcbNeeded
> cbBuf
) {
2507 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2510 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2511 addjobA
->JobId
= addjobW
->JobId
;
2512 addjobA
->Path
= (char *)(addjobA
+ 1);
2513 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2519 /*****************************************************************************
2520 * AddJobW [WINSPOOL.@]
2522 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2524 opened_printer_t
*printer
;
2527 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2528 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2529 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2531 ADDJOB_INFO_1W
*addjob
;
2533 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2535 EnterCriticalSection(&printer_handles_cs
);
2537 printer
= get_opened_printer(hPrinter
);
2540 SetLastError(ERROR_INVALID_HANDLE
);
2545 SetLastError(ERROR_INVALID_LEVEL
);
2549 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2553 job
->job_id
= InterlockedIncrement(&next_job_id
);
2555 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2556 if(path
[len
- 1] != '\\')
2558 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2559 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2561 len
= strlenW(filename
);
2562 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2563 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2564 job
->document_title
= strdupW(default_doc_title
);
2565 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2567 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2568 if(*pcbNeeded
<= cbBuf
) {
2569 addjob
= (ADDJOB_INFO_1W
*)pData
;
2570 addjob
->JobId
= job
->job_id
;
2571 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2572 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2575 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2578 LeaveCriticalSection(&printer_handles_cs
);
2582 /*****************************************************************************
2583 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2585 * Return the PATH for the Print-Processors
2587 * See GetPrintProcessorDirectoryW.
2591 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2592 DWORD level
, LPBYTE Info
,
2593 DWORD cbBuf
, LPDWORD pcbNeeded
)
2595 LPWSTR serverW
= NULL
;
2600 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2601 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2605 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2606 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2607 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2611 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2612 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2613 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2616 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2617 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2619 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2622 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2623 cbBuf
, NULL
, NULL
) > 0;
2626 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2627 HeapFree(GetProcessHeap(), 0, envW
);
2628 HeapFree(GetProcessHeap(), 0, serverW
);
2632 /*****************************************************************************
2633 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2635 * Return the PATH for the Print-Processors
2638 * server [I] Servername (NT only) or NULL (local Computer)
2639 * env [I] Printing-Environment (see below) or NULL (Default)
2640 * level [I] Structure-Level (must be 1)
2641 * Info [O] PTR to Buffer that receives the Result
2642 * cbBuf [I] Size of Buffer at "Info"
2643 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2644 * required for the Buffer at "Info"
2647 * Success: TRUE and in pcbNeeded the Bytes used in Info
2648 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2649 * if cbBuf is too small
2651 * Native Values returned in Info on Success:
2652 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2653 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2654 *| win9x(Windows 4.0): "%winsysdir%"
2656 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2659 * Only NULL or "" is supported for server
2662 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2663 DWORD level
, LPBYTE Info
,
2664 DWORD cbBuf
, LPDWORD pcbNeeded
)
2667 const printenv_t
* env_t
;
2669 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2670 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2672 if(server
!= NULL
&& server
[0]) {
2673 FIXME("server not supported: %s\n", debugstr_w(server
));
2674 SetLastError(ERROR_INVALID_PARAMETER
);
2678 env_t
= validate_envW(env
);
2679 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2682 WARN("(Level: %d) is ignored in win9x\n", level
);
2683 SetLastError(ERROR_INVALID_LEVEL
);
2687 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2688 needed
= GetSystemDirectoryW(NULL
, 0);
2689 /* add the Size for the Subdirectories */
2690 needed
+= lstrlenW(spoolprtprocsW
);
2691 needed
+= lstrlenW(env_t
->subdir
);
2692 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2694 if(pcbNeeded
) *pcbNeeded
= needed
;
2695 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2696 if (needed
> cbBuf
) {
2697 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2700 if(pcbNeeded
== NULL
) {
2701 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2702 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2703 SetLastError(RPC_X_NULL_REF_POINTER
);
2707 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2708 SetLastError(RPC_X_NULL_REF_POINTER
);
2712 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2713 /* add the Subdirectories */
2714 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2715 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2716 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2720 /*****************************************************************************
2721 * WINSPOOL_OpenDriverReg [internal]
2723 * opens the registry for the printer drivers depending on the given input
2724 * variable pEnvironment
2727 * the opened hkey on success
2730 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2734 const printenv_t
* env
;
2737 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2739 if (!pEnvironment
|| unicode
) {
2740 /* pEnvironment was NULL or an Unicode-String: use it direct */
2741 env
= validate_envW(pEnvironment
);
2745 /* pEnvironment was an ANSI-String: convert to unicode first */
2747 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2748 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2749 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2750 env
= validate_envW(buffer
);
2751 HeapFree(GetProcessHeap(), 0, buffer
);
2753 if (!env
) return NULL
;
2755 buffer
= HeapAlloc( GetProcessHeap(), 0,
2756 (strlenW(DriversW
) + strlenW(env
->envname
) +
2757 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2759 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2760 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2761 HeapFree(GetProcessHeap(), 0, buffer
);
2766 /*****************************************************************************
2767 * AddPrinterW [WINSPOOL.@]
2769 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2771 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2775 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2777 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2778 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2779 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2780 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2781 statusW
[] = {'S','t','a','t','u','s',0},
2782 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2784 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2787 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2788 SetLastError(ERROR_INVALID_PARAMETER
);
2792 ERR("Level = %d, unsupported!\n", Level
);
2793 SetLastError(ERROR_INVALID_LEVEL
);
2797 SetLastError(ERROR_INVALID_PARAMETER
);
2800 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2802 ERR("Can't create Printers key\n");
2805 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2806 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2807 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2808 RegCloseKey(hkeyPrinter
);
2809 RegCloseKey(hkeyPrinters
);
2812 RegCloseKey(hkeyPrinter
);
2814 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2816 ERR("Can't create Drivers key\n");
2817 RegCloseKey(hkeyPrinters
);
2820 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2822 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2823 RegCloseKey(hkeyPrinters
);
2824 RegCloseKey(hkeyDrivers
);
2825 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2828 RegCloseKey(hkeyDriver
);
2829 RegCloseKey(hkeyDrivers
);
2831 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2832 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2833 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2834 RegCloseKey(hkeyPrinters
);
2838 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2840 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2841 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2842 RegCloseKey(hkeyPrinters
);
2845 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2846 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2847 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2849 /* See if we can load the driver. We may need the devmode structure anyway
2852 * Note that DocumentPropertiesW will briefly try to open the printer we
2853 * just create to find a DEVMODEA struct (it will use the WINEPS default
2854 * one in case it is not there, so we are ok).
2856 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2859 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2860 size
= sizeof(DEVMODEW
);
2866 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2868 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2870 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2871 HeapFree(GetProcessHeap(),0,dmW
);
2876 /* set devmode to printer name */
2877 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2881 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2882 and we support these drivers. NT writes DEVMODEW so somehow
2883 we'll need to distinguish between these when we support NT
2887 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2888 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2889 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2890 HeapFree(GetProcessHeap(), 0, dmA
);
2892 HeapFree(GetProcessHeap(), 0, dmW
);
2894 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2895 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2896 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2897 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2899 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2900 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2901 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2902 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2903 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2904 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2905 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2906 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2907 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2908 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2909 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2910 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2911 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2913 RegCloseKey(hkeyPrinter
);
2914 RegCloseKey(hkeyPrinters
);
2915 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2916 ERR("OpenPrinter failing\n");
2922 /*****************************************************************************
2923 * AddPrinterA [WINSPOOL.@]
2925 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2927 UNICODE_STRING pNameW
;
2929 PRINTER_INFO_2W
*piW
;
2930 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2933 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2935 ERR("Level = %d, unsupported!\n", Level
);
2936 SetLastError(ERROR_INVALID_LEVEL
);
2939 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2940 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2942 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2944 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2945 RtlFreeUnicodeString(&pNameW
);
2950 /*****************************************************************************
2951 * ClosePrinter [WINSPOOL.@]
2953 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2955 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2956 opened_printer_t
*printer
= NULL
;
2959 TRACE("(%p)\n", hPrinter
);
2961 EnterCriticalSection(&printer_handles_cs
);
2963 if ((i
> 0) && (i
<= nb_printer_handles
))
2964 printer
= printer_handles
[i
- 1];
2969 struct list
*cursor
, *cursor2
;
2971 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2972 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2973 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2976 EndDocPrinter(hPrinter
);
2978 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2980 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2982 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2983 ScheduleJob(hPrinter
, job
->job_id
);
2985 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2987 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2988 monitor_unload(printer
->pm
);
2989 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2990 HeapFree(GetProcessHeap(), 0, printer
->name
);
2991 HeapFree(GetProcessHeap(), 0, printer
);
2992 printer_handles
[i
- 1] = NULL
;
2995 LeaveCriticalSection(&printer_handles_cs
);
2999 /*****************************************************************************
3000 * DeleteFormA [WINSPOOL.@]
3002 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3004 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3008 /*****************************************************************************
3009 * DeleteFormW [WINSPOOL.@]
3011 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3013 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3017 /*****************************************************************************
3018 * DeletePrinter [WINSPOOL.@]
3020 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3022 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3023 HKEY hkeyPrinters
, hkey
;
3026 SetLastError(ERROR_INVALID_HANDLE
);
3029 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3030 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3031 RegCloseKey(hkeyPrinters
);
3033 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3034 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3035 RegDeleteValueW(hkey
, lpNameW
);
3041 /*****************************************************************************
3042 * SetPrinterA [WINSPOOL.@]
3044 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3047 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3051 /*****************************************************************************
3052 * SetJobA [WINSPOOL.@]
3054 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3055 LPBYTE pJob
, DWORD Command
)
3059 UNICODE_STRING usBuffer
;
3061 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3063 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3064 are all ignored by SetJob, so we don't bother copying them */
3072 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3073 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3075 JobW
= (LPBYTE
)info1W
;
3076 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3077 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3078 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3079 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3080 info1W
->Status
= info1A
->Status
;
3081 info1W
->Priority
= info1A
->Priority
;
3082 info1W
->Position
= info1A
->Position
;
3083 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3088 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3089 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3091 JobW
= (LPBYTE
)info2W
;
3092 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3093 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3094 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3095 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3096 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3097 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3098 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3099 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3100 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3101 info2W
->Status
= info2A
->Status
;
3102 info2W
->Priority
= info2A
->Priority
;
3103 info2W
->Position
= info2A
->Position
;
3104 info2W
->StartTime
= info2A
->StartTime
;
3105 info2W
->UntilTime
= info2A
->UntilTime
;
3106 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3110 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3111 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3114 SetLastError(ERROR_INVALID_LEVEL
);
3118 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3124 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3125 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3126 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3127 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3128 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3133 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3134 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3135 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3136 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3137 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3138 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3139 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3140 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3141 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3145 HeapFree(GetProcessHeap(), 0, JobW
);
3150 /*****************************************************************************
3151 * SetJobW [WINSPOOL.@]
3153 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3154 LPBYTE pJob
, DWORD Command
)
3159 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3160 FIXME("Ignoring everything other than document title\n");
3162 EnterCriticalSection(&printer_handles_cs
);
3163 job
= get_job(hPrinter
, JobId
);
3173 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3174 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3175 job
->document_title
= strdupW(info1
->pDocument
);
3180 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3181 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3182 job
->document_title
= strdupW(info2
->pDocument
);
3188 SetLastError(ERROR_INVALID_LEVEL
);
3193 LeaveCriticalSection(&printer_handles_cs
);
3197 /*****************************************************************************
3198 * EndDocPrinter [WINSPOOL.@]
3200 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3202 opened_printer_t
*printer
;
3204 TRACE("(%p)\n", hPrinter
);
3206 EnterCriticalSection(&printer_handles_cs
);
3208 printer
= get_opened_printer(hPrinter
);
3211 SetLastError(ERROR_INVALID_HANDLE
);
3217 SetLastError(ERROR_SPL_NO_STARTDOC
);
3221 CloseHandle(printer
->doc
->hf
);
3222 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3223 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3224 printer
->doc
= NULL
;
3227 LeaveCriticalSection(&printer_handles_cs
);
3231 /*****************************************************************************
3232 * EndPagePrinter [WINSPOOL.@]
3234 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3236 FIXME("(%p): stub\n", hPrinter
);
3240 /*****************************************************************************
3241 * StartDocPrinterA [WINSPOOL.@]
3243 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3245 UNICODE_STRING usBuffer
;
3247 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3250 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3251 or one (DOC_INFO_3) extra DWORDs */
3255 doc2W
.JobId
= doc2
->JobId
;
3258 doc2W
.dwMode
= doc2
->dwMode
;
3261 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3262 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3263 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3267 SetLastError(ERROR_INVALID_LEVEL
);
3271 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3273 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3274 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3275 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3280 /*****************************************************************************
3281 * StartDocPrinterW [WINSPOOL.@]
3283 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3285 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3286 opened_printer_t
*printer
;
3287 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3288 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3289 JOB_INFO_1W job_info
;
3290 DWORD needed
, ret
= 0;
3294 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3295 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3296 debugstr_w(doc
->pDatatype
));
3298 if(Level
< 1 || Level
> 3)
3300 SetLastError(ERROR_INVALID_LEVEL
);
3304 EnterCriticalSection(&printer_handles_cs
);
3305 printer
= get_opened_printer(hPrinter
);
3308 SetLastError(ERROR_INVALID_HANDLE
);
3314 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3318 /* Even if we're printing to a file we still add a print job, we'll
3319 just ignore the spool file name */
3321 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3323 ERR("AddJob failed gle %u\n", GetLastError());
3327 if(doc
->pOutputFile
)
3328 filename
= doc
->pOutputFile
;
3330 filename
= addjob
->Path
;
3332 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3333 if(hf
== INVALID_HANDLE_VALUE
)
3336 memset(&job_info
, 0, sizeof(job_info
));
3337 job_info
.pDocument
= doc
->pDocName
;
3338 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3340 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3341 printer
->doc
->hf
= hf
;
3342 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3344 LeaveCriticalSection(&printer_handles_cs
);
3349 /*****************************************************************************
3350 * StartPagePrinter [WINSPOOL.@]
3352 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3354 FIXME("(%p): stub\n", hPrinter
);
3358 /*****************************************************************************
3359 * GetFormA [WINSPOOL.@]
3361 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3362 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3364 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3365 Level
,pForm
,cbBuf
,pcbNeeded
);
3369 /*****************************************************************************
3370 * GetFormW [WINSPOOL.@]
3372 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3373 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3375 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3376 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3380 /*****************************************************************************
3381 * SetFormA [WINSPOOL.@]
3383 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3386 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3390 /*****************************************************************************
3391 * SetFormW [WINSPOOL.@]
3393 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3396 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3400 /*****************************************************************************
3401 * ReadPrinter [WINSPOOL.@]
3403 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3404 LPDWORD pNoBytesRead
)
3406 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3410 /*****************************************************************************
3411 * ResetPrinterA [WINSPOOL.@]
3413 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3415 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3419 /*****************************************************************************
3420 * ResetPrinterW [WINSPOOL.@]
3422 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3424 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3428 /*****************************************************************************
3429 * WINSPOOL_GetDWORDFromReg
3431 * Return DWORD associated with ValueName from hkey.
3433 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3435 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3438 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3440 if(ret
!= ERROR_SUCCESS
) {
3441 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3444 if(type
!= REG_DWORD
) {
3445 ERR("Got type %d\n", type
);
3452 /*****************************************************************************
3453 * get_filename_from_reg [internal]
3455 * Get ValueName from hkey storing result in out
3456 * when the Value in the registry has only a filename, use driverdir as prefix
3457 * outlen is space left in out
3458 * String is stored either as unicode or ascii
3462 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3463 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3465 WCHAR filename
[MAX_PATH
];
3469 LPWSTR buffer
= filename
;
3473 size
= sizeof(filename
);
3475 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3476 if (ret
== ERROR_MORE_DATA
) {
3477 TRACE("need dynamic buffer: %u\n", size
);
3478 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3480 /* No Memory is bad */
3484 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3487 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3488 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3494 /* do we have a full path ? */
3495 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3496 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3499 /* we must build the full Path */
3501 if ((out
) && (outlen
> dirlen
)) {
3503 lstrcpyW((LPWSTR
)out
, driverdir
);
3507 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3516 /* write the filename */
3518 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3519 if ((out
) && (outlen
>= size
)) {
3520 lstrcpyW((LPWSTR
)out
, ptr
);
3529 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3530 if ((out
) && (outlen
>= size
)) {
3531 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3539 ptr
+= lstrlenW(ptr
)+1;
3540 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3543 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3545 /* write the multisz-termination */
3546 if (type
== REG_MULTI_SZ
) {
3547 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3550 if (out
&& (outlen
>= size
)) {
3551 memset (out
, 0, size
);
3557 /*****************************************************************************
3558 * WINSPOOL_GetStringFromReg
3560 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3561 * String is stored either as unicode or ascii.
3562 * Bit of a hack here to get the ValueName if we want ascii.
3564 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3565 DWORD buflen
, DWORD
*needed
,
3568 DWORD sz
= buflen
, type
;
3572 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3574 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3575 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3576 HeapFree(GetProcessHeap(),0,ValueNameA
);
3578 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3579 WARN("Got ret = %d\n", ret
);
3583 /* add space for terminating '\0' */
3584 sz
+= unicode
? sizeof(WCHAR
) : 1;
3588 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3593 /*****************************************************************************
3594 * WINSPOOL_GetDefaultDevMode
3596 * Get a default DevMode values for wineps.
3600 static void WINSPOOL_GetDefaultDevMode(
3602 DWORD buflen
, DWORD
*needed
,
3606 static const char szwps
[] = "wineps.drv";
3608 /* fill default DEVMODE - should be read from ppd... */
3609 ZeroMemory( &dm
, sizeof(dm
) );
3610 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3611 dm
.dmSpecVersion
= DM_SPECVERSION
;
3612 dm
.dmDriverVersion
= 1;
3613 dm
.dmSize
= sizeof(DEVMODEA
);
3614 dm
.dmDriverExtra
= 0;
3616 DM_ORIENTATION
| DM_PAPERSIZE
|
3617 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3620 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3621 DM_YRESOLUTION
| DM_TTOPTION
;
3623 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3624 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3625 dm
.u1
.s1
.dmPaperLength
= 2970;
3626 dm
.u1
.s1
.dmPaperWidth
= 2100;
3628 dm
.u1
.s1
.dmScale
= 100;
3629 dm
.u1
.s1
.dmCopies
= 1;
3630 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3631 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3634 dm
.dmYResolution
= 300; /* 300dpi */
3635 dm
.dmTTOption
= DMTT_BITMAP
;
3638 /* dm.dmLogPixels */
3639 /* dm.dmBitsPerPel */
3640 /* dm.dmPelsWidth */
3641 /* dm.dmPelsHeight */
3642 /* dm.u2.dmDisplayFlags */
3643 /* dm.dmDisplayFrequency */
3644 /* dm.dmICMMethod */
3645 /* dm.dmICMIntent */
3646 /* dm.dmMediaType */
3647 /* dm.dmDitherType */
3648 /* dm.dmReserved1 */
3649 /* dm.dmReserved2 */
3650 /* dm.dmPanningWidth */
3651 /* dm.dmPanningHeight */
3654 if(buflen
>= sizeof(DEVMODEW
)) {
3655 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3656 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3657 HeapFree(GetProcessHeap(),0,pdmW
);
3659 *needed
= sizeof(DEVMODEW
);
3663 if(buflen
>= sizeof(DEVMODEA
)) {
3664 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3666 *needed
= sizeof(DEVMODEA
);
3670 /*****************************************************************************
3671 * WINSPOOL_GetDevModeFromReg
3673 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3674 * DevMode is stored either as unicode or ascii.
3676 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3678 DWORD buflen
, DWORD
*needed
,
3681 DWORD sz
= buflen
, type
;
3684 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3685 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3686 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3687 if (sz
< sizeof(DEVMODEA
))
3689 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3692 /* ensures that dmSize is not erratically bogus if registry is invalid */
3693 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3694 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3696 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3698 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3699 memcpy(ptr
, dmW
, sz
);
3700 HeapFree(GetProcessHeap(),0,dmW
);
3707 /*********************************************************************
3708 * WINSPOOL_GetPrinter_1
3710 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3711 * The strings are either stored as unicode or ascii.
3713 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3714 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3717 DWORD size
, left
= cbBuf
;
3718 BOOL space
= (cbBuf
> 0);
3723 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3725 if(space
&& size
<= left
) {
3726 pi1
->pName
= (LPWSTR
)ptr
;
3734 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3735 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3737 if(space
&& size
<= left
) {
3738 pi1
->pDescription
= (LPWSTR
)ptr
;
3746 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3748 if(space
&& size
<= left
) {
3749 pi1
->pComment
= (LPWSTR
)ptr
;
3757 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3759 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3760 memset(pi1
, 0, sizeof(*pi1
));
3764 /*********************************************************************
3765 * WINSPOOL_GetPrinter_2
3767 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3768 * The strings are either stored as unicode or ascii.
3770 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3771 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3774 DWORD size
, left
= cbBuf
;
3775 BOOL space
= (cbBuf
> 0);
3780 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3782 if(space
&& size
<= left
) {
3783 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3790 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3792 if(space
&& size
<= left
) {
3793 pi2
->pShareName
= (LPWSTR
)ptr
;
3800 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3802 if(space
&& size
<= left
) {
3803 pi2
->pPortName
= (LPWSTR
)ptr
;
3810 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3812 if(space
&& size
<= left
) {
3813 pi2
->pDriverName
= (LPWSTR
)ptr
;
3820 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3822 if(space
&& size
<= left
) {
3823 pi2
->pComment
= (LPWSTR
)ptr
;
3830 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3832 if(space
&& size
<= left
) {
3833 pi2
->pLocation
= (LPWSTR
)ptr
;
3840 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3842 if(space
&& size
<= left
) {
3843 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3852 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3853 if(space
&& size
<= left
) {
3854 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3861 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3863 if(space
&& size
<= left
) {
3864 pi2
->pSepFile
= (LPWSTR
)ptr
;
3871 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3873 if(space
&& size
<= left
) {
3874 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3881 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3883 if(space
&& size
<= left
) {
3884 pi2
->pDatatype
= (LPWSTR
)ptr
;
3891 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3893 if(space
&& size
<= left
) {
3894 pi2
->pParameters
= (LPWSTR
)ptr
;
3902 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3903 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3904 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3905 "Default Priority");
3906 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3907 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3910 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3911 memset(pi2
, 0, sizeof(*pi2
));
3916 /*********************************************************************
3917 * WINSPOOL_GetPrinter_4
3919 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3921 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3922 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3925 DWORD size
, left
= cbBuf
;
3926 BOOL space
= (cbBuf
> 0);
3931 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3933 if(space
&& size
<= left
) {
3934 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3942 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3945 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3946 memset(pi4
, 0, sizeof(*pi4
));
3951 /*********************************************************************
3952 * WINSPOOL_GetPrinter_5
3954 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3956 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3957 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3960 DWORD size
, left
= cbBuf
;
3961 BOOL space
= (cbBuf
> 0);
3966 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3968 if(space
&& size
<= left
) {
3969 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3976 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3978 if(space
&& size
<= left
) {
3979 pi5
->pPortName
= (LPWSTR
)ptr
;
3987 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3988 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3990 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3994 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3995 memset(pi5
, 0, sizeof(*pi5
));
4000 /*********************************************************************
4001 * WINSPOOL_GetPrinter_7
4003 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4005 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4006 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4008 DWORD size
, left
= cbBuf
;
4009 BOOL space
= (cbBuf
> 0);
4014 if (WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
, unicode
))
4016 if (space
&& size
<= left
) {
4017 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4025 /* We do not have a Directory Service */
4026 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4029 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4030 memset(pi7
, 0, sizeof(*pi7
));
4035 /*********************************************************************
4036 * WINSPOOL_GetPrinter_9
4038 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4039 * The strings are either stored as unicode or ascii.
4041 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4042 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4045 BOOL space
= (cbBuf
> 0);
4049 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
, unicode
)) {
4050 if(space
&& size
<= cbBuf
) {
4051 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4058 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
, unicode
);
4059 if(space
&& size
<= cbBuf
) {
4060 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4066 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4067 memset(pi9
, 0, sizeof(*pi9
));
4072 /*****************************************************************************
4073 * WINSPOOL_GetPrinter
4075 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4076 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4077 * just a collection of pointers to strings.
4079 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4080 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4083 DWORD size
, needed
= 0;
4085 HKEY hkeyPrinter
, hkeyPrinters
;
4088 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4090 if (!(name
= get_opened_printer_name(hPrinter
))) {
4091 SetLastError(ERROR_INVALID_HANDLE
);
4095 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4097 ERR("Can't create Printers key\n");
4100 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4102 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4103 RegCloseKey(hkeyPrinters
);
4104 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4111 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4113 size
= sizeof(PRINTER_INFO_2W
);
4115 ptr
= pPrinter
+ size
;
4117 memset(pPrinter
, 0, size
);
4122 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4130 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4132 size
= sizeof(PRINTER_INFO_4W
);
4134 ptr
= pPrinter
+ size
;
4136 memset(pPrinter
, 0, size
);
4141 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4150 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4152 size
= sizeof(PRINTER_INFO_5W
);
4154 ptr
= pPrinter
+ size
;
4156 memset(pPrinter
, 0, size
);
4162 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4171 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4173 size
= sizeof(PRINTER_INFO_6
);
4174 if (size
<= cbBuf
) {
4175 /* FIXME: We do not update the status yet */
4176 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
4188 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4190 size
= sizeof(PRINTER_INFO_7W
);
4191 if (size
<= cbBuf
) {
4192 ptr
= pPrinter
+ size
;
4194 memset(pPrinter
, 0, size
);
4200 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
, unicode
);
4208 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4210 size
= sizeof(PRINTER_INFO_9W
);
4212 ptr
= pPrinter
+ size
;
4214 memset(pPrinter
, 0, size
);
4220 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
, unicode
);
4227 FIXME("Unimplemented level %d\n", Level
);
4228 SetLastError(ERROR_INVALID_LEVEL
);
4229 RegCloseKey(hkeyPrinters
);
4230 RegCloseKey(hkeyPrinter
);
4234 RegCloseKey(hkeyPrinter
);
4235 RegCloseKey(hkeyPrinters
);
4237 TRACE("returning %d needed = %d\n", ret
, needed
);
4238 if(pcbNeeded
) *pcbNeeded
= needed
;
4240 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4244 /*****************************************************************************
4245 * GetPrinterW [WINSPOOL.@]
4247 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4248 DWORD cbBuf
, LPDWORD pcbNeeded
)
4250 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4254 /*****************************************************************************
4255 * GetPrinterA [WINSPOOL.@]
4257 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4258 DWORD cbBuf
, LPDWORD pcbNeeded
)
4260 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4264 /*****************************************************************************
4265 * WINSPOOL_EnumPrinters
4267 * Implementation of EnumPrintersA|W
4269 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4270 DWORD dwLevel
, LPBYTE lpbPrinters
,
4271 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4272 LPDWORD lpdwReturned
, BOOL unicode
)
4275 HKEY hkeyPrinters
, hkeyPrinter
;
4276 WCHAR PrinterName
[255];
4277 DWORD needed
= 0, number
= 0;
4278 DWORD used
, i
, left
;
4282 memset(lpbPrinters
, 0, cbBuf
);
4288 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4289 if(dwType
== PRINTER_ENUM_DEFAULT
)
4292 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4293 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4294 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4296 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4304 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4305 FIXME("dwType = %08x\n", dwType
);
4306 SetLastError(ERROR_INVALID_FLAGS
);
4310 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4312 ERR("Can't create Printers key\n");
4316 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4317 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4318 RegCloseKey(hkeyPrinters
);
4319 ERR("Can't query Printers key\n");
4322 TRACE("Found %d printers\n", number
);
4326 used
= number
* sizeof(PRINTER_INFO_1W
);
4329 used
= number
* sizeof(PRINTER_INFO_2W
);
4332 used
= number
* sizeof(PRINTER_INFO_4W
);
4335 used
= number
* sizeof(PRINTER_INFO_5W
);
4339 SetLastError(ERROR_INVALID_LEVEL
);
4340 RegCloseKey(hkeyPrinters
);
4343 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4345 for(i
= 0; i
< number
; i
++) {
4346 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4348 ERR("Can't enum key number %d\n", i
);
4349 RegCloseKey(hkeyPrinters
);
4352 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4353 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4355 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4356 RegCloseKey(hkeyPrinters
);
4361 buf
= lpbPrinters
+ used
;
4362 left
= cbBuf
- used
;
4370 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4371 left
, &needed
, unicode
);
4373 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4376 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4377 left
, &needed
, unicode
);
4379 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4382 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4383 left
, &needed
, unicode
);
4385 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4388 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4389 left
, &needed
, unicode
);
4391 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4394 ERR("Shouldn't be here!\n");
4395 RegCloseKey(hkeyPrinter
);
4396 RegCloseKey(hkeyPrinters
);
4399 RegCloseKey(hkeyPrinter
);
4401 RegCloseKey(hkeyPrinters
);
4408 memset(lpbPrinters
, 0, cbBuf
);
4409 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4413 *lpdwReturned
= number
;
4414 SetLastError(ERROR_SUCCESS
);
4419 /******************************************************************
4420 * EnumPrintersW [WINSPOOL.@]
4422 * Enumerates the available printers, print servers and print
4423 * providers, depending on the specified flags, name and level.
4427 * If level is set to 1:
4428 * Returns an array of PRINTER_INFO_1 data structures in the
4429 * lpbPrinters buffer.
4431 * If level is set to 2:
4432 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4433 * Returns an array of PRINTER_INFO_2 data structures in the
4434 * lpbPrinters buffer. Note that according to MSDN also an
4435 * OpenPrinter should be performed on every remote printer.
4437 * If level is set to 4 (officially WinNT only):
4438 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4439 * Fast: Only the registry is queried to retrieve printer names,
4440 * no connection to the driver is made.
4441 * Returns an array of PRINTER_INFO_4 data structures in the
4442 * lpbPrinters buffer.
4444 * If level is set to 5 (officially WinNT4/Win9x only):
4445 * Fast: Only the registry is queried to retrieve printer names,
4446 * no connection to the driver is made.
4447 * Returns an array of PRINTER_INFO_5 data structures in the
4448 * lpbPrinters buffer.
4450 * If level set to 3 or 6+:
4451 * returns zero (failure!)
4453 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4457 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4458 * - Only levels 2, 4 and 5 are implemented at the moment.
4459 * - 16-bit printer drivers are not enumerated.
4460 * - Returned amount of bytes used/needed does not match the real Windoze
4461 * implementation (as in this implementation, all strings are part
4462 * of the buffer, whereas Win32 keeps them somewhere else)
4463 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4466 * - In a regular Wine installation, no registry settings for printers
4467 * exist, which makes this function return an empty list.
4469 BOOL WINAPI
EnumPrintersW(
4470 DWORD dwType
, /* [in] Types of print objects to enumerate */
4471 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4472 DWORD dwLevel
, /* [in] type of printer info structure */
4473 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4474 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4475 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4476 LPDWORD lpdwReturned
/* [out] number of entries returned */
4479 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4480 lpdwNeeded
, lpdwReturned
, TRUE
);
4483 /******************************************************************
4484 * EnumPrintersA [WINSPOOL.@]
4487 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4488 DWORD dwLevel
, LPBYTE lpbPrinters
,
4489 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4490 LPDWORD lpdwReturned
)
4492 BOOL ret
, unicode
= FALSE
;
4493 UNICODE_STRING lpszNameW
;
4496 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4497 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4498 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4499 lpdwNeeded
, lpdwReturned
, unicode
);
4500 RtlFreeUnicodeString(&lpszNameW
);
4504 /*****************************************************************************
4505 * WINSPOOL_GetDriverInfoFromReg [internal]
4507 * Enters the information from the registry into the DRIVER_INFO struct
4510 * zero if the printer driver does not exist in the registry
4511 * (only if Level > 1) otherwise nonzero
4513 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4516 const printenv_t
* env
,
4518 LPBYTE ptr
, /* DRIVER_INFO */
4519 LPBYTE pDriverStrings
, /* strings buffer */
4520 DWORD cbBuf
, /* size of string buffer */
4521 LPDWORD pcbNeeded
, /* space needed for str. */
4522 BOOL unicode
) /* type of strings */
4526 WCHAR driverdir
[MAX_PATH
];
4528 LPBYTE strPtr
= pDriverStrings
;
4529 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4531 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4532 debugstr_w(DriverName
), env
,
4533 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4535 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4538 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4539 if (*pcbNeeded
<= cbBuf
)
4540 strcpyW((LPWSTR
)strPtr
, DriverName
);
4544 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4545 if (*pcbNeeded
<= cbBuf
)
4546 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4549 /* pName for level 1 has a different offset! */
4551 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4555 /* .cVersion and .pName for level > 1 */
4557 di
->cVersion
= env
->driverversion
;
4558 di
->pName
= (LPWSTR
) strPtr
;
4559 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4562 /* Reserve Space for the largest subdir and a Backslash*/
4563 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4564 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4565 /* Should never Fail */
4568 lstrcatW(driverdir
, env
->versionsubdir
);
4569 lstrcatW(driverdir
, backslashW
);
4571 /* dirlen must not include the terminating zero */
4572 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4573 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4575 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4576 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4577 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4583 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4585 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4588 if (*pcbNeeded
<= cbBuf
) {
4590 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4594 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4596 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4597 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4600 /* .pDriverPath is the Graphics rendering engine.
4601 The full Path is required to avoid a crash in some apps */
4602 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4604 if (*pcbNeeded
<= cbBuf
)
4605 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4607 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4608 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4611 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4612 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4614 if (*pcbNeeded
<= cbBuf
)
4615 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4617 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4618 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4621 /* .pConfigFile is the Driver user Interface */
4622 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4624 if (*pcbNeeded
<= cbBuf
)
4625 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4627 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4628 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4632 RegCloseKey(hkeyDriver
);
4633 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4638 RegCloseKey(hkeyDriver
);
4639 FIXME("level 5: incomplete\n");
4644 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4646 if (*pcbNeeded
<= cbBuf
)
4647 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4649 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4650 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4653 /* .pDependentFiles */
4654 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4656 if (*pcbNeeded
<= cbBuf
)
4657 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4659 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4660 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4662 else if (GetVersion() & 0x80000000) {
4663 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4664 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4666 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4668 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4669 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4672 /* .pMonitorName is the optional Language Monitor */
4673 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4675 if (*pcbNeeded
<= cbBuf
)
4676 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4678 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4679 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4682 /* .pDefaultDataType */
4683 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4685 if(*pcbNeeded
<= cbBuf
)
4686 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4688 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4689 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4693 RegCloseKey(hkeyDriver
);
4694 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4698 /* .pszzPreviousNames */
4699 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4701 if(*pcbNeeded
<= cbBuf
)
4702 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4704 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4705 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4709 RegCloseKey(hkeyDriver
);
4710 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4714 /* support is missing, but not important enough for a FIXME */
4715 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4718 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4720 if(*pcbNeeded
<= cbBuf
)
4721 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4723 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4724 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4728 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4730 if(*pcbNeeded
<= cbBuf
)
4731 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4733 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4734 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4737 /* .pszHardwareID */
4738 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4740 if(*pcbNeeded
<= cbBuf
)
4741 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4743 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4744 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4748 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4750 if(*pcbNeeded
<= cbBuf
)
4751 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4753 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4754 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4758 RegCloseKey(hkeyDriver
);
4762 /* support is missing, but not important enough for a FIXME */
4763 TRACE("level 8: incomplete\n");
4765 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4766 RegCloseKey(hkeyDriver
);
4770 /*****************************************************************************
4771 * WINSPOOL_GetPrinterDriver
4773 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4774 DWORD Level
, LPBYTE pDriverInfo
,
4775 DWORD cbBuf
, LPDWORD pcbNeeded
,
4779 WCHAR DriverName
[100];
4780 DWORD ret
, type
, size
, needed
= 0;
4782 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4783 const printenv_t
* env
;
4785 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4786 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4789 if (!(name
= get_opened_printer_name(hPrinter
))) {
4790 SetLastError(ERROR_INVALID_HANDLE
);
4794 if (Level
< 1 || Level
== 7 || Level
> 8) {
4795 SetLastError(ERROR_INVALID_LEVEL
);
4799 env
= validate_envW(pEnvironment
);
4800 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4802 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4804 ERR("Can't create Printers key\n");
4807 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4809 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4810 RegCloseKey(hkeyPrinters
);
4811 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4814 size
= sizeof(DriverName
);
4816 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4817 (LPBYTE
)DriverName
, &size
);
4818 RegCloseKey(hkeyPrinter
);
4819 RegCloseKey(hkeyPrinters
);
4820 if(ret
!= ERROR_SUCCESS
) {
4821 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4825 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4827 ERR("Can't create Drivers key\n");
4831 size
= di_sizeof
[Level
];
4832 if ((size
<= cbBuf
) && pDriverInfo
)
4833 ptr
= pDriverInfo
+ size
;
4835 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4836 env
, Level
, pDriverInfo
, ptr
,
4837 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4838 &needed
, unicode
)) {
4839 RegCloseKey(hkeyDrivers
);
4843 RegCloseKey(hkeyDrivers
);
4845 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4846 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4847 if(cbBuf
>= needed
) return TRUE
;
4848 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4852 /*****************************************************************************
4853 * GetPrinterDriverA [WINSPOOL.@]
4855 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4856 DWORD Level
, LPBYTE pDriverInfo
,
4857 DWORD cbBuf
, LPDWORD pcbNeeded
)
4860 UNICODE_STRING pEnvW
;
4863 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4864 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4865 cbBuf
, pcbNeeded
, FALSE
);
4866 RtlFreeUnicodeString(&pEnvW
);
4869 /*****************************************************************************
4870 * GetPrinterDriverW [WINSPOOL.@]
4872 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4873 DWORD Level
, LPBYTE pDriverInfo
,
4874 DWORD cbBuf
, LPDWORD pcbNeeded
)
4876 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4877 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4880 /*****************************************************************************
4881 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4883 * Return the PATH for the Printer-Drivers (UNICODE)
4886 * pName [I] Servername (NT only) or NULL (local Computer)
4887 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4888 * Level [I] Structure-Level (must be 1)
4889 * pDriverDirectory [O] PTR to Buffer that receives the Result
4890 * cbBuf [I] Size of Buffer at pDriverDirectory
4891 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4892 * required for pDriverDirectory
4895 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4896 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4897 * if cbBuf is too small
4899 * Native Values returned in pDriverDirectory on Success:
4900 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4901 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4902 *| win9x(Windows 4.0): "%winsysdir%"
4904 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4907 *- Only NULL or "" is supported for pName
4910 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4911 DWORD Level
, LPBYTE pDriverDirectory
,
4912 DWORD cbBuf
, LPDWORD pcbNeeded
)
4914 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4915 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4917 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4920 /* (Level != 1) is ignored in win9x */
4921 SetLastError(ERROR_INVALID_LEVEL
);
4924 if (pcbNeeded
== NULL
) {
4925 /* (pcbNeeded == NULL) is ignored in win9x */
4926 SetLastError(RPC_X_NULL_REF_POINTER
);
4930 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4931 pDriverDirectory
, cbBuf
, pcbNeeded
);
4936 /*****************************************************************************
4937 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4939 * Return the PATH for the Printer-Drivers (ANSI)
4941 * See GetPrinterDriverDirectoryW.
4944 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4947 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4948 DWORD Level
, LPBYTE pDriverDirectory
,
4949 DWORD cbBuf
, LPDWORD pcbNeeded
)
4951 UNICODE_STRING nameW
, environmentW
;
4954 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4955 WCHAR
*driverDirectoryW
= NULL
;
4957 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4958 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4960 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4962 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4963 else nameW
.Buffer
= NULL
;
4964 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4965 else environmentW
.Buffer
= NULL
;
4967 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4968 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4971 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4972 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4974 *pcbNeeded
= needed
;
4975 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4977 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4979 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4981 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4982 RtlFreeUnicodeString(&environmentW
);
4983 RtlFreeUnicodeString(&nameW
);
4988 /*****************************************************************************
4989 * AddPrinterDriverA [WINSPOOL.@]
4991 * See AddPrinterDriverW.
4994 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4996 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4997 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5000 /******************************************************************************
5001 * AddPrinterDriverW (WINSPOOL.@)
5003 * Install a Printer Driver
5006 * pName [I] Servername or NULL (local Computer)
5007 * level [I] Level for the supplied DRIVER_INFO_*W struct
5008 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5015 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5017 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5018 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5021 /*****************************************************************************
5022 * AddPrintProcessorA [WINSPOOL.@]
5024 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5025 LPSTR pPrintProcessorName
)
5027 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5028 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5032 /*****************************************************************************
5033 * AddPrintProcessorW [WINSPOOL.@]
5035 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5036 LPWSTR pPrintProcessorName
)
5038 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5039 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5043 /*****************************************************************************
5044 * AddPrintProvidorA [WINSPOOL.@]
5046 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5048 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5052 /*****************************************************************************
5053 * AddPrintProvidorW [WINSPOOL.@]
5055 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5057 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5061 /*****************************************************************************
5062 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5064 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5065 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5067 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5068 pDevModeOutput
, pDevModeInput
);
5072 /*****************************************************************************
5073 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5075 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5076 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5078 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5079 pDevModeOutput
, pDevModeInput
);
5083 /*****************************************************************************
5084 * PrinterProperties [WINSPOOL.@]
5086 * Displays a dialog to set the properties of the printer.
5089 * nonzero on success or zero on failure
5092 * implemented as stub only
5094 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5095 HANDLE hPrinter
/* [in] handle to printer object */
5097 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5098 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5102 /*****************************************************************************
5103 * EnumJobsA [WINSPOOL.@]
5106 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5107 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5110 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5111 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5113 if(pcbNeeded
) *pcbNeeded
= 0;
5114 if(pcReturned
) *pcReturned
= 0;
5119 /*****************************************************************************
5120 * EnumJobsW [WINSPOOL.@]
5123 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5124 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5127 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5128 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5130 if(pcbNeeded
) *pcbNeeded
= 0;
5131 if(pcReturned
) *pcReturned
= 0;
5135 /*****************************************************************************
5136 * WINSPOOL_EnumPrinterDrivers [internal]
5138 * Delivers information about all printer drivers installed on the
5139 * localhost or a given server
5142 * nonzero on success or zero on failure. If the buffer for the returned
5143 * information is too small the function will return an error
5146 * - only implemented for localhost, foreign hosts will return an error
5148 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5149 DWORD Level
, LPBYTE pDriverInfo
,
5150 DWORD cbBuf
, LPDWORD pcbNeeded
,
5151 LPDWORD pcReturned
, BOOL unicode
)
5154 DWORD i
, needed
, number
= 0, size
= 0;
5155 WCHAR DriverNameW
[255];
5157 const printenv_t
* env
;
5159 TRACE("%s,%s,%d,%p,%d,%d\n",
5160 debugstr_w(pName
), debugstr_w(pEnvironment
),
5161 Level
, pDriverInfo
, cbBuf
, unicode
);
5163 /* check for local drivers */
5164 if((pName
) && (pName
[0])) {
5165 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5166 SetLastError(ERROR_ACCESS_DENIED
);
5170 env
= validate_envW(pEnvironment
);
5171 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5173 /* check input parameter */
5174 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5175 SetLastError(ERROR_INVALID_LEVEL
);
5179 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
5180 SetLastError(RPC_X_NULL_REF_POINTER
);
5184 /* initialize return values */
5186 memset( pDriverInfo
, 0, cbBuf
);
5190 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5192 ERR("Can't open Drivers key\n");
5196 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5197 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5198 RegCloseKey(hkeyDrivers
);
5199 ERR("Can't query Drivers key\n");
5202 TRACE("Found %d Drivers\n", number
);
5204 /* get size of single struct
5205 * unicode and ascii structure have the same size
5207 size
= di_sizeof
[Level
];
5209 /* calculate required buffer size */
5210 *pcbNeeded
= size
* number
;
5212 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5214 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5215 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5217 ERR("Can't enum key number %d\n", i
);
5218 RegCloseKey(hkeyDrivers
);
5221 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5223 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5224 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5225 &needed
, unicode
)) {
5226 RegCloseKey(hkeyDrivers
);
5229 (*pcbNeeded
) += needed
;
5232 RegCloseKey(hkeyDrivers
);
5234 if(cbBuf
< *pcbNeeded
){
5235 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5239 *pcReturned
= number
;
5243 /*****************************************************************************
5244 * EnumPrinterDriversW [WINSPOOL.@]
5246 * see function EnumPrinterDrivers for RETURNS, BUGS
5248 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5249 LPBYTE pDriverInfo
, DWORD cbBuf
,
5250 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5252 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5253 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5256 /*****************************************************************************
5257 * EnumPrinterDriversA [WINSPOOL.@]
5259 * see function EnumPrinterDrivers for RETURNS, BUGS
5261 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5262 LPBYTE pDriverInfo
, DWORD cbBuf
,
5263 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5265 UNICODE_STRING pNameW
, pEnvironmentW
;
5266 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5268 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5269 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5271 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5272 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5274 RtlFreeUnicodeString(&pNameW
);
5275 RtlFreeUnicodeString(&pEnvironmentW
);
5280 /******************************************************************************
5281 * EnumPortsA (WINSPOOL.@)
5286 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5287 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5290 LPBYTE bufferW
= NULL
;
5291 LPWSTR nameW
= NULL
;
5293 DWORD numentries
= 0;
5296 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5297 cbBuf
, pcbNeeded
, pcReturned
);
5299 /* convert servername to unicode */
5301 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5302 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5303 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5305 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5306 needed
= cbBuf
* sizeof(WCHAR
);
5307 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5308 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5310 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5311 if (pcbNeeded
) needed
= *pcbNeeded
;
5312 /* HeapReAlloc return NULL, when bufferW was NULL */
5313 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5314 HeapAlloc(GetProcessHeap(), 0, needed
);
5316 /* Try again with the large Buffer */
5317 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5319 needed
= pcbNeeded
? *pcbNeeded
: 0;
5320 numentries
= pcReturned
? *pcReturned
: 0;
5323 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5324 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5327 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5328 DWORD entrysize
= 0;
5331 LPPORT_INFO_2W pi2w
;
5332 LPPORT_INFO_2A pi2a
;
5335 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5337 /* First pass: calculate the size for all Entries */
5338 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5339 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5341 while (index
< numentries
) {
5343 needed
+= entrysize
; /* PORT_INFO_?A */
5344 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5346 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5347 NULL
, 0, NULL
, NULL
);
5349 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5350 NULL
, 0, NULL
, NULL
);
5351 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5352 NULL
, 0, NULL
, NULL
);
5354 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5355 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5356 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5359 /* check for errors and quit on failure */
5360 if (cbBuf
< needed
) {
5361 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5365 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5366 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5367 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5368 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5369 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5371 /* Second Pass: Fill the User Buffer (if we have one) */
5372 while ((index
< numentries
) && pPorts
) {
5374 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5375 pi2a
->pPortName
= ptr
;
5376 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5377 ptr
, cbBuf
, NULL
, NULL
);
5381 pi2a
->pMonitorName
= ptr
;
5382 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5383 ptr
, cbBuf
, NULL
, NULL
);
5387 pi2a
->pDescription
= ptr
;
5388 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5389 ptr
, cbBuf
, NULL
, NULL
);
5393 pi2a
->fPortType
= pi2w
->fPortType
;
5394 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5397 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5398 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5399 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5404 if (pcbNeeded
) *pcbNeeded
= needed
;
5405 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5407 HeapFree(GetProcessHeap(), 0, nameW
);
5408 HeapFree(GetProcessHeap(), 0, bufferW
);
5410 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5411 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5417 /******************************************************************************
5418 * EnumPortsW (WINSPOOL.@)
5420 * Enumerate available Ports
5423 * name [I] Servername or NULL (local Computer)
5424 * level [I] Structure-Level (1 or 2)
5425 * buffer [O] PTR to Buffer that receives the Result
5426 * bufsize [I] Size of Buffer at buffer
5427 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5428 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5432 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5436 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5439 DWORD numentries
= 0;
5442 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5443 cbBuf
, pcbNeeded
, pcReturned
);
5445 if (pName
&& (pName
[0])) {
5446 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5447 SetLastError(ERROR_ACCESS_DENIED
);
5451 /* Level is not checked in win9x */
5452 if (!Level
|| (Level
> 2)) {
5453 WARN("level (%d) is ignored in win9x\n", Level
);
5454 SetLastError(ERROR_INVALID_LEVEL
);
5458 SetLastError(RPC_X_NULL_REF_POINTER
);
5462 EnterCriticalSection(&monitor_handles_cs
);
5465 /* Scan all local Ports */
5467 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5469 /* we calculated the needed buffersize. now do the error-checks */
5470 if (cbBuf
< needed
) {
5471 monitor_unloadall();
5472 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5473 goto emP_cleanup_cs
;
5475 else if (!pPorts
|| !pcReturned
) {
5476 monitor_unloadall();
5477 SetLastError(RPC_X_NULL_REF_POINTER
);
5478 goto emP_cleanup_cs
;
5481 /* Fill the Buffer */
5482 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5484 monitor_unloadall();
5487 LeaveCriticalSection(&monitor_handles_cs
);
5490 if (pcbNeeded
) *pcbNeeded
= needed
;
5491 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5493 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5494 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5499 /******************************************************************************
5500 * GetDefaultPrinterW (WINSPOOL.@)
5503 * This function must read the value from data 'device' of key
5504 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5506 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5510 WCHAR
*buffer
, *ptr
;
5514 SetLastError(ERROR_INVALID_PARAMETER
);
5518 /* make the buffer big enough for the stuff from the profile/registry,
5519 * the content must fit into the local buffer to compute the correct
5520 * size even if the extern buffer is too small or not given.
5521 * (20 for ,driver,port) */
5523 len
= max(100, (insize
+ 20));
5524 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5526 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5528 SetLastError (ERROR_FILE_NOT_FOUND
);
5532 TRACE("%s\n", debugstr_w(buffer
));
5534 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5536 SetLastError(ERROR_INVALID_NAME
);
5542 *namesize
= strlenW(buffer
) + 1;
5543 if(!name
|| (*namesize
> insize
))
5545 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5549 strcpyW(name
, buffer
);
5552 HeapFree( GetProcessHeap(), 0, buffer
);
5557 /******************************************************************************
5558 * GetDefaultPrinterA (WINSPOOL.@)
5560 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5564 WCHAR
*bufferW
= NULL
;
5568 SetLastError(ERROR_INVALID_PARAMETER
);
5572 if(name
&& *namesize
) {
5574 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5577 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5582 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5586 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5589 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5592 HeapFree( GetProcessHeap(), 0, bufferW
);
5597 /******************************************************************************
5598 * SetDefaultPrinterW (WINSPOOL.204)
5600 * Set the Name of the Default Printer
5603 * pszPrinter [I] Name of the Printer or NULL
5610 * When the Parameter is NULL or points to an Empty String and
5611 * a Default Printer was already present, then this Function changes nothing.
5612 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5613 * the First enumerated local Printer is used.
5616 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5619 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5621 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5625 /******************************************************************************
5626 * SetDefaultPrinterA (WINSPOOL.202)
5628 * See SetDefaultPrinterW.
5631 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5634 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5636 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5641 /******************************************************************************
5642 * SetPrinterDataExA (WINSPOOL.@)
5644 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5645 LPCSTR pValueName
, DWORD Type
,
5646 LPBYTE pData
, DWORD cbData
)
5648 HKEY hkeyPrinter
, hkeySubkey
;
5651 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5652 debugstr_a(pValueName
), Type
, pData
, cbData
);
5654 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5658 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5660 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5661 RegCloseKey(hkeyPrinter
);
5664 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5665 RegCloseKey(hkeySubkey
);
5666 RegCloseKey(hkeyPrinter
);
5670 /******************************************************************************
5671 * SetPrinterDataExW (WINSPOOL.@)
5673 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5674 LPCWSTR pValueName
, DWORD Type
,
5675 LPBYTE pData
, DWORD cbData
)
5677 HKEY hkeyPrinter
, hkeySubkey
;
5680 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5681 debugstr_w(pValueName
), Type
, pData
, cbData
);
5683 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5687 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5689 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5690 RegCloseKey(hkeyPrinter
);
5693 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5694 RegCloseKey(hkeySubkey
);
5695 RegCloseKey(hkeyPrinter
);
5699 /******************************************************************************
5700 * SetPrinterDataA (WINSPOOL.@)
5702 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5703 LPBYTE pData
, DWORD cbData
)
5705 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5709 /******************************************************************************
5710 * SetPrinterDataW (WINSPOOL.@)
5712 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5713 LPBYTE pData
, DWORD cbData
)
5715 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5719 /******************************************************************************
5720 * GetPrinterDataExA (WINSPOOL.@)
5722 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5723 LPCSTR pValueName
, LPDWORD pType
,
5724 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5726 HKEY hkeyPrinter
, hkeySubkey
;
5729 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5730 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5733 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5737 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5739 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5740 RegCloseKey(hkeyPrinter
);
5744 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5745 RegCloseKey(hkeySubkey
);
5746 RegCloseKey(hkeyPrinter
);
5750 /******************************************************************************
5751 * GetPrinterDataExW (WINSPOOL.@)
5753 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5754 LPCWSTR pValueName
, LPDWORD pType
,
5755 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5757 HKEY hkeyPrinter
, hkeySubkey
;
5760 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5761 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5764 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5768 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5770 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5771 RegCloseKey(hkeyPrinter
);
5775 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5776 RegCloseKey(hkeySubkey
);
5777 RegCloseKey(hkeyPrinter
);
5781 /******************************************************************************
5782 * GetPrinterDataA (WINSPOOL.@)
5784 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5785 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5787 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5788 pData
, nSize
, pcbNeeded
);
5791 /******************************************************************************
5792 * GetPrinterDataW (WINSPOOL.@)
5794 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5795 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5797 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5798 pData
, nSize
, pcbNeeded
);
5801 /*******************************************************************************
5802 * EnumPrinterDataExW [WINSPOOL.@]
5804 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5805 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5806 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5808 HKEY hkPrinter
, hkSubKey
;
5809 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5810 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5815 PPRINTER_ENUM_VALUESW ppev
;
5817 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5819 if (pKeyName
== NULL
|| *pKeyName
== 0)
5820 return ERROR_INVALID_PARAMETER
;
5822 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5823 if (ret
!= ERROR_SUCCESS
)
5825 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5830 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5831 if (ret
!= ERROR_SUCCESS
)
5833 r
= RegCloseKey (hkPrinter
);
5834 if (r
!= ERROR_SUCCESS
)
5835 WARN ("RegCloseKey returned %i\n", r
);
5836 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5837 debugstr_w (pKeyName
), ret
);
5841 ret
= RegCloseKey (hkPrinter
);
5842 if (ret
!= ERROR_SUCCESS
)
5844 ERR ("RegCloseKey returned %i\n", ret
);
5845 r
= RegCloseKey (hkSubKey
);
5846 if (r
!= ERROR_SUCCESS
)
5847 WARN ("RegCloseKey returned %i\n", r
);
5851 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5852 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5853 if (ret
!= ERROR_SUCCESS
)
5855 r
= RegCloseKey (hkSubKey
);
5856 if (r
!= ERROR_SUCCESS
)
5857 WARN ("RegCloseKey returned %i\n", r
);
5858 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5862 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5863 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5865 if (cValues
== 0) /* empty key */
5867 r
= RegCloseKey (hkSubKey
);
5868 if (r
!= ERROR_SUCCESS
)
5869 WARN ("RegCloseKey returned %i\n", r
);
5870 *pcbEnumValues
= *pnEnumValues
= 0;
5871 return ERROR_SUCCESS
;
5874 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5876 hHeap
= GetProcessHeap ();
5879 ERR ("GetProcessHeap failed\n");
5880 r
= RegCloseKey (hkSubKey
);
5881 if (r
!= ERROR_SUCCESS
)
5882 WARN ("RegCloseKey returned %i\n", r
);
5883 return ERROR_OUTOFMEMORY
;
5886 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5887 if (lpValueName
== NULL
)
5889 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5890 r
= RegCloseKey (hkSubKey
);
5891 if (r
!= ERROR_SUCCESS
)
5892 WARN ("RegCloseKey returned %i\n", r
);
5893 return ERROR_OUTOFMEMORY
;
5896 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5897 if (lpValue
== NULL
)
5899 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5900 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5901 WARN ("HeapFree failed with code %i\n", GetLastError ());
5902 r
= RegCloseKey (hkSubKey
);
5903 if (r
!= ERROR_SUCCESS
)
5904 WARN ("RegCloseKey returned %i\n", r
);
5905 return ERROR_OUTOFMEMORY
;
5908 TRACE ("pass 1: calculating buffer required for all names and values\n");
5910 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5912 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5914 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5916 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5917 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5918 NULL
, NULL
, lpValue
, &cbValueLen
);
5919 if (ret
!= ERROR_SUCCESS
)
5921 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5922 WARN ("HeapFree failed with code %i\n", GetLastError ());
5923 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5924 WARN ("HeapFree failed with code %i\n", GetLastError ());
5925 r
= RegCloseKey (hkSubKey
);
5926 if (r
!= ERROR_SUCCESS
)
5927 WARN ("RegCloseKey returned %i\n", r
);
5928 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5932 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5933 debugstr_w (lpValueName
), dwIndex
,
5934 cbValueNameLen
+ 1, cbValueLen
);
5936 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5937 cbBufSize
+= cbValueLen
;
5940 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5942 *pcbEnumValues
= cbBufSize
;
5943 *pnEnumValues
= cValues
;
5945 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5947 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5948 WARN ("HeapFree failed with code %i\n", GetLastError ());
5949 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5950 WARN ("HeapFree failed with code %i\n", GetLastError ());
5951 r
= RegCloseKey (hkSubKey
);
5952 if (r
!= ERROR_SUCCESS
)
5953 WARN ("RegCloseKey returned %i\n", r
);
5954 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5955 return ERROR_MORE_DATA
;
5958 TRACE ("pass 2: copying all names and values to buffer\n");
5960 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5961 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5963 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5965 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5966 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5967 NULL
, &dwType
, lpValue
, &cbValueLen
);
5968 if (ret
!= ERROR_SUCCESS
)
5970 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5971 WARN ("HeapFree failed with code %i\n", GetLastError ());
5972 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5973 WARN ("HeapFree failed with code %i\n", GetLastError ());
5974 r
= RegCloseKey (hkSubKey
);
5975 if (r
!= ERROR_SUCCESS
)
5976 WARN ("RegCloseKey returned %i\n", r
);
5977 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5981 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5982 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5983 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5984 pEnumValues
+= cbValueNameLen
;
5986 /* return # of *bytes* (including trailing \0), not # of chars */
5987 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5989 ppev
[dwIndex
].dwType
= dwType
;
5991 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5992 ppev
[dwIndex
].pData
= pEnumValues
;
5993 pEnumValues
+= cbValueLen
;
5995 ppev
[dwIndex
].cbData
= cbValueLen
;
5997 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5998 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6001 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6003 ret
= GetLastError ();
6004 ERR ("HeapFree failed with code %i\n", ret
);
6005 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6006 WARN ("HeapFree failed with code %i\n", GetLastError ());
6007 r
= RegCloseKey (hkSubKey
);
6008 if (r
!= ERROR_SUCCESS
)
6009 WARN ("RegCloseKey returned %i\n", r
);
6013 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6015 ret
= GetLastError ();
6016 ERR ("HeapFree failed with code %i\n", ret
);
6017 r
= RegCloseKey (hkSubKey
);
6018 if (r
!= ERROR_SUCCESS
)
6019 WARN ("RegCloseKey returned %i\n", r
);
6023 ret
= RegCloseKey (hkSubKey
);
6024 if (ret
!= ERROR_SUCCESS
)
6026 ERR ("RegCloseKey returned %i\n", ret
);
6030 return ERROR_SUCCESS
;
6033 /*******************************************************************************
6034 * EnumPrinterDataExA [WINSPOOL.@]
6036 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6037 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6038 * what Windows 2000 SP1 does.
6041 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6042 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6043 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6047 DWORD ret
, dwIndex
, dwBufSize
;
6051 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6053 if (pKeyName
== NULL
|| *pKeyName
== 0)
6054 return ERROR_INVALID_PARAMETER
;
6056 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6059 ret
= GetLastError ();
6060 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6064 hHeap
= GetProcessHeap ();
6067 ERR ("GetProcessHeap failed\n");
6068 return ERROR_OUTOFMEMORY
;
6071 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6072 if (pKeyNameW
== NULL
)
6074 ERR ("Failed to allocate %i bytes from process heap\n",
6075 (LONG
)(len
* sizeof (WCHAR
)));
6076 return ERROR_OUTOFMEMORY
;
6079 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6081 ret
= GetLastError ();
6082 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6083 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6084 WARN ("HeapFree failed with code %i\n", GetLastError ());
6088 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6089 pcbEnumValues
, pnEnumValues
);
6090 if (ret
!= ERROR_SUCCESS
)
6092 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6093 WARN ("HeapFree failed with code %i\n", GetLastError ());
6094 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6098 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6100 ret
= GetLastError ();
6101 ERR ("HeapFree failed with code %i\n", ret
);
6105 if (*pnEnumValues
== 0) /* empty key */
6106 return ERROR_SUCCESS
;
6109 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6111 PPRINTER_ENUM_VALUESW ppev
=
6112 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6114 if (dwBufSize
< ppev
->cbValueName
)
6115 dwBufSize
= ppev
->cbValueName
;
6117 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6118 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6119 dwBufSize
= ppev
->cbData
;
6122 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6124 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6125 if (pBuffer
== NULL
)
6127 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6128 return ERROR_OUTOFMEMORY
;
6131 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6133 PPRINTER_ENUM_VALUESW ppev
=
6134 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6136 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6137 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6141 ret
= GetLastError ();
6142 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6143 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6144 WARN ("HeapFree failed with code %i\n", GetLastError ());
6148 memcpy (ppev
->pValueName
, pBuffer
, len
);
6150 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6152 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6153 ppev
->dwType
!= REG_MULTI_SZ
)
6156 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6157 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6160 ret
= GetLastError ();
6161 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6162 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6163 WARN ("HeapFree failed with code %i\n", GetLastError ());
6167 memcpy (ppev
->pData
, pBuffer
, len
);
6169 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6170 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6173 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6175 ret
= GetLastError ();
6176 ERR ("HeapFree failed with code %i\n", ret
);
6180 return ERROR_SUCCESS
;
6183 /******************************************************************************
6184 * AbortPrinter (WINSPOOL.@)
6186 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6188 FIXME("(%p), stub!\n", hPrinter
);
6192 /******************************************************************************
6193 * AddPortA (WINSPOOL.@)
6198 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6200 LPWSTR nameW
= NULL
;
6201 LPWSTR monitorW
= NULL
;
6205 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6208 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6209 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6210 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6214 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6215 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6216 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6218 res
= AddPortW(nameW
, hWnd
, monitorW
);
6219 HeapFree(GetProcessHeap(), 0, nameW
);
6220 HeapFree(GetProcessHeap(), 0, monitorW
);
6224 /******************************************************************************
6225 * AddPortW (WINSPOOL.@)
6227 * Add a Port for a specific Monitor
6230 * pName [I] Servername or NULL (local Computer)
6231 * hWnd [I] Handle to parent Window for the Dialog-Box
6232 * pMonitorName [I] Name of the Monitor that manage the Port
6239 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6245 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6247 if (pName
&& pName
[0]) {
6248 SetLastError(ERROR_INVALID_PARAMETER
);
6252 if (!pMonitorName
) {
6253 SetLastError(RPC_X_NULL_REF_POINTER
);
6257 /* an empty Monitorname is Invalid */
6258 if (!pMonitorName
[0]) {
6259 SetLastError(ERROR_NOT_SUPPORTED
);
6263 pm
= monitor_load(pMonitorName
, NULL
);
6264 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6265 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6266 TRACE("got %d with %u\n", res
, GetLastError());
6271 pui
= monitor_loadui(pm
);
6272 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6273 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6274 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6275 TRACE("got %d with %u\n", res
, GetLastError());
6280 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6281 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6283 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6284 SetLastError(ERROR_NOT_SUPPORTED
);
6287 monitor_unload(pui
);
6290 TRACE("returning %d with %u\n", res
, GetLastError());
6294 /******************************************************************************
6295 * AddPortExA (WINSPOOL.@)
6300 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6303 PORT_INFO_2A
* pi2A
;
6304 LPWSTR nameW
= NULL
;
6305 LPWSTR monitorW
= NULL
;
6309 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6311 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6312 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6314 if ((level
< 1) || (level
> 2)) {
6315 SetLastError(ERROR_INVALID_LEVEL
);
6320 SetLastError(ERROR_INVALID_PARAMETER
);
6325 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6326 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6327 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6331 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6332 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6333 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6336 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6338 if (pi2A
->pPortName
) {
6339 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6340 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6341 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6345 if (pi2A
->pMonitorName
) {
6346 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6347 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6348 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6351 if (pi2A
->pDescription
) {
6352 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6353 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6354 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6356 pi2W
.fPortType
= pi2A
->fPortType
;
6357 pi2W
.Reserved
= pi2A
->Reserved
;
6360 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6362 HeapFree(GetProcessHeap(), 0, nameW
);
6363 HeapFree(GetProcessHeap(), 0, monitorW
);
6364 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6365 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6366 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6371 /******************************************************************************
6372 * AddPortExW (WINSPOOL.@)
6374 * Add a Port for a specific Monitor, without presenting a user interface
6377 * pName [I] Servername or NULL (local Computer)
6378 * level [I] Structure-Level (1 or 2) for pBuffer
6379 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6380 * pMonitorName [I] Name of the Monitor that manage the Port
6387 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6393 pi2
= (PORT_INFO_2W
*) pBuffer
;
6395 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6396 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6397 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6398 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6401 if ((level
< 1) || (level
> 2)) {
6402 SetLastError(ERROR_INVALID_LEVEL
);
6406 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6407 SetLastError(ERROR_INVALID_PARAMETER
);
6411 /* load the Monitor */
6412 pm
= monitor_load(pMonitorName
, NULL
);
6414 SetLastError(ERROR_INVALID_PARAMETER
);
6418 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6419 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6420 TRACE("got %u with %u\n", res
, GetLastError());
6424 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6430 /******************************************************************************
6431 * AddPrinterConnectionA (WINSPOOL.@)
6433 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6435 FIXME("%s\n", debugstr_a(pName
));
6439 /******************************************************************************
6440 * AddPrinterConnectionW (WINSPOOL.@)
6442 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6444 FIXME("%s\n", debugstr_w(pName
));
6448 /******************************************************************************
6449 * AddPrinterDriverExW (WINSPOOL.@)
6451 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6454 * pName [I] Servername or NULL (local Computer)
6455 * level [I] Level for the supplied DRIVER_INFO_*W struct
6456 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6457 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6464 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6466 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6468 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6470 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6471 SetLastError(ERROR_INVALID_LEVEL
);
6476 SetLastError(ERROR_INVALID_PARAMETER
);
6480 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6483 /******************************************************************************
6484 * AddPrinterDriverExA (WINSPOOL.@)
6486 * See AddPrinterDriverExW.
6489 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6491 DRIVER_INFO_8A
*diA
;
6493 LPWSTR nameW
= NULL
;
6498 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6500 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6501 ZeroMemory(&diW
, sizeof(diW
));
6503 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6504 SetLastError(ERROR_INVALID_LEVEL
);
6509 SetLastError(ERROR_INVALID_PARAMETER
);
6513 /* convert servername to unicode */
6515 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6516 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6517 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6521 diW
.cVersion
= diA
->cVersion
;
6524 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6525 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6526 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6529 if (diA
->pEnvironment
) {
6530 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6531 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6532 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6535 if (diA
->pDriverPath
) {
6536 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6537 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6538 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6541 if (diA
->pDataFile
) {
6542 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6543 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6544 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6547 if (diA
->pConfigFile
) {
6548 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6549 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6550 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6553 if ((Level
> 2) && diA
->pDependentFiles
) {
6554 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6555 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6556 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6557 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6560 if ((Level
> 2) && diA
->pMonitorName
) {
6561 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6562 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6563 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6566 if ((Level
> 3) && diA
->pDefaultDataType
) {
6567 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6568 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6569 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6572 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6573 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6574 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6575 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6576 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6579 if ((Level
> 5) && diA
->pszMfgName
) {
6580 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6581 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6582 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6585 if ((Level
> 5) && diA
->pszOEMUrl
) {
6586 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6587 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6588 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6591 if ((Level
> 5) && diA
->pszHardwareID
) {
6592 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6593 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6594 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6597 if ((Level
> 5) && diA
->pszProvider
) {
6598 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6599 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6600 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6604 FIXME("level %u is incomplete\n", Level
);
6607 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6608 TRACE("got %u with %u\n", res
, GetLastError());
6609 HeapFree(GetProcessHeap(), 0, nameW
);
6610 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6611 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6612 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6613 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6614 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6615 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6616 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6617 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6618 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6619 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6620 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6621 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6622 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6624 TRACE("=> %u with %u\n", res
, GetLastError());
6628 /******************************************************************************
6629 * ConfigurePortA (WINSPOOL.@)
6631 * See ConfigurePortW.
6634 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6636 LPWSTR nameW
= NULL
;
6637 LPWSTR portW
= NULL
;
6641 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6643 /* convert servername to unicode */
6645 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6646 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6647 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6650 /* convert portname to unicode */
6652 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6653 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6654 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6657 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6658 HeapFree(GetProcessHeap(), 0, nameW
);
6659 HeapFree(GetProcessHeap(), 0, portW
);
6663 /******************************************************************************
6664 * ConfigurePortW (WINSPOOL.@)
6666 * Display the Configuration-Dialog for a specific Port
6669 * pName [I] Servername or NULL (local Computer)
6670 * hWnd [I] Handle to parent Window for the Dialog-Box
6671 * pPortName [I] Name of the Port, that should be configured
6678 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6684 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6686 if (pName
&& pName
[0]) {
6687 SetLastError(ERROR_INVALID_PARAMETER
);
6692 SetLastError(RPC_X_NULL_REF_POINTER
);
6696 /* an empty Portname is Invalid, but can popup a Dialog */
6697 if (!pPortName
[0]) {
6698 SetLastError(ERROR_NOT_SUPPORTED
);
6702 pm
= monitor_load_by_port(pPortName
);
6703 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6704 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6705 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6706 TRACE("got %d with %u\n", res
, GetLastError());
6710 pui
= monitor_loadui(pm
);
6711 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6712 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6713 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6714 TRACE("got %d with %u\n", res
, GetLastError());
6718 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6719 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6721 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6722 SetLastError(ERROR_NOT_SUPPORTED
);
6725 monitor_unload(pui
);
6729 TRACE("returning %d with %u\n", res
, GetLastError());
6733 /******************************************************************************
6734 * ConnectToPrinterDlg (WINSPOOL.@)
6736 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6738 FIXME("%p %x\n", hWnd
, Flags
);
6742 /******************************************************************************
6743 * DeletePrinterConnectionA (WINSPOOL.@)
6745 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6747 FIXME("%s\n", debugstr_a(pName
));
6751 /******************************************************************************
6752 * DeletePrinterConnectionW (WINSPOOL.@)
6754 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6756 FIXME("%s\n", debugstr_w(pName
));
6760 /******************************************************************************
6761 * DeletePrinterDriverExW (WINSPOOL.@)
6763 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6764 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6769 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6770 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6772 if(pName
&& pName
[0])
6774 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6775 SetLastError(ERROR_INVALID_PARAMETER
);
6781 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6782 SetLastError(ERROR_INVALID_PARAMETER
);
6786 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6790 ERR("Can't open drivers key\n");
6794 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6797 RegCloseKey(hkey_drivers
);
6802 /******************************************************************************
6803 * DeletePrinterDriverExA (WINSPOOL.@)
6805 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6806 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6808 UNICODE_STRING NameW
, EnvW
, DriverW
;
6811 asciitounicode(&NameW
, pName
);
6812 asciitounicode(&EnvW
, pEnvironment
);
6813 asciitounicode(&DriverW
, pDriverName
);
6815 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6817 RtlFreeUnicodeString(&DriverW
);
6818 RtlFreeUnicodeString(&EnvW
);
6819 RtlFreeUnicodeString(&NameW
);
6824 /******************************************************************************
6825 * DeletePrinterDataExW (WINSPOOL.@)
6827 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6830 FIXME("%p %s %s\n", hPrinter
,
6831 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6832 return ERROR_INVALID_PARAMETER
;
6835 /******************************************************************************
6836 * DeletePrinterDataExA (WINSPOOL.@)
6838 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6841 FIXME("%p %s %s\n", hPrinter
,
6842 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6843 return ERROR_INVALID_PARAMETER
;
6846 /******************************************************************************
6847 * DeletePrintProcessorA (WINSPOOL.@)
6849 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6851 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6852 debugstr_a(pPrintProcessorName
));
6856 /******************************************************************************
6857 * DeletePrintProcessorW (WINSPOOL.@)
6859 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6861 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6862 debugstr_w(pPrintProcessorName
));
6866 /******************************************************************************
6867 * DeletePrintProvidorA (WINSPOOL.@)
6869 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6871 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6872 debugstr_a(pPrintProviderName
));
6876 /******************************************************************************
6877 * DeletePrintProvidorW (WINSPOOL.@)
6879 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6881 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6882 debugstr_w(pPrintProviderName
));
6886 /******************************************************************************
6887 * EnumFormsA (WINSPOOL.@)
6889 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6890 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6892 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6893 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6897 /******************************************************************************
6898 * EnumFormsW (WINSPOOL.@)
6900 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6901 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6903 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6904 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6908 /*****************************************************************************
6909 * EnumMonitorsA [WINSPOOL.@]
6911 * See EnumMonitorsW.
6914 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6915 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6918 LPBYTE bufferW
= NULL
;
6919 LPWSTR nameW
= NULL
;
6921 DWORD numentries
= 0;
6924 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6925 cbBuf
, pcbNeeded
, pcReturned
);
6927 /* convert servername to unicode */
6929 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6930 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6931 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6933 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6934 needed
= cbBuf
* sizeof(WCHAR
);
6935 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6936 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6938 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6939 if (pcbNeeded
) needed
= *pcbNeeded
;
6940 /* HeapReAlloc return NULL, when bufferW was NULL */
6941 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6942 HeapAlloc(GetProcessHeap(), 0, needed
);
6944 /* Try again with the large Buffer */
6945 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6947 numentries
= pcReturned
? *pcReturned
: 0;
6950 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6951 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6954 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6955 DWORD entrysize
= 0;
6958 LPMONITOR_INFO_2W mi2w
;
6959 LPMONITOR_INFO_2A mi2a
;
6961 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6962 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6964 /* First pass: calculate the size for all Entries */
6965 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6966 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6968 while (index
< numentries
) {
6970 needed
+= entrysize
; /* MONITOR_INFO_?A */
6971 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6973 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6974 NULL
, 0, NULL
, NULL
);
6976 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6977 NULL
, 0, NULL
, NULL
);
6978 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6979 NULL
, 0, NULL
, NULL
);
6981 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6982 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6983 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6986 /* check for errors and quit on failure */
6987 if (cbBuf
< needed
) {
6988 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6992 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6993 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6994 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6995 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6996 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6998 /* Second Pass: Fill the User Buffer (if we have one) */
6999 while ((index
< numentries
) && pMonitors
) {
7001 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7003 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7004 ptr
, cbBuf
, NULL
, NULL
);
7008 mi2a
->pEnvironment
= ptr
;
7009 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7010 ptr
, cbBuf
, NULL
, NULL
);
7014 mi2a
->pDLLName
= ptr
;
7015 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7016 ptr
, cbBuf
, NULL
, NULL
);
7020 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7021 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7022 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7026 if (pcbNeeded
) *pcbNeeded
= needed
;
7027 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7029 HeapFree(GetProcessHeap(), 0, nameW
);
7030 HeapFree(GetProcessHeap(), 0, bufferW
);
7032 TRACE("returning %d with %d (%d byte for %d entries)\n",
7033 (res
), GetLastError(), needed
, numentries
);
7039 /*****************************************************************************
7040 * EnumMonitorsW [WINSPOOL.@]
7042 * Enumerate available Port-Monitors
7045 * pName [I] Servername or NULL (local Computer)
7046 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7047 * pMonitors [O] PTR to Buffer that receives the Result
7048 * cbBuf [I] Size of Buffer at pMonitors
7049 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7050 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7054 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7057 * Windows reads the Registry once and cache the Results.
7059 *| Language-Monitors are also installed in the same Registry-Location but
7060 *| they are filtered in Windows (not returned by EnumMonitors).
7061 *| We do no filtering to simplify our Code.
7064 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7065 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7068 DWORD numentries
= 0;
7071 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7072 cbBuf
, pcbNeeded
, pcReturned
);
7074 if (pName
&& (lstrlenW(pName
))) {
7075 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
7076 SetLastError(ERROR_ACCESS_DENIED
);
7080 /* Level is not checked in win9x */
7081 if (!Level
|| (Level
> 2)) {
7082 WARN("level (%d) is ignored in win9x\n", Level
);
7083 SetLastError(ERROR_INVALID_LEVEL
);
7087 SetLastError(RPC_X_NULL_REF_POINTER
);
7091 /* Scan all Monitor-Keys */
7093 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
7095 /* we calculated the needed buffersize. now do the error-checks */
7096 if (cbBuf
< needed
) {
7097 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7100 else if (!pMonitors
|| !pcReturned
) {
7101 SetLastError(RPC_X_NULL_REF_POINTER
);
7105 /* fill the Buffer with the Monitor-Keys */
7106 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
7110 if (pcbNeeded
) *pcbNeeded
= needed
;
7111 if (pcReturned
) *pcReturned
= numentries
;
7113 TRACE("returning %d with %d (%d byte for %d entries)\n",
7114 res
, GetLastError(), needed
, numentries
);
7119 /******************************************************************************
7120 * XcvDataW (WINSPOOL.@)
7122 * Execute commands in the Printmonitor DLL
7125 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7126 * pszDataName [i] Name of the command to execute
7127 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7128 * cbInputData [i] Size in Bytes of Buffer at pInputData
7129 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7130 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7131 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7132 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7139 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7140 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7142 * Minimal List of commands, that a Printmonitor DLL should support:
7144 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7145 *| "AddPort" : Add a Port
7146 *| "DeletePort": Delete a Port
7148 * Many Printmonitors support additional commands. Examples for localspl.dll:
7149 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7150 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7153 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7154 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7155 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7157 opened_printer_t
*printer
;
7159 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7160 pInputData
, cbInputData
, pOutputData
,
7161 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7163 printer
= get_opened_printer(hXcv
);
7164 if (!printer
|| (!printer
->hXcv
)) {
7165 SetLastError(ERROR_INVALID_HANDLE
);
7169 if (!pcbOutputNeeded
) {
7170 SetLastError(ERROR_INVALID_PARAMETER
);
7174 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7175 SetLastError(RPC_X_NULL_REF_POINTER
);
7179 *pcbOutputNeeded
= 0;
7181 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
7182 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
7187 /*****************************************************************************
7188 * EnumPrinterDataA [WINSPOOL.@]
7191 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7192 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7193 DWORD cbData
, LPDWORD pcbData
)
7195 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7196 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7197 return ERROR_NO_MORE_ITEMS
;
7200 /*****************************************************************************
7201 * EnumPrinterDataW [WINSPOOL.@]
7204 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7205 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7206 DWORD cbData
, LPDWORD pcbData
)
7208 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7209 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7210 return ERROR_NO_MORE_ITEMS
;
7213 /*****************************************************************************
7214 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7217 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7218 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7219 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7221 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7222 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7223 pcbNeeded
, pcReturned
);
7227 /*****************************************************************************
7228 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7231 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7232 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7233 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7235 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7236 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7237 pcbNeeded
, pcReturned
);
7241 /*****************************************************************************
7242 * EnumPrintProcessorsA [WINSPOOL.@]
7245 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7246 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7248 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7249 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7253 /*****************************************************************************
7254 * EnumPrintProcessorsW [WINSPOOL.@]
7257 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7258 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7260 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7261 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7262 cbBuf
, pcbNeeded
, pcbReturned
);
7266 /*****************************************************************************
7267 * ExtDeviceMode [WINSPOOL.@]
7270 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7271 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7274 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7275 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7276 debugstr_a(pProfile
), fMode
);
7280 /*****************************************************************************
7281 * FindClosePrinterChangeNotification [WINSPOOL.@]
7284 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7286 FIXME("Stub: %p\n", hChange
);
7290 /*****************************************************************************
7291 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7294 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7295 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7297 FIXME("Stub: %p %x %x %p\n",
7298 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7299 return INVALID_HANDLE_VALUE
;
7302 /*****************************************************************************
7303 * FindNextPrinterChangeNotification [WINSPOOL.@]
7306 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7307 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7309 FIXME("Stub: %p %p %p %p\n",
7310 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7314 /*****************************************************************************
7315 * FreePrinterNotifyInfo [WINSPOOL.@]
7318 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7320 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7324 /*****************************************************************************
7327 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7328 * ansi depending on the unicode parameter.
7330 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7340 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7343 memcpy(ptr
, str
, *size
);
7350 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7353 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7360 /*****************************************************************************
7363 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7364 LPDWORD pcbNeeded
, BOOL unicode
)
7366 DWORD size
, left
= cbBuf
;
7367 BOOL space
= (cbBuf
> 0);
7374 ji1
->JobId
= job
->job_id
;
7377 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7378 if(space
&& size
<= left
)
7380 ji1
->pDocument
= (LPWSTR
)ptr
;
7391 /*****************************************************************************
7394 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7395 LPDWORD pcbNeeded
, BOOL unicode
)
7397 DWORD size
, left
= cbBuf
;
7398 BOOL space
= (cbBuf
> 0);
7405 ji2
->JobId
= job
->job_id
;
7408 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7409 if(space
&& size
<= left
)
7411 ji2
->pDocument
= (LPWSTR
)ptr
;
7422 /*****************************************************************************
7425 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7426 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7429 DWORD needed
= 0, size
;
7433 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7435 EnterCriticalSection(&printer_handles_cs
);
7436 job
= get_job(hPrinter
, JobId
);
7443 size
= sizeof(JOB_INFO_1W
);
7448 memset(pJob
, 0, size
);
7452 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7457 size
= sizeof(JOB_INFO_2W
);
7462 memset(pJob
, 0, size
);
7466 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7471 size
= sizeof(JOB_INFO_3
);
7475 memset(pJob
, 0, size
);
7484 SetLastError(ERROR_INVALID_LEVEL
);
7488 *pcbNeeded
= needed
;
7490 LeaveCriticalSection(&printer_handles_cs
);
7494 /*****************************************************************************
7495 * GetJobA [WINSPOOL.@]
7498 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7499 DWORD cbBuf
, LPDWORD pcbNeeded
)
7501 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7504 /*****************************************************************************
7505 * GetJobW [WINSPOOL.@]
7508 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7509 DWORD cbBuf
, LPDWORD pcbNeeded
)
7511 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7514 /*****************************************************************************
7517 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7519 char *unixname
, *queue
, *cmd
;
7520 char fmt
[] = "lpr -P%s %s";
7523 if(!(unixname
= wine_get_unix_file_name(filename
)))
7526 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7527 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7528 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7530 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7531 sprintf(cmd
, fmt
, queue
, unixname
);
7533 TRACE("printing with: %s\n", cmd
);
7536 HeapFree(GetProcessHeap(), 0, cmd
);
7537 HeapFree(GetProcessHeap(), 0, queue
);
7538 HeapFree(GetProcessHeap(), 0, unixname
);
7542 /*****************************************************************************
7545 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7547 #ifdef SONAME_LIBCUPS
7550 char *unixname
, *queue
, *doc_titleA
;
7554 if(!(unixname
= wine_get_unix_file_name(filename
)))
7557 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7558 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7559 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7561 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7562 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7563 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7565 TRACE("printing via cups\n");
7566 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7567 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7568 HeapFree(GetProcessHeap(), 0, queue
);
7569 HeapFree(GetProcessHeap(), 0, unixname
);
7575 return schedule_lpr(printer_name
, filename
);
7579 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7586 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7590 if(HIWORD(wparam
) == BN_CLICKED
)
7592 if(LOWORD(wparam
) == IDOK
)
7595 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7598 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7599 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7601 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7603 WCHAR caption
[200], message
[200];
7606 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7607 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7608 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7609 if(mb_ret
== IDCANCEL
)
7611 HeapFree(GetProcessHeap(), 0, filename
);
7615 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7616 if(hf
== INVALID_HANDLE_VALUE
)
7618 WCHAR caption
[200], message
[200];
7620 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7621 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7622 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7623 HeapFree(GetProcessHeap(), 0, filename
);
7627 DeleteFileW(filename
);
7628 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7630 EndDialog(hwnd
, IDOK
);
7633 if(LOWORD(wparam
) == IDCANCEL
)
7635 EndDialog(hwnd
, IDCANCEL
);
7644 /*****************************************************************************
7647 static BOOL
get_filename(LPWSTR
*filename
)
7649 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7650 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7653 /*****************************************************************************
7656 static BOOL
schedule_file(LPCWSTR filename
)
7658 LPWSTR output
= NULL
;
7660 if(get_filename(&output
))
7662 TRACE("copy to %s\n", debugstr_w(output
));
7663 CopyFileW(filename
, output
, FALSE
);
7664 HeapFree(GetProcessHeap(), 0, output
);
7670 /*****************************************************************************
7673 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7676 char *unixname
, *cmdA
;
7678 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7682 if(!(unixname
= wine_get_unix_file_name(filename
)))
7685 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7686 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7687 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7689 TRACE("printing with: %s\n", cmdA
);
7691 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7696 ERR("pipe() failed!\n");
7706 /* reset signals that we previously set to SIG_IGN */
7707 signal(SIGPIPE
, SIG_DFL
);
7708 signal(SIGCHLD
, SIG_DFL
);
7710 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7714 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7715 write(fds
[1], buf
, no_read
);
7720 if(file_fd
!= -1) close(file_fd
);
7721 if(fds
[0] != -1) close(fds
[0]);
7722 if(fds
[1] != -1) close(fds
[1]);
7724 HeapFree(GetProcessHeap(), 0, cmdA
);
7725 HeapFree(GetProcessHeap(), 0, unixname
);
7732 /*****************************************************************************
7735 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7737 int in_fd
, out_fd
, no_read
;
7740 char *unixname
, *outputA
;
7743 if(!(unixname
= wine_get_unix_file_name(filename
)))
7746 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7747 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7748 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7750 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7751 in_fd
= open(unixname
, O_RDONLY
);
7752 if(out_fd
== -1 || in_fd
== -1)
7755 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7756 write(out_fd
, buf
, no_read
);
7760 if(in_fd
!= -1) close(in_fd
);
7761 if(out_fd
!= -1) close(out_fd
);
7762 HeapFree(GetProcessHeap(), 0, outputA
);
7763 HeapFree(GetProcessHeap(), 0, unixname
);
7767 /*****************************************************************************
7768 * ScheduleJob [WINSPOOL.@]
7771 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7773 opened_printer_t
*printer
;
7775 struct list
*cursor
, *cursor2
;
7777 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7778 EnterCriticalSection(&printer_handles_cs
);
7779 printer
= get_opened_printer(hPrinter
);
7783 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7785 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7788 if(job
->job_id
!= dwJobID
) continue;
7790 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7791 if(hf
!= INVALID_HANDLE_VALUE
)
7793 PRINTER_INFO_5W
*pi5
;
7797 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7798 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7800 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7801 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7802 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7803 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7804 debugstr_w(pi5
->pPortName
));
7808 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7809 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7811 DWORD type
, count
= sizeof(output
);
7812 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7815 if(output
[0] == '|')
7817 schedule_pipe(output
+ 1, job
->filename
);
7821 schedule_unixfile(output
, job
->filename
);
7823 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7825 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7827 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7829 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7831 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7833 schedule_file(job
->filename
);
7837 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7839 HeapFree(GetProcessHeap(), 0, pi5
);
7841 DeleteFileW(job
->filename
);
7843 list_remove(cursor
);
7844 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7845 HeapFree(GetProcessHeap(), 0, job
->filename
);
7846 HeapFree(GetProcessHeap(), 0, job
);
7851 LeaveCriticalSection(&printer_handles_cs
);
7855 /*****************************************************************************
7856 * StartDocDlgA [WINSPOOL.@]
7858 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7860 UNICODE_STRING usBuffer
;
7863 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7866 docW
.cbSize
= sizeof(docW
);
7867 if (doc
->lpszDocName
)
7869 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7870 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7872 if (doc
->lpszOutput
)
7874 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7875 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7877 if (doc
->lpszDatatype
)
7879 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7880 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7882 docW
.fwType
= doc
->fwType
;
7884 retW
= StartDocDlgW(hPrinter
, &docW
);
7888 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7889 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7890 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7891 HeapFree(GetProcessHeap(), 0, retW
);
7894 HeapFree(GetProcessHeap(), 0, datatypeW
);
7895 HeapFree(GetProcessHeap(), 0, outputW
);
7896 HeapFree(GetProcessHeap(), 0, docnameW
);
7901 /*****************************************************************************
7902 * StartDocDlgW [WINSPOOL.@]
7904 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7905 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7906 * port is "FILE:". Also returns the full path if passed a relative path.
7908 * The caller should free the returned string from the process heap.
7910 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7915 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7917 PRINTER_INFO_5W
*pi5
;
7918 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7919 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7921 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7922 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7923 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7925 HeapFree(GetProcessHeap(), 0, pi5
);
7928 HeapFree(GetProcessHeap(), 0, pi5
);
7931 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7935 if (get_filename(&name
))
7937 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7939 HeapFree(GetProcessHeap(), 0, name
);
7942 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7943 GetFullPathNameW(name
, len
, ret
, NULL
);
7944 HeapFree(GetProcessHeap(), 0, name
);
7949 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7952 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7953 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7955 attr
= GetFileAttributesW(ret
);
7956 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7958 HeapFree(GetProcessHeap(), 0, ret
);