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 WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
191 'M','i','c','r','o','s','o','f','t','\\',
192 'W','i','n','d','o','w','s',' ','N','T','\\',
193 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
194 'P','r','i','n','t','e','r','P','o','r','t','s',0};
196 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
197 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
198 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
200 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
201 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
202 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
203 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
204 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
206 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
207 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
209 static const WCHAR backslashW
[] = {'\\',0};
210 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
211 'i','o','n',' ','F','i','l','e',0};
212 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
213 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
214 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
215 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
216 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
217 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
218 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
219 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
220 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
221 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
222 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
223 static const WCHAR MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
224 static const WCHAR NameW
[] = {'N','a','m','e',0};
225 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
226 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
227 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
228 static const WCHAR PortW
[] = {'P','o','r','t',0};
229 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
230 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
231 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
232 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
233 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
234 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
235 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW
[] = {0};
244 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
245 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
247 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
249 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
250 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
251 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
253 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
254 'D','o','c','u','m','e','n','t',0};
256 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
257 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
258 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
259 0, sizeof(DRIVER_INFO_8W
)};
262 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
263 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
264 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
265 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
266 sizeof(PRINTER_INFO_9W
)};
268 /******************************************************************
269 * validate the user-supplied printing-environment [internal]
272 * env [I] PTR to Environment-String or NULL
276 * Success: PTR to printenv_t
279 * An empty string is handled the same way as NULL.
280 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
284 static const printenv_t
* validate_envW(LPCWSTR env
)
286 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
287 3, Version3_RegPathW
, Version3_SubdirW
};
288 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
289 0, Version0_RegPathW
, Version0_SubdirW
};
291 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
293 const printenv_t
*result
= NULL
;
296 TRACE("testing %s\n", debugstr_w(env
));
299 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
301 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
303 result
= all_printenv
[i
];
308 if (result
== NULL
) {
309 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
310 SetLastError(ERROR_INVALID_ENVIRONMENT
);
312 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
316 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
318 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
324 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
325 if passed a NULL string. This returns NULLs to the result.
327 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
331 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
332 return usBufferPtr
->Buffer
;
334 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
338 static LPWSTR
strdupW(LPCWSTR p
)
344 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
345 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
350 static LPSTR
strdupWtoA( LPCWSTR str
)
355 if (!str
) return NULL
;
356 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
357 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
358 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
362 /******************************************************************
363 * Return the number of bytes for an multi_sz string.
364 * The result includes all \0s
365 * (specifically the extra \0, that is needed as multi_sz terminator).
368 static int multi_sz_lenW(const WCHAR
*str
)
370 const WCHAR
*ptr
= str
;
374 ptr
+= lstrlenW(ptr
) + 1;
377 return (ptr
- str
+ 1) * sizeof(WCHAR
);
380 /* ################################ */
382 static int multi_sz_lenA(const char *str
)
384 const char *ptr
= str
;
388 ptr
+= lstrlenA(ptr
) + 1;
391 return ptr
- str
+ 1;
395 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
398 /* If forcing, or no profile string entry for device yet, set the entry
400 * The always change entry if not WINEPS yet is discussable.
403 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
405 !strstr(qbuf
,"WINEPS.DRV")
407 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
410 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
411 WriteProfileStringA("windows","device",buf
);
412 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
413 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
416 HeapFree(GetProcessHeap(),0,buf
);
420 static BOOL
add_printer_driver(const char *name
)
424 static char driver_9x
[] = "wineps16.drv",
425 driver_nt
[] = "wineps.drv",
426 env_9x
[] = "Windows 4.0",
427 env_nt
[] = "Windows NT x86",
428 data_file
[] = "generic.ppd",
429 default_data_type
[] = "RAW";
431 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
433 di3a
.pName
= (char *)name
;
434 di3a
.pEnvironment
= env_nt
;
435 di3a
.pDriverPath
= driver_nt
;
436 di3a
.pDataFile
= data_file
;
437 di3a
.pConfigFile
= driver_nt
;
438 di3a
.pDefaultDataType
= default_data_type
;
440 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
441 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
444 di3a
.pEnvironment
= env_9x
;
445 di3a
.pDriverPath
= driver_9x
;
446 di3a
.pConfigFile
= driver_9x
;
447 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
448 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
453 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
454 debugstr_a(di3a
.pEnvironment
), GetLastError());
458 #ifdef SONAME_LIBCUPS
459 static typeof(cupsGetDests
) *pcupsGetDests
;
460 static typeof(cupsGetPPD
) *pcupsGetPPD
;
461 static typeof(cupsPrintFile
) *pcupsPrintFile
;
462 static void *cupshandle
;
464 static BOOL
CUPS_LoadPrinters(void)
467 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
469 PRINTER_INFO_2A pinfo2a
;
471 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
474 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
476 TRACE("%s\n", loaderror
);
479 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
482 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
483 if (!p##x) return FALSE;
486 DYNCUPS(cupsGetDests
);
487 DYNCUPS(cupsPrintFile
);
490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
492 ERR("Can't create Printers key\n");
496 nrofdests
= pcupsGetDests(&dests
);
497 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
498 for (i
=0;i
<nrofdests
;i
++) {
499 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
500 port
= HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests
[i
].name
)+1);
501 sprintf(port
,"LPR:%s", dests
[i
].name
);
502 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
503 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
504 sprintf(devline
, "WINEPS.DRV,%s", port
);
505 WriteProfileStringA("devices", dests
[i
].name
, devline
);
506 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
507 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
511 lstrcatA(devline
, ",15,45");
512 WriteProfileStringA("PrinterPorts", dests
[i
].name
, devline
);
513 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
514 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
518 HeapFree(GetProcessHeap(), 0, devline
);
520 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
521 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
522 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
524 TRACE("Printer already exists\n");
525 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
526 RegCloseKey(hkeyPrinter
);
527 add_printer_driver(dests
[i
].name
);
529 static CHAR data_type
[] = "RAW",
530 print_proc
[] = "WinPrint",
531 comment
[] = "WINEPS Printer using CUPS",
532 location
[] = "<physical location of printer>",
533 params
[] = "<parameters?>",
534 share_name
[] = "<share name?>",
535 sep_file
[] = "<sep file?>";
537 add_printer_driver(dests
[i
].name
);
539 memset(&pinfo2a
,0,sizeof(pinfo2a
));
540 pinfo2a
.pPrinterName
= dests
[i
].name
;
541 pinfo2a
.pDatatype
= data_type
;
542 pinfo2a
.pPrintProcessor
= print_proc
;
543 pinfo2a
.pDriverName
= dests
[i
].name
;
544 pinfo2a
.pComment
= comment
;
545 pinfo2a
.pLocation
= location
;
546 pinfo2a
.pPortName
= port
;
547 pinfo2a
.pParameters
= params
;
548 pinfo2a
.pShareName
= share_name
;
549 pinfo2a
.pSepFile
= sep_file
;
551 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
552 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
553 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
556 HeapFree(GetProcessHeap(),0,port
);
559 if (dests
[i
].is_default
) {
560 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
564 if (hadprinter
& !haddefault
)
565 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
566 RegCloseKey(hkeyPrinters
);
572 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
573 PRINTER_INFO_2A pinfo2a
;
574 char *e
,*s
,*name
,*prettyname
,*devname
;
575 BOOL ret
= FALSE
, set_default
= FALSE
;
576 char *port
= NULL
, *devline
,*env_default
;
577 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
579 while (isspace(*pent
)) pent
++;
580 s
= strchr(pent
,':');
582 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
590 TRACE("name=%s entry=%s\n",name
, pent
);
592 if(ispunct(*name
)) { /* a tc entry, not a real printer */
593 TRACE("skipping tc entry\n");
597 if(strstr(pent
,":server")) { /* server only version so skip */
598 TRACE("skipping server entry\n");
602 /* Determine whether this is a postscript printer. */
605 env_default
= getenv("PRINTER");
607 /* Get longest name, usually the one at the right for later display. */
608 while((s
=strchr(prettyname
,'|'))) {
611 while(isspace(*--e
)) *e
= '\0';
612 TRACE("\t%s\n", debugstr_a(prettyname
));
613 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
614 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
617 e
= prettyname
+ strlen(prettyname
);
618 while(isspace(*--e
)) *e
= '\0';
619 TRACE("\t%s\n", debugstr_a(prettyname
));
620 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
622 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
623 * if it is too long, we use it as comment below. */
624 devname
= prettyname
;
625 if (strlen(devname
)>=CCHDEVICENAME
-1)
627 if (strlen(devname
)>=CCHDEVICENAME
-1) {
632 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
633 sprintf(port
,"LPR:%s",name
);
635 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
636 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
637 sprintf(devline
, "WINEPS.DRV,%s", port
);
638 WriteProfileStringA("devices", devname
, devline
);
639 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
640 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
644 lstrcatA(devline
, ",15,45");
645 WriteProfileStringA("PrinterPorts", devname
, devline
);
646 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
647 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
651 HeapFree(GetProcessHeap(),0,devline
);
653 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
655 ERR("Can't create Printers key\n");
659 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
660 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
662 TRACE("Printer already exists\n");
663 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
664 RegCloseKey(hkeyPrinter
);
665 add_printer_driver(devname
);
667 static CHAR data_type
[] = "RAW",
668 print_proc
[] = "WinPrint",
669 comment
[] = "WINEPS Printer using LPR",
670 params
[] = "<parameters?>",
671 share_name
[] = "<share name?>",
672 sep_file
[] = "<sep file?>";
674 add_printer_driver(devname
);
676 memset(&pinfo2a
,0,sizeof(pinfo2a
));
677 pinfo2a
.pPrinterName
= devname
;
678 pinfo2a
.pDatatype
= data_type
;
679 pinfo2a
.pPrintProcessor
= print_proc
;
680 pinfo2a
.pDriverName
= devname
;
681 pinfo2a
.pComment
= comment
;
682 pinfo2a
.pLocation
= prettyname
;
683 pinfo2a
.pPortName
= port
;
684 pinfo2a
.pParameters
= params
;
685 pinfo2a
.pShareName
= share_name
;
686 pinfo2a
.pSepFile
= sep_file
;
688 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
689 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
690 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
693 RegCloseKey(hkeyPrinters
);
695 if (isfirst
|| set_default
)
696 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
699 HeapFree(GetProcessHeap(), 0, port
);
700 HeapFree(GetProcessHeap(), 0, name
);
705 PRINTCAP_LoadPrinters(void) {
706 BOOL hadprinter
= FALSE
;
710 BOOL had_bash
= FALSE
;
712 f
= fopen("/etc/printcap","r");
716 while(fgets(buf
,sizeof(buf
),f
)) {
719 end
=strchr(buf
,'\n');
723 while(isspace(*start
)) start
++;
724 if(*start
== '#' || *start
== '\0')
727 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
728 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
729 HeapFree(GetProcessHeap(),0,pent
);
733 if (end
&& *--end
== '\\') {
740 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
743 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
749 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
750 HeapFree(GetProcessHeap(),0,pent
);
756 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
759 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
760 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
762 return ERROR_FILE_NOT_FOUND
;
765 /******************************************************************
766 * monitor_unload [internal]
768 * release a printmonitor and unload it from memory, when needed
771 static void monitor_unload(monitor_t
* pm
)
773 if (pm
== NULL
) return;
774 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
776 EnterCriticalSection(&monitor_handles_cs
);
778 if (pm
->refcount
) pm
->refcount
--;
780 if (pm
->refcount
== 0) {
781 list_remove(&pm
->entry
);
782 FreeLibrary(pm
->hdll
);
783 HeapFree(GetProcessHeap(), 0, pm
->name
);
784 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
785 HeapFree(GetProcessHeap(), 0, pm
);
787 LeaveCriticalSection(&monitor_handles_cs
);
790 /******************************************************************
791 * monitor_unloadall [internal]
793 * release all printmonitors and unload them from memory, when needed
796 static void monitor_unloadall(void)
801 EnterCriticalSection(&monitor_handles_cs
);
802 /* iterate through the list, with safety against removal */
803 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
807 LeaveCriticalSection(&monitor_handles_cs
);
810 /******************************************************************
811 * monitor_load [internal]
813 * load a printmonitor, get the dllname from the registry, when needed
814 * initialize the monitor and dump found function-pointers
816 * On failure, SetLastError() is called and NULL is returned
819 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
821 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
822 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
823 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
824 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
825 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
827 monitor_t
* pm
= NULL
;
829 LPWSTR regroot
= NULL
;
830 LPWSTR driver
= dllname
;
832 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
833 /* Is the Monitor already loaded? */
834 EnterCriticalSection(&monitor_handles_cs
);
837 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
839 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
847 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
848 if (pm
== NULL
) goto cleanup
;
849 list_add_tail(&monitor_handles
, &pm
->entry
);
853 if (pm
->name
== NULL
) {
854 /* Load the monitor */
855 LPMONITOREX pmonitorEx
;
859 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
860 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
864 lstrcpyW(regroot
, MonitorsW
);
865 lstrcatW(regroot
, name
);
866 /* Get the Driver from the Registry */
867 if (driver
== NULL
) {
870 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
871 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
872 &namesize
) == ERROR_SUCCESS
) {
873 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
874 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
881 pm
->name
= strdupW(name
);
882 pm
->dllname
= strdupW(driver
);
884 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
886 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
891 pm
->hdll
= LoadLibraryW(driver
);
892 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
894 if (pm
->hdll
== NULL
) {
896 SetLastError(ERROR_MOD_NOT_FOUND
);
901 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
902 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
903 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
904 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
905 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
908 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
909 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
910 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
911 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
912 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
914 if (pInitializePrintMonitorUI
!= NULL
) {
915 pm
->monitorUI
= pInitializePrintMonitorUI();
916 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
918 TRACE( "0x%08x: dwMonitorSize (%d)\n",
919 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
924 if (pInitializePrintMonitor
&& regroot
) {
925 pmonitorEx
= pInitializePrintMonitor(regroot
);
926 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
927 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
930 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
931 pm
->monitor
= &(pmonitorEx
->Monitor
);
936 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
940 if (!pm
->monitor
&& regroot
) {
941 if (pInitializePrintMonitor2
!= NULL
) {
942 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
944 if (pInitializeMonitorEx
!= NULL
) {
945 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
947 if (pInitializeMonitor
!= NULL
) {
948 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
951 if (!pm
->monitor
&& !pm
->monitorUI
) {
953 SetLastError(ERROR_PROC_NOT_FOUND
);
958 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
962 LeaveCriticalSection(&monitor_handles_cs
);
963 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
964 HeapFree(GetProcessHeap(), 0, regroot
);
965 TRACE("=> %p\n", pm
);
969 /******************************************************************
970 * monitor_loadall [internal]
972 * Load all registered monitors
975 static DWORD
monitor_loadall(void)
978 DWORD registered
= 0;
981 WCHAR buffer
[MAX_PATH
];
984 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
985 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
986 NULL
, NULL
, NULL
, NULL
, NULL
);
988 TRACE("%d monitors registered\n", registered
);
990 EnterCriticalSection(&monitor_handles_cs
);
991 while (id
< registered
) {
993 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
994 pm
= monitor_load(buffer
, NULL
);
998 LeaveCriticalSection(&monitor_handles_cs
);
999 RegCloseKey(hmonitors
);
1001 TRACE("%d monitors loaded\n", loaded
);
1005 /******************************************************************
1006 * monitor_loadui [internal]
1008 * load the userinterface-dll for a given portmonitor
1010 * On failure, NULL is returned
1013 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1015 monitor_t
* pui
= NULL
;
1016 LPWSTR buffer
[MAX_PATH
];
1021 if (pm
== NULL
) return NULL
;
1022 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1024 /* Try the Portmonitor first; works for many monitors */
1025 if (pm
->monitorUI
) {
1026 EnterCriticalSection(&monitor_handles_cs
);
1028 LeaveCriticalSection(&monitor_handles_cs
);
1032 /* query the userinterface-dllname from the Portmonitor */
1033 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1034 /* building (",XcvMonitor %s",pm->name) not needed yet */
1035 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1036 TRACE("got %u with %p\n", res
, hXcv
);
1038 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1039 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1040 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1041 pm
->monitor
->pfnXcvClosePort(hXcv
);
1048 /******************************************************************
1049 * monitor_load_by_port [internal]
1051 * load a printmonitor for a given port
1053 * On failure, NULL is returned
1056 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1061 monitor_t
* pm
= NULL
;
1062 DWORD registered
= 0;
1066 TRACE("(%s)\n", debugstr_w(portname
));
1068 /* Try the Local Monitor first */
1069 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1070 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1071 /* found the portname */
1073 return monitor_load(LocalPortW
, NULL
);
1078 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1079 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1080 if (buffer
== NULL
) return NULL
;
1082 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1083 EnterCriticalSection(&monitor_handles_cs
);
1084 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1086 while ((pm
== NULL
) && (id
< registered
)) {
1088 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1089 TRACE("testing %s\n", debugstr_w(buffer
));
1090 len
= lstrlenW(buffer
);
1091 lstrcatW(buffer
, bs_Ports_bsW
);
1092 lstrcatW(buffer
, portname
);
1093 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1095 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1096 pm
= monitor_load(buffer
, NULL
);
1100 LeaveCriticalSection(&monitor_handles_cs
);
1103 HeapFree(GetProcessHeap(), 0, buffer
);
1107 /******************************************************************
1108 * enumerate the local Ports from all loaded monitors (internal)
1110 * returns the needed size (in bytes) for pPorts
1111 * and *lpreturned is set to number of entries returned in pPorts
1114 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1118 LPPORT_INFO_2W cache
;
1120 LPBYTE pi_buffer
= NULL
;
1121 DWORD pi_allocated
= 0;
1132 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1133 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1135 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1136 needed
= entrysize
* numentries
;
1137 ptr
= (LPWSTR
) &pPorts
[needed
];
1142 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1144 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1147 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1148 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1149 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1150 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1151 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1152 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1153 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1155 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1156 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1158 numentries
+= pi_returned
;
1159 needed
+= pi_needed
;
1161 /* fill the output-buffer (pPorts), if we have one */
1162 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1164 while (pi_returned
> pi_index
) {
1165 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1166 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1167 out
->pPortName
= ptr
;
1168 lstrcpyW(ptr
, cache
->pPortName
);
1169 ptr
+= (lstrlenW(ptr
)+1);
1171 out
->pMonitorName
= ptr
;
1172 lstrcpyW(ptr
, cache
->pMonitorName
);
1173 ptr
+= (lstrlenW(ptr
)+1);
1175 out
->pDescription
= ptr
;
1176 lstrcpyW(ptr
, cache
->pDescription
);
1177 ptr
+= (lstrlenW(ptr
)+1);
1178 out
->fPortType
= cache
->fPortType
;
1179 out
->Reserved
= cache
->Reserved
;
1187 /* the temporary portinfo-buffer is no longer needed */
1188 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1190 *lpreturned
= numentries
;
1191 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1195 /******************************************************************
1196 * get_servername_from_name (internal)
1198 * for an external server, a copy of the serverpart from the full name is returned
1201 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1205 WCHAR buffer
[MAX_PATH
];
1208 if (name
== NULL
) return NULL
;
1209 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1211 server
= strdupW(&name
[2]); /* skip over both backslash */
1212 if (server
== NULL
) return NULL
;
1214 /* strip '\' and the printername */
1215 ptr
= strchrW(server
, '\\');
1216 if (ptr
) ptr
[0] = '\0';
1218 TRACE("found %s\n", debugstr_w(server
));
1220 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1221 if (GetComputerNameW(buffer
, &len
)) {
1222 if (lstrcmpW(buffer
, server
) == 0) {
1223 /* The requested Servername is our computername */
1224 HeapFree(GetProcessHeap(), 0, server
);
1231 /******************************************************************
1232 * get_basename_from_name (internal)
1234 * skip over the serverpart from the full name
1237 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1239 if (name
== NULL
) return NULL
;
1240 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1241 /* skip over the servername and search for the following '\' */
1242 name
= strchrW(&name
[2], '\\');
1243 if ((name
) && (name
[1])) {
1244 /* found a separator ('\') followed by a name:
1245 skip over the separator and return the rest */
1250 /* no basename present (we found only a servername) */
1257 /******************************************************************
1258 * get_opened_printer_entry
1259 * Get the first place empty in the opened printer table
1262 * - pDefault is ignored
1264 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1266 UINT_PTR handle
= nb_printer_handles
, i
;
1267 jobqueue_t
*queue
= NULL
;
1268 opened_printer_t
*printer
= NULL
;
1270 LPCWSTR printername
;
1275 servername
= get_servername_from_name(name
);
1277 FIXME("server %s not supported\n", debugstr_w(servername
));
1278 HeapFree(GetProcessHeap(), 0, servername
);
1279 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1283 printername
= get_basename_from_name(name
);
1284 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1286 /* an empty printername is invalid */
1287 if (printername
&& (!printername
[0])) {
1288 SetLastError(ERROR_INVALID_PARAMETER
);
1292 EnterCriticalSection(&printer_handles_cs
);
1294 for (i
= 0; i
< nb_printer_handles
; i
++)
1296 if (!printer_handles
[i
])
1298 if(handle
== nb_printer_handles
)
1303 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1304 queue
= printer_handles
[i
]->queue
;
1308 if (handle
>= nb_printer_handles
)
1310 opened_printer_t
**new_array
;
1311 if (printer_handles
)
1312 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1313 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1315 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1316 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1323 printer_handles
= new_array
;
1324 nb_printer_handles
+= 16;
1327 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1334 /* clone the base name. This is NULL for the printserver */
1335 printer
->printername
= strdupW(printername
);
1337 /* clone the full name */
1338 printer
->name
= strdupW(name
);
1339 if (name
&& (!printer
->name
)) {
1345 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1346 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1347 /* OpenPrinter(",XcvMonitor " detected */
1348 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1349 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1350 if (printer
->pm
== NULL
) {
1351 SetLastError(ERROR_UNKNOWN_PORT
);
1358 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1359 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1360 /* OpenPrinter(",XcvPort " detected */
1361 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1362 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1363 if (printer
->pm
== NULL
) {
1364 SetLastError(ERROR_UNKNOWN_PORT
);
1372 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1373 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1374 pDefault
? pDefault
->DesiredAccess
: 0,
1377 if (printer
->hXcv
== NULL
) {
1378 SetLastError(ERROR_INVALID_PARAMETER
);
1385 /* Does the Printer exist? */
1386 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1387 ERR("Can't create Printers key\n");
1391 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1392 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1393 RegCloseKey(hkeyPrinters
);
1394 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1398 RegCloseKey(hkeyPrinter
);
1399 RegCloseKey(hkeyPrinters
);
1404 TRACE("using the local printserver\n");
1408 printer
->queue
= queue
;
1411 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1412 if (!printer
->queue
) {
1416 list_init(&printer
->queue
->jobs
);
1417 printer
->queue
->ref
= 0;
1419 InterlockedIncrement(&printer
->queue
->ref
);
1421 printer_handles
[handle
] = printer
;
1424 LeaveCriticalSection(&printer_handles_cs
);
1425 if (!handle
&& printer
) {
1426 /* Something failed: Free all resources */
1427 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1428 monitor_unload(printer
->pm
);
1429 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1430 HeapFree(GetProcessHeap(), 0, printer
->name
);
1431 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1432 HeapFree(GetProcessHeap(), 0, printer
);
1435 return (HANDLE
)handle
;
1438 /******************************************************************
1439 * get_opened_printer
1440 * Get the pointer to the opened printer referred by the handle
1442 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1444 UINT_PTR idx
= (UINT_PTR
)hprn
;
1445 opened_printer_t
*ret
= NULL
;
1447 EnterCriticalSection(&printer_handles_cs
);
1449 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
1450 ret
= printer_handles
[idx
- 1];
1452 LeaveCriticalSection(&printer_handles_cs
);
1456 /******************************************************************
1457 * get_opened_printer_name
1458 * Get the pointer to the opened printer name referred by the handle
1460 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1462 opened_printer_t
*printer
= get_opened_printer(hprn
);
1463 if(!printer
) return NULL
;
1464 return printer
->name
;
1467 /******************************************************************
1468 * WINSPOOL_GetOpenedPrinterRegKey
1471 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1473 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1477 if(!name
) return ERROR_INVALID_HANDLE
;
1479 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1483 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1485 ERR("Can't find opened printer %s in registry\n",
1487 RegCloseKey(hkeyPrinters
);
1488 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1490 RegCloseKey(hkeyPrinters
);
1491 return ERROR_SUCCESS
;
1494 void WINSPOOL_LoadSystemPrinters(void)
1496 HKEY hkey
, hkeyPrinters
;
1498 DWORD needed
, num
, i
;
1499 WCHAR PrinterName
[256];
1502 /* This ensures that all printer entries have a valid Name value. If causes
1503 problems later if they don't. If one is found to be missed we create one
1504 and set it equal to the name of the key */
1505 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1506 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1507 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1508 for(i
= 0; i
< num
; i
++) {
1509 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1510 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1511 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1512 set_reg_szW(hkey
, NameW
, PrinterName
);
1519 RegCloseKey(hkeyPrinters
);
1522 /* We want to avoid calling AddPrinter on printers as much as
1523 possible, because on cups printers this will (eventually) lead
1524 to a call to cupsGetPPD which takes forever, even with non-cups
1525 printers AddPrinter takes a while. So we'll tag all printers that
1526 were automatically added last time around, if they still exist
1527 we'll leave them be otherwise we'll delete them. */
1528 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1530 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1531 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1532 for(i
= 0; i
< num
; i
++) {
1533 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1534 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1535 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1537 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1545 HeapFree(GetProcessHeap(), 0, pi
);
1549 #ifdef SONAME_LIBCUPS
1550 done
= CUPS_LoadPrinters();
1553 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1554 PRINTCAP_LoadPrinters();
1556 /* Now enumerate the list again and delete any printers that are still tagged */
1557 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1559 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1560 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1561 for(i
= 0; i
< num
; i
++) {
1562 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1563 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1564 BOOL delete_driver
= FALSE
;
1565 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1566 DWORD dw
, type
, size
= sizeof(dw
);
1567 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1568 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1569 DeletePrinter(hprn
);
1570 delete_driver
= TRUE
;
1576 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1581 HeapFree(GetProcessHeap(), 0, pi
);
1588 /******************************************************************
1591 * Get the pointer to the specified job.
1592 * Should hold the printer_handles_cs before calling.
1594 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1596 opened_printer_t
*printer
= get_opened_printer(hprn
);
1599 if(!printer
) return NULL
;
1600 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1602 if(job
->job_id
== JobId
)
1608 /***********************************************************
1611 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1614 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1617 Formname
= (dmA
->dmSize
> off_formname
);
1618 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1619 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1620 dmW
->dmDeviceName
, CCHDEVICENAME
);
1622 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1623 dmA
->dmSize
- CCHDEVICENAME
);
1625 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1626 off_formname
- CCHDEVICENAME
);
1627 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1628 dmW
->dmFormName
, CCHFORMNAME
);
1629 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1630 (off_formname
+ CCHFORMNAME
));
1633 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1634 dmA
->dmDriverExtra
);
1638 /***********************************************************
1640 * Creates an ansi copy of supplied devmode
1642 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1647 if (!dmW
) return NULL
;
1648 size
= dmW
->dmSize
- CCHDEVICENAME
-
1649 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1651 dmA
= HeapAlloc(GetProcessHeap(), 0, size
+ dmW
->dmDriverExtra
);
1652 if (!dmA
) return NULL
;
1654 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1655 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1657 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1658 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1659 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1663 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1664 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1665 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1666 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1668 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1672 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1676 /******************************************************************
1677 * convert_printerinfo_W_to_A [internal]
1680 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1681 DWORD level
, DWORD outlen
, DWORD numentries
)
1687 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1689 len
= pi_sizeof
[level
] * numentries
;
1690 ptr
= (LPSTR
) out
+ len
;
1693 /* copy the numbers of all PRINTER_INFO_* first */
1694 memcpy(out
, pPrintersW
, len
);
1696 while (id
< numentries
) {
1700 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1701 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1703 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1704 if (piW
->pDescription
) {
1705 piA
->pDescription
= ptr
;
1706 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1707 ptr
, outlen
, NULL
, NULL
);
1713 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1714 ptr
, outlen
, NULL
, NULL
);
1718 if (piW
->pComment
) {
1719 piA
->pComment
= ptr
;
1720 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1721 ptr
, outlen
, NULL
, NULL
);
1730 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1731 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1734 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1735 if (piW
->pServerName
) {
1736 piA
->pServerName
= ptr
;
1737 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1738 ptr
, outlen
, NULL
, NULL
);
1742 if (piW
->pPrinterName
) {
1743 piA
->pPrinterName
= ptr
;
1744 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1745 ptr
, outlen
, NULL
, NULL
);
1749 if (piW
->pShareName
) {
1750 piA
->pShareName
= ptr
;
1751 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1752 ptr
, outlen
, NULL
, NULL
);
1756 if (piW
->pPortName
) {
1757 piA
->pPortName
= ptr
;
1758 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1759 ptr
, outlen
, NULL
, NULL
);
1763 if (piW
->pDriverName
) {
1764 piA
->pDriverName
= ptr
;
1765 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1766 ptr
, outlen
, NULL
, NULL
);
1770 if (piW
->pComment
) {
1771 piA
->pComment
= ptr
;
1772 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1773 ptr
, outlen
, NULL
, NULL
);
1777 if (piW
->pLocation
) {
1778 piA
->pLocation
= ptr
;
1779 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1780 ptr
, outlen
, NULL
, NULL
);
1785 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1787 /* align DEVMODEA to a DWORD boundary */
1788 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1792 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1793 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1794 memcpy(ptr
, dmA
, len
);
1795 HeapFree(GetProcessHeap(), 0, dmA
);
1801 if (piW
->pSepFile
) {
1802 piA
->pSepFile
= ptr
;
1803 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1804 ptr
, outlen
, NULL
, NULL
);
1808 if (piW
->pPrintProcessor
) {
1809 piA
->pPrintProcessor
= ptr
;
1810 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1811 ptr
, outlen
, NULL
, NULL
);
1815 if (piW
->pDatatype
) {
1816 piA
->pDatatype
= ptr
;
1817 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1818 ptr
, outlen
, NULL
, NULL
);
1822 if (piW
->pParameters
) {
1823 piA
->pParameters
= ptr
;
1824 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1825 ptr
, outlen
, NULL
, NULL
);
1829 if (piW
->pSecurityDescriptor
) {
1830 piA
->pSecurityDescriptor
= NULL
;
1831 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1838 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1839 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1841 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1843 if (piW
->pPrinterName
) {
1844 piA
->pPrinterName
= ptr
;
1845 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1846 ptr
, outlen
, NULL
, NULL
);
1850 if (piW
->pServerName
) {
1851 piA
->pServerName
= ptr
;
1852 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1853 ptr
, outlen
, NULL
, NULL
);
1862 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1863 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1865 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1867 if (piW
->pPrinterName
) {
1868 piA
->pPrinterName
= ptr
;
1869 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1870 ptr
, outlen
, NULL
, NULL
);
1874 if (piW
->pPortName
) {
1875 piA
->pPortName
= ptr
;
1876 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1877 ptr
, outlen
, NULL
, NULL
);
1885 FIXME("for level %u\n", level
);
1887 pPrintersW
+= pi_sizeof
[level
];
1888 out
+= pi_sizeof
[level
];
1893 /***********************************************************
1894 * PRINTER_INFO_2AtoW
1895 * Creates a unicode copy of PRINTER_INFO_2A on heap
1897 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1899 LPPRINTER_INFO_2W piW
;
1900 UNICODE_STRING usBuffer
;
1902 if(!piA
) return NULL
;
1903 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1904 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1906 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1907 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1908 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1909 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1910 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1911 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1912 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1913 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1914 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1915 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1916 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1917 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1921 /***********************************************************
1922 * FREE_PRINTER_INFO_2W
1923 * Free PRINTER_INFO_2W and all strings
1925 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1929 HeapFree(heap
,0,piW
->pServerName
);
1930 HeapFree(heap
,0,piW
->pPrinterName
);
1931 HeapFree(heap
,0,piW
->pShareName
);
1932 HeapFree(heap
,0,piW
->pPortName
);
1933 HeapFree(heap
,0,piW
->pDriverName
);
1934 HeapFree(heap
,0,piW
->pComment
);
1935 HeapFree(heap
,0,piW
->pLocation
);
1936 HeapFree(heap
,0,piW
->pDevMode
);
1937 HeapFree(heap
,0,piW
->pSepFile
);
1938 HeapFree(heap
,0,piW
->pPrintProcessor
);
1939 HeapFree(heap
,0,piW
->pDatatype
);
1940 HeapFree(heap
,0,piW
->pParameters
);
1941 HeapFree(heap
,0,piW
);
1945 /******************************************************************
1946 * DeviceCapabilities [WINSPOOL.@]
1947 * DeviceCapabilitiesA [WINSPOOL.@]
1950 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1951 LPSTR pOutput
, LPDEVMODEA lpdm
)
1955 if (!GDI_CallDeviceCapabilities16
)
1957 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1959 if (!GDI_CallDeviceCapabilities16
) return -1;
1961 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1963 /* If DC_PAPERSIZE map POINT16s to POINTs */
1964 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1965 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1966 POINT
*pt
= (POINT
*)pOutput
;
1968 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1969 for(i
= 0; i
< ret
; i
++, pt
++)
1974 HeapFree( GetProcessHeap(), 0, tmp
);
1980 /*****************************************************************************
1981 * DeviceCapabilitiesW [WINSPOOL.@]
1983 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1986 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1987 WORD fwCapability
, LPWSTR pOutput
,
1988 const DEVMODEW
*pDevMode
)
1990 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1991 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1992 LPSTR pPortA
= strdupWtoA(pPort
);
1995 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1996 fwCapability
== DC_FILEDEPENDENCIES
||
1997 fwCapability
== DC_PAPERNAMES
)) {
1998 /* These need A -> W translation */
2001 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2005 switch(fwCapability
) {
2010 case DC_FILEDEPENDENCIES
:
2014 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2015 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2017 for(i
= 0; i
< ret
; i
++)
2018 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2019 pOutput
+ (i
* size
), size
);
2020 HeapFree(GetProcessHeap(), 0, pOutputA
);
2022 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2023 (LPSTR
)pOutput
, dmA
);
2025 HeapFree(GetProcessHeap(),0,pPortA
);
2026 HeapFree(GetProcessHeap(),0,pDeviceA
);
2027 HeapFree(GetProcessHeap(),0,dmA
);
2031 /******************************************************************
2032 * DocumentPropertiesA [WINSPOOL.@]
2034 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2036 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2037 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2038 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2040 LPSTR lpName
= pDeviceName
;
2041 static CHAR port
[] = "LPT1:";
2044 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2045 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2049 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2051 ERR("no name from hPrinter?\n");
2052 SetLastError(ERROR_INVALID_HANDLE
);
2055 lpName
= strdupWtoA(lpNameW
);
2058 if (!GDI_CallExtDeviceMode16
)
2060 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2062 if (!GDI_CallExtDeviceMode16
) {
2063 ERR("No CallExtDeviceMode16?\n");
2067 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2068 pDevModeInput
, NULL
, fMode
);
2071 HeapFree(GetProcessHeap(),0,lpName
);
2076 /*****************************************************************************
2077 * DocumentPropertiesW (WINSPOOL.@)
2079 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2081 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2083 LPDEVMODEW pDevModeOutput
,
2084 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2087 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2088 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
2089 LPDEVMODEA pDevModeOutputA
= NULL
;
2092 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2093 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2095 if(pDevModeOutput
) {
2096 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2097 if(ret
< 0) return ret
;
2098 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2100 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2101 pDevModeInputA
, fMode
);
2102 if(pDevModeOutput
) {
2103 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2104 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2106 if(fMode
== 0 && ret
> 0)
2107 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2108 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2109 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2113 /******************************************************************
2114 * OpenPrinterA [WINSPOOL.@]
2119 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2120 LPPRINTER_DEFAULTSA pDefault
)
2122 UNICODE_STRING lpPrinterNameW
;
2123 UNICODE_STRING usBuffer
;
2124 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2125 PWSTR pwstrPrinterNameW
;
2128 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2131 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2132 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2133 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2134 pDefaultW
= &DefaultW
;
2136 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2138 RtlFreeUnicodeString(&usBuffer
);
2139 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2141 RtlFreeUnicodeString(&lpPrinterNameW
);
2145 /******************************************************************
2146 * OpenPrinterW [WINSPOOL.@]
2148 * Open a Printer / Printserver or a Printer-Object
2151 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2152 * phPrinter [O] The resulting Handle is stored here
2153 * pDefault [I] PTR to Default Printer Settings or NULL
2160 * lpPrinterName is one of:
2161 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2162 *| Printer: "PrinterName"
2163 *| Printer-Object: "PrinterName,Job xxx"
2164 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2165 *| XcvPort: "Servername,XcvPort PortName"
2168 *| Printer-Object not supported
2169 *| pDefaults is ignored
2172 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2175 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2177 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2178 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2182 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2183 SetLastError(ERROR_INVALID_PARAMETER
);
2187 /* Get the unique handle of the printer or Printserver */
2188 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2189 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2190 return (*phPrinter
!= 0);
2193 /******************************************************************
2194 * AddMonitorA [WINSPOOL.@]
2199 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2201 LPWSTR nameW
= NULL
;
2204 LPMONITOR_INFO_2A mi2a
;
2205 MONITOR_INFO_2W mi2w
;
2207 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2208 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2209 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2210 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2211 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2214 SetLastError(ERROR_INVALID_LEVEL
);
2218 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2224 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2225 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2226 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2229 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2231 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2232 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2233 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2235 if (mi2a
->pEnvironment
) {
2236 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2237 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2238 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2240 if (mi2a
->pDLLName
) {
2241 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2242 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2243 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2246 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2248 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2249 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2250 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2252 HeapFree(GetProcessHeap(), 0, nameW
);
2256 /******************************************************************************
2257 * AddMonitorW [WINSPOOL.@]
2259 * Install a Printmonitor
2262 * pName [I] Servername or NULL (local Computer)
2263 * Level [I] Structure-Level (Must be 2)
2264 * pMonitors [I] PTR to MONITOR_INFO_2
2271 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2274 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2276 monitor_t
* pm
= NULL
;
2277 LPMONITOR_INFO_2W mi2w
;
2283 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2284 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2285 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2286 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2287 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2290 SetLastError(ERROR_INVALID_LEVEL
);
2294 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2299 if (pName
&& (pName
[0])) {
2300 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2301 SetLastError(ERROR_ACCESS_DENIED
);
2306 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2307 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2308 SetLastError(ERROR_INVALID_PARAMETER
);
2311 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2312 WARN("Environment %s requested (we support only %s)\n",
2313 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2314 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2318 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2319 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2320 SetLastError(ERROR_INVALID_PARAMETER
);
2324 /* Load and initialize the monitor. SetLastError() is called on failure */
2325 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2330 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2331 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2335 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2336 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2337 &disposition
) == ERROR_SUCCESS
) {
2339 /* Some installers set options for the port before calling AddMonitor.
2340 We query the "Driver" entry to verify that the monitor is installed,
2341 before we return an error.
2342 When a user installs two print monitors at the same time with the
2343 same name but with a different driver DLL and a task switch comes
2344 between RegQueryValueExW and RegSetValueExW, a race condition
2345 is possible but silently ignored. */
2349 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2350 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2351 &namesize
) == ERROR_SUCCESS
)) {
2352 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2353 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2354 9x: ERROR_ALREADY_EXISTS (183) */
2355 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2360 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2361 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2362 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2364 RegCloseKey(hentry
);
2371 /******************************************************************
2372 * DeletePrinterDriverA [WINSPOOL.@]
2375 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2377 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2380 /******************************************************************
2381 * DeletePrinterDriverW [WINSPOOL.@]
2384 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2386 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2389 /******************************************************************
2390 * DeleteMonitorA [WINSPOOL.@]
2392 * See DeleteMonitorW.
2395 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2397 LPWSTR nameW
= NULL
;
2398 LPWSTR EnvironmentW
= NULL
;
2399 LPWSTR MonitorNameW
= NULL
;
2404 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2405 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2406 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2410 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2411 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2412 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2415 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2416 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2417 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2420 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2422 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2423 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2424 HeapFree(GetProcessHeap(), 0, nameW
);
2428 /******************************************************************
2429 * DeleteMonitorW [WINSPOOL.@]
2431 * Delete a specific Printmonitor from a Printing-Environment
2434 * pName [I] Servername or NULL (local Computer)
2435 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2436 * pMonitorName [I] Name of the Monitor, that should be deleted
2443 * pEnvironment is ignored in Windows for the local Computer.
2447 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2451 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2452 debugstr_w(pMonitorName
));
2454 if (pName
&& (pName
[0])) {
2455 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2456 SetLastError(ERROR_ACCESS_DENIED
);
2460 /* pEnvironment is ignored in Windows for the local Computer */
2462 if (!pMonitorName
|| !pMonitorName
[0]) {
2463 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2464 SetLastError(ERROR_INVALID_PARAMETER
);
2468 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2469 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2473 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2474 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2479 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2482 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2483 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2487 /******************************************************************
2488 * DeletePortA [WINSPOOL.@]
2493 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2495 LPWSTR nameW
= NULL
;
2496 LPWSTR portW
= NULL
;
2500 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2502 /* convert servername to unicode */
2504 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2505 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2506 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2509 /* convert portname to unicode */
2511 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2512 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2513 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2516 res
= DeletePortW(nameW
, hWnd
, portW
);
2517 HeapFree(GetProcessHeap(), 0, nameW
);
2518 HeapFree(GetProcessHeap(), 0, portW
);
2522 /******************************************************************
2523 * DeletePortW [WINSPOOL.@]
2525 * Delete a specific Port
2528 * pName [I] Servername or NULL (local Computer)
2529 * hWnd [I] Handle to parent Window for the Dialog-Box
2530 * pPortName [I] Name of the Port, that should be deleted
2537 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2543 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2545 if (pName
&& pName
[0]) {
2546 SetLastError(ERROR_INVALID_PARAMETER
);
2551 SetLastError(RPC_X_NULL_REF_POINTER
);
2555 /* an empty Portname is Invalid */
2556 if (!pPortName
[0]) {
2557 SetLastError(ERROR_NOT_SUPPORTED
);
2561 pm
= monitor_load_by_port(pPortName
);
2562 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2563 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2564 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2565 TRACE("got %d with %u\n", res
, GetLastError());
2569 pui
= monitor_loadui(pm
);
2570 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2571 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2572 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2573 TRACE("got %d with %u\n", res
, GetLastError());
2577 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2578 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2580 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2581 SetLastError(ERROR_NOT_SUPPORTED
);
2584 monitor_unload(pui
);
2588 TRACE("returning %d with %u\n", res
, GetLastError());
2592 /******************************************************************************
2593 * SetPrinterW [WINSPOOL.@]
2595 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2597 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2598 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2602 /******************************************************************************
2603 * WritePrinter [WINSPOOL.@]
2605 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2607 opened_printer_t
*printer
;
2610 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2612 EnterCriticalSection(&printer_handles_cs
);
2613 printer
= get_opened_printer(hPrinter
);
2616 SetLastError(ERROR_INVALID_HANDLE
);
2622 SetLastError(ERROR_SPL_NO_STARTDOC
);
2626 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2628 LeaveCriticalSection(&printer_handles_cs
);
2632 /*****************************************************************************
2633 * AddFormA [WINSPOOL.@]
2635 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2637 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2641 /*****************************************************************************
2642 * AddFormW [WINSPOOL.@]
2644 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2646 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2650 /*****************************************************************************
2651 * AddJobA [WINSPOOL.@]
2653 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2656 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2660 SetLastError(ERROR_INVALID_LEVEL
);
2664 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2667 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2668 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2669 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2670 if(*pcbNeeded
> cbBuf
) {
2671 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2674 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2675 addjobA
->JobId
= addjobW
->JobId
;
2676 addjobA
->Path
= (char *)(addjobA
+ 1);
2677 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2683 /*****************************************************************************
2684 * AddJobW [WINSPOOL.@]
2686 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2688 opened_printer_t
*printer
;
2691 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2692 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2693 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2695 ADDJOB_INFO_1W
*addjob
;
2697 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2699 EnterCriticalSection(&printer_handles_cs
);
2701 printer
= get_opened_printer(hPrinter
);
2704 SetLastError(ERROR_INVALID_HANDLE
);
2709 SetLastError(ERROR_INVALID_LEVEL
);
2713 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2717 job
->job_id
= InterlockedIncrement(&next_job_id
);
2719 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2720 if(path
[len
- 1] != '\\')
2722 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2723 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2725 len
= strlenW(filename
);
2726 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2727 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2728 job
->document_title
= strdupW(default_doc_title
);
2729 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2731 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2732 if(*pcbNeeded
<= cbBuf
) {
2733 addjob
= (ADDJOB_INFO_1W
*)pData
;
2734 addjob
->JobId
= job
->job_id
;
2735 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2736 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2739 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2742 LeaveCriticalSection(&printer_handles_cs
);
2746 /*****************************************************************************
2747 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2749 * Return the PATH for the Print-Processors
2751 * See GetPrintProcessorDirectoryW.
2755 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2756 DWORD level
, LPBYTE Info
,
2757 DWORD cbBuf
, LPDWORD pcbNeeded
)
2759 LPWSTR serverW
= NULL
;
2764 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2765 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2769 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2770 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2771 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2775 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2776 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2777 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2780 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2781 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2783 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2786 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2787 cbBuf
, NULL
, NULL
) > 0;
2790 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2791 HeapFree(GetProcessHeap(), 0, envW
);
2792 HeapFree(GetProcessHeap(), 0, serverW
);
2796 /*****************************************************************************
2797 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2799 * Return the PATH for the Print-Processors
2802 * server [I] Servername (NT only) or NULL (local Computer)
2803 * env [I] Printing-Environment (see below) or NULL (Default)
2804 * level [I] Structure-Level (must be 1)
2805 * Info [O] PTR to Buffer that receives the Result
2806 * cbBuf [I] Size of Buffer at "Info"
2807 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2808 * required for the Buffer at "Info"
2811 * Success: TRUE and in pcbNeeded the Bytes used in Info
2812 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2813 * if cbBuf is too small
2815 * Native Values returned in Info on Success:
2816 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2817 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2818 *| win9x(Windows 4.0): "%winsysdir%"
2820 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2823 * Only NULL or "" is supported for server
2826 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2827 DWORD level
, LPBYTE Info
,
2828 DWORD cbBuf
, LPDWORD pcbNeeded
)
2831 const printenv_t
* env_t
;
2833 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2834 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2836 if(server
!= NULL
&& server
[0]) {
2837 FIXME("server not supported: %s\n", debugstr_w(server
));
2838 SetLastError(ERROR_INVALID_PARAMETER
);
2842 env_t
= validate_envW(env
);
2843 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2846 WARN("(Level: %d) is ignored in win9x\n", level
);
2847 SetLastError(ERROR_INVALID_LEVEL
);
2851 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2852 needed
= GetSystemDirectoryW(NULL
, 0);
2853 /* add the Size for the Subdirectories */
2854 needed
+= lstrlenW(spoolprtprocsW
);
2855 needed
+= lstrlenW(env_t
->subdir
);
2856 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2858 if(pcbNeeded
) *pcbNeeded
= needed
;
2859 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2860 if (needed
> cbBuf
) {
2861 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2864 if(pcbNeeded
== NULL
) {
2865 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2866 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2867 SetLastError(RPC_X_NULL_REF_POINTER
);
2871 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2872 SetLastError(RPC_X_NULL_REF_POINTER
);
2876 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2877 /* add the Subdirectories */
2878 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2879 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2880 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2884 /*****************************************************************************
2885 * WINSPOOL_OpenDriverReg [internal]
2887 * opens the registry for the printer drivers depending on the given input
2888 * variable pEnvironment
2891 * the opened hkey on success
2894 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2898 const printenv_t
* env
;
2901 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2903 if (!pEnvironment
|| unicode
) {
2904 /* pEnvironment was NULL or an Unicode-String: use it direct */
2905 env
= validate_envW(pEnvironment
);
2909 /* pEnvironment was an ANSI-String: convert to unicode first */
2911 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2912 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2913 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2914 env
= validate_envW(buffer
);
2915 HeapFree(GetProcessHeap(), 0, buffer
);
2917 if (!env
) return NULL
;
2919 buffer
= HeapAlloc( GetProcessHeap(), 0,
2920 (strlenW(DriversW
) + strlenW(env
->envname
) +
2921 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2923 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2924 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2925 HeapFree(GetProcessHeap(), 0, buffer
);
2930 /*****************************************************************************
2931 * AddPrinterW [WINSPOOL.@]
2933 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2935 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2939 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2941 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2942 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2943 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2944 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2945 statusW
[] = {'S','t','a','t','u','s',0},
2946 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2948 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2951 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2952 SetLastError(ERROR_INVALID_PARAMETER
);
2956 ERR("Level = %d, unsupported!\n", Level
);
2957 SetLastError(ERROR_INVALID_LEVEL
);
2961 SetLastError(ERROR_INVALID_PARAMETER
);
2964 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2966 ERR("Can't create Printers key\n");
2969 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2970 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2971 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2972 RegCloseKey(hkeyPrinter
);
2973 RegCloseKey(hkeyPrinters
);
2976 RegCloseKey(hkeyPrinter
);
2978 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2980 ERR("Can't create Drivers key\n");
2981 RegCloseKey(hkeyPrinters
);
2984 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2986 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2987 RegCloseKey(hkeyPrinters
);
2988 RegCloseKey(hkeyDrivers
);
2989 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2992 RegCloseKey(hkeyDriver
);
2993 RegCloseKey(hkeyDrivers
);
2995 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2996 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2997 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2998 RegCloseKey(hkeyPrinters
);
3002 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3004 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3005 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3006 RegCloseKey(hkeyPrinters
);
3009 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
3010 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
3011 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3013 /* See if we can load the driver. We may need the devmode structure anyway
3016 * Note that DocumentPropertiesW will briefly try to open the printer we
3017 * just create to find a DEVMODEA struct (it will use the WINEPS default
3018 * one in case it is not there, so we are ok).
3020 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3023 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3024 size
= sizeof(DEVMODEW
);
3030 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3032 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
3034 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3035 HeapFree(GetProcessHeap(),0,dmW
);
3040 /* set devmode to printer name */
3041 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3045 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3046 and we support these drivers. NT writes DEVMODEW so somehow
3047 we'll need to distinguish between these when we support NT
3051 dmA
= DEVMODEdupWtoA(dmW
);
3052 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
3053 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
3054 HeapFree(GetProcessHeap(), 0, dmA
);
3056 HeapFree(GetProcessHeap(), 0, dmW
);
3058 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3059 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3060 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3061 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3063 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3064 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3065 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3066 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
3067 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
3068 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3069 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3070 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
3071 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
3072 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
3073 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
3074 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
3075 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
3077 RegCloseKey(hkeyPrinter
);
3078 RegCloseKey(hkeyPrinters
);
3079 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3080 ERR("OpenPrinter failing\n");
3086 /*****************************************************************************
3087 * AddPrinterA [WINSPOOL.@]
3089 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3091 UNICODE_STRING pNameW
;
3093 PRINTER_INFO_2W
*piW
;
3094 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3097 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
3099 ERR("Level = %d, unsupported!\n", Level
);
3100 SetLastError(ERROR_INVALID_LEVEL
);
3103 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3104 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
3106 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3108 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
3109 RtlFreeUnicodeString(&pNameW
);
3114 /*****************************************************************************
3115 * ClosePrinter [WINSPOOL.@]
3117 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3119 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3120 opened_printer_t
*printer
= NULL
;
3123 TRACE("(%p)\n", hPrinter
);
3125 EnterCriticalSection(&printer_handles_cs
);
3127 if ((i
> 0) && (i
<= nb_printer_handles
))
3128 printer
= printer_handles
[i
- 1];
3133 struct list
*cursor
, *cursor2
;
3135 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
3136 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
3137 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
3140 EndDocPrinter(hPrinter
);
3142 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3144 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3146 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3147 ScheduleJob(hPrinter
, job
->job_id
);
3149 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3151 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
3152 monitor_unload(printer
->pm
);
3153 HeapFree(GetProcessHeap(), 0, printer
->printername
);
3154 HeapFree(GetProcessHeap(), 0, printer
->name
);
3155 HeapFree(GetProcessHeap(), 0, printer
);
3156 printer_handles
[i
- 1] = NULL
;
3159 LeaveCriticalSection(&printer_handles_cs
);
3163 /*****************************************************************************
3164 * DeleteFormA [WINSPOOL.@]
3166 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3168 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3172 /*****************************************************************************
3173 * DeleteFormW [WINSPOOL.@]
3175 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3177 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3181 /*****************************************************************************
3182 * DeletePrinter [WINSPOOL.@]
3184 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3186 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3187 HKEY hkeyPrinters
, hkey
;
3190 SetLastError(ERROR_INVALID_HANDLE
);
3193 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3194 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3195 RegCloseKey(hkeyPrinters
);
3197 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3198 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3200 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3201 RegDeleteValueW(hkey
, lpNameW
);
3205 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3206 RegDeleteValueW(hkey
, lpNameW
);
3212 /*****************************************************************************
3213 * SetPrinterA [WINSPOOL.@]
3215 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3218 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3222 /*****************************************************************************
3223 * SetJobA [WINSPOOL.@]
3225 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3226 LPBYTE pJob
, DWORD Command
)
3230 UNICODE_STRING usBuffer
;
3232 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3234 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3235 are all ignored by SetJob, so we don't bother copying them */
3243 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3244 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3246 JobW
= (LPBYTE
)info1W
;
3247 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3248 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3249 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3250 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3251 info1W
->Status
= info1A
->Status
;
3252 info1W
->Priority
= info1A
->Priority
;
3253 info1W
->Position
= info1A
->Position
;
3254 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3259 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3260 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3262 JobW
= (LPBYTE
)info2W
;
3263 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3264 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3265 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3266 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3267 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3268 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3269 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3270 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3271 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3272 info2W
->Status
= info2A
->Status
;
3273 info2W
->Priority
= info2A
->Priority
;
3274 info2W
->Position
= info2A
->Position
;
3275 info2W
->StartTime
= info2A
->StartTime
;
3276 info2W
->UntilTime
= info2A
->UntilTime
;
3277 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3281 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3282 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3285 SetLastError(ERROR_INVALID_LEVEL
);
3289 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3295 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3296 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3297 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3298 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3299 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3304 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3305 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3306 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3307 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3308 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3309 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3310 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3311 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3312 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3316 HeapFree(GetProcessHeap(), 0, JobW
);
3321 /*****************************************************************************
3322 * SetJobW [WINSPOOL.@]
3324 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3325 LPBYTE pJob
, DWORD Command
)
3330 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3331 FIXME("Ignoring everything other than document title\n");
3333 EnterCriticalSection(&printer_handles_cs
);
3334 job
= get_job(hPrinter
, JobId
);
3344 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3345 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3346 job
->document_title
= strdupW(info1
->pDocument
);
3351 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3352 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3353 job
->document_title
= strdupW(info2
->pDocument
);
3359 SetLastError(ERROR_INVALID_LEVEL
);
3364 LeaveCriticalSection(&printer_handles_cs
);
3368 /*****************************************************************************
3369 * EndDocPrinter [WINSPOOL.@]
3371 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3373 opened_printer_t
*printer
;
3375 TRACE("(%p)\n", hPrinter
);
3377 EnterCriticalSection(&printer_handles_cs
);
3379 printer
= get_opened_printer(hPrinter
);
3382 SetLastError(ERROR_INVALID_HANDLE
);
3388 SetLastError(ERROR_SPL_NO_STARTDOC
);
3392 CloseHandle(printer
->doc
->hf
);
3393 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3394 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3395 printer
->doc
= NULL
;
3398 LeaveCriticalSection(&printer_handles_cs
);
3402 /*****************************************************************************
3403 * EndPagePrinter [WINSPOOL.@]
3405 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3407 FIXME("(%p): stub\n", hPrinter
);
3411 /*****************************************************************************
3412 * StartDocPrinterA [WINSPOOL.@]
3414 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3416 UNICODE_STRING usBuffer
;
3418 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3421 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3422 or one (DOC_INFO_3) extra DWORDs */
3426 doc2W
.JobId
= doc2
->JobId
;
3429 doc2W
.dwMode
= doc2
->dwMode
;
3432 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3433 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3434 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3438 SetLastError(ERROR_INVALID_LEVEL
);
3442 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3444 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3445 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3446 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3451 /*****************************************************************************
3452 * StartDocPrinterW [WINSPOOL.@]
3454 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3456 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3457 opened_printer_t
*printer
;
3458 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3459 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3460 JOB_INFO_1W job_info
;
3461 DWORD needed
, ret
= 0;
3465 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3466 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3467 debugstr_w(doc
->pDatatype
));
3469 if(Level
< 1 || Level
> 3)
3471 SetLastError(ERROR_INVALID_LEVEL
);
3475 EnterCriticalSection(&printer_handles_cs
);
3476 printer
= get_opened_printer(hPrinter
);
3479 SetLastError(ERROR_INVALID_HANDLE
);
3485 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3489 /* Even if we're printing to a file we still add a print job, we'll
3490 just ignore the spool file name */
3492 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3494 ERR("AddJob failed gle %u\n", GetLastError());
3498 if(doc
->pOutputFile
)
3499 filename
= doc
->pOutputFile
;
3501 filename
= addjob
->Path
;
3503 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3504 if(hf
== INVALID_HANDLE_VALUE
)
3507 memset(&job_info
, 0, sizeof(job_info
));
3508 job_info
.pDocument
= doc
->pDocName
;
3509 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3511 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3512 printer
->doc
->hf
= hf
;
3513 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3515 LeaveCriticalSection(&printer_handles_cs
);
3520 /*****************************************************************************
3521 * StartPagePrinter [WINSPOOL.@]
3523 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3525 FIXME("(%p): stub\n", hPrinter
);
3529 /*****************************************************************************
3530 * GetFormA [WINSPOOL.@]
3532 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3533 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3535 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3536 Level
,pForm
,cbBuf
,pcbNeeded
);
3540 /*****************************************************************************
3541 * GetFormW [WINSPOOL.@]
3543 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3544 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3546 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3547 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3551 /*****************************************************************************
3552 * SetFormA [WINSPOOL.@]
3554 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3557 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3561 /*****************************************************************************
3562 * SetFormW [WINSPOOL.@]
3564 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3567 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3571 /*****************************************************************************
3572 * ReadPrinter [WINSPOOL.@]
3574 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3575 LPDWORD pNoBytesRead
)
3577 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3581 /*****************************************************************************
3582 * ResetPrinterA [WINSPOOL.@]
3584 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3586 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3590 /*****************************************************************************
3591 * ResetPrinterW [WINSPOOL.@]
3593 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3595 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3599 /*****************************************************************************
3600 * WINSPOOL_GetDWORDFromReg
3602 * Return DWORD associated with ValueName from hkey.
3604 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3606 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3609 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3611 if(ret
!= ERROR_SUCCESS
) {
3612 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3615 if(type
!= REG_DWORD
) {
3616 ERR("Got type %d\n", type
);
3623 /*****************************************************************************
3624 * get_filename_from_reg [internal]
3626 * Get ValueName from hkey storing result in out
3627 * when the Value in the registry has only a filename, use driverdir as prefix
3628 * outlen is space left in out
3629 * String is stored either as unicode or ascii
3633 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3634 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3636 WCHAR filename
[MAX_PATH
];
3640 LPWSTR buffer
= filename
;
3644 size
= sizeof(filename
);
3646 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3647 if (ret
== ERROR_MORE_DATA
) {
3648 TRACE("need dynamic buffer: %u\n", size
);
3649 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3651 /* No Memory is bad */
3655 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3658 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3659 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3665 /* do we have a full path ? */
3666 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3667 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3670 /* we must build the full Path */
3672 if ((out
) && (outlen
> dirlen
)) {
3674 lstrcpyW((LPWSTR
)out
, driverdir
);
3678 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3687 /* write the filename */
3689 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3690 if ((out
) && (outlen
>= size
)) {
3691 lstrcpyW((LPWSTR
)out
, ptr
);
3700 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3701 if ((out
) && (outlen
>= size
)) {
3702 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3710 ptr
+= lstrlenW(ptr
)+1;
3711 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3714 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3716 /* write the multisz-termination */
3717 if (type
== REG_MULTI_SZ
) {
3718 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3721 if (out
&& (outlen
>= size
)) {
3722 memset (out
, 0, size
);
3728 /*****************************************************************************
3729 * WINSPOOL_GetStringFromReg
3731 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3732 * String is stored either as unicode or ascii.
3733 * Bit of a hack here to get the ValueName if we want ascii.
3735 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3736 DWORD buflen
, DWORD
*needed
,
3739 DWORD sz
= buflen
, type
;
3743 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3745 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3746 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3747 HeapFree(GetProcessHeap(),0,ValueNameA
);
3749 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3750 WARN("Got ret = %d\n", ret
);
3754 /* add space for terminating '\0' */
3755 sz
+= unicode
? sizeof(WCHAR
) : 1;
3759 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3764 /*****************************************************************************
3765 * WINSPOOL_GetDefaultDevMode
3767 * Get a default DevMode values for wineps.
3771 static void WINSPOOL_GetDefaultDevMode(
3773 DWORD buflen
, DWORD
*needed
,
3777 static const char szwps
[] = "wineps.drv";
3779 /* fill default DEVMODE - should be read from ppd... */
3780 ZeroMemory( &dm
, sizeof(dm
) );
3781 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3782 dm
.dmSpecVersion
= DM_SPECVERSION
;
3783 dm
.dmDriverVersion
= 1;
3784 dm
.dmSize
= sizeof(DEVMODEA
);
3785 dm
.dmDriverExtra
= 0;
3787 DM_ORIENTATION
| DM_PAPERSIZE
|
3788 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3791 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3792 DM_YRESOLUTION
| DM_TTOPTION
;
3794 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3795 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3796 dm
.u1
.s1
.dmPaperLength
= 2970;
3797 dm
.u1
.s1
.dmPaperWidth
= 2100;
3799 dm
.u1
.s1
.dmScale
= 100;
3800 dm
.u1
.s1
.dmCopies
= 1;
3801 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3802 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3805 dm
.dmYResolution
= 300; /* 300dpi */
3806 dm
.dmTTOption
= DMTT_BITMAP
;
3809 /* dm.dmLogPixels */
3810 /* dm.dmBitsPerPel */
3811 /* dm.dmPelsWidth */
3812 /* dm.dmPelsHeight */
3813 /* dm.u2.dmDisplayFlags */
3814 /* dm.dmDisplayFrequency */
3815 /* dm.dmICMMethod */
3816 /* dm.dmICMIntent */
3817 /* dm.dmMediaType */
3818 /* dm.dmDitherType */
3819 /* dm.dmReserved1 */
3820 /* dm.dmReserved2 */
3821 /* dm.dmPanningWidth */
3822 /* dm.dmPanningHeight */
3825 if(buflen
>= sizeof(DEVMODEW
)) {
3826 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3827 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3828 HeapFree(GetProcessHeap(),0,pdmW
);
3830 *needed
= sizeof(DEVMODEW
);
3834 if(buflen
>= sizeof(DEVMODEA
)) {
3835 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3837 *needed
= sizeof(DEVMODEA
);
3841 /*****************************************************************************
3842 * WINSPOOL_GetDevModeFromReg
3844 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3845 * DevMode is stored either as unicode or ascii.
3847 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3849 DWORD buflen
, DWORD
*needed
,
3852 DWORD sz
= buflen
, type
;
3855 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3856 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3857 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3858 if (sz
< sizeof(DEVMODEA
))
3860 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3863 /* ensures that dmSize is not erratically bogus if registry is invalid */
3864 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3865 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3867 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3869 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3870 memcpy(ptr
, dmW
, sz
);
3871 HeapFree(GetProcessHeap(),0,dmW
);
3878 /*********************************************************************
3879 * WINSPOOL_GetPrinter_1
3881 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3882 * The strings are either stored as unicode or ascii.
3884 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3885 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3888 DWORD size
, left
= cbBuf
;
3889 BOOL space
= (cbBuf
> 0);
3894 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3896 if(space
&& size
<= left
) {
3897 pi1
->pName
= (LPWSTR
)ptr
;
3905 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3906 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3908 if(space
&& size
<= left
) {
3909 pi1
->pDescription
= (LPWSTR
)ptr
;
3917 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3919 if(space
&& size
<= left
) {
3920 pi1
->pComment
= (LPWSTR
)ptr
;
3928 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3930 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3931 memset(pi1
, 0, sizeof(*pi1
));
3935 /*********************************************************************
3936 * WINSPOOL_GetPrinter_2
3938 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3939 * The strings are either stored as unicode or ascii.
3941 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3942 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3945 DWORD size
, left
= cbBuf
;
3946 BOOL space
= (cbBuf
> 0);
3951 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3953 if(space
&& size
<= left
) {
3954 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3961 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3963 if(space
&& size
<= left
) {
3964 pi2
->pShareName
= (LPWSTR
)ptr
;
3971 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3973 if(space
&& size
<= left
) {
3974 pi2
->pPortName
= (LPWSTR
)ptr
;
3981 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3983 if(space
&& size
<= left
) {
3984 pi2
->pDriverName
= (LPWSTR
)ptr
;
3991 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3993 if(space
&& size
<= left
) {
3994 pi2
->pComment
= (LPWSTR
)ptr
;
4001 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
4003 if(space
&& size
<= left
) {
4004 pi2
->pLocation
= (LPWSTR
)ptr
;
4011 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
4013 if(space
&& size
<= left
) {
4014 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4023 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
4024 if(space
&& size
<= left
) {
4025 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4032 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
4034 if(space
&& size
<= left
) {
4035 pi2
->pSepFile
= (LPWSTR
)ptr
;
4042 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
4044 if(space
&& size
<= left
) {
4045 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4052 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
4054 if(space
&& size
<= left
) {
4055 pi2
->pDatatype
= (LPWSTR
)ptr
;
4062 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
4064 if(space
&& size
<= left
) {
4065 pi2
->pParameters
= (LPWSTR
)ptr
;
4073 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4074 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
4075 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4076 "Default Priority");
4077 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
4078 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
4081 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4082 memset(pi2
, 0, sizeof(*pi2
));
4087 /*********************************************************************
4088 * WINSPOOL_GetPrinter_4
4090 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4092 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4093 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4096 DWORD size
, left
= cbBuf
;
4097 BOOL space
= (cbBuf
> 0);
4102 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
4104 if(space
&& size
<= left
) {
4105 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4113 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4116 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4117 memset(pi4
, 0, sizeof(*pi4
));
4122 /*********************************************************************
4123 * WINSPOOL_GetPrinter_5
4125 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4127 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4128 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4131 DWORD size
, left
= cbBuf
;
4132 BOOL space
= (cbBuf
> 0);
4137 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
4139 if(space
&& size
<= left
) {
4140 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4147 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
4149 if(space
&& size
<= left
) {
4150 pi5
->pPortName
= (LPWSTR
)ptr
;
4158 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4159 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4161 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4165 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4166 memset(pi5
, 0, sizeof(*pi5
));
4171 /*********************************************************************
4172 * WINSPOOL_GetPrinter_7
4174 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4176 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4177 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4179 DWORD size
, left
= cbBuf
;
4180 BOOL space
= (cbBuf
> 0);
4185 if (WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
, unicode
))
4187 if (space
&& size
<= left
) {
4188 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4196 /* We do not have a Directory Service */
4197 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4200 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4201 memset(pi7
, 0, sizeof(*pi7
));
4206 /*********************************************************************
4207 * WINSPOOL_GetPrinter_9
4209 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4210 * The strings are either stored as unicode or ascii.
4212 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4213 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4216 BOOL space
= (cbBuf
> 0);
4220 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
, unicode
)) {
4221 if(space
&& size
<= cbBuf
) {
4222 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4229 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
, unicode
);
4230 if(space
&& size
<= cbBuf
) {
4231 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4237 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4238 memset(pi9
, 0, sizeof(*pi9
));
4243 /*****************************************************************************
4244 * WINSPOOL_GetPrinter
4246 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4247 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4248 * just a collection of pointers to strings.
4250 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4251 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4254 DWORD size
, needed
= 0;
4256 HKEY hkeyPrinter
, hkeyPrinters
;
4259 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4261 if (!(name
= get_opened_printer_name(hPrinter
))) {
4262 SetLastError(ERROR_INVALID_HANDLE
);
4266 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4268 ERR("Can't create Printers key\n");
4271 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4273 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4274 RegCloseKey(hkeyPrinters
);
4275 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4282 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4284 size
= sizeof(PRINTER_INFO_2W
);
4286 ptr
= pPrinter
+ size
;
4288 memset(pPrinter
, 0, size
);
4293 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4301 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4303 size
= sizeof(PRINTER_INFO_4W
);
4305 ptr
= pPrinter
+ size
;
4307 memset(pPrinter
, 0, size
);
4312 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4321 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4323 size
= sizeof(PRINTER_INFO_5W
);
4325 ptr
= pPrinter
+ size
;
4327 memset(pPrinter
, 0, size
);
4333 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4342 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4344 size
= sizeof(PRINTER_INFO_6
);
4345 if (size
<= cbBuf
) {
4346 /* FIXME: We do not update the status yet */
4347 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
4359 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4361 size
= sizeof(PRINTER_INFO_7W
);
4362 if (size
<= cbBuf
) {
4363 ptr
= pPrinter
+ size
;
4365 memset(pPrinter
, 0, size
);
4371 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
, unicode
);
4379 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4381 size
= sizeof(PRINTER_INFO_9W
);
4383 ptr
= pPrinter
+ size
;
4385 memset(pPrinter
, 0, size
);
4391 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
, unicode
);
4398 FIXME("Unimplemented level %d\n", Level
);
4399 SetLastError(ERROR_INVALID_LEVEL
);
4400 RegCloseKey(hkeyPrinters
);
4401 RegCloseKey(hkeyPrinter
);
4405 RegCloseKey(hkeyPrinter
);
4406 RegCloseKey(hkeyPrinters
);
4408 TRACE("returning %d needed = %d\n", ret
, needed
);
4409 if(pcbNeeded
) *pcbNeeded
= needed
;
4411 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4415 /*****************************************************************************
4416 * GetPrinterW [WINSPOOL.@]
4418 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4419 DWORD cbBuf
, LPDWORD pcbNeeded
)
4421 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4425 /*****************************************************************************
4426 * GetPrinterA [WINSPOOL.@]
4428 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4429 DWORD cbBuf
, LPDWORD pcbNeeded
)
4431 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4435 /*****************************************************************************
4436 * WINSPOOL_EnumPrinters
4438 * Implementation of EnumPrintersA|W
4440 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4441 DWORD dwLevel
, LPBYTE lpbPrinters
,
4442 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4443 LPDWORD lpdwReturned
, BOOL unicode
)
4446 HKEY hkeyPrinters
, hkeyPrinter
;
4447 WCHAR PrinterName
[255];
4448 DWORD needed
= 0, number
= 0;
4449 DWORD used
, i
, left
;
4453 memset(lpbPrinters
, 0, cbBuf
);
4459 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4460 if(dwType
== PRINTER_ENUM_DEFAULT
)
4463 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4464 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4465 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4467 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4475 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4476 FIXME("dwType = %08x\n", dwType
);
4477 SetLastError(ERROR_INVALID_FLAGS
);
4481 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4483 ERR("Can't create Printers key\n");
4487 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4488 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4489 RegCloseKey(hkeyPrinters
);
4490 ERR("Can't query Printers key\n");
4493 TRACE("Found %d printers\n", number
);
4497 used
= number
* sizeof(PRINTER_INFO_1W
);
4500 used
= number
* sizeof(PRINTER_INFO_2W
);
4503 used
= number
* sizeof(PRINTER_INFO_4W
);
4506 used
= number
* sizeof(PRINTER_INFO_5W
);
4510 SetLastError(ERROR_INVALID_LEVEL
);
4511 RegCloseKey(hkeyPrinters
);
4514 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4516 for(i
= 0; i
< number
; i
++) {
4517 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4519 ERR("Can't enum key number %d\n", i
);
4520 RegCloseKey(hkeyPrinters
);
4523 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4524 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4526 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4527 RegCloseKey(hkeyPrinters
);
4532 buf
= lpbPrinters
+ used
;
4533 left
= cbBuf
- used
;
4541 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4542 left
, &needed
, unicode
);
4544 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4547 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4548 left
, &needed
, unicode
);
4550 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4553 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4554 left
, &needed
, unicode
);
4556 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4559 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4560 left
, &needed
, unicode
);
4562 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4565 ERR("Shouldn't be here!\n");
4566 RegCloseKey(hkeyPrinter
);
4567 RegCloseKey(hkeyPrinters
);
4570 RegCloseKey(hkeyPrinter
);
4572 RegCloseKey(hkeyPrinters
);
4579 memset(lpbPrinters
, 0, cbBuf
);
4580 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4584 *lpdwReturned
= number
;
4585 SetLastError(ERROR_SUCCESS
);
4590 /******************************************************************
4591 * EnumPrintersW [WINSPOOL.@]
4593 * Enumerates the available printers, print servers and print
4594 * providers, depending on the specified flags, name and level.
4598 * If level is set to 1:
4599 * Returns an array of PRINTER_INFO_1 data structures in the
4600 * lpbPrinters buffer.
4602 * If level is set to 2:
4603 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4604 * Returns an array of PRINTER_INFO_2 data structures in the
4605 * lpbPrinters buffer. Note that according to MSDN also an
4606 * OpenPrinter should be performed on every remote printer.
4608 * If level is set to 4 (officially WinNT only):
4609 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4610 * Fast: Only the registry is queried to retrieve printer names,
4611 * no connection to the driver is made.
4612 * Returns an array of PRINTER_INFO_4 data structures in the
4613 * lpbPrinters buffer.
4615 * If level is set to 5 (officially WinNT4/Win9x only):
4616 * Fast: Only the registry is queried to retrieve printer names,
4617 * no connection to the driver is made.
4618 * Returns an array of PRINTER_INFO_5 data structures in the
4619 * lpbPrinters buffer.
4621 * If level set to 3 or 6+:
4622 * returns zero (failure!)
4624 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4628 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4629 * - Only levels 2, 4 and 5 are implemented at the moment.
4630 * - 16-bit printer drivers are not enumerated.
4631 * - Returned amount of bytes used/needed does not match the real Windoze
4632 * implementation (as in this implementation, all strings are part
4633 * of the buffer, whereas Win32 keeps them somewhere else)
4634 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4637 * - In a regular Wine installation, no registry settings for printers
4638 * exist, which makes this function return an empty list.
4640 BOOL WINAPI
EnumPrintersW(
4641 DWORD dwType
, /* [in] Types of print objects to enumerate */
4642 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4643 DWORD dwLevel
, /* [in] type of printer info structure */
4644 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4645 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4646 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4647 LPDWORD lpdwReturned
/* [out] number of entries returned */
4650 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4651 lpdwNeeded
, lpdwReturned
, TRUE
);
4654 /******************************************************************
4655 * EnumPrintersA [WINSPOOL.@]
4660 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4661 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4664 UNICODE_STRING pNameU
;
4668 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4669 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4671 pNameW
= asciitounicode(&pNameU
, pName
);
4673 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4674 MS Office need this */
4675 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4677 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4679 RtlFreeUnicodeString(&pNameU
);
4681 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4683 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4687 /*****************************************************************************
4688 * WINSPOOL_GetDriverInfoFromReg [internal]
4690 * Enters the information from the registry into the DRIVER_INFO struct
4693 * zero if the printer driver does not exist in the registry
4694 * (only if Level > 1) otherwise nonzero
4696 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4699 const printenv_t
* env
,
4701 LPBYTE ptr
, /* DRIVER_INFO */
4702 LPBYTE pDriverStrings
, /* strings buffer */
4703 DWORD cbBuf
, /* size of string buffer */
4704 LPDWORD pcbNeeded
, /* space needed for str. */
4705 BOOL unicode
) /* type of strings */
4709 WCHAR driverdir
[MAX_PATH
];
4711 LPBYTE strPtr
= pDriverStrings
;
4712 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4714 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4715 debugstr_w(DriverName
), env
,
4716 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4718 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4721 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4722 if (*pcbNeeded
<= cbBuf
)
4723 strcpyW((LPWSTR
)strPtr
, DriverName
);
4727 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4728 if (*pcbNeeded
<= cbBuf
)
4729 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4732 /* pName for level 1 has a different offset! */
4734 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4738 /* .cVersion and .pName for level > 1 */
4740 di
->cVersion
= env
->driverversion
;
4741 di
->pName
= (LPWSTR
) strPtr
;
4742 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4745 /* Reserve Space for the largest subdir and a Backslash*/
4746 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4747 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4748 /* Should never Fail */
4751 lstrcatW(driverdir
, env
->versionsubdir
);
4752 lstrcatW(driverdir
, backslashW
);
4754 /* dirlen must not include the terminating zero */
4755 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4756 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4758 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4759 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4760 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4766 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4768 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4771 if (*pcbNeeded
<= cbBuf
) {
4773 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4777 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4779 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4780 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4783 /* .pDriverPath is the Graphics rendering engine.
4784 The full Path is required to avoid a crash in some apps */
4785 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4787 if (*pcbNeeded
<= cbBuf
)
4788 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4790 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4791 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4794 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4795 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4797 if (*pcbNeeded
<= cbBuf
)
4798 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4800 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4801 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4804 /* .pConfigFile is the Driver user Interface */
4805 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4807 if (*pcbNeeded
<= cbBuf
)
4808 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4810 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4811 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4815 RegCloseKey(hkeyDriver
);
4816 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4821 RegCloseKey(hkeyDriver
);
4822 FIXME("level 5: incomplete\n");
4827 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4829 if (*pcbNeeded
<= cbBuf
)
4830 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4832 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4833 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4836 /* .pDependentFiles */
4837 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4839 if (*pcbNeeded
<= cbBuf
)
4840 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4842 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4843 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4845 else if (GetVersion() & 0x80000000) {
4846 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4847 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4849 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4851 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4852 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4855 /* .pMonitorName is the optional Language Monitor */
4856 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4858 if (*pcbNeeded
<= cbBuf
)
4859 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4861 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4862 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4865 /* .pDefaultDataType */
4866 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4868 if(*pcbNeeded
<= cbBuf
)
4869 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4871 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4872 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4876 RegCloseKey(hkeyDriver
);
4877 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4881 /* .pszzPreviousNames */
4882 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4884 if(*pcbNeeded
<= cbBuf
)
4885 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4887 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4888 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4892 RegCloseKey(hkeyDriver
);
4893 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4897 /* support is missing, but not important enough for a FIXME */
4898 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4901 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4903 if(*pcbNeeded
<= cbBuf
)
4904 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4906 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4907 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4911 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4913 if(*pcbNeeded
<= cbBuf
)
4914 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4916 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4917 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4920 /* .pszHardwareID */
4921 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4923 if(*pcbNeeded
<= cbBuf
)
4924 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4926 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4927 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4931 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4933 if(*pcbNeeded
<= cbBuf
)
4934 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4936 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4937 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4941 RegCloseKey(hkeyDriver
);
4945 /* support is missing, but not important enough for a FIXME */
4946 TRACE("level 8: incomplete\n");
4948 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4949 RegCloseKey(hkeyDriver
);
4953 /*****************************************************************************
4954 * WINSPOOL_GetPrinterDriver
4956 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4957 DWORD Level
, LPBYTE pDriverInfo
,
4958 DWORD cbBuf
, LPDWORD pcbNeeded
,
4962 WCHAR DriverName
[100];
4963 DWORD ret
, type
, size
, needed
= 0;
4965 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4966 const printenv_t
* env
;
4968 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4969 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4972 if (!(name
= get_opened_printer_name(hPrinter
))) {
4973 SetLastError(ERROR_INVALID_HANDLE
);
4977 if (Level
< 1 || Level
== 7 || Level
> 8) {
4978 SetLastError(ERROR_INVALID_LEVEL
);
4982 env
= validate_envW(pEnvironment
);
4983 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4985 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4987 ERR("Can't create Printers key\n");
4990 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4992 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4993 RegCloseKey(hkeyPrinters
);
4994 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4997 size
= sizeof(DriverName
);
4999 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5000 (LPBYTE
)DriverName
, &size
);
5001 RegCloseKey(hkeyPrinter
);
5002 RegCloseKey(hkeyPrinters
);
5003 if(ret
!= ERROR_SUCCESS
) {
5004 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5008 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
5010 ERR("Can't create Drivers key\n");
5014 size
= di_sizeof
[Level
];
5015 if ((size
<= cbBuf
) && pDriverInfo
)
5016 ptr
= pDriverInfo
+ size
;
5018 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5019 env
, Level
, pDriverInfo
, ptr
,
5020 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5021 &needed
, unicode
)) {
5022 RegCloseKey(hkeyDrivers
);
5026 RegCloseKey(hkeyDrivers
);
5028 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5029 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5030 if(cbBuf
>= needed
) return TRUE
;
5031 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5035 /*****************************************************************************
5036 * GetPrinterDriverA [WINSPOOL.@]
5038 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5039 DWORD Level
, LPBYTE pDriverInfo
,
5040 DWORD cbBuf
, LPDWORD pcbNeeded
)
5043 UNICODE_STRING pEnvW
;
5046 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5047 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
5048 cbBuf
, pcbNeeded
, FALSE
);
5049 RtlFreeUnicodeString(&pEnvW
);
5052 /*****************************************************************************
5053 * GetPrinterDriverW [WINSPOOL.@]
5055 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5056 DWORD Level
, LPBYTE pDriverInfo
,
5057 DWORD cbBuf
, LPDWORD pcbNeeded
)
5059 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
5060 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
5063 /*****************************************************************************
5064 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5066 * Return the PATH for the Printer-Drivers (UNICODE)
5069 * pName [I] Servername (NT only) or NULL (local Computer)
5070 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5071 * Level [I] Structure-Level (must be 1)
5072 * pDriverDirectory [O] PTR to Buffer that receives the Result
5073 * cbBuf [I] Size of Buffer at pDriverDirectory
5074 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5075 * required for pDriverDirectory
5078 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5079 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5080 * if cbBuf is too small
5082 * Native Values returned in pDriverDirectory on Success:
5083 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5084 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5085 *| win9x(Windows 4.0): "%winsysdir%"
5087 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5090 *- Only NULL or "" is supported for pName
5093 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5094 DWORD Level
, LPBYTE pDriverDirectory
,
5095 DWORD cbBuf
, LPDWORD pcbNeeded
)
5097 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5098 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5100 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5103 /* (Level != 1) is ignored in win9x */
5104 SetLastError(ERROR_INVALID_LEVEL
);
5107 if (pcbNeeded
== NULL
) {
5108 /* (pcbNeeded == NULL) is ignored in win9x */
5109 SetLastError(RPC_X_NULL_REF_POINTER
);
5113 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5114 pDriverDirectory
, cbBuf
, pcbNeeded
);
5119 /*****************************************************************************
5120 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5122 * Return the PATH for the Printer-Drivers (ANSI)
5124 * See GetPrinterDriverDirectoryW.
5127 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5130 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5131 DWORD Level
, LPBYTE pDriverDirectory
,
5132 DWORD cbBuf
, LPDWORD pcbNeeded
)
5134 UNICODE_STRING nameW
, environmentW
;
5137 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5138 WCHAR
*driverDirectoryW
= NULL
;
5140 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5141 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5143 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5145 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5146 else nameW
.Buffer
= NULL
;
5147 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5148 else environmentW
.Buffer
= NULL
;
5150 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5151 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5154 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5155 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5157 *pcbNeeded
= needed
;
5158 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
5160 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5162 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5164 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5165 RtlFreeUnicodeString(&environmentW
);
5166 RtlFreeUnicodeString(&nameW
);
5171 /*****************************************************************************
5172 * AddPrinterDriverA [WINSPOOL.@]
5174 * See AddPrinterDriverW.
5177 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5179 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5180 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5183 /******************************************************************************
5184 * AddPrinterDriverW (WINSPOOL.@)
5186 * Install a Printer Driver
5189 * pName [I] Servername or NULL (local Computer)
5190 * level [I] Level for the supplied DRIVER_INFO_*W struct
5191 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5198 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5200 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5201 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5204 /*****************************************************************************
5205 * AddPrintProcessorA [WINSPOOL.@]
5207 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5208 LPSTR pPrintProcessorName
)
5210 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5211 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5215 /*****************************************************************************
5216 * AddPrintProcessorW [WINSPOOL.@]
5218 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5219 LPWSTR pPrintProcessorName
)
5221 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5222 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5226 /*****************************************************************************
5227 * AddPrintProvidorA [WINSPOOL.@]
5229 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5231 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5235 /*****************************************************************************
5236 * AddPrintProvidorW [WINSPOOL.@]
5238 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5240 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5244 /*****************************************************************************
5245 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5247 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5248 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5250 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5251 pDevModeOutput
, pDevModeInput
);
5255 /*****************************************************************************
5256 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5258 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5259 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5261 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5262 pDevModeOutput
, pDevModeInput
);
5266 /*****************************************************************************
5267 * PrinterProperties [WINSPOOL.@]
5269 * Displays a dialog to set the properties of the printer.
5272 * nonzero on success or zero on failure
5275 * implemented as stub only
5277 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5278 HANDLE hPrinter
/* [in] handle to printer object */
5280 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5281 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5285 /*****************************************************************************
5286 * EnumJobsA [WINSPOOL.@]
5289 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5290 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5293 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5294 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5296 if(pcbNeeded
) *pcbNeeded
= 0;
5297 if(pcReturned
) *pcReturned
= 0;
5302 /*****************************************************************************
5303 * EnumJobsW [WINSPOOL.@]
5306 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5307 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5310 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5311 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5313 if(pcbNeeded
) *pcbNeeded
= 0;
5314 if(pcReturned
) *pcReturned
= 0;
5318 /*****************************************************************************
5319 * WINSPOOL_EnumPrinterDrivers [internal]
5321 * Delivers information about all printer drivers installed on the
5322 * localhost or a given server
5325 * nonzero on success or zero on failure. If the buffer for the returned
5326 * information is too small the function will return an error
5329 * - only implemented for localhost, foreign hosts will return an error
5331 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5332 DWORD Level
, LPBYTE pDriverInfo
,
5333 DWORD cbBuf
, LPDWORD pcbNeeded
,
5334 LPDWORD pcReturned
, BOOL unicode
)
5337 DWORD i
, needed
, number
= 0, size
= 0;
5338 WCHAR DriverNameW
[255];
5340 const printenv_t
* env
;
5342 TRACE("%s,%s,%d,%p,%d,%d\n",
5343 debugstr_w(pName
), debugstr_w(pEnvironment
),
5344 Level
, pDriverInfo
, cbBuf
, unicode
);
5346 /* check for local drivers */
5347 if((pName
) && (pName
[0])) {
5348 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5349 SetLastError(ERROR_ACCESS_DENIED
);
5353 env
= validate_envW(pEnvironment
);
5354 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5356 /* check input parameter */
5357 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5358 SetLastError(ERROR_INVALID_LEVEL
);
5362 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
5363 SetLastError(RPC_X_NULL_REF_POINTER
);
5367 /* initialize return values */
5369 memset( pDriverInfo
, 0, cbBuf
);
5373 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5375 ERR("Can't open Drivers key\n");
5379 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5380 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5381 RegCloseKey(hkeyDrivers
);
5382 ERR("Can't query Drivers key\n");
5385 TRACE("Found %d Drivers\n", number
);
5387 /* get size of single struct
5388 * unicode and ascii structure have the same size
5390 size
= di_sizeof
[Level
];
5392 /* calculate required buffer size */
5393 *pcbNeeded
= size
* number
;
5395 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5397 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5398 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5400 ERR("Can't enum key number %d\n", i
);
5401 RegCloseKey(hkeyDrivers
);
5404 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5406 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5407 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5408 &needed
, unicode
)) {
5409 RegCloseKey(hkeyDrivers
);
5412 (*pcbNeeded
) += needed
;
5415 RegCloseKey(hkeyDrivers
);
5417 if(cbBuf
< *pcbNeeded
){
5418 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5422 *pcReturned
= number
;
5426 /*****************************************************************************
5427 * EnumPrinterDriversW [WINSPOOL.@]
5429 * see function EnumPrinterDrivers for RETURNS, BUGS
5431 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5432 LPBYTE pDriverInfo
, DWORD cbBuf
,
5433 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5435 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5436 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5439 /*****************************************************************************
5440 * EnumPrinterDriversA [WINSPOOL.@]
5442 * see function EnumPrinterDrivers for RETURNS, BUGS
5444 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5445 LPBYTE pDriverInfo
, DWORD cbBuf
,
5446 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5448 UNICODE_STRING pNameW
, pEnvironmentW
;
5449 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5451 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5452 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5454 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5455 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5457 RtlFreeUnicodeString(&pNameW
);
5458 RtlFreeUnicodeString(&pEnvironmentW
);
5463 /******************************************************************************
5464 * EnumPortsA (WINSPOOL.@)
5469 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5470 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5473 LPBYTE bufferW
= NULL
;
5474 LPWSTR nameW
= NULL
;
5476 DWORD numentries
= 0;
5479 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5480 cbBuf
, pcbNeeded
, pcReturned
);
5482 /* convert servername to unicode */
5484 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5485 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5486 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5488 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5489 needed
= cbBuf
* sizeof(WCHAR
);
5490 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5491 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5493 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5494 if (pcbNeeded
) needed
= *pcbNeeded
;
5495 /* HeapReAlloc return NULL, when bufferW was NULL */
5496 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5497 HeapAlloc(GetProcessHeap(), 0, needed
);
5499 /* Try again with the large Buffer */
5500 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5502 needed
= pcbNeeded
? *pcbNeeded
: 0;
5503 numentries
= pcReturned
? *pcReturned
: 0;
5506 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5507 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5510 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5511 DWORD entrysize
= 0;
5514 LPPORT_INFO_2W pi2w
;
5515 LPPORT_INFO_2A pi2a
;
5518 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5520 /* First pass: calculate the size for all Entries */
5521 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5522 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5524 while (index
< numentries
) {
5526 needed
+= entrysize
; /* PORT_INFO_?A */
5527 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5529 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5530 NULL
, 0, NULL
, NULL
);
5532 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5533 NULL
, 0, NULL
, NULL
);
5534 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5535 NULL
, 0, NULL
, NULL
);
5537 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5538 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5539 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5542 /* check for errors and quit on failure */
5543 if (cbBuf
< needed
) {
5544 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5548 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5549 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5550 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5551 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5552 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5554 /* Second Pass: Fill the User Buffer (if we have one) */
5555 while ((index
< numentries
) && pPorts
) {
5557 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5558 pi2a
->pPortName
= ptr
;
5559 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5560 ptr
, cbBuf
, NULL
, NULL
);
5564 pi2a
->pMonitorName
= ptr
;
5565 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5566 ptr
, cbBuf
, NULL
, NULL
);
5570 pi2a
->pDescription
= ptr
;
5571 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5572 ptr
, cbBuf
, NULL
, NULL
);
5576 pi2a
->fPortType
= pi2w
->fPortType
;
5577 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5580 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5581 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5582 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5587 if (pcbNeeded
) *pcbNeeded
= needed
;
5588 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5590 HeapFree(GetProcessHeap(), 0, nameW
);
5591 HeapFree(GetProcessHeap(), 0, bufferW
);
5593 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5594 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5600 /******************************************************************************
5601 * EnumPortsW (WINSPOOL.@)
5603 * Enumerate available Ports
5606 * name [I] Servername or NULL (local Computer)
5607 * level [I] Structure-Level (1 or 2)
5608 * buffer [O] PTR to Buffer that receives the Result
5609 * bufsize [I] Size of Buffer at buffer
5610 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5611 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5615 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5619 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5622 DWORD numentries
= 0;
5625 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5626 cbBuf
, pcbNeeded
, pcReturned
);
5628 if (pName
&& (pName
[0])) {
5629 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5630 SetLastError(ERROR_ACCESS_DENIED
);
5634 /* Level is not checked in win9x */
5635 if (!Level
|| (Level
> 2)) {
5636 WARN("level (%d) is ignored in win9x\n", Level
);
5637 SetLastError(ERROR_INVALID_LEVEL
);
5641 SetLastError(RPC_X_NULL_REF_POINTER
);
5645 EnterCriticalSection(&monitor_handles_cs
);
5648 /* Scan all local Ports */
5650 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5652 /* we calculated the needed buffersize. now do the error-checks */
5653 if (cbBuf
< needed
) {
5654 monitor_unloadall();
5655 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5656 goto emP_cleanup_cs
;
5658 else if (!pPorts
|| !pcReturned
) {
5659 monitor_unloadall();
5660 SetLastError(RPC_X_NULL_REF_POINTER
);
5661 goto emP_cleanup_cs
;
5664 /* Fill the Buffer */
5665 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5667 monitor_unloadall();
5670 LeaveCriticalSection(&monitor_handles_cs
);
5673 if (pcbNeeded
) *pcbNeeded
= needed
;
5674 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5676 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5677 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5682 /******************************************************************************
5683 * GetDefaultPrinterW (WINSPOOL.@)
5686 * This function must read the value from data 'device' of key
5687 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5689 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5693 WCHAR
*buffer
, *ptr
;
5697 SetLastError(ERROR_INVALID_PARAMETER
);
5701 /* make the buffer big enough for the stuff from the profile/registry,
5702 * the content must fit into the local buffer to compute the correct
5703 * size even if the extern buffer is too small or not given.
5704 * (20 for ,driver,port) */
5706 len
= max(100, (insize
+ 20));
5707 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5709 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5711 SetLastError (ERROR_FILE_NOT_FOUND
);
5715 TRACE("%s\n", debugstr_w(buffer
));
5717 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5719 SetLastError(ERROR_INVALID_NAME
);
5725 *namesize
= strlenW(buffer
) + 1;
5726 if(!name
|| (*namesize
> insize
))
5728 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5732 strcpyW(name
, buffer
);
5735 HeapFree( GetProcessHeap(), 0, buffer
);
5740 /******************************************************************************
5741 * GetDefaultPrinterA (WINSPOOL.@)
5743 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5747 WCHAR
*bufferW
= NULL
;
5751 SetLastError(ERROR_INVALID_PARAMETER
);
5755 if(name
&& *namesize
) {
5757 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5760 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5765 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5769 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5772 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5775 HeapFree( GetProcessHeap(), 0, bufferW
);
5780 /******************************************************************************
5781 * SetDefaultPrinterW (WINSPOOL.204)
5783 * Set the Name of the Default Printer
5786 * pszPrinter [I] Name of the Printer or NULL
5793 * When the Parameter is NULL or points to an Empty String and
5794 * a Default Printer was already present, then this Function changes nothing.
5795 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5796 * the First enumerated local Printer is used.
5799 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5802 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5804 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5808 /******************************************************************************
5809 * SetDefaultPrinterA (WINSPOOL.202)
5811 * See SetDefaultPrinterW.
5814 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5817 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5819 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5824 /******************************************************************************
5825 * SetPrinterDataExA (WINSPOOL.@)
5827 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5828 LPCSTR pValueName
, DWORD Type
,
5829 LPBYTE pData
, DWORD cbData
)
5831 HKEY hkeyPrinter
, hkeySubkey
;
5834 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5835 debugstr_a(pValueName
), Type
, pData
, cbData
);
5837 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5841 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5843 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5844 RegCloseKey(hkeyPrinter
);
5847 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5848 RegCloseKey(hkeySubkey
);
5849 RegCloseKey(hkeyPrinter
);
5853 /******************************************************************************
5854 * SetPrinterDataExW (WINSPOOL.@)
5856 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5857 LPCWSTR pValueName
, DWORD Type
,
5858 LPBYTE pData
, DWORD cbData
)
5860 HKEY hkeyPrinter
, hkeySubkey
;
5863 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5864 debugstr_w(pValueName
), Type
, pData
, cbData
);
5866 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5870 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5872 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5873 RegCloseKey(hkeyPrinter
);
5876 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5877 RegCloseKey(hkeySubkey
);
5878 RegCloseKey(hkeyPrinter
);
5882 /******************************************************************************
5883 * SetPrinterDataA (WINSPOOL.@)
5885 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5886 LPBYTE pData
, DWORD cbData
)
5888 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5892 /******************************************************************************
5893 * SetPrinterDataW (WINSPOOL.@)
5895 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5896 LPBYTE pData
, DWORD cbData
)
5898 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5902 /******************************************************************************
5903 * GetPrinterDataExA (WINSPOOL.@)
5905 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5906 LPCSTR pValueName
, LPDWORD pType
,
5907 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5909 HKEY hkeyPrinter
, hkeySubkey
;
5912 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5913 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5916 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5920 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5922 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5923 RegCloseKey(hkeyPrinter
);
5927 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5928 RegCloseKey(hkeySubkey
);
5929 RegCloseKey(hkeyPrinter
);
5933 /******************************************************************************
5934 * GetPrinterDataExW (WINSPOOL.@)
5936 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5937 LPCWSTR pValueName
, LPDWORD pType
,
5938 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5940 HKEY hkeyPrinter
, hkeySubkey
;
5943 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5944 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5947 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5951 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5953 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5954 RegCloseKey(hkeyPrinter
);
5958 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5959 RegCloseKey(hkeySubkey
);
5960 RegCloseKey(hkeyPrinter
);
5964 /******************************************************************************
5965 * GetPrinterDataA (WINSPOOL.@)
5967 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5968 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5970 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5971 pData
, nSize
, pcbNeeded
);
5974 /******************************************************************************
5975 * GetPrinterDataW (WINSPOOL.@)
5977 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5978 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5980 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5981 pData
, nSize
, pcbNeeded
);
5984 /*******************************************************************************
5985 * EnumPrinterDataExW [WINSPOOL.@]
5987 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5988 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5989 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5991 HKEY hkPrinter
, hkSubKey
;
5992 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5993 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5998 PPRINTER_ENUM_VALUESW ppev
;
6000 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6002 if (pKeyName
== NULL
|| *pKeyName
== 0)
6003 return ERROR_INVALID_PARAMETER
;
6005 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6006 if (ret
!= ERROR_SUCCESS
)
6008 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6013 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6014 if (ret
!= ERROR_SUCCESS
)
6016 r
= RegCloseKey (hkPrinter
);
6017 if (r
!= ERROR_SUCCESS
)
6018 WARN ("RegCloseKey returned %i\n", r
);
6019 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6020 debugstr_w (pKeyName
), ret
);
6024 ret
= RegCloseKey (hkPrinter
);
6025 if (ret
!= ERROR_SUCCESS
)
6027 ERR ("RegCloseKey returned %i\n", ret
);
6028 r
= RegCloseKey (hkSubKey
);
6029 if (r
!= ERROR_SUCCESS
)
6030 WARN ("RegCloseKey returned %i\n", r
);
6034 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6035 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6036 if (ret
!= ERROR_SUCCESS
)
6038 r
= RegCloseKey (hkSubKey
);
6039 if (r
!= ERROR_SUCCESS
)
6040 WARN ("RegCloseKey returned %i\n", r
);
6041 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6045 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6046 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6048 if (cValues
== 0) /* empty key */
6050 r
= RegCloseKey (hkSubKey
);
6051 if (r
!= ERROR_SUCCESS
)
6052 WARN ("RegCloseKey returned %i\n", r
);
6053 *pcbEnumValues
= *pnEnumValues
= 0;
6054 return ERROR_SUCCESS
;
6057 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6059 hHeap
= GetProcessHeap ();
6062 ERR ("GetProcessHeap failed\n");
6063 r
= RegCloseKey (hkSubKey
);
6064 if (r
!= ERROR_SUCCESS
)
6065 WARN ("RegCloseKey returned %i\n", r
);
6066 return ERROR_OUTOFMEMORY
;
6069 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6070 if (lpValueName
== NULL
)
6072 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6073 r
= RegCloseKey (hkSubKey
);
6074 if (r
!= ERROR_SUCCESS
)
6075 WARN ("RegCloseKey returned %i\n", r
);
6076 return ERROR_OUTOFMEMORY
;
6079 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6080 if (lpValue
== NULL
)
6082 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6083 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6084 WARN ("HeapFree failed with code %i\n", GetLastError ());
6085 r
= RegCloseKey (hkSubKey
);
6086 if (r
!= ERROR_SUCCESS
)
6087 WARN ("RegCloseKey returned %i\n", r
);
6088 return ERROR_OUTOFMEMORY
;
6091 TRACE ("pass 1: calculating buffer required for all names and values\n");
6093 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6095 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6097 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6099 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6100 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6101 NULL
, NULL
, lpValue
, &cbValueLen
);
6102 if (ret
!= ERROR_SUCCESS
)
6104 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6105 WARN ("HeapFree failed with code %i\n", GetLastError ());
6106 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6107 WARN ("HeapFree failed with code %i\n", GetLastError ());
6108 r
= RegCloseKey (hkSubKey
);
6109 if (r
!= ERROR_SUCCESS
)
6110 WARN ("RegCloseKey returned %i\n", r
);
6111 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6115 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6116 debugstr_w (lpValueName
), dwIndex
,
6117 cbValueNameLen
+ 1, cbValueLen
);
6119 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6120 cbBufSize
+= cbValueLen
;
6123 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6125 *pcbEnumValues
= cbBufSize
;
6126 *pnEnumValues
= cValues
;
6128 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6130 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6131 WARN ("HeapFree failed with code %i\n", GetLastError ());
6132 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6133 WARN ("HeapFree failed with code %i\n", GetLastError ());
6134 r
= RegCloseKey (hkSubKey
);
6135 if (r
!= ERROR_SUCCESS
)
6136 WARN ("RegCloseKey returned %i\n", r
);
6137 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6138 return ERROR_MORE_DATA
;
6141 TRACE ("pass 2: copying all names and values to buffer\n");
6143 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6144 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6146 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6148 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6149 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6150 NULL
, &dwType
, lpValue
, &cbValueLen
);
6151 if (ret
!= ERROR_SUCCESS
)
6153 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6154 WARN ("HeapFree failed with code %i\n", GetLastError ());
6155 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6156 WARN ("HeapFree failed with code %i\n", GetLastError ());
6157 r
= RegCloseKey (hkSubKey
);
6158 if (r
!= ERROR_SUCCESS
)
6159 WARN ("RegCloseKey returned %i\n", r
);
6160 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6164 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6165 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6166 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6167 pEnumValues
+= cbValueNameLen
;
6169 /* return # of *bytes* (including trailing \0), not # of chars */
6170 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6172 ppev
[dwIndex
].dwType
= dwType
;
6174 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6175 ppev
[dwIndex
].pData
= pEnumValues
;
6176 pEnumValues
+= cbValueLen
;
6178 ppev
[dwIndex
].cbData
= cbValueLen
;
6180 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6181 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6184 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6186 ret
= GetLastError ();
6187 ERR ("HeapFree failed with code %i\n", ret
);
6188 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6189 WARN ("HeapFree failed with code %i\n", GetLastError ());
6190 r
= RegCloseKey (hkSubKey
);
6191 if (r
!= ERROR_SUCCESS
)
6192 WARN ("RegCloseKey returned %i\n", r
);
6196 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6198 ret
= GetLastError ();
6199 ERR ("HeapFree failed with code %i\n", ret
);
6200 r
= RegCloseKey (hkSubKey
);
6201 if (r
!= ERROR_SUCCESS
)
6202 WARN ("RegCloseKey returned %i\n", r
);
6206 ret
= RegCloseKey (hkSubKey
);
6207 if (ret
!= ERROR_SUCCESS
)
6209 ERR ("RegCloseKey returned %i\n", ret
);
6213 return ERROR_SUCCESS
;
6216 /*******************************************************************************
6217 * EnumPrinterDataExA [WINSPOOL.@]
6219 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6220 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6221 * what Windows 2000 SP1 does.
6224 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6225 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6226 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6230 DWORD ret
, dwIndex
, dwBufSize
;
6234 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6236 if (pKeyName
== NULL
|| *pKeyName
== 0)
6237 return ERROR_INVALID_PARAMETER
;
6239 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6242 ret
= GetLastError ();
6243 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6247 hHeap
= GetProcessHeap ();
6250 ERR ("GetProcessHeap failed\n");
6251 return ERROR_OUTOFMEMORY
;
6254 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6255 if (pKeyNameW
== NULL
)
6257 ERR ("Failed to allocate %i bytes from process heap\n",
6258 (LONG
)(len
* sizeof (WCHAR
)));
6259 return ERROR_OUTOFMEMORY
;
6262 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6264 ret
= GetLastError ();
6265 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6266 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6267 WARN ("HeapFree failed with code %i\n", GetLastError ());
6271 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6272 pcbEnumValues
, pnEnumValues
);
6273 if (ret
!= ERROR_SUCCESS
)
6275 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6276 WARN ("HeapFree failed with code %i\n", GetLastError ());
6277 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6281 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6283 ret
= GetLastError ();
6284 ERR ("HeapFree failed with code %i\n", ret
);
6288 if (*pnEnumValues
== 0) /* empty key */
6289 return ERROR_SUCCESS
;
6292 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6294 PPRINTER_ENUM_VALUESW ppev
=
6295 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6297 if (dwBufSize
< ppev
->cbValueName
)
6298 dwBufSize
= ppev
->cbValueName
;
6300 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6301 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6302 dwBufSize
= ppev
->cbData
;
6305 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6307 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6308 if (pBuffer
== NULL
)
6310 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6311 return ERROR_OUTOFMEMORY
;
6314 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6316 PPRINTER_ENUM_VALUESW ppev
=
6317 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6319 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6320 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6324 ret
= GetLastError ();
6325 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6326 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6327 WARN ("HeapFree failed with code %i\n", GetLastError ());
6331 memcpy (ppev
->pValueName
, pBuffer
, len
);
6333 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6335 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6336 ppev
->dwType
!= REG_MULTI_SZ
)
6339 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6340 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6343 ret
= GetLastError ();
6344 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6345 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6346 WARN ("HeapFree failed with code %i\n", GetLastError ());
6350 memcpy (ppev
->pData
, pBuffer
, len
);
6352 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6353 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6356 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6358 ret
= GetLastError ();
6359 ERR ("HeapFree failed with code %i\n", ret
);
6363 return ERROR_SUCCESS
;
6366 /******************************************************************************
6367 * AbortPrinter (WINSPOOL.@)
6369 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6371 FIXME("(%p), stub!\n", hPrinter
);
6375 /******************************************************************************
6376 * AddPortA (WINSPOOL.@)
6381 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6383 LPWSTR nameW
= NULL
;
6384 LPWSTR monitorW
= NULL
;
6388 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6391 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6392 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6393 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6397 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6398 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6399 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6401 res
= AddPortW(nameW
, hWnd
, monitorW
);
6402 HeapFree(GetProcessHeap(), 0, nameW
);
6403 HeapFree(GetProcessHeap(), 0, monitorW
);
6407 /******************************************************************************
6408 * AddPortW (WINSPOOL.@)
6410 * Add a Port for a specific Monitor
6413 * pName [I] Servername or NULL (local Computer)
6414 * hWnd [I] Handle to parent Window for the Dialog-Box
6415 * pMonitorName [I] Name of the Monitor that manage the Port
6422 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6428 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6430 if (pName
&& pName
[0]) {
6431 SetLastError(ERROR_INVALID_PARAMETER
);
6435 if (!pMonitorName
) {
6436 SetLastError(RPC_X_NULL_REF_POINTER
);
6440 /* an empty Monitorname is Invalid */
6441 if (!pMonitorName
[0]) {
6442 SetLastError(ERROR_NOT_SUPPORTED
);
6446 pm
= monitor_load(pMonitorName
, NULL
);
6447 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6448 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6449 TRACE("got %d with %u\n", res
, GetLastError());
6454 pui
= monitor_loadui(pm
);
6455 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6456 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6457 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6458 TRACE("got %d with %u\n", res
, GetLastError());
6463 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6464 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6466 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6467 SetLastError(ERROR_NOT_SUPPORTED
);
6470 monitor_unload(pui
);
6473 TRACE("returning %d with %u\n", res
, GetLastError());
6477 /******************************************************************************
6478 * AddPortExA (WINSPOOL.@)
6483 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6486 PORT_INFO_2A
* pi2A
;
6487 LPWSTR nameW
= NULL
;
6488 LPWSTR monitorW
= NULL
;
6492 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6494 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6495 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6497 if ((level
< 1) || (level
> 2)) {
6498 SetLastError(ERROR_INVALID_LEVEL
);
6503 SetLastError(ERROR_INVALID_PARAMETER
);
6508 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6509 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6510 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6514 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6515 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6516 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6519 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6521 if (pi2A
->pPortName
) {
6522 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6523 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6524 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6528 if (pi2A
->pMonitorName
) {
6529 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6530 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6531 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6534 if (pi2A
->pDescription
) {
6535 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6536 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6537 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6539 pi2W
.fPortType
= pi2A
->fPortType
;
6540 pi2W
.Reserved
= pi2A
->Reserved
;
6543 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6545 HeapFree(GetProcessHeap(), 0, nameW
);
6546 HeapFree(GetProcessHeap(), 0, monitorW
);
6547 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6548 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6549 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6554 /******************************************************************************
6555 * AddPortExW (WINSPOOL.@)
6557 * Add a Port for a specific Monitor, without presenting a user interface
6560 * pName [I] Servername or NULL (local Computer)
6561 * level [I] Structure-Level (1 or 2) for pBuffer
6562 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6563 * pMonitorName [I] Name of the Monitor that manage the Port
6570 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6576 pi2
= (PORT_INFO_2W
*) pBuffer
;
6578 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6579 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6580 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6581 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6584 if ((level
< 1) || (level
> 2)) {
6585 SetLastError(ERROR_INVALID_LEVEL
);
6589 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6590 SetLastError(ERROR_INVALID_PARAMETER
);
6594 /* load the Monitor */
6595 pm
= monitor_load(pMonitorName
, NULL
);
6597 SetLastError(ERROR_INVALID_PARAMETER
);
6601 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6602 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6603 TRACE("got %u with %u\n", res
, GetLastError());
6607 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6613 /******************************************************************************
6614 * AddPrinterConnectionA (WINSPOOL.@)
6616 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6618 FIXME("%s\n", debugstr_a(pName
));
6622 /******************************************************************************
6623 * AddPrinterConnectionW (WINSPOOL.@)
6625 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6627 FIXME("%s\n", debugstr_w(pName
));
6631 /******************************************************************************
6632 * AddPrinterDriverExW (WINSPOOL.@)
6634 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6637 * pName [I] Servername or NULL (local Computer)
6638 * level [I] Level for the supplied DRIVER_INFO_*W struct
6639 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6640 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6647 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6649 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6651 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6653 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6654 SetLastError(ERROR_INVALID_LEVEL
);
6659 SetLastError(ERROR_INVALID_PARAMETER
);
6663 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6666 /******************************************************************************
6667 * AddPrinterDriverExA (WINSPOOL.@)
6669 * See AddPrinterDriverExW.
6672 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6674 DRIVER_INFO_8A
*diA
;
6676 LPWSTR nameW
= NULL
;
6681 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6683 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6684 ZeroMemory(&diW
, sizeof(diW
));
6686 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6687 SetLastError(ERROR_INVALID_LEVEL
);
6692 SetLastError(ERROR_INVALID_PARAMETER
);
6696 /* convert servername to unicode */
6698 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6699 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6700 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6704 diW
.cVersion
= diA
->cVersion
;
6707 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6708 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6709 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6712 if (diA
->pEnvironment
) {
6713 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6714 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6715 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6718 if (diA
->pDriverPath
) {
6719 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6720 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6721 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6724 if (diA
->pDataFile
) {
6725 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6726 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6727 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6730 if (diA
->pConfigFile
) {
6731 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6732 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6733 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6736 if ((Level
> 2) && diA
->pDependentFiles
) {
6737 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6738 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6739 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6740 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6743 if ((Level
> 2) && diA
->pMonitorName
) {
6744 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6745 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6746 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6749 if ((Level
> 3) && diA
->pDefaultDataType
) {
6750 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6751 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6752 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6755 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6756 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6757 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6758 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6759 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6762 if ((Level
> 5) && diA
->pszMfgName
) {
6763 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6764 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6765 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6768 if ((Level
> 5) && diA
->pszOEMUrl
) {
6769 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6770 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6771 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6774 if ((Level
> 5) && diA
->pszHardwareID
) {
6775 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6776 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6777 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6780 if ((Level
> 5) && diA
->pszProvider
) {
6781 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6782 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6783 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6787 FIXME("level %u is incomplete\n", Level
);
6790 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6791 TRACE("got %u with %u\n", res
, GetLastError());
6792 HeapFree(GetProcessHeap(), 0, nameW
);
6793 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6794 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6795 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6796 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6797 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6798 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6799 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6800 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6801 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6802 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6803 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6804 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6805 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6807 TRACE("=> %u with %u\n", res
, GetLastError());
6811 /******************************************************************************
6812 * ConfigurePortA (WINSPOOL.@)
6814 * See ConfigurePortW.
6817 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6819 LPWSTR nameW
= NULL
;
6820 LPWSTR portW
= NULL
;
6824 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6826 /* convert servername to unicode */
6828 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6829 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6830 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6833 /* convert portname to unicode */
6835 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6836 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6837 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6840 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6841 HeapFree(GetProcessHeap(), 0, nameW
);
6842 HeapFree(GetProcessHeap(), 0, portW
);
6846 /******************************************************************************
6847 * ConfigurePortW (WINSPOOL.@)
6849 * Display the Configuration-Dialog for a specific Port
6852 * pName [I] Servername or NULL (local Computer)
6853 * hWnd [I] Handle to parent Window for the Dialog-Box
6854 * pPortName [I] Name of the Port, that should be configured
6861 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6867 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6869 if (pName
&& pName
[0]) {
6870 SetLastError(ERROR_INVALID_PARAMETER
);
6875 SetLastError(RPC_X_NULL_REF_POINTER
);
6879 /* an empty Portname is Invalid, but can popup a Dialog */
6880 if (!pPortName
[0]) {
6881 SetLastError(ERROR_NOT_SUPPORTED
);
6885 pm
= monitor_load_by_port(pPortName
);
6886 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6887 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6888 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6889 TRACE("got %d with %u\n", res
, GetLastError());
6893 pui
= monitor_loadui(pm
);
6894 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6895 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6896 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6897 TRACE("got %d with %u\n", res
, GetLastError());
6901 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6902 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6904 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6905 SetLastError(ERROR_NOT_SUPPORTED
);
6908 monitor_unload(pui
);
6912 TRACE("returning %d with %u\n", res
, GetLastError());
6916 /******************************************************************************
6917 * ConnectToPrinterDlg (WINSPOOL.@)
6919 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6921 FIXME("%p %x\n", hWnd
, Flags
);
6925 /******************************************************************************
6926 * DeletePrinterConnectionA (WINSPOOL.@)
6928 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6930 FIXME("%s\n", debugstr_a(pName
));
6934 /******************************************************************************
6935 * DeletePrinterConnectionW (WINSPOOL.@)
6937 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6939 FIXME("%s\n", debugstr_w(pName
));
6943 /******************************************************************************
6944 * DeletePrinterDriverExW (WINSPOOL.@)
6946 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6947 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6952 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6953 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6955 if(pName
&& pName
[0])
6957 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6958 SetLastError(ERROR_INVALID_PARAMETER
);
6964 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6965 SetLastError(ERROR_INVALID_PARAMETER
);
6969 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6973 ERR("Can't open drivers key\n");
6977 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6980 RegCloseKey(hkey_drivers
);
6985 /******************************************************************************
6986 * DeletePrinterDriverExA (WINSPOOL.@)
6988 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6989 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6991 UNICODE_STRING NameW
, EnvW
, DriverW
;
6994 asciitounicode(&NameW
, pName
);
6995 asciitounicode(&EnvW
, pEnvironment
);
6996 asciitounicode(&DriverW
, pDriverName
);
6998 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7000 RtlFreeUnicodeString(&DriverW
);
7001 RtlFreeUnicodeString(&EnvW
);
7002 RtlFreeUnicodeString(&NameW
);
7007 /******************************************************************************
7008 * DeletePrinterDataExW (WINSPOOL.@)
7010 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7013 FIXME("%p %s %s\n", hPrinter
,
7014 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7015 return ERROR_INVALID_PARAMETER
;
7018 /******************************************************************************
7019 * DeletePrinterDataExA (WINSPOOL.@)
7021 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7024 FIXME("%p %s %s\n", hPrinter
,
7025 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7026 return ERROR_INVALID_PARAMETER
;
7029 /******************************************************************************
7030 * DeletePrintProcessorA (WINSPOOL.@)
7032 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7034 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7035 debugstr_a(pPrintProcessorName
));
7039 /******************************************************************************
7040 * DeletePrintProcessorW (WINSPOOL.@)
7042 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7044 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7045 debugstr_w(pPrintProcessorName
));
7049 /******************************************************************************
7050 * DeletePrintProvidorA (WINSPOOL.@)
7052 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7054 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7055 debugstr_a(pPrintProviderName
));
7059 /******************************************************************************
7060 * DeletePrintProvidorW (WINSPOOL.@)
7062 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7064 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7065 debugstr_w(pPrintProviderName
));
7069 /******************************************************************************
7070 * EnumFormsA (WINSPOOL.@)
7072 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7073 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7075 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7076 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7080 /******************************************************************************
7081 * EnumFormsW (WINSPOOL.@)
7083 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7084 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7086 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7087 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7091 /*****************************************************************************
7092 * EnumMonitorsA [WINSPOOL.@]
7094 * See EnumMonitorsW.
7097 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7098 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7101 LPBYTE bufferW
= NULL
;
7102 LPWSTR nameW
= NULL
;
7104 DWORD numentries
= 0;
7107 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7108 cbBuf
, pcbNeeded
, pcReturned
);
7110 /* convert servername to unicode */
7112 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7113 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7114 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7116 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7117 needed
= cbBuf
* sizeof(WCHAR
);
7118 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7119 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7121 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7122 if (pcbNeeded
) needed
= *pcbNeeded
;
7123 /* HeapReAlloc return NULL, when bufferW was NULL */
7124 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7125 HeapAlloc(GetProcessHeap(), 0, needed
);
7127 /* Try again with the large Buffer */
7128 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7130 numentries
= pcReturned
? *pcReturned
: 0;
7133 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7134 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7137 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7138 DWORD entrysize
= 0;
7141 LPMONITOR_INFO_2W mi2w
;
7142 LPMONITOR_INFO_2A mi2a
;
7144 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7145 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7147 /* First pass: calculate the size for all Entries */
7148 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7149 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7151 while (index
< numentries
) {
7153 needed
+= entrysize
; /* MONITOR_INFO_?A */
7154 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7156 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7157 NULL
, 0, NULL
, NULL
);
7159 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7160 NULL
, 0, NULL
, NULL
);
7161 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7162 NULL
, 0, NULL
, NULL
);
7164 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7165 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7166 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7169 /* check for errors and quit on failure */
7170 if (cbBuf
< needed
) {
7171 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7175 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7176 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7177 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7178 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7179 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7181 /* Second Pass: Fill the User Buffer (if we have one) */
7182 while ((index
< numentries
) && pMonitors
) {
7184 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7186 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7187 ptr
, cbBuf
, NULL
, NULL
);
7191 mi2a
->pEnvironment
= ptr
;
7192 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7193 ptr
, cbBuf
, NULL
, NULL
);
7197 mi2a
->pDLLName
= ptr
;
7198 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7199 ptr
, cbBuf
, NULL
, NULL
);
7203 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7204 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7205 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7209 if (pcbNeeded
) *pcbNeeded
= needed
;
7210 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7212 HeapFree(GetProcessHeap(), 0, nameW
);
7213 HeapFree(GetProcessHeap(), 0, bufferW
);
7215 TRACE("returning %d with %d (%d byte for %d entries)\n",
7216 (res
), GetLastError(), needed
, numentries
);
7222 /*****************************************************************************
7223 * EnumMonitorsW [WINSPOOL.@]
7225 * Enumerate available Port-Monitors
7228 * pName [I] Servername or NULL (local Computer)
7229 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7230 * pMonitors [O] PTR to Buffer that receives the Result
7231 * cbBuf [I] Size of Buffer at pMonitors
7232 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7233 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7237 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7240 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7241 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7244 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7245 cbBuf
, pcbNeeded
, pcReturned
);
7247 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7249 /* Level is not checked in win9x */
7250 if (!Level
|| (Level
> 2)) {
7251 WARN("level (%d) is ignored in win9x\n", Level
);
7252 SetLastError(ERROR_INVALID_LEVEL
);
7256 SetLastError(RPC_X_NULL_REF_POINTER
);
7260 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7263 /******************************************************************************
7264 * SpoolerInit (WINSPOOL.@)
7266 * Initialize the Spooler
7273 * The function fails on windows, when the spooler service is not running
7276 BOOL WINAPI
SpoolerInit(void)
7279 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7283 /******************************************************************************
7284 * XcvDataW (WINSPOOL.@)
7286 * Execute commands in the Printmonitor DLL
7289 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7290 * pszDataName [i] Name of the command to execute
7291 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7292 * cbInputData [i] Size in Bytes of Buffer at pInputData
7293 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7294 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7295 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7296 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7303 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7304 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7306 * Minimal List of commands, that a Printmonitor DLL should support:
7308 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7309 *| "AddPort" : Add a Port
7310 *| "DeletePort": Delete a Port
7312 * Many Printmonitors support additional commands. Examples for localspl.dll:
7313 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7314 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7317 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7318 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7319 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7321 opened_printer_t
*printer
;
7323 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7324 pInputData
, cbInputData
, pOutputData
,
7325 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7327 printer
= get_opened_printer(hXcv
);
7328 if (!printer
|| (!printer
->hXcv
)) {
7329 SetLastError(ERROR_INVALID_HANDLE
);
7333 if (!pcbOutputNeeded
) {
7334 SetLastError(ERROR_INVALID_PARAMETER
);
7338 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7339 SetLastError(RPC_X_NULL_REF_POINTER
);
7343 *pcbOutputNeeded
= 0;
7345 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
7346 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
7351 /*****************************************************************************
7352 * EnumPrinterDataA [WINSPOOL.@]
7355 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7356 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7357 DWORD cbData
, LPDWORD pcbData
)
7359 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7360 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7361 return ERROR_NO_MORE_ITEMS
;
7364 /*****************************************************************************
7365 * EnumPrinterDataW [WINSPOOL.@]
7368 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7369 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7370 DWORD cbData
, LPDWORD pcbData
)
7372 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7373 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7374 return ERROR_NO_MORE_ITEMS
;
7377 /*****************************************************************************
7378 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7381 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7382 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7383 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7385 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7386 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7387 pcbNeeded
, pcReturned
);
7391 /*****************************************************************************
7392 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7395 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7396 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7397 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7399 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7400 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7401 pcbNeeded
, pcReturned
);
7405 /*****************************************************************************
7406 * EnumPrintProcessorsA [WINSPOOL.@]
7409 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7410 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7412 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7413 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7417 /*****************************************************************************
7418 * EnumPrintProcessorsW [WINSPOOL.@]
7421 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7422 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7424 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7425 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7426 cbBuf
, pcbNeeded
, pcbReturned
);
7430 /*****************************************************************************
7431 * ExtDeviceMode [WINSPOOL.@]
7434 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7435 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7438 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7439 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7440 debugstr_a(pProfile
), fMode
);
7444 /*****************************************************************************
7445 * FindClosePrinterChangeNotification [WINSPOOL.@]
7448 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7450 FIXME("Stub: %p\n", hChange
);
7454 /*****************************************************************************
7455 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7458 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7459 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7461 FIXME("Stub: %p %x %x %p\n",
7462 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7463 return INVALID_HANDLE_VALUE
;
7466 /*****************************************************************************
7467 * FindNextPrinterChangeNotification [WINSPOOL.@]
7470 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7471 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7473 FIXME("Stub: %p %p %p %p\n",
7474 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7478 /*****************************************************************************
7479 * FreePrinterNotifyInfo [WINSPOOL.@]
7482 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7484 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7488 /*****************************************************************************
7491 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7492 * ansi depending on the unicode parameter.
7494 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7504 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7507 memcpy(ptr
, str
, *size
);
7514 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7517 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7524 /*****************************************************************************
7527 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7528 LPDWORD pcbNeeded
, BOOL unicode
)
7530 DWORD size
, left
= cbBuf
;
7531 BOOL space
= (cbBuf
> 0);
7538 ji1
->JobId
= job
->job_id
;
7541 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7542 if(space
&& size
<= left
)
7544 ji1
->pDocument
= (LPWSTR
)ptr
;
7555 /*****************************************************************************
7558 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7559 LPDWORD pcbNeeded
, BOOL unicode
)
7561 DWORD size
, left
= cbBuf
;
7562 BOOL space
= (cbBuf
> 0);
7569 ji2
->JobId
= job
->job_id
;
7572 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7573 if(space
&& size
<= left
)
7575 ji2
->pDocument
= (LPWSTR
)ptr
;
7586 /*****************************************************************************
7589 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7590 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7593 DWORD needed
= 0, size
;
7597 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7599 EnterCriticalSection(&printer_handles_cs
);
7600 job
= get_job(hPrinter
, JobId
);
7607 size
= sizeof(JOB_INFO_1W
);
7612 memset(pJob
, 0, size
);
7616 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7621 size
= sizeof(JOB_INFO_2W
);
7626 memset(pJob
, 0, size
);
7630 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7635 size
= sizeof(JOB_INFO_3
);
7639 memset(pJob
, 0, size
);
7648 SetLastError(ERROR_INVALID_LEVEL
);
7652 *pcbNeeded
= needed
;
7654 LeaveCriticalSection(&printer_handles_cs
);
7658 /*****************************************************************************
7659 * GetJobA [WINSPOOL.@]
7662 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7663 DWORD cbBuf
, LPDWORD pcbNeeded
)
7665 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7668 /*****************************************************************************
7669 * GetJobW [WINSPOOL.@]
7672 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7673 DWORD cbBuf
, LPDWORD pcbNeeded
)
7675 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7678 /*****************************************************************************
7681 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7683 char *unixname
, *queue
, *cmd
;
7684 char fmt
[] = "lpr -P%s %s";
7687 if(!(unixname
= wine_get_unix_file_name(filename
)))
7690 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7691 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7692 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7694 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7695 sprintf(cmd
, fmt
, queue
, unixname
);
7697 TRACE("printing with: %s\n", cmd
);
7700 HeapFree(GetProcessHeap(), 0, cmd
);
7701 HeapFree(GetProcessHeap(), 0, queue
);
7702 HeapFree(GetProcessHeap(), 0, unixname
);
7706 /*****************************************************************************
7709 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7711 #ifdef SONAME_LIBCUPS
7714 char *unixname
, *queue
, *doc_titleA
;
7718 if(!(unixname
= wine_get_unix_file_name(filename
)))
7721 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7722 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7723 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7725 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7726 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7727 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7729 TRACE("printing via cups\n");
7730 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7731 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7732 HeapFree(GetProcessHeap(), 0, queue
);
7733 HeapFree(GetProcessHeap(), 0, unixname
);
7739 return schedule_lpr(printer_name
, filename
);
7743 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7750 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7754 if(HIWORD(wparam
) == BN_CLICKED
)
7756 if(LOWORD(wparam
) == IDOK
)
7759 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7762 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7763 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7765 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7767 WCHAR caption
[200], message
[200];
7770 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7771 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7772 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7773 if(mb_ret
== IDCANCEL
)
7775 HeapFree(GetProcessHeap(), 0, filename
);
7779 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7780 if(hf
== INVALID_HANDLE_VALUE
)
7782 WCHAR caption
[200], message
[200];
7784 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7785 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7786 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7787 HeapFree(GetProcessHeap(), 0, filename
);
7791 DeleteFileW(filename
);
7792 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7794 EndDialog(hwnd
, IDOK
);
7797 if(LOWORD(wparam
) == IDCANCEL
)
7799 EndDialog(hwnd
, IDCANCEL
);
7808 /*****************************************************************************
7811 static BOOL
get_filename(LPWSTR
*filename
)
7813 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7814 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7817 /*****************************************************************************
7820 static BOOL
schedule_file(LPCWSTR filename
)
7822 LPWSTR output
= NULL
;
7824 if(get_filename(&output
))
7826 TRACE("copy to %s\n", debugstr_w(output
));
7827 CopyFileW(filename
, output
, FALSE
);
7828 HeapFree(GetProcessHeap(), 0, output
);
7834 /*****************************************************************************
7837 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7840 char *unixname
, *cmdA
;
7842 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7846 if(!(unixname
= wine_get_unix_file_name(filename
)))
7849 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7850 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7851 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7853 TRACE("printing with: %s\n", cmdA
);
7855 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7860 ERR("pipe() failed!\n");
7870 /* reset signals that we previously set to SIG_IGN */
7871 signal(SIGPIPE
, SIG_DFL
);
7872 signal(SIGCHLD
, SIG_DFL
);
7874 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7878 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7879 write(fds
[1], buf
, no_read
);
7884 if(file_fd
!= -1) close(file_fd
);
7885 if(fds
[0] != -1) close(fds
[0]);
7886 if(fds
[1] != -1) close(fds
[1]);
7888 HeapFree(GetProcessHeap(), 0, cmdA
);
7889 HeapFree(GetProcessHeap(), 0, unixname
);
7896 /*****************************************************************************
7899 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7901 int in_fd
, out_fd
, no_read
;
7904 char *unixname
, *outputA
;
7907 if(!(unixname
= wine_get_unix_file_name(filename
)))
7910 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7911 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7912 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7914 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7915 in_fd
= open(unixname
, O_RDONLY
);
7916 if(out_fd
== -1 || in_fd
== -1)
7919 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7920 write(out_fd
, buf
, no_read
);
7924 if(in_fd
!= -1) close(in_fd
);
7925 if(out_fd
!= -1) close(out_fd
);
7926 HeapFree(GetProcessHeap(), 0, outputA
);
7927 HeapFree(GetProcessHeap(), 0, unixname
);
7931 /*****************************************************************************
7932 * ScheduleJob [WINSPOOL.@]
7935 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7937 opened_printer_t
*printer
;
7939 struct list
*cursor
, *cursor2
;
7941 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7942 EnterCriticalSection(&printer_handles_cs
);
7943 printer
= get_opened_printer(hPrinter
);
7947 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7949 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7952 if(job
->job_id
!= dwJobID
) continue;
7954 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7955 if(hf
!= INVALID_HANDLE_VALUE
)
7957 PRINTER_INFO_5W
*pi5
;
7961 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7962 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7964 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7965 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7966 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7967 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7968 debugstr_w(pi5
->pPortName
));
7972 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7973 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7975 DWORD type
, count
= sizeof(output
);
7976 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7979 if(output
[0] == '|')
7981 schedule_pipe(output
+ 1, job
->filename
);
7985 schedule_unixfile(output
, job
->filename
);
7987 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7989 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7991 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7993 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7995 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7997 schedule_file(job
->filename
);
8001 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
8003 HeapFree(GetProcessHeap(), 0, pi5
);
8005 DeleteFileW(job
->filename
);
8007 list_remove(cursor
);
8008 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8009 HeapFree(GetProcessHeap(), 0, job
->filename
);
8010 HeapFree(GetProcessHeap(), 0, job
);
8015 LeaveCriticalSection(&printer_handles_cs
);
8019 /*****************************************************************************
8020 * StartDocDlgA [WINSPOOL.@]
8022 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8024 UNICODE_STRING usBuffer
;
8027 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8030 docW
.cbSize
= sizeof(docW
);
8031 if (doc
->lpszDocName
)
8033 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8034 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
8036 if (doc
->lpszOutput
)
8038 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8039 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
8041 if (doc
->lpszDatatype
)
8043 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8044 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8046 docW
.fwType
= doc
->fwType
;
8048 retW
= StartDocDlgW(hPrinter
, &docW
);
8052 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8053 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8054 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8055 HeapFree(GetProcessHeap(), 0, retW
);
8058 HeapFree(GetProcessHeap(), 0, datatypeW
);
8059 HeapFree(GetProcessHeap(), 0, outputW
);
8060 HeapFree(GetProcessHeap(), 0, docnameW
);
8065 /*****************************************************************************
8066 * StartDocDlgW [WINSPOOL.@]
8068 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8069 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8070 * port is "FILE:". Also returns the full path if passed a relative path.
8072 * The caller should free the returned string from the process heap.
8074 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8079 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8081 PRINTER_INFO_5W
*pi5
;
8082 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8083 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8085 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8086 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8087 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8089 HeapFree(GetProcessHeap(), 0, pi5
);
8092 HeapFree(GetProcessHeap(), 0, pi5
);
8095 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8099 if (get_filename(&name
))
8101 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8103 HeapFree(GetProcessHeap(), 0, name
);
8106 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8107 GetFullPathNameW(name
, len
, ret
, NULL
);
8108 HeapFree(GetProcessHeap(), 0, name
);
8113 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8116 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8117 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8119 attr
= GetFileAttributesW(ret
);
8120 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8122 HeapFree(GetProcessHeap(), 0, ret
);