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
);
528 static CHAR data_type
[] = "RAW",
529 print_proc
[] = "WinPrint",
530 comment
[] = "WINEPS Printer using CUPS",
531 location
[] = "<physical location of printer>",
532 params
[] = "<parameters?>",
533 share_name
[] = "<share name?>",
534 sep_file
[] = "<sep file?>";
536 add_printer_driver(dests
[i
].name
);
538 memset(&pinfo2a
,0,sizeof(pinfo2a
));
539 pinfo2a
.pPrinterName
= dests
[i
].name
;
540 pinfo2a
.pDatatype
= data_type
;
541 pinfo2a
.pPrintProcessor
= print_proc
;
542 pinfo2a
.pDriverName
= dests
[i
].name
;
543 pinfo2a
.pComment
= comment
;
544 pinfo2a
.pLocation
= location
;
545 pinfo2a
.pPortName
= port
;
546 pinfo2a
.pParameters
= params
;
547 pinfo2a
.pShareName
= share_name
;
548 pinfo2a
.pSepFile
= sep_file
;
550 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
551 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
552 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
555 HeapFree(GetProcessHeap(),0,port
);
558 if (dests
[i
].is_default
) {
559 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
563 if (hadprinter
& !haddefault
)
564 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
565 RegCloseKey(hkeyPrinters
);
571 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
572 PRINTER_INFO_2A pinfo2a
;
573 char *e
,*s
,*name
,*prettyname
,*devname
;
574 BOOL ret
= FALSE
, set_default
= FALSE
;
575 char *port
= NULL
, *devline
,*env_default
;
576 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
578 while (isspace(*pent
)) pent
++;
579 s
= strchr(pent
,':');
581 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
589 TRACE("name=%s entry=%s\n",name
, pent
);
591 if(ispunct(*name
)) { /* a tc entry, not a real printer */
592 TRACE("skipping tc entry\n");
596 if(strstr(pent
,":server")) { /* server only version so skip */
597 TRACE("skipping server entry\n");
601 /* Determine whether this is a postscript printer. */
604 env_default
= getenv("PRINTER");
606 /* Get longest name, usually the one at the right for later display. */
607 while((s
=strchr(prettyname
,'|'))) {
610 while(isspace(*--e
)) *e
= '\0';
611 TRACE("\t%s\n", debugstr_a(prettyname
));
612 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
613 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
616 e
= prettyname
+ strlen(prettyname
);
617 while(isspace(*--e
)) *e
= '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname
));
619 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
621 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
622 * if it is too long, we use it as comment below. */
623 devname
= prettyname
;
624 if (strlen(devname
)>=CCHDEVICENAME
-1)
626 if (strlen(devname
)>=CCHDEVICENAME
-1) {
631 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
632 sprintf(port
,"LPR:%s",name
);
634 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
635 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
636 sprintf(devline
, "WINEPS.DRV,%s", port
);
637 WriteProfileStringA("devices", devname
, devline
);
638 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
639 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
643 lstrcatA(devline
, ",15,45");
644 WriteProfileStringA("PrinterPorts", devname
, devline
);
645 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
646 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
650 HeapFree(GetProcessHeap(),0,devline
);
652 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
654 ERR("Can't create Printers key\n");
658 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
659 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
661 TRACE("Printer already exists\n");
662 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
663 RegCloseKey(hkeyPrinter
);
665 static CHAR data_type
[] = "RAW",
666 print_proc
[] = "WinPrint",
667 comment
[] = "WINEPS Printer using LPR",
668 params
[] = "<parameters?>",
669 share_name
[] = "<share name?>",
670 sep_file
[] = "<sep file?>";
672 add_printer_driver(devname
);
674 memset(&pinfo2a
,0,sizeof(pinfo2a
));
675 pinfo2a
.pPrinterName
= devname
;
676 pinfo2a
.pDatatype
= data_type
;
677 pinfo2a
.pPrintProcessor
= print_proc
;
678 pinfo2a
.pDriverName
= devname
;
679 pinfo2a
.pComment
= comment
;
680 pinfo2a
.pLocation
= prettyname
;
681 pinfo2a
.pPortName
= port
;
682 pinfo2a
.pParameters
= params
;
683 pinfo2a
.pShareName
= share_name
;
684 pinfo2a
.pSepFile
= sep_file
;
686 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
687 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
688 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
691 RegCloseKey(hkeyPrinters
);
693 if (isfirst
|| set_default
)
694 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
697 HeapFree(GetProcessHeap(), 0, port
);
698 HeapFree(GetProcessHeap(), 0, name
);
703 PRINTCAP_LoadPrinters(void) {
704 BOOL hadprinter
= FALSE
;
708 BOOL had_bash
= FALSE
;
710 f
= fopen("/etc/printcap","r");
714 while(fgets(buf
,sizeof(buf
),f
)) {
717 end
=strchr(buf
,'\n');
721 while(isspace(*start
)) start
++;
722 if(*start
== '#' || *start
== '\0')
725 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
726 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
727 HeapFree(GetProcessHeap(),0,pent
);
731 if (end
&& *--end
== '\\') {
738 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
741 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
747 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
748 HeapFree(GetProcessHeap(),0,pent
);
754 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
757 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
758 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
760 return ERROR_FILE_NOT_FOUND
;
763 /*****************************************************************************
764 * enumerate the local monitors (INTERNAL)
766 * returns the needed size (in bytes) for pMonitors
767 * and *lpreturned is set to number of entries returned in pMonitors
770 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
775 LPMONITOR_INFO_2W mi
;
776 WCHAR buffer
[MAX_PATH
];
777 WCHAR dllname
[MAX_PATH
];
785 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
787 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
788 len
= entrysize
* numentries
;
789 ptr
= (LPWSTR
) &pMonitors
[len
];
792 len
= sizeof(buffer
)/sizeof(buffer
[0]);
795 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
796 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
797 /* Scan all Monitor-Registry-Keys */
798 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
799 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
800 dllsize
= sizeof(dllname
);
803 /* The Monitor must have a Driver-DLL */
804 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
805 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
806 /* We found a valid DLL for this Monitor. */
807 TRACE("using Driver: %s\n", debugstr_w(dllname
));
812 /* Windows returns only Port-Monitors here, but to simplify our code,
813 we do no filtering for Language-Monitors */
817 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
819 /* we install and return only monitors for "Windows NT x86" */
820 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
824 /* required size is calculated. Now fill the user-buffer */
825 if (pMonitors
&& (cbBuf
>= needed
)){
826 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
827 pMonitors
+= entrysize
;
829 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
831 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
832 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
834 mi
->pEnvironment
= ptr
;
835 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
836 ptr
+= (lstrlenW(envname_x86W
)+1);
839 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
840 ptr
+= (dllsize
/ sizeof(WCHAR
));
845 len
= sizeof(buffer
)/sizeof(buffer
[0]);
850 *lpreturned
= numentries
;
851 TRACE("need %d byte for %d entries\n", needed
, numentries
);
855 /******************************************************************
856 * monitor_unload [internal]
858 * release a printmonitor and unload it from memory, when needed
861 static void monitor_unload(monitor_t
* pm
)
863 if (pm
== NULL
) return;
864 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
866 EnterCriticalSection(&monitor_handles_cs
);
868 if (pm
->refcount
) pm
->refcount
--;
870 if (pm
->refcount
== 0) {
871 list_remove(&pm
->entry
);
872 FreeLibrary(pm
->hdll
);
873 HeapFree(GetProcessHeap(), 0, pm
->name
);
874 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
875 HeapFree(GetProcessHeap(), 0, pm
);
877 LeaveCriticalSection(&monitor_handles_cs
);
880 /******************************************************************
881 * monitor_unloadall [internal]
883 * release all printmonitors and unload them from memory, when needed
886 static void monitor_unloadall(void)
891 EnterCriticalSection(&monitor_handles_cs
);
892 /* iterate through the list, with safety against removal */
893 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
897 LeaveCriticalSection(&monitor_handles_cs
);
900 /******************************************************************
901 * monitor_load [internal]
903 * load a printmonitor, get the dllname from the registry, when needed
904 * initialize the monitor and dump found function-pointers
906 * On failure, SetLastError() is called and NULL is returned
909 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
911 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
912 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
913 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
914 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
915 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
917 monitor_t
* pm
= NULL
;
919 LPWSTR regroot
= NULL
;
920 LPWSTR driver
= dllname
;
922 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
923 /* Is the Monitor already loaded? */
924 EnterCriticalSection(&monitor_handles_cs
);
927 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
929 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
937 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
938 if (pm
== NULL
) goto cleanup
;
939 list_add_tail(&monitor_handles
, &pm
->entry
);
943 if (pm
->name
== NULL
) {
944 /* Load the monitor */
945 LPMONITOREX pmonitorEx
;
949 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
950 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
954 lstrcpyW(regroot
, MonitorsW
);
955 lstrcatW(regroot
, name
);
956 /* Get the Driver from the Registry */
957 if (driver
== NULL
) {
960 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
961 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
962 &namesize
) == ERROR_SUCCESS
) {
963 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
964 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
971 pm
->name
= strdupW(name
);
972 pm
->dllname
= strdupW(driver
);
974 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
976 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
981 pm
->hdll
= LoadLibraryW(driver
);
982 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
984 if (pm
->hdll
== NULL
) {
986 SetLastError(ERROR_MOD_NOT_FOUND
);
991 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
992 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
993 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
994 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
995 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
998 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
999 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
1000 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
1001 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
1002 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
1004 if (pInitializePrintMonitorUI
!= NULL
) {
1005 pm
->monitorUI
= pInitializePrintMonitorUI();
1006 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
1007 if (pm
->monitorUI
) {
1008 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1009 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
1014 if (pInitializePrintMonitor
&& regroot
) {
1015 pmonitorEx
= pInitializePrintMonitor(regroot
);
1016 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1017 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
1020 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
1021 pm
->monitor
= &(pmonitorEx
->Monitor
);
1026 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
1030 if (!pm
->monitor
&& regroot
) {
1031 if (pInitializePrintMonitor2
!= NULL
) {
1032 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
1034 if (pInitializeMonitorEx
!= NULL
) {
1035 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
1037 if (pInitializeMonitor
!= NULL
) {
1038 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
1041 if (!pm
->monitor
&& !pm
->monitorUI
) {
1043 SetLastError(ERROR_PROC_NOT_FOUND
);
1048 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
1052 LeaveCriticalSection(&monitor_handles_cs
);
1053 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
1054 HeapFree(GetProcessHeap(), 0, regroot
);
1055 TRACE("=> %p\n", pm
);
1059 /******************************************************************
1060 * monitor_loadall [internal]
1062 * Load all registered monitors
1065 static DWORD
monitor_loadall(void)
1068 DWORD registered
= 0;
1071 WCHAR buffer
[MAX_PATH
];
1074 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1075 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1076 NULL
, NULL
, NULL
, NULL
, NULL
);
1078 TRACE("%d monitors registered\n", registered
);
1080 EnterCriticalSection(&monitor_handles_cs
);
1081 while (id
< registered
) {
1083 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1084 pm
= monitor_load(buffer
, NULL
);
1088 LeaveCriticalSection(&monitor_handles_cs
);
1089 RegCloseKey(hmonitors
);
1091 TRACE("%d monitors loaded\n", loaded
);
1095 /******************************************************************
1096 * monitor_loadui [internal]
1098 * load the userinterface-dll for a given portmonitor
1100 * On failure, NULL is returned
1103 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1105 monitor_t
* pui
= NULL
;
1106 LPWSTR buffer
[MAX_PATH
];
1111 if (pm
== NULL
) return NULL
;
1112 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1114 /* Try the Portmonitor first; works for many monitors */
1115 if (pm
->monitorUI
) {
1116 EnterCriticalSection(&monitor_handles_cs
);
1118 LeaveCriticalSection(&monitor_handles_cs
);
1122 /* query the userinterface-dllname from the Portmonitor */
1123 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1124 /* building (",XcvMonitor %s",pm->name) not needed yet */
1125 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1126 TRACE("got %u with %p\n", res
, hXcv
);
1128 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1129 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1130 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1131 pm
->monitor
->pfnXcvClosePort(hXcv
);
1138 /******************************************************************
1139 * monitor_load_by_port [internal]
1141 * load a printmonitor for a given port
1143 * On failure, NULL is returned
1146 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1151 monitor_t
* pm
= NULL
;
1152 DWORD registered
= 0;
1156 TRACE("(%s)\n", debugstr_w(portname
));
1158 /* Try the Local Monitor first */
1159 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1160 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1161 /* found the portname */
1163 return monitor_load(LocalPortW
, NULL
);
1168 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1169 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1170 if (buffer
== NULL
) return NULL
;
1172 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1173 EnterCriticalSection(&monitor_handles_cs
);
1174 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1176 while ((pm
== NULL
) && (id
< registered
)) {
1178 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1179 TRACE("testing %s\n", debugstr_w(buffer
));
1180 len
= lstrlenW(buffer
);
1181 lstrcatW(buffer
, bs_Ports_bsW
);
1182 lstrcatW(buffer
, portname
);
1183 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1185 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1186 pm
= monitor_load(buffer
, NULL
);
1190 LeaveCriticalSection(&monitor_handles_cs
);
1193 HeapFree(GetProcessHeap(), 0, buffer
);
1197 /******************************************************************
1198 * enumerate the local Ports from all loaded monitors (internal)
1200 * returns the needed size (in bytes) for pPorts
1201 * and *lpreturned is set to number of entries returned in pPorts
1204 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1208 LPPORT_INFO_2W cache
;
1210 LPBYTE pi_buffer
= NULL
;
1211 DWORD pi_allocated
= 0;
1222 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1223 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1225 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1226 needed
= entrysize
* numentries
;
1227 ptr
= (LPWSTR
) &pPorts
[needed
];
1232 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1234 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1237 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1238 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1239 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1240 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1241 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1242 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1243 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1245 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1246 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1248 numentries
+= pi_returned
;
1249 needed
+= pi_needed
;
1251 /* fill the output-buffer (pPorts), if we have one */
1252 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1254 while (pi_returned
> pi_index
) {
1255 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1256 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1257 out
->pPortName
= ptr
;
1258 lstrcpyW(ptr
, cache
->pPortName
);
1259 ptr
+= (lstrlenW(ptr
)+1);
1261 out
->pMonitorName
= ptr
;
1262 lstrcpyW(ptr
, cache
->pMonitorName
);
1263 ptr
+= (lstrlenW(ptr
)+1);
1265 out
->pDescription
= ptr
;
1266 lstrcpyW(ptr
, cache
->pDescription
);
1267 ptr
+= (lstrlenW(ptr
)+1);
1268 out
->fPortType
= cache
->fPortType
;
1269 out
->Reserved
= cache
->Reserved
;
1277 /* the temporary portinfo-buffer is no longer needed */
1278 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1280 *lpreturned
= numentries
;
1281 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1285 /******************************************************************
1286 * get_servername_from_name (internal)
1288 * for an external server, a copy of the serverpart from the full name is returned
1291 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1295 WCHAR buffer
[MAX_PATH
];
1298 if (name
== NULL
) return NULL
;
1299 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1301 server
= strdupW(&name
[2]); /* skip over both backslash */
1302 if (server
== NULL
) return NULL
;
1304 /* strip '\' and the printername */
1305 ptr
= strchrW(server
, '\\');
1306 if (ptr
) ptr
[0] = '\0';
1308 TRACE("found %s\n", debugstr_w(server
));
1310 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1311 if (GetComputerNameW(buffer
, &len
)) {
1312 if (lstrcmpW(buffer
, server
) == 0) {
1313 /* The requested Servername is our computername */
1314 HeapFree(GetProcessHeap(), 0, server
);
1321 /******************************************************************
1322 * get_basename_from_name (internal)
1324 * skip over the serverpart from the full name
1327 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1329 if (name
== NULL
) return NULL
;
1330 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1331 /* skip over the servername and search for the following '\' */
1332 name
= strchrW(&name
[2], '\\');
1333 if ((name
) && (name
[1])) {
1334 /* found a separator ('\') followed by a name:
1335 skip over the separator and return the rest */
1340 /* no basename present (we found only a servername) */
1347 /******************************************************************
1348 * get_opened_printer_entry
1349 * Get the first place empty in the opened printer table
1352 * - pDefault is ignored
1354 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1356 UINT_PTR handle
= nb_printer_handles
, i
;
1357 jobqueue_t
*queue
= NULL
;
1358 opened_printer_t
*printer
= NULL
;
1360 LPCWSTR printername
;
1365 servername
= get_servername_from_name(name
);
1367 FIXME("server %s not supported\n", debugstr_w(servername
));
1368 HeapFree(GetProcessHeap(), 0, servername
);
1369 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1373 printername
= get_basename_from_name(name
);
1374 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1376 /* an empty printername is invalid */
1377 if (printername
&& (!printername
[0])) {
1378 SetLastError(ERROR_INVALID_PARAMETER
);
1382 EnterCriticalSection(&printer_handles_cs
);
1384 for (i
= 0; i
< nb_printer_handles
; i
++)
1386 if (!printer_handles
[i
])
1388 if(handle
== nb_printer_handles
)
1393 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1394 queue
= printer_handles
[i
]->queue
;
1398 if (handle
>= nb_printer_handles
)
1400 opened_printer_t
**new_array
;
1401 if (printer_handles
)
1402 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1403 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1405 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1406 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1413 printer_handles
= new_array
;
1414 nb_printer_handles
+= 16;
1417 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1424 /* clone the base name. This is NULL for the printserver */
1425 printer
->printername
= strdupW(printername
);
1427 /* clone the full name */
1428 printer
->name
= strdupW(name
);
1429 if (name
&& (!printer
->name
)) {
1435 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1436 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1437 /* OpenPrinter(",XcvMonitor " detected */
1438 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1439 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1440 if (printer
->pm
== NULL
) {
1441 SetLastError(ERROR_UNKNOWN_PORT
);
1448 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1449 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1450 /* OpenPrinter(",XcvPort " detected */
1451 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1452 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1453 if (printer
->pm
== NULL
) {
1454 SetLastError(ERROR_UNKNOWN_PORT
);
1462 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1463 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1464 pDefault
? pDefault
->DesiredAccess
: 0,
1467 if (printer
->hXcv
== NULL
) {
1468 SetLastError(ERROR_INVALID_PARAMETER
);
1475 /* Does the Printer exist? */
1476 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1477 ERR("Can't create Printers key\n");
1481 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1482 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1483 RegCloseKey(hkeyPrinters
);
1484 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1488 RegCloseKey(hkeyPrinter
);
1489 RegCloseKey(hkeyPrinters
);
1494 TRACE("using the local printserver\n");
1498 printer
->queue
= queue
;
1501 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1502 if (!printer
->queue
) {
1506 list_init(&printer
->queue
->jobs
);
1507 printer
->queue
->ref
= 0;
1509 InterlockedIncrement(&printer
->queue
->ref
);
1511 printer_handles
[handle
] = printer
;
1514 LeaveCriticalSection(&printer_handles_cs
);
1515 if (!handle
&& printer
) {
1516 /* Something failed: Free all resources */
1517 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1518 monitor_unload(printer
->pm
);
1519 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1520 HeapFree(GetProcessHeap(), 0, printer
->name
);
1521 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1522 HeapFree(GetProcessHeap(), 0, printer
);
1525 return (HANDLE
)handle
;
1528 /******************************************************************
1529 * get_opened_printer
1530 * Get the pointer to the opened printer referred by the handle
1532 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1534 UINT_PTR idx
= (UINT_PTR
)hprn
;
1535 opened_printer_t
*ret
= NULL
;
1537 EnterCriticalSection(&printer_handles_cs
);
1539 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
1540 ret
= printer_handles
[idx
- 1];
1542 LeaveCriticalSection(&printer_handles_cs
);
1546 /******************************************************************
1547 * get_opened_printer_name
1548 * Get the pointer to the opened printer name referred by the handle
1550 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1552 opened_printer_t
*printer
= get_opened_printer(hprn
);
1553 if(!printer
) return NULL
;
1554 return printer
->name
;
1557 /******************************************************************
1558 * WINSPOOL_GetOpenedPrinterRegKey
1561 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1563 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1567 if(!name
) return ERROR_INVALID_HANDLE
;
1569 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1573 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1575 ERR("Can't find opened printer %s in registry\n",
1577 RegCloseKey(hkeyPrinters
);
1578 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1580 RegCloseKey(hkeyPrinters
);
1581 return ERROR_SUCCESS
;
1584 void WINSPOOL_LoadSystemPrinters(void)
1586 HKEY hkey
, hkeyPrinters
;
1588 DWORD needed
, num
, i
;
1589 WCHAR PrinterName
[256];
1592 /* This ensures that all printer entries have a valid Name value. If causes
1593 problems later if they don't. If one is found to be missed we create one
1594 and set it equal to the name of the key */
1595 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1596 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1597 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1598 for(i
= 0; i
< num
; i
++) {
1599 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1600 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1601 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1602 set_reg_szW(hkey
, NameW
, PrinterName
);
1609 RegCloseKey(hkeyPrinters
);
1612 /* We want to avoid calling AddPrinter on printers as much as
1613 possible, because on cups printers this will (eventually) lead
1614 to a call to cupsGetPPD which takes forever, even with non-cups
1615 printers AddPrinter takes a while. So we'll tag all printers that
1616 were automatically added last time around, if they still exist
1617 we'll leave them be otherwise we'll delete them. */
1618 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1620 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1621 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1622 for(i
= 0; i
< num
; i
++) {
1623 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1624 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1625 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1627 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1635 HeapFree(GetProcessHeap(), 0, pi
);
1639 #ifdef SONAME_LIBCUPS
1640 done
= CUPS_LoadPrinters();
1643 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1644 PRINTCAP_LoadPrinters();
1646 /* Now enumerate the list again and delete any printers that are still tagged */
1647 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1649 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1650 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1651 for(i
= 0; i
< num
; i
++) {
1652 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1653 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1654 BOOL delete_driver
= FALSE
;
1655 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1656 DWORD dw
, type
, size
= sizeof(dw
);
1657 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1658 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1659 DeletePrinter(hprn
);
1660 delete_driver
= TRUE
;
1666 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1671 HeapFree(GetProcessHeap(), 0, pi
);
1678 /******************************************************************
1681 * Get the pointer to the specified job.
1682 * Should hold the printer_handles_cs before calling.
1684 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1686 opened_printer_t
*printer
= get_opened_printer(hprn
);
1689 if(!printer
) return NULL
;
1690 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1692 if(job
->job_id
== JobId
)
1698 /***********************************************************
1701 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1704 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1707 Formname
= (dmA
->dmSize
> off_formname
);
1708 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1709 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1710 dmW
->dmDeviceName
, CCHDEVICENAME
);
1712 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1713 dmA
->dmSize
- CCHDEVICENAME
);
1715 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1716 off_formname
- CCHDEVICENAME
);
1717 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1718 dmW
->dmFormName
, CCHFORMNAME
);
1719 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1720 (off_formname
+ CCHFORMNAME
));
1723 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1724 dmA
->dmDriverExtra
);
1728 /***********************************************************
1730 * Creates an ansi copy of supplied devmode
1732 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1737 if (!dmW
) return NULL
;
1738 size
= dmW
->dmSize
- CCHDEVICENAME
-
1739 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1741 dmA
= HeapAlloc(GetProcessHeap(), 0, size
+ dmW
->dmDriverExtra
);
1742 if (!dmA
) return NULL
;
1744 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1745 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1747 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1748 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1749 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1753 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1754 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1755 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1756 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1758 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1762 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1766 /******************************************************************
1767 * convert_printerinfo_W_to_A [internal]
1770 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1771 DWORD level
, DWORD outlen
, DWORD numentries
)
1777 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1779 len
= pi_sizeof
[level
] * numentries
;
1780 ptr
= (LPSTR
) out
+ len
;
1783 /* copy the numbers of all PRINTER_INFO_* first */
1784 memcpy(out
, pPrintersW
, len
);
1786 while (id
< numentries
) {
1790 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1791 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1793 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1794 if (piW
->pDescription
) {
1795 piA
->pDescription
= ptr
;
1796 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1797 ptr
, outlen
, NULL
, NULL
);
1803 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1804 ptr
, outlen
, NULL
, NULL
);
1808 if (piW
->pComment
) {
1809 piA
->pComment
= ptr
;
1810 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1811 ptr
, outlen
, NULL
, NULL
);
1820 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1821 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1824 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1825 if (piW
->pServerName
) {
1826 piA
->pServerName
= ptr
;
1827 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1828 ptr
, outlen
, NULL
, NULL
);
1832 if (piW
->pPrinterName
) {
1833 piA
->pPrinterName
= ptr
;
1834 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1835 ptr
, outlen
, NULL
, NULL
);
1839 if (piW
->pShareName
) {
1840 piA
->pShareName
= ptr
;
1841 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1842 ptr
, outlen
, NULL
, NULL
);
1846 if (piW
->pPortName
) {
1847 piA
->pPortName
= ptr
;
1848 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1849 ptr
, outlen
, NULL
, NULL
);
1853 if (piW
->pDriverName
) {
1854 piA
->pDriverName
= ptr
;
1855 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1856 ptr
, outlen
, NULL
, NULL
);
1860 if (piW
->pComment
) {
1861 piA
->pComment
= ptr
;
1862 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1863 ptr
, outlen
, NULL
, NULL
);
1867 if (piW
->pLocation
) {
1868 piA
->pLocation
= ptr
;
1869 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1870 ptr
, outlen
, NULL
, NULL
);
1875 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1877 /* align DEVMODEA to a DWORD boundary */
1878 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1882 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1883 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1884 memcpy(ptr
, dmA
, len
);
1885 HeapFree(GetProcessHeap(), 0, dmA
);
1891 if (piW
->pSepFile
) {
1892 piA
->pSepFile
= ptr
;
1893 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1894 ptr
, outlen
, NULL
, NULL
);
1898 if (piW
->pPrintProcessor
) {
1899 piA
->pPrintProcessor
= ptr
;
1900 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1901 ptr
, outlen
, NULL
, NULL
);
1905 if (piW
->pDatatype
) {
1906 piA
->pDatatype
= ptr
;
1907 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1908 ptr
, outlen
, NULL
, NULL
);
1912 if (piW
->pParameters
) {
1913 piA
->pParameters
= ptr
;
1914 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1915 ptr
, outlen
, NULL
, NULL
);
1919 if (piW
->pSecurityDescriptor
) {
1920 piA
->pSecurityDescriptor
= NULL
;
1921 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1928 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1929 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1931 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1933 if (piW
->pPrinterName
) {
1934 piA
->pPrinterName
= ptr
;
1935 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1936 ptr
, outlen
, NULL
, NULL
);
1940 if (piW
->pServerName
) {
1941 piA
->pServerName
= ptr
;
1942 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1943 ptr
, outlen
, NULL
, NULL
);
1952 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1953 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1955 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1957 if (piW
->pPrinterName
) {
1958 piA
->pPrinterName
= ptr
;
1959 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1960 ptr
, outlen
, NULL
, NULL
);
1964 if (piW
->pPortName
) {
1965 piA
->pPortName
= ptr
;
1966 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1967 ptr
, outlen
, NULL
, NULL
);
1975 FIXME("for level %u\n", level
);
1977 pPrintersW
+= pi_sizeof
[level
];
1978 out
+= pi_sizeof
[level
];
1983 /***********************************************************
1984 * PRINTER_INFO_2AtoW
1985 * Creates a unicode copy of PRINTER_INFO_2A on heap
1987 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1989 LPPRINTER_INFO_2W piW
;
1990 UNICODE_STRING usBuffer
;
1992 if(!piA
) return NULL
;
1993 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1994 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1996 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1997 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1998 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1999 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
2000 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
2001 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
2002 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
2003 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
2004 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
2005 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
2006 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
2007 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
2011 /***********************************************************
2012 * FREE_PRINTER_INFO_2W
2013 * Free PRINTER_INFO_2W and all strings
2015 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
2019 HeapFree(heap
,0,piW
->pServerName
);
2020 HeapFree(heap
,0,piW
->pPrinterName
);
2021 HeapFree(heap
,0,piW
->pShareName
);
2022 HeapFree(heap
,0,piW
->pPortName
);
2023 HeapFree(heap
,0,piW
->pDriverName
);
2024 HeapFree(heap
,0,piW
->pComment
);
2025 HeapFree(heap
,0,piW
->pLocation
);
2026 HeapFree(heap
,0,piW
->pDevMode
);
2027 HeapFree(heap
,0,piW
->pSepFile
);
2028 HeapFree(heap
,0,piW
->pPrintProcessor
);
2029 HeapFree(heap
,0,piW
->pDatatype
);
2030 HeapFree(heap
,0,piW
->pParameters
);
2031 HeapFree(heap
,0,piW
);
2035 /******************************************************************
2036 * DeviceCapabilities [WINSPOOL.@]
2037 * DeviceCapabilitiesA [WINSPOOL.@]
2040 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2041 LPSTR pOutput
, LPDEVMODEA lpdm
)
2045 if (!GDI_CallDeviceCapabilities16
)
2047 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2049 if (!GDI_CallDeviceCapabilities16
) return -1;
2051 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2053 /* If DC_PAPERSIZE map POINT16s to POINTs */
2054 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2055 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2056 POINT
*pt
= (POINT
*)pOutput
;
2058 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2059 for(i
= 0; i
< ret
; i
++, pt
++)
2064 HeapFree( GetProcessHeap(), 0, tmp
);
2070 /*****************************************************************************
2071 * DeviceCapabilitiesW [WINSPOOL.@]
2073 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2076 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2077 WORD fwCapability
, LPWSTR pOutput
,
2078 const DEVMODEW
*pDevMode
)
2080 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2081 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2082 LPSTR pPortA
= strdupWtoA(pPort
);
2085 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2086 fwCapability
== DC_FILEDEPENDENCIES
||
2087 fwCapability
== DC_PAPERNAMES
)) {
2088 /* These need A -> W translation */
2091 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2095 switch(fwCapability
) {
2100 case DC_FILEDEPENDENCIES
:
2104 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2105 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2107 for(i
= 0; i
< ret
; i
++)
2108 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2109 pOutput
+ (i
* size
), size
);
2110 HeapFree(GetProcessHeap(), 0, pOutputA
);
2112 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2113 (LPSTR
)pOutput
, dmA
);
2115 HeapFree(GetProcessHeap(),0,pPortA
);
2116 HeapFree(GetProcessHeap(),0,pDeviceA
);
2117 HeapFree(GetProcessHeap(),0,dmA
);
2121 /******************************************************************
2122 * DocumentPropertiesA [WINSPOOL.@]
2124 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2126 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2127 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2128 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2130 LPSTR lpName
= pDeviceName
;
2131 static CHAR port
[] = "LPT1:";
2134 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2135 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2139 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2141 ERR("no name from hPrinter?\n");
2142 SetLastError(ERROR_INVALID_HANDLE
);
2145 lpName
= strdupWtoA(lpNameW
);
2148 if (!GDI_CallExtDeviceMode16
)
2150 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2152 if (!GDI_CallExtDeviceMode16
) {
2153 ERR("No CallExtDeviceMode16?\n");
2157 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2158 pDevModeInput
, NULL
, fMode
);
2161 HeapFree(GetProcessHeap(),0,lpName
);
2166 /*****************************************************************************
2167 * DocumentPropertiesW (WINSPOOL.@)
2169 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2171 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2173 LPDEVMODEW pDevModeOutput
,
2174 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2177 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2178 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
2179 LPDEVMODEA pDevModeOutputA
= NULL
;
2182 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2183 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2185 if(pDevModeOutput
) {
2186 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2187 if(ret
< 0) return ret
;
2188 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2190 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2191 pDevModeInputA
, fMode
);
2192 if(pDevModeOutput
) {
2193 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2194 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2196 if(fMode
== 0 && ret
> 0)
2197 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2198 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2199 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2203 /******************************************************************
2204 * OpenPrinterA [WINSPOOL.@]
2209 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2210 LPPRINTER_DEFAULTSA pDefault
)
2212 UNICODE_STRING lpPrinterNameW
;
2213 UNICODE_STRING usBuffer
;
2214 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2215 PWSTR pwstrPrinterNameW
;
2218 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2221 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2222 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2223 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2224 pDefaultW
= &DefaultW
;
2226 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2228 RtlFreeUnicodeString(&usBuffer
);
2229 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2231 RtlFreeUnicodeString(&lpPrinterNameW
);
2235 /******************************************************************
2236 * OpenPrinterW [WINSPOOL.@]
2238 * Open a Printer / Printserver or a Printer-Object
2241 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2242 * phPrinter [O] The resulting Handle is stored here
2243 * pDefault [I] PTR to Default Printer Settings or NULL
2250 * lpPrinterName is one of:
2251 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2252 *| Printer: "PrinterName"
2253 *| Printer-Object: "PrinterName,Job xxx"
2254 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2255 *| XcvPort: "Servername,XcvPort PortName"
2258 *| Printer-Object not supported
2259 *| pDefaults is ignored
2262 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2265 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2267 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2268 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2272 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2273 SetLastError(ERROR_INVALID_PARAMETER
);
2277 /* Get the unique handle of the printer or Printserver */
2278 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2279 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2280 return (*phPrinter
!= 0);
2283 /******************************************************************
2284 * AddMonitorA [WINSPOOL.@]
2289 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2291 LPWSTR nameW
= NULL
;
2294 LPMONITOR_INFO_2A mi2a
;
2295 MONITOR_INFO_2W mi2w
;
2297 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2298 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2299 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2300 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2301 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2304 SetLastError(ERROR_INVALID_LEVEL
);
2308 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2314 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2315 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2316 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2319 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2321 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2322 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2323 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2325 if (mi2a
->pEnvironment
) {
2326 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2327 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2328 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2330 if (mi2a
->pDLLName
) {
2331 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2332 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2333 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2336 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2338 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2339 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2340 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2342 HeapFree(GetProcessHeap(), 0, nameW
);
2346 /******************************************************************************
2347 * AddMonitorW [WINSPOOL.@]
2349 * Install a Printmonitor
2352 * pName [I] Servername or NULL (local Computer)
2353 * Level [I] Structure-Level (Must be 2)
2354 * pMonitors [I] PTR to MONITOR_INFO_2
2361 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2364 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2366 monitor_t
* pm
= NULL
;
2367 LPMONITOR_INFO_2W mi2w
;
2373 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2374 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2375 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2376 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2377 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2380 SetLastError(ERROR_INVALID_LEVEL
);
2384 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2389 if (pName
&& (pName
[0])) {
2390 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2391 SetLastError(ERROR_ACCESS_DENIED
);
2396 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2397 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2398 SetLastError(ERROR_INVALID_PARAMETER
);
2401 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2402 WARN("Environment %s requested (we support only %s)\n",
2403 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2404 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2408 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2409 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2410 SetLastError(ERROR_INVALID_PARAMETER
);
2414 /* Load and initialize the monitor. SetLastError() is called on failure */
2415 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2420 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2421 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2425 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2426 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2427 &disposition
) == ERROR_SUCCESS
) {
2429 /* Some installers set options for the port before calling AddMonitor.
2430 We query the "Driver" entry to verify that the monitor is installed,
2431 before we return an error.
2432 When a user installs two print monitors at the same time with the
2433 same name but with a different driver DLL and a task switch comes
2434 between RegQueryValueExW and RegSetValueExW, a race condition
2435 is possible but silently ignored. */
2439 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2440 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2441 &namesize
) == ERROR_SUCCESS
)) {
2442 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2443 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2444 9x: ERROR_ALREADY_EXISTS (183) */
2445 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2450 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2451 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2452 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2454 RegCloseKey(hentry
);
2461 /******************************************************************
2462 * DeletePrinterDriverA [WINSPOOL.@]
2465 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2467 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2470 /******************************************************************
2471 * DeletePrinterDriverW [WINSPOOL.@]
2474 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2476 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2479 /******************************************************************
2480 * DeleteMonitorA [WINSPOOL.@]
2482 * See DeleteMonitorW.
2485 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2487 LPWSTR nameW
= NULL
;
2488 LPWSTR EnvironmentW
= NULL
;
2489 LPWSTR MonitorNameW
= NULL
;
2494 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2495 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2496 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2500 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2501 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2502 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2505 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2506 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2507 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2510 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2512 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2513 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2514 HeapFree(GetProcessHeap(), 0, nameW
);
2518 /******************************************************************
2519 * DeleteMonitorW [WINSPOOL.@]
2521 * Delete a specific Printmonitor from a Printing-Environment
2524 * pName [I] Servername or NULL (local Computer)
2525 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2526 * pMonitorName [I] Name of the Monitor, that should be deleted
2533 * pEnvironment is ignored in Windows for the local Computer.
2537 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2541 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2542 debugstr_w(pMonitorName
));
2544 if (pName
&& (pName
[0])) {
2545 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2546 SetLastError(ERROR_ACCESS_DENIED
);
2550 /* pEnvironment is ignored in Windows for the local Computer */
2552 if (!pMonitorName
|| !pMonitorName
[0]) {
2553 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2554 SetLastError(ERROR_INVALID_PARAMETER
);
2558 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2559 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2563 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2564 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2569 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2572 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2573 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2577 /******************************************************************
2578 * DeletePortA [WINSPOOL.@]
2583 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2585 LPWSTR nameW
= NULL
;
2586 LPWSTR portW
= NULL
;
2590 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2592 /* convert servername to unicode */
2594 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2595 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2596 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2599 /* convert portname to unicode */
2601 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2602 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2603 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2606 res
= DeletePortW(nameW
, hWnd
, portW
);
2607 HeapFree(GetProcessHeap(), 0, nameW
);
2608 HeapFree(GetProcessHeap(), 0, portW
);
2612 /******************************************************************
2613 * DeletePortW [WINSPOOL.@]
2615 * Delete a specific Port
2618 * pName [I] Servername or NULL (local Computer)
2619 * hWnd [I] Handle to parent Window for the Dialog-Box
2620 * pPortName [I] Name of the Port, that should be deleted
2627 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2633 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2635 if (pName
&& pName
[0]) {
2636 SetLastError(ERROR_INVALID_PARAMETER
);
2641 SetLastError(RPC_X_NULL_REF_POINTER
);
2645 /* an empty Portname is Invalid */
2646 if (!pPortName
[0]) {
2647 SetLastError(ERROR_NOT_SUPPORTED
);
2651 pm
= monitor_load_by_port(pPortName
);
2652 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2653 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2654 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2655 TRACE("got %d with %u\n", res
, GetLastError());
2659 pui
= monitor_loadui(pm
);
2660 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2661 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2662 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2663 TRACE("got %d with %u\n", res
, GetLastError());
2667 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2668 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2670 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2671 SetLastError(ERROR_NOT_SUPPORTED
);
2674 monitor_unload(pui
);
2678 TRACE("returning %d with %u\n", res
, GetLastError());
2682 /******************************************************************************
2683 * SetPrinterW [WINSPOOL.@]
2685 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2687 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2688 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2692 /******************************************************************************
2693 * WritePrinter [WINSPOOL.@]
2695 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2697 opened_printer_t
*printer
;
2700 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2702 EnterCriticalSection(&printer_handles_cs
);
2703 printer
= get_opened_printer(hPrinter
);
2706 SetLastError(ERROR_INVALID_HANDLE
);
2712 SetLastError(ERROR_SPL_NO_STARTDOC
);
2716 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2718 LeaveCriticalSection(&printer_handles_cs
);
2722 /*****************************************************************************
2723 * AddFormA [WINSPOOL.@]
2725 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2727 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2731 /*****************************************************************************
2732 * AddFormW [WINSPOOL.@]
2734 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2736 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2740 /*****************************************************************************
2741 * AddJobA [WINSPOOL.@]
2743 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2746 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2750 SetLastError(ERROR_INVALID_LEVEL
);
2754 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2757 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2758 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2759 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2760 if(*pcbNeeded
> cbBuf
) {
2761 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2764 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2765 addjobA
->JobId
= addjobW
->JobId
;
2766 addjobA
->Path
= (char *)(addjobA
+ 1);
2767 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2773 /*****************************************************************************
2774 * AddJobW [WINSPOOL.@]
2776 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2778 opened_printer_t
*printer
;
2781 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2782 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2783 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2785 ADDJOB_INFO_1W
*addjob
;
2787 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2789 EnterCriticalSection(&printer_handles_cs
);
2791 printer
= get_opened_printer(hPrinter
);
2794 SetLastError(ERROR_INVALID_HANDLE
);
2799 SetLastError(ERROR_INVALID_LEVEL
);
2803 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2807 job
->job_id
= InterlockedIncrement(&next_job_id
);
2809 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2810 if(path
[len
- 1] != '\\')
2812 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2813 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2815 len
= strlenW(filename
);
2816 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2817 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2818 job
->document_title
= strdupW(default_doc_title
);
2819 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2821 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2822 if(*pcbNeeded
<= cbBuf
) {
2823 addjob
= (ADDJOB_INFO_1W
*)pData
;
2824 addjob
->JobId
= job
->job_id
;
2825 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2826 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2829 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2832 LeaveCriticalSection(&printer_handles_cs
);
2836 /*****************************************************************************
2837 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2839 * Return the PATH for the Print-Processors
2841 * See GetPrintProcessorDirectoryW.
2845 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2846 DWORD level
, LPBYTE Info
,
2847 DWORD cbBuf
, LPDWORD pcbNeeded
)
2849 LPWSTR serverW
= NULL
;
2854 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2855 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2859 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2860 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2861 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2865 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2866 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2867 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2870 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2871 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2873 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2876 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2877 cbBuf
, NULL
, NULL
) > 0;
2880 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2881 HeapFree(GetProcessHeap(), 0, envW
);
2882 HeapFree(GetProcessHeap(), 0, serverW
);
2886 /*****************************************************************************
2887 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2889 * Return the PATH for the Print-Processors
2892 * server [I] Servername (NT only) or NULL (local Computer)
2893 * env [I] Printing-Environment (see below) or NULL (Default)
2894 * level [I] Structure-Level (must be 1)
2895 * Info [O] PTR to Buffer that receives the Result
2896 * cbBuf [I] Size of Buffer at "Info"
2897 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2898 * required for the Buffer at "Info"
2901 * Success: TRUE and in pcbNeeded the Bytes used in Info
2902 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2903 * if cbBuf is too small
2905 * Native Values returned in Info on Success:
2906 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2907 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2908 *| win9x(Windows 4.0): "%winsysdir%"
2910 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2913 * Only NULL or "" is supported for server
2916 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2917 DWORD level
, LPBYTE Info
,
2918 DWORD cbBuf
, LPDWORD pcbNeeded
)
2921 const printenv_t
* env_t
;
2923 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2924 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2926 if(server
!= NULL
&& server
[0]) {
2927 FIXME("server not supported: %s\n", debugstr_w(server
));
2928 SetLastError(ERROR_INVALID_PARAMETER
);
2932 env_t
= validate_envW(env
);
2933 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2936 WARN("(Level: %d) is ignored in win9x\n", level
);
2937 SetLastError(ERROR_INVALID_LEVEL
);
2941 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2942 needed
= GetSystemDirectoryW(NULL
, 0);
2943 /* add the Size for the Subdirectories */
2944 needed
+= lstrlenW(spoolprtprocsW
);
2945 needed
+= lstrlenW(env_t
->subdir
);
2946 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2948 if(pcbNeeded
) *pcbNeeded
= needed
;
2949 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2950 if (needed
> cbBuf
) {
2951 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2954 if(pcbNeeded
== NULL
) {
2955 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2956 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2957 SetLastError(RPC_X_NULL_REF_POINTER
);
2961 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2962 SetLastError(RPC_X_NULL_REF_POINTER
);
2966 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2967 /* add the Subdirectories */
2968 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2969 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2970 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2974 /*****************************************************************************
2975 * WINSPOOL_OpenDriverReg [internal]
2977 * opens the registry for the printer drivers depending on the given input
2978 * variable pEnvironment
2981 * the opened hkey on success
2984 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2988 const printenv_t
* env
;
2991 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2993 if (!pEnvironment
|| unicode
) {
2994 /* pEnvironment was NULL or an Unicode-String: use it direct */
2995 env
= validate_envW(pEnvironment
);
2999 /* pEnvironment was an ANSI-String: convert to unicode first */
3001 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
3002 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3003 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
3004 env
= validate_envW(buffer
);
3005 HeapFree(GetProcessHeap(), 0, buffer
);
3007 if (!env
) return NULL
;
3009 buffer
= HeapAlloc( GetProcessHeap(), 0,
3010 (strlenW(DriversW
) + strlenW(env
->envname
) +
3011 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3013 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3014 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3015 HeapFree(GetProcessHeap(), 0, buffer
);
3020 /*****************************************************************************
3021 * AddPrinterW [WINSPOOL.@]
3023 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3025 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3029 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3031 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
3032 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
3033 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
3034 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
3035 statusW
[] = {'S','t','a','t','u','s',0},
3036 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
3038 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3041 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3042 SetLastError(ERROR_INVALID_PARAMETER
);
3046 ERR("Level = %d, unsupported!\n", Level
);
3047 SetLastError(ERROR_INVALID_LEVEL
);
3051 SetLastError(ERROR_INVALID_PARAMETER
);
3054 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3056 ERR("Can't create Printers key\n");
3059 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3060 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
3061 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3062 RegCloseKey(hkeyPrinter
);
3063 RegCloseKey(hkeyPrinters
);
3066 RegCloseKey(hkeyPrinter
);
3068 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
3070 ERR("Can't create Drivers key\n");
3071 RegCloseKey(hkeyPrinters
);
3074 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3076 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3077 RegCloseKey(hkeyPrinters
);
3078 RegCloseKey(hkeyDrivers
);
3079 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3082 RegCloseKey(hkeyDriver
);
3083 RegCloseKey(hkeyDrivers
);
3085 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3086 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3087 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3088 RegCloseKey(hkeyPrinters
);
3092 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3094 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3095 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3096 RegCloseKey(hkeyPrinters
);
3099 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
3100 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
3101 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3103 /* See if we can load the driver. We may need the devmode structure anyway
3106 * Note that DocumentPropertiesW will briefly try to open the printer we
3107 * just create to find a DEVMODEA struct (it will use the WINEPS default
3108 * one in case it is not there, so we are ok).
3110 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3113 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3114 size
= sizeof(DEVMODEW
);
3120 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3122 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
3124 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3125 HeapFree(GetProcessHeap(),0,dmW
);
3130 /* set devmode to printer name */
3131 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3135 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3136 and we support these drivers. NT writes DEVMODEW so somehow
3137 we'll need to distinguish between these when we support NT
3141 dmA
= DEVMODEdupWtoA(dmW
);
3142 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
3143 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
3144 HeapFree(GetProcessHeap(), 0, dmA
);
3146 HeapFree(GetProcessHeap(), 0, dmW
);
3148 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3149 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3150 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3151 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3153 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3154 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3155 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3156 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
3157 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
3158 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3159 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3160 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
3161 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
3162 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
3163 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
3164 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
3165 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
3167 RegCloseKey(hkeyPrinter
);
3168 RegCloseKey(hkeyPrinters
);
3169 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3170 ERR("OpenPrinter failing\n");
3176 /*****************************************************************************
3177 * AddPrinterA [WINSPOOL.@]
3179 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3181 UNICODE_STRING pNameW
;
3183 PRINTER_INFO_2W
*piW
;
3184 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3187 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
3189 ERR("Level = %d, unsupported!\n", Level
);
3190 SetLastError(ERROR_INVALID_LEVEL
);
3193 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3194 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
3196 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3198 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
3199 RtlFreeUnicodeString(&pNameW
);
3204 /*****************************************************************************
3205 * ClosePrinter [WINSPOOL.@]
3207 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3209 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3210 opened_printer_t
*printer
= NULL
;
3213 TRACE("(%p)\n", hPrinter
);
3215 EnterCriticalSection(&printer_handles_cs
);
3217 if ((i
> 0) && (i
<= nb_printer_handles
))
3218 printer
= printer_handles
[i
- 1];
3223 struct list
*cursor
, *cursor2
;
3225 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
3226 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
3227 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
3230 EndDocPrinter(hPrinter
);
3232 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3234 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3236 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3237 ScheduleJob(hPrinter
, job
->job_id
);
3239 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3241 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
3242 monitor_unload(printer
->pm
);
3243 HeapFree(GetProcessHeap(), 0, printer
->printername
);
3244 HeapFree(GetProcessHeap(), 0, printer
->name
);
3245 HeapFree(GetProcessHeap(), 0, printer
);
3246 printer_handles
[i
- 1] = NULL
;
3249 LeaveCriticalSection(&printer_handles_cs
);
3253 /*****************************************************************************
3254 * DeleteFormA [WINSPOOL.@]
3256 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3258 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3262 /*****************************************************************************
3263 * DeleteFormW [WINSPOOL.@]
3265 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3267 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3271 /*****************************************************************************
3272 * DeletePrinter [WINSPOOL.@]
3274 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3276 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3277 HKEY hkeyPrinters
, hkey
;
3280 SetLastError(ERROR_INVALID_HANDLE
);
3283 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3284 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3285 RegCloseKey(hkeyPrinters
);
3287 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3288 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3290 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3291 RegDeleteValueW(hkey
, lpNameW
);
3295 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3296 RegDeleteValueW(hkey
, lpNameW
);
3302 /*****************************************************************************
3303 * SetPrinterA [WINSPOOL.@]
3305 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3308 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3312 /*****************************************************************************
3313 * SetJobA [WINSPOOL.@]
3315 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3316 LPBYTE pJob
, DWORD Command
)
3320 UNICODE_STRING usBuffer
;
3322 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3324 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3325 are all ignored by SetJob, so we don't bother copying them */
3333 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3334 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3336 JobW
= (LPBYTE
)info1W
;
3337 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3338 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3339 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3340 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3341 info1W
->Status
= info1A
->Status
;
3342 info1W
->Priority
= info1A
->Priority
;
3343 info1W
->Position
= info1A
->Position
;
3344 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3349 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3350 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3352 JobW
= (LPBYTE
)info2W
;
3353 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3354 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3355 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3356 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3357 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3358 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3359 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3360 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3361 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3362 info2W
->Status
= info2A
->Status
;
3363 info2W
->Priority
= info2A
->Priority
;
3364 info2W
->Position
= info2A
->Position
;
3365 info2W
->StartTime
= info2A
->StartTime
;
3366 info2W
->UntilTime
= info2A
->UntilTime
;
3367 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3371 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3372 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3375 SetLastError(ERROR_INVALID_LEVEL
);
3379 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3385 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3386 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3387 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3388 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3389 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3394 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3395 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3396 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3397 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3398 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3399 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3400 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3401 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3402 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3406 HeapFree(GetProcessHeap(), 0, JobW
);
3411 /*****************************************************************************
3412 * SetJobW [WINSPOOL.@]
3414 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3415 LPBYTE pJob
, DWORD Command
)
3420 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3421 FIXME("Ignoring everything other than document title\n");
3423 EnterCriticalSection(&printer_handles_cs
);
3424 job
= get_job(hPrinter
, JobId
);
3434 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3435 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3436 job
->document_title
= strdupW(info1
->pDocument
);
3441 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3442 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3443 job
->document_title
= strdupW(info2
->pDocument
);
3449 SetLastError(ERROR_INVALID_LEVEL
);
3454 LeaveCriticalSection(&printer_handles_cs
);
3458 /*****************************************************************************
3459 * EndDocPrinter [WINSPOOL.@]
3461 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3463 opened_printer_t
*printer
;
3465 TRACE("(%p)\n", hPrinter
);
3467 EnterCriticalSection(&printer_handles_cs
);
3469 printer
= get_opened_printer(hPrinter
);
3472 SetLastError(ERROR_INVALID_HANDLE
);
3478 SetLastError(ERROR_SPL_NO_STARTDOC
);
3482 CloseHandle(printer
->doc
->hf
);
3483 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3484 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3485 printer
->doc
= NULL
;
3488 LeaveCriticalSection(&printer_handles_cs
);
3492 /*****************************************************************************
3493 * EndPagePrinter [WINSPOOL.@]
3495 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3497 FIXME("(%p): stub\n", hPrinter
);
3501 /*****************************************************************************
3502 * StartDocPrinterA [WINSPOOL.@]
3504 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3506 UNICODE_STRING usBuffer
;
3508 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3511 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3512 or one (DOC_INFO_3) extra DWORDs */
3516 doc2W
.JobId
= doc2
->JobId
;
3519 doc2W
.dwMode
= doc2
->dwMode
;
3522 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3523 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3524 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3528 SetLastError(ERROR_INVALID_LEVEL
);
3532 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3534 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3535 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3536 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3541 /*****************************************************************************
3542 * StartDocPrinterW [WINSPOOL.@]
3544 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3546 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3547 opened_printer_t
*printer
;
3548 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3549 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3550 JOB_INFO_1W job_info
;
3551 DWORD needed
, ret
= 0;
3555 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3556 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3557 debugstr_w(doc
->pDatatype
));
3559 if(Level
< 1 || Level
> 3)
3561 SetLastError(ERROR_INVALID_LEVEL
);
3565 EnterCriticalSection(&printer_handles_cs
);
3566 printer
= get_opened_printer(hPrinter
);
3569 SetLastError(ERROR_INVALID_HANDLE
);
3575 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3579 /* Even if we're printing to a file we still add a print job, we'll
3580 just ignore the spool file name */
3582 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3584 ERR("AddJob failed gle %u\n", GetLastError());
3588 if(doc
->pOutputFile
)
3589 filename
= doc
->pOutputFile
;
3591 filename
= addjob
->Path
;
3593 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3594 if(hf
== INVALID_HANDLE_VALUE
)
3597 memset(&job_info
, 0, sizeof(job_info
));
3598 job_info
.pDocument
= doc
->pDocName
;
3599 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3601 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3602 printer
->doc
->hf
= hf
;
3603 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3605 LeaveCriticalSection(&printer_handles_cs
);
3610 /*****************************************************************************
3611 * StartPagePrinter [WINSPOOL.@]
3613 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3615 FIXME("(%p): stub\n", hPrinter
);
3619 /*****************************************************************************
3620 * GetFormA [WINSPOOL.@]
3622 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3623 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3625 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3626 Level
,pForm
,cbBuf
,pcbNeeded
);
3630 /*****************************************************************************
3631 * GetFormW [WINSPOOL.@]
3633 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3634 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3636 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3637 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3641 /*****************************************************************************
3642 * SetFormA [WINSPOOL.@]
3644 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3647 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3651 /*****************************************************************************
3652 * SetFormW [WINSPOOL.@]
3654 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3657 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3661 /*****************************************************************************
3662 * ReadPrinter [WINSPOOL.@]
3664 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3665 LPDWORD pNoBytesRead
)
3667 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3671 /*****************************************************************************
3672 * ResetPrinterA [WINSPOOL.@]
3674 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3676 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3680 /*****************************************************************************
3681 * ResetPrinterW [WINSPOOL.@]
3683 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3685 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3689 /*****************************************************************************
3690 * WINSPOOL_GetDWORDFromReg
3692 * Return DWORD associated with ValueName from hkey.
3694 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3696 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3699 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3701 if(ret
!= ERROR_SUCCESS
) {
3702 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3705 if(type
!= REG_DWORD
) {
3706 ERR("Got type %d\n", type
);
3713 /*****************************************************************************
3714 * get_filename_from_reg [internal]
3716 * Get ValueName from hkey storing result in out
3717 * when the Value in the registry has only a filename, use driverdir as prefix
3718 * outlen is space left in out
3719 * String is stored either as unicode or ascii
3723 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3724 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3726 WCHAR filename
[MAX_PATH
];
3730 LPWSTR buffer
= filename
;
3734 size
= sizeof(filename
);
3736 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3737 if (ret
== ERROR_MORE_DATA
) {
3738 TRACE("need dynamic buffer: %u\n", size
);
3739 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3741 /* No Memory is bad */
3745 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3748 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3749 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3755 /* do we have a full path ? */
3756 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3757 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3760 /* we must build the full Path */
3762 if ((out
) && (outlen
> dirlen
)) {
3764 lstrcpyW((LPWSTR
)out
, driverdir
);
3768 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3777 /* write the filename */
3779 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3780 if ((out
) && (outlen
>= size
)) {
3781 lstrcpyW((LPWSTR
)out
, ptr
);
3790 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3791 if ((out
) && (outlen
>= size
)) {
3792 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3800 ptr
+= lstrlenW(ptr
)+1;
3801 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3804 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3806 /* write the multisz-termination */
3807 if (type
== REG_MULTI_SZ
) {
3808 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3811 if (out
&& (outlen
>= size
)) {
3812 memset (out
, 0, size
);
3818 /*****************************************************************************
3819 * WINSPOOL_GetStringFromReg
3821 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3822 * String is stored either as unicode or ascii.
3823 * Bit of a hack here to get the ValueName if we want ascii.
3825 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3826 DWORD buflen
, DWORD
*needed
,
3829 DWORD sz
= buflen
, type
;
3833 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3835 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3836 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3837 HeapFree(GetProcessHeap(),0,ValueNameA
);
3839 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3840 WARN("Got ret = %d\n", ret
);
3844 /* add space for terminating '\0' */
3845 sz
+= unicode
? sizeof(WCHAR
) : 1;
3849 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3854 /*****************************************************************************
3855 * WINSPOOL_GetDefaultDevMode
3857 * Get a default DevMode values for wineps.
3861 static void WINSPOOL_GetDefaultDevMode(
3863 DWORD buflen
, DWORD
*needed
,
3867 static const char szwps
[] = "wineps.drv";
3869 /* fill default DEVMODE - should be read from ppd... */
3870 ZeroMemory( &dm
, sizeof(dm
) );
3871 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3872 dm
.dmSpecVersion
= DM_SPECVERSION
;
3873 dm
.dmDriverVersion
= 1;
3874 dm
.dmSize
= sizeof(DEVMODEA
);
3875 dm
.dmDriverExtra
= 0;
3877 DM_ORIENTATION
| DM_PAPERSIZE
|
3878 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3881 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3882 DM_YRESOLUTION
| DM_TTOPTION
;
3884 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3885 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3886 dm
.u1
.s1
.dmPaperLength
= 2970;
3887 dm
.u1
.s1
.dmPaperWidth
= 2100;
3889 dm
.u1
.s1
.dmScale
= 100;
3890 dm
.u1
.s1
.dmCopies
= 1;
3891 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3892 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3895 dm
.dmYResolution
= 300; /* 300dpi */
3896 dm
.dmTTOption
= DMTT_BITMAP
;
3899 /* dm.dmLogPixels */
3900 /* dm.dmBitsPerPel */
3901 /* dm.dmPelsWidth */
3902 /* dm.dmPelsHeight */
3903 /* dm.u2.dmDisplayFlags */
3904 /* dm.dmDisplayFrequency */
3905 /* dm.dmICMMethod */
3906 /* dm.dmICMIntent */
3907 /* dm.dmMediaType */
3908 /* dm.dmDitherType */
3909 /* dm.dmReserved1 */
3910 /* dm.dmReserved2 */
3911 /* dm.dmPanningWidth */
3912 /* dm.dmPanningHeight */
3915 if(buflen
>= sizeof(DEVMODEW
)) {
3916 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3917 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3918 HeapFree(GetProcessHeap(),0,pdmW
);
3920 *needed
= sizeof(DEVMODEW
);
3924 if(buflen
>= sizeof(DEVMODEA
)) {
3925 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3927 *needed
= sizeof(DEVMODEA
);
3931 /*****************************************************************************
3932 * WINSPOOL_GetDevModeFromReg
3934 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3935 * DevMode is stored either as unicode or ascii.
3937 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3939 DWORD buflen
, DWORD
*needed
,
3942 DWORD sz
= buflen
, type
;
3945 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3946 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3947 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3948 if (sz
< sizeof(DEVMODEA
))
3950 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3953 /* ensures that dmSize is not erratically bogus if registry is invalid */
3954 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3955 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3957 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3959 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3960 memcpy(ptr
, dmW
, sz
);
3961 HeapFree(GetProcessHeap(),0,dmW
);
3968 /*********************************************************************
3969 * WINSPOOL_GetPrinter_1
3971 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3972 * The strings are either stored as unicode or ascii.
3974 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3975 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3978 DWORD size
, left
= cbBuf
;
3979 BOOL space
= (cbBuf
> 0);
3984 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3986 if(space
&& size
<= left
) {
3987 pi1
->pName
= (LPWSTR
)ptr
;
3995 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3996 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3998 if(space
&& size
<= left
) {
3999 pi1
->pDescription
= (LPWSTR
)ptr
;
4007 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
4009 if(space
&& size
<= left
) {
4010 pi1
->pComment
= (LPWSTR
)ptr
;
4018 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4020 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4021 memset(pi1
, 0, sizeof(*pi1
));
4025 /*********************************************************************
4026 * WINSPOOL_GetPrinter_2
4028 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
4029 * The strings are either stored as unicode or ascii.
4031 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4032 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4035 DWORD size
, left
= cbBuf
;
4036 BOOL space
= (cbBuf
> 0);
4041 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
4043 if(space
&& size
<= left
) {
4044 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4051 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
4053 if(space
&& size
<= left
) {
4054 pi2
->pShareName
= (LPWSTR
)ptr
;
4061 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
4063 if(space
&& size
<= left
) {
4064 pi2
->pPortName
= (LPWSTR
)ptr
;
4071 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
4073 if(space
&& size
<= left
) {
4074 pi2
->pDriverName
= (LPWSTR
)ptr
;
4081 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
4083 if(space
&& size
<= left
) {
4084 pi2
->pComment
= (LPWSTR
)ptr
;
4091 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
4093 if(space
&& size
<= left
) {
4094 pi2
->pLocation
= (LPWSTR
)ptr
;
4101 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
4103 if(space
&& size
<= left
) {
4104 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4113 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
4114 if(space
&& size
<= left
) {
4115 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4122 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
4124 if(space
&& size
<= left
) {
4125 pi2
->pSepFile
= (LPWSTR
)ptr
;
4132 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
4134 if(space
&& size
<= left
) {
4135 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4142 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
4144 if(space
&& size
<= left
) {
4145 pi2
->pDatatype
= (LPWSTR
)ptr
;
4152 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
4154 if(space
&& size
<= left
) {
4155 pi2
->pParameters
= (LPWSTR
)ptr
;
4163 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4164 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
4165 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4166 "Default Priority");
4167 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
4168 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
4171 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4172 memset(pi2
, 0, sizeof(*pi2
));
4177 /*********************************************************************
4178 * WINSPOOL_GetPrinter_4
4180 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4182 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4183 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4186 DWORD size
, left
= cbBuf
;
4187 BOOL space
= (cbBuf
> 0);
4192 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
4194 if(space
&& size
<= left
) {
4195 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4203 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4206 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4207 memset(pi4
, 0, sizeof(*pi4
));
4212 /*********************************************************************
4213 * WINSPOOL_GetPrinter_5
4215 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4217 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4218 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4221 DWORD size
, left
= cbBuf
;
4222 BOOL space
= (cbBuf
> 0);
4227 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
4229 if(space
&& size
<= left
) {
4230 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4237 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
4239 if(space
&& size
<= left
) {
4240 pi5
->pPortName
= (LPWSTR
)ptr
;
4248 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4249 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4251 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4255 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4256 memset(pi5
, 0, sizeof(*pi5
));
4261 /*********************************************************************
4262 * WINSPOOL_GetPrinter_7
4264 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4266 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4267 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4269 DWORD size
, left
= cbBuf
;
4270 BOOL space
= (cbBuf
> 0);
4275 if (WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
, unicode
))
4277 if (space
&& size
<= left
) {
4278 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4286 /* We do not have a Directory Service */
4287 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4290 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4291 memset(pi7
, 0, sizeof(*pi7
));
4296 /*********************************************************************
4297 * WINSPOOL_GetPrinter_9
4299 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4300 * The strings are either stored as unicode or ascii.
4302 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4303 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4306 BOOL space
= (cbBuf
> 0);
4310 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
, unicode
)) {
4311 if(space
&& size
<= cbBuf
) {
4312 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4319 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
, unicode
);
4320 if(space
&& size
<= cbBuf
) {
4321 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4327 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4328 memset(pi9
, 0, sizeof(*pi9
));
4333 /*****************************************************************************
4334 * WINSPOOL_GetPrinter
4336 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4337 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4338 * just a collection of pointers to strings.
4340 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4341 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4344 DWORD size
, needed
= 0;
4346 HKEY hkeyPrinter
, hkeyPrinters
;
4349 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4351 if (!(name
= get_opened_printer_name(hPrinter
))) {
4352 SetLastError(ERROR_INVALID_HANDLE
);
4356 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4358 ERR("Can't create Printers key\n");
4361 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4363 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4364 RegCloseKey(hkeyPrinters
);
4365 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4372 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4374 size
= sizeof(PRINTER_INFO_2W
);
4376 ptr
= pPrinter
+ size
;
4378 memset(pPrinter
, 0, size
);
4383 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4391 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4393 size
= sizeof(PRINTER_INFO_4W
);
4395 ptr
= pPrinter
+ size
;
4397 memset(pPrinter
, 0, size
);
4402 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4411 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4413 size
= sizeof(PRINTER_INFO_5W
);
4415 ptr
= pPrinter
+ size
;
4417 memset(pPrinter
, 0, size
);
4423 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4432 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4434 size
= sizeof(PRINTER_INFO_6
);
4435 if (size
<= cbBuf
) {
4436 /* FIXME: We do not update the status yet */
4437 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
4449 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4451 size
= sizeof(PRINTER_INFO_7W
);
4452 if (size
<= cbBuf
) {
4453 ptr
= pPrinter
+ size
;
4455 memset(pPrinter
, 0, size
);
4461 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
, unicode
);
4469 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4471 size
= sizeof(PRINTER_INFO_9W
);
4473 ptr
= pPrinter
+ size
;
4475 memset(pPrinter
, 0, size
);
4481 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
, unicode
);
4488 FIXME("Unimplemented level %d\n", Level
);
4489 SetLastError(ERROR_INVALID_LEVEL
);
4490 RegCloseKey(hkeyPrinters
);
4491 RegCloseKey(hkeyPrinter
);
4495 RegCloseKey(hkeyPrinter
);
4496 RegCloseKey(hkeyPrinters
);
4498 TRACE("returning %d needed = %d\n", ret
, needed
);
4499 if(pcbNeeded
) *pcbNeeded
= needed
;
4501 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4505 /*****************************************************************************
4506 * GetPrinterW [WINSPOOL.@]
4508 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4509 DWORD cbBuf
, LPDWORD pcbNeeded
)
4511 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4515 /*****************************************************************************
4516 * GetPrinterA [WINSPOOL.@]
4518 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4519 DWORD cbBuf
, LPDWORD pcbNeeded
)
4521 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4525 /*****************************************************************************
4526 * WINSPOOL_EnumPrinters
4528 * Implementation of EnumPrintersA|W
4530 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4531 DWORD dwLevel
, LPBYTE lpbPrinters
,
4532 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4533 LPDWORD lpdwReturned
, BOOL unicode
)
4536 HKEY hkeyPrinters
, hkeyPrinter
;
4537 WCHAR PrinterName
[255];
4538 DWORD needed
= 0, number
= 0;
4539 DWORD used
, i
, left
;
4543 memset(lpbPrinters
, 0, cbBuf
);
4549 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4550 if(dwType
== PRINTER_ENUM_DEFAULT
)
4553 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4554 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4555 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4557 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4565 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4566 FIXME("dwType = %08x\n", dwType
);
4567 SetLastError(ERROR_INVALID_FLAGS
);
4571 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4573 ERR("Can't create Printers key\n");
4577 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4578 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4579 RegCloseKey(hkeyPrinters
);
4580 ERR("Can't query Printers key\n");
4583 TRACE("Found %d printers\n", number
);
4587 used
= number
* sizeof(PRINTER_INFO_1W
);
4590 used
= number
* sizeof(PRINTER_INFO_2W
);
4593 used
= number
* sizeof(PRINTER_INFO_4W
);
4596 used
= number
* sizeof(PRINTER_INFO_5W
);
4600 SetLastError(ERROR_INVALID_LEVEL
);
4601 RegCloseKey(hkeyPrinters
);
4604 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4606 for(i
= 0; i
< number
; i
++) {
4607 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4609 ERR("Can't enum key number %d\n", i
);
4610 RegCloseKey(hkeyPrinters
);
4613 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4614 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4616 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4617 RegCloseKey(hkeyPrinters
);
4622 buf
= lpbPrinters
+ used
;
4623 left
= cbBuf
- used
;
4631 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4632 left
, &needed
, unicode
);
4634 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4637 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4638 left
, &needed
, unicode
);
4640 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4643 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4644 left
, &needed
, unicode
);
4646 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4649 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4650 left
, &needed
, unicode
);
4652 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4655 ERR("Shouldn't be here!\n");
4656 RegCloseKey(hkeyPrinter
);
4657 RegCloseKey(hkeyPrinters
);
4660 RegCloseKey(hkeyPrinter
);
4662 RegCloseKey(hkeyPrinters
);
4669 memset(lpbPrinters
, 0, cbBuf
);
4670 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4674 *lpdwReturned
= number
;
4675 SetLastError(ERROR_SUCCESS
);
4680 /******************************************************************
4681 * EnumPrintersW [WINSPOOL.@]
4683 * Enumerates the available printers, print servers and print
4684 * providers, depending on the specified flags, name and level.
4688 * If level is set to 1:
4689 * Returns an array of PRINTER_INFO_1 data structures in the
4690 * lpbPrinters buffer.
4692 * If level is set to 2:
4693 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4694 * Returns an array of PRINTER_INFO_2 data structures in the
4695 * lpbPrinters buffer. Note that according to MSDN also an
4696 * OpenPrinter should be performed on every remote printer.
4698 * If level is set to 4 (officially WinNT only):
4699 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4700 * Fast: Only the registry is queried to retrieve printer names,
4701 * no connection to the driver is made.
4702 * Returns an array of PRINTER_INFO_4 data structures in the
4703 * lpbPrinters buffer.
4705 * If level is set to 5 (officially WinNT4/Win9x only):
4706 * Fast: Only the registry is queried to retrieve printer names,
4707 * no connection to the driver is made.
4708 * Returns an array of PRINTER_INFO_5 data structures in the
4709 * lpbPrinters buffer.
4711 * If level set to 3 or 6+:
4712 * returns zero (failure!)
4714 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4718 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4719 * - Only levels 2, 4 and 5 are implemented at the moment.
4720 * - 16-bit printer drivers are not enumerated.
4721 * - Returned amount of bytes used/needed does not match the real Windoze
4722 * implementation (as in this implementation, all strings are part
4723 * of the buffer, whereas Win32 keeps them somewhere else)
4724 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4727 * - In a regular Wine installation, no registry settings for printers
4728 * exist, which makes this function return an empty list.
4730 BOOL WINAPI
EnumPrintersW(
4731 DWORD dwType
, /* [in] Types of print objects to enumerate */
4732 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4733 DWORD dwLevel
, /* [in] type of printer info structure */
4734 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4735 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4736 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4737 LPDWORD lpdwReturned
/* [out] number of entries returned */
4740 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4741 lpdwNeeded
, lpdwReturned
, TRUE
);
4744 /******************************************************************
4745 * EnumPrintersA [WINSPOOL.@]
4750 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4751 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4754 UNICODE_STRING pNameU
;
4758 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4759 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4761 pNameW
= asciitounicode(&pNameU
, pName
);
4763 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4764 MS Office need this */
4765 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4767 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4769 RtlFreeUnicodeString(&pNameU
);
4771 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4773 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4777 /*****************************************************************************
4778 * WINSPOOL_GetDriverInfoFromReg [internal]
4780 * Enters the information from the registry into the DRIVER_INFO struct
4783 * zero if the printer driver does not exist in the registry
4784 * (only if Level > 1) otherwise nonzero
4786 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4789 const printenv_t
* env
,
4791 LPBYTE ptr
, /* DRIVER_INFO */
4792 LPBYTE pDriverStrings
, /* strings buffer */
4793 DWORD cbBuf
, /* size of string buffer */
4794 LPDWORD pcbNeeded
, /* space needed for str. */
4795 BOOL unicode
) /* type of strings */
4799 WCHAR driverdir
[MAX_PATH
];
4801 LPBYTE strPtr
= pDriverStrings
;
4802 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4804 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4805 debugstr_w(DriverName
), env
,
4806 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4808 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4811 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4812 if (*pcbNeeded
<= cbBuf
)
4813 strcpyW((LPWSTR
)strPtr
, DriverName
);
4817 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4818 if (*pcbNeeded
<= cbBuf
)
4819 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4822 /* pName for level 1 has a different offset! */
4824 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4828 /* .cVersion and .pName for level > 1 */
4830 di
->cVersion
= env
->driverversion
;
4831 di
->pName
= (LPWSTR
) strPtr
;
4832 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4835 /* Reserve Space for the largest subdir and a Backslash*/
4836 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4837 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4838 /* Should never Fail */
4841 lstrcatW(driverdir
, env
->versionsubdir
);
4842 lstrcatW(driverdir
, backslashW
);
4844 /* dirlen must not include the terminating zero */
4845 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4846 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4848 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4849 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4850 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4856 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4858 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4861 if (*pcbNeeded
<= cbBuf
) {
4863 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4867 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4869 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4870 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4873 /* .pDriverPath is the Graphics rendering engine.
4874 The full Path is required to avoid a crash in some apps */
4875 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4877 if (*pcbNeeded
<= cbBuf
)
4878 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4880 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4881 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4884 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4885 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4887 if (*pcbNeeded
<= cbBuf
)
4888 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4890 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4891 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4894 /* .pConfigFile is the Driver user Interface */
4895 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4897 if (*pcbNeeded
<= cbBuf
)
4898 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4900 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4901 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4905 RegCloseKey(hkeyDriver
);
4906 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4911 RegCloseKey(hkeyDriver
);
4912 FIXME("level 5: incomplete\n");
4917 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4919 if (*pcbNeeded
<= cbBuf
)
4920 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4922 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4923 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4926 /* .pDependentFiles */
4927 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4929 if (*pcbNeeded
<= cbBuf
)
4930 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4932 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4933 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4935 else if (GetVersion() & 0x80000000) {
4936 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4937 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4939 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4941 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4942 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4945 /* .pMonitorName is the optional Language Monitor */
4946 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4948 if (*pcbNeeded
<= cbBuf
)
4949 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4951 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4952 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4955 /* .pDefaultDataType */
4956 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4958 if(*pcbNeeded
<= cbBuf
)
4959 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4961 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4962 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4966 RegCloseKey(hkeyDriver
);
4967 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4971 /* .pszzPreviousNames */
4972 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4974 if(*pcbNeeded
<= cbBuf
)
4975 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4977 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4978 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4982 RegCloseKey(hkeyDriver
);
4983 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4987 /* support is missing, but not important enough for a FIXME */
4988 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4991 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4993 if(*pcbNeeded
<= cbBuf
)
4994 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4996 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4997 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5001 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
5003 if(*pcbNeeded
<= cbBuf
)
5004 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
5006 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5007 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5010 /* .pszHardwareID */
5011 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
5013 if(*pcbNeeded
<= cbBuf
)
5014 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
5016 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5017 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5021 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
5023 if(*pcbNeeded
<= cbBuf
)
5024 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
5026 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5027 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5031 RegCloseKey(hkeyDriver
);
5035 /* support is missing, but not important enough for a FIXME */
5036 TRACE("level 8: incomplete\n");
5038 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5039 RegCloseKey(hkeyDriver
);
5043 /*****************************************************************************
5044 * WINSPOOL_GetPrinterDriver
5046 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
5047 DWORD Level
, LPBYTE pDriverInfo
,
5048 DWORD cbBuf
, LPDWORD pcbNeeded
,
5052 WCHAR DriverName
[100];
5053 DWORD ret
, type
, size
, needed
= 0;
5055 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
5056 const printenv_t
* env
;
5058 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5059 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5062 if (!(name
= get_opened_printer_name(hPrinter
))) {
5063 SetLastError(ERROR_INVALID_HANDLE
);
5067 if (Level
< 1 || Level
== 7 || Level
> 8) {
5068 SetLastError(ERROR_INVALID_LEVEL
);
5072 env
= validate_envW(pEnvironment
);
5073 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5075 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
5077 ERR("Can't create Printers key\n");
5080 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
5082 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
5083 RegCloseKey(hkeyPrinters
);
5084 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
5087 size
= sizeof(DriverName
);
5089 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5090 (LPBYTE
)DriverName
, &size
);
5091 RegCloseKey(hkeyPrinter
);
5092 RegCloseKey(hkeyPrinters
);
5093 if(ret
!= ERROR_SUCCESS
) {
5094 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5098 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
5100 ERR("Can't create Drivers key\n");
5104 size
= di_sizeof
[Level
];
5105 if ((size
<= cbBuf
) && pDriverInfo
)
5106 ptr
= pDriverInfo
+ size
;
5108 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5109 env
, Level
, pDriverInfo
, ptr
,
5110 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5111 &needed
, unicode
)) {
5112 RegCloseKey(hkeyDrivers
);
5116 RegCloseKey(hkeyDrivers
);
5118 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5119 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5120 if(cbBuf
>= needed
) return TRUE
;
5121 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5125 /*****************************************************************************
5126 * GetPrinterDriverA [WINSPOOL.@]
5128 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5129 DWORD Level
, LPBYTE pDriverInfo
,
5130 DWORD cbBuf
, LPDWORD pcbNeeded
)
5133 UNICODE_STRING pEnvW
;
5136 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5137 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
5138 cbBuf
, pcbNeeded
, FALSE
);
5139 RtlFreeUnicodeString(&pEnvW
);
5142 /*****************************************************************************
5143 * GetPrinterDriverW [WINSPOOL.@]
5145 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5146 DWORD Level
, LPBYTE pDriverInfo
,
5147 DWORD cbBuf
, LPDWORD pcbNeeded
)
5149 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
5150 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
5153 /*****************************************************************************
5154 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5156 * Return the PATH for the Printer-Drivers (UNICODE)
5159 * pName [I] Servername (NT only) or NULL (local Computer)
5160 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5161 * Level [I] Structure-Level (must be 1)
5162 * pDriverDirectory [O] PTR to Buffer that receives the Result
5163 * cbBuf [I] Size of Buffer at pDriverDirectory
5164 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5165 * required for pDriverDirectory
5168 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5169 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5170 * if cbBuf is too small
5172 * Native Values returned in pDriverDirectory on Success:
5173 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5174 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5175 *| win9x(Windows 4.0): "%winsysdir%"
5177 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5180 *- Only NULL or "" is supported for pName
5183 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5184 DWORD Level
, LPBYTE pDriverDirectory
,
5185 DWORD cbBuf
, LPDWORD pcbNeeded
)
5187 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5188 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5190 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5193 /* (Level != 1) is ignored in win9x */
5194 SetLastError(ERROR_INVALID_LEVEL
);
5197 if (pcbNeeded
== NULL
) {
5198 /* (pcbNeeded == NULL) is ignored in win9x */
5199 SetLastError(RPC_X_NULL_REF_POINTER
);
5203 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5204 pDriverDirectory
, cbBuf
, pcbNeeded
);
5209 /*****************************************************************************
5210 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5212 * Return the PATH for the Printer-Drivers (ANSI)
5214 * See GetPrinterDriverDirectoryW.
5217 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5220 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5221 DWORD Level
, LPBYTE pDriverDirectory
,
5222 DWORD cbBuf
, LPDWORD pcbNeeded
)
5224 UNICODE_STRING nameW
, environmentW
;
5227 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5228 WCHAR
*driverDirectoryW
= NULL
;
5230 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5231 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5233 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5235 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5236 else nameW
.Buffer
= NULL
;
5237 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5238 else environmentW
.Buffer
= NULL
;
5240 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5241 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5244 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5245 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5247 *pcbNeeded
= needed
;
5248 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
5250 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5252 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5254 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5255 RtlFreeUnicodeString(&environmentW
);
5256 RtlFreeUnicodeString(&nameW
);
5261 /*****************************************************************************
5262 * AddPrinterDriverA [WINSPOOL.@]
5264 * See AddPrinterDriverW.
5267 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5269 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5270 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5273 /******************************************************************************
5274 * AddPrinterDriverW (WINSPOOL.@)
5276 * Install a Printer Driver
5279 * pName [I] Servername or NULL (local Computer)
5280 * level [I] Level for the supplied DRIVER_INFO_*W struct
5281 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5288 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5290 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5291 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5294 /*****************************************************************************
5295 * AddPrintProcessorA [WINSPOOL.@]
5297 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5298 LPSTR pPrintProcessorName
)
5300 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5301 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5305 /*****************************************************************************
5306 * AddPrintProcessorW [WINSPOOL.@]
5308 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5309 LPWSTR pPrintProcessorName
)
5311 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5312 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5316 /*****************************************************************************
5317 * AddPrintProvidorA [WINSPOOL.@]
5319 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5321 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5325 /*****************************************************************************
5326 * AddPrintProvidorW [WINSPOOL.@]
5328 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5330 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5334 /*****************************************************************************
5335 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5337 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5338 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5340 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5341 pDevModeOutput
, pDevModeInput
);
5345 /*****************************************************************************
5346 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5348 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5349 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5351 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5352 pDevModeOutput
, pDevModeInput
);
5356 /*****************************************************************************
5357 * PrinterProperties [WINSPOOL.@]
5359 * Displays a dialog to set the properties of the printer.
5362 * nonzero on success or zero on failure
5365 * implemented as stub only
5367 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5368 HANDLE hPrinter
/* [in] handle to printer object */
5370 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5371 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5375 /*****************************************************************************
5376 * EnumJobsA [WINSPOOL.@]
5379 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5380 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5383 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5384 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5386 if(pcbNeeded
) *pcbNeeded
= 0;
5387 if(pcReturned
) *pcReturned
= 0;
5392 /*****************************************************************************
5393 * EnumJobsW [WINSPOOL.@]
5396 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5397 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5400 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5401 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5403 if(pcbNeeded
) *pcbNeeded
= 0;
5404 if(pcReturned
) *pcReturned
= 0;
5408 /*****************************************************************************
5409 * WINSPOOL_EnumPrinterDrivers [internal]
5411 * Delivers information about all printer drivers installed on the
5412 * localhost or a given server
5415 * nonzero on success or zero on failure. If the buffer for the returned
5416 * information is too small the function will return an error
5419 * - only implemented for localhost, foreign hosts will return an error
5421 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5422 DWORD Level
, LPBYTE pDriverInfo
,
5423 DWORD cbBuf
, LPDWORD pcbNeeded
,
5424 LPDWORD pcReturned
, BOOL unicode
)
5427 DWORD i
, needed
, number
= 0, size
= 0;
5428 WCHAR DriverNameW
[255];
5430 const printenv_t
* env
;
5432 TRACE("%s,%s,%d,%p,%d,%d\n",
5433 debugstr_w(pName
), debugstr_w(pEnvironment
),
5434 Level
, pDriverInfo
, cbBuf
, unicode
);
5436 /* check for local drivers */
5437 if((pName
) && (pName
[0])) {
5438 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5439 SetLastError(ERROR_ACCESS_DENIED
);
5443 env
= validate_envW(pEnvironment
);
5444 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5446 /* check input parameter */
5447 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5448 SetLastError(ERROR_INVALID_LEVEL
);
5452 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
5453 SetLastError(RPC_X_NULL_REF_POINTER
);
5457 /* initialize return values */
5459 memset( pDriverInfo
, 0, cbBuf
);
5463 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5465 ERR("Can't open Drivers key\n");
5469 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5470 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5471 RegCloseKey(hkeyDrivers
);
5472 ERR("Can't query Drivers key\n");
5475 TRACE("Found %d Drivers\n", number
);
5477 /* get size of single struct
5478 * unicode and ascii structure have the same size
5480 size
= di_sizeof
[Level
];
5482 /* calculate required buffer size */
5483 *pcbNeeded
= size
* number
;
5485 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5487 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5488 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5490 ERR("Can't enum key number %d\n", i
);
5491 RegCloseKey(hkeyDrivers
);
5494 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5496 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5497 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5498 &needed
, unicode
)) {
5499 RegCloseKey(hkeyDrivers
);
5502 (*pcbNeeded
) += needed
;
5505 RegCloseKey(hkeyDrivers
);
5507 if(cbBuf
< *pcbNeeded
){
5508 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5512 *pcReturned
= number
;
5516 /*****************************************************************************
5517 * EnumPrinterDriversW [WINSPOOL.@]
5519 * see function EnumPrinterDrivers for RETURNS, BUGS
5521 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5522 LPBYTE pDriverInfo
, DWORD cbBuf
,
5523 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5525 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5526 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5529 /*****************************************************************************
5530 * EnumPrinterDriversA [WINSPOOL.@]
5532 * see function EnumPrinterDrivers for RETURNS, BUGS
5534 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5535 LPBYTE pDriverInfo
, DWORD cbBuf
,
5536 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5538 UNICODE_STRING pNameW
, pEnvironmentW
;
5539 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5541 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5542 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5544 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5545 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5547 RtlFreeUnicodeString(&pNameW
);
5548 RtlFreeUnicodeString(&pEnvironmentW
);
5553 /******************************************************************************
5554 * EnumPortsA (WINSPOOL.@)
5559 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5560 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5563 LPBYTE bufferW
= NULL
;
5564 LPWSTR nameW
= NULL
;
5566 DWORD numentries
= 0;
5569 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5570 cbBuf
, pcbNeeded
, pcReturned
);
5572 /* convert servername to unicode */
5574 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5575 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5576 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5578 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5579 needed
= cbBuf
* sizeof(WCHAR
);
5580 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5581 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5583 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5584 if (pcbNeeded
) needed
= *pcbNeeded
;
5585 /* HeapReAlloc return NULL, when bufferW was NULL */
5586 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5587 HeapAlloc(GetProcessHeap(), 0, needed
);
5589 /* Try again with the large Buffer */
5590 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5592 needed
= pcbNeeded
? *pcbNeeded
: 0;
5593 numentries
= pcReturned
? *pcReturned
: 0;
5596 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5597 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5600 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5601 DWORD entrysize
= 0;
5604 LPPORT_INFO_2W pi2w
;
5605 LPPORT_INFO_2A pi2a
;
5608 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5610 /* First pass: calculate the size for all Entries */
5611 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5612 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5614 while (index
< numentries
) {
5616 needed
+= entrysize
; /* PORT_INFO_?A */
5617 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5619 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5620 NULL
, 0, NULL
, NULL
);
5622 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5623 NULL
, 0, NULL
, NULL
);
5624 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5625 NULL
, 0, NULL
, NULL
);
5627 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5628 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5629 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5632 /* check for errors and quit on failure */
5633 if (cbBuf
< needed
) {
5634 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5638 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5639 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5640 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5641 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5642 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5644 /* Second Pass: Fill the User Buffer (if we have one) */
5645 while ((index
< numentries
) && pPorts
) {
5647 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5648 pi2a
->pPortName
= ptr
;
5649 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5650 ptr
, cbBuf
, NULL
, NULL
);
5654 pi2a
->pMonitorName
= ptr
;
5655 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5656 ptr
, cbBuf
, NULL
, NULL
);
5660 pi2a
->pDescription
= ptr
;
5661 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5662 ptr
, cbBuf
, NULL
, NULL
);
5666 pi2a
->fPortType
= pi2w
->fPortType
;
5667 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5670 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5671 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5672 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5677 if (pcbNeeded
) *pcbNeeded
= needed
;
5678 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5680 HeapFree(GetProcessHeap(), 0, nameW
);
5681 HeapFree(GetProcessHeap(), 0, bufferW
);
5683 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5684 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5690 /******************************************************************************
5691 * EnumPortsW (WINSPOOL.@)
5693 * Enumerate available Ports
5696 * name [I] Servername or NULL (local Computer)
5697 * level [I] Structure-Level (1 or 2)
5698 * buffer [O] PTR to Buffer that receives the Result
5699 * bufsize [I] Size of Buffer at buffer
5700 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5701 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5705 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5709 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5712 DWORD numentries
= 0;
5715 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5716 cbBuf
, pcbNeeded
, pcReturned
);
5718 if (pName
&& (pName
[0])) {
5719 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5720 SetLastError(ERROR_ACCESS_DENIED
);
5724 /* Level is not checked in win9x */
5725 if (!Level
|| (Level
> 2)) {
5726 WARN("level (%d) is ignored in win9x\n", Level
);
5727 SetLastError(ERROR_INVALID_LEVEL
);
5731 SetLastError(RPC_X_NULL_REF_POINTER
);
5735 EnterCriticalSection(&monitor_handles_cs
);
5738 /* Scan all local Ports */
5740 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5742 /* we calculated the needed buffersize. now do the error-checks */
5743 if (cbBuf
< needed
) {
5744 monitor_unloadall();
5745 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5746 goto emP_cleanup_cs
;
5748 else if (!pPorts
|| !pcReturned
) {
5749 monitor_unloadall();
5750 SetLastError(RPC_X_NULL_REF_POINTER
);
5751 goto emP_cleanup_cs
;
5754 /* Fill the Buffer */
5755 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5757 monitor_unloadall();
5760 LeaveCriticalSection(&monitor_handles_cs
);
5763 if (pcbNeeded
) *pcbNeeded
= needed
;
5764 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5766 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5767 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5772 /******************************************************************************
5773 * GetDefaultPrinterW (WINSPOOL.@)
5776 * This function must read the value from data 'device' of key
5777 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5779 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5783 WCHAR
*buffer
, *ptr
;
5787 SetLastError(ERROR_INVALID_PARAMETER
);
5791 /* make the buffer big enough for the stuff from the profile/registry,
5792 * the content must fit into the local buffer to compute the correct
5793 * size even if the extern buffer is too small or not given.
5794 * (20 for ,driver,port) */
5796 len
= max(100, (insize
+ 20));
5797 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5799 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5801 SetLastError (ERROR_FILE_NOT_FOUND
);
5805 TRACE("%s\n", debugstr_w(buffer
));
5807 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5809 SetLastError(ERROR_INVALID_NAME
);
5815 *namesize
= strlenW(buffer
) + 1;
5816 if(!name
|| (*namesize
> insize
))
5818 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5822 strcpyW(name
, buffer
);
5825 HeapFree( GetProcessHeap(), 0, buffer
);
5830 /******************************************************************************
5831 * GetDefaultPrinterA (WINSPOOL.@)
5833 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5837 WCHAR
*bufferW
= NULL
;
5841 SetLastError(ERROR_INVALID_PARAMETER
);
5845 if(name
&& *namesize
) {
5847 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5850 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5855 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5859 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5862 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5865 HeapFree( GetProcessHeap(), 0, bufferW
);
5870 /******************************************************************************
5871 * SetDefaultPrinterW (WINSPOOL.204)
5873 * Set the Name of the Default Printer
5876 * pszPrinter [I] Name of the Printer or NULL
5883 * When the Parameter is NULL or points to an Empty String and
5884 * a Default Printer was already present, then this Function changes nothing.
5885 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5886 * the First enumerated local Printer is used.
5889 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5892 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5894 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5898 /******************************************************************************
5899 * SetDefaultPrinterA (WINSPOOL.202)
5901 * See SetDefaultPrinterW.
5904 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5907 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5909 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5914 /******************************************************************************
5915 * SetPrinterDataExA (WINSPOOL.@)
5917 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5918 LPCSTR pValueName
, DWORD Type
,
5919 LPBYTE pData
, DWORD cbData
)
5921 HKEY hkeyPrinter
, hkeySubkey
;
5924 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5925 debugstr_a(pValueName
), Type
, pData
, cbData
);
5927 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5931 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5933 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5934 RegCloseKey(hkeyPrinter
);
5937 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5938 RegCloseKey(hkeySubkey
);
5939 RegCloseKey(hkeyPrinter
);
5943 /******************************************************************************
5944 * SetPrinterDataExW (WINSPOOL.@)
5946 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5947 LPCWSTR pValueName
, DWORD Type
,
5948 LPBYTE pData
, DWORD cbData
)
5950 HKEY hkeyPrinter
, hkeySubkey
;
5953 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5954 debugstr_w(pValueName
), Type
, pData
, cbData
);
5956 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5960 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5962 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5963 RegCloseKey(hkeyPrinter
);
5966 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5967 RegCloseKey(hkeySubkey
);
5968 RegCloseKey(hkeyPrinter
);
5972 /******************************************************************************
5973 * SetPrinterDataA (WINSPOOL.@)
5975 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5976 LPBYTE pData
, DWORD cbData
)
5978 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5982 /******************************************************************************
5983 * SetPrinterDataW (WINSPOOL.@)
5985 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5986 LPBYTE pData
, DWORD cbData
)
5988 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5992 /******************************************************************************
5993 * GetPrinterDataExA (WINSPOOL.@)
5995 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5996 LPCSTR pValueName
, LPDWORD pType
,
5997 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5999 HKEY hkeyPrinter
, hkeySubkey
;
6002 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
6003 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
6006 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6010 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6012 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
6013 RegCloseKey(hkeyPrinter
);
6017 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
6018 RegCloseKey(hkeySubkey
);
6019 RegCloseKey(hkeyPrinter
);
6023 /******************************************************************************
6024 * GetPrinterDataExW (WINSPOOL.@)
6026 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6027 LPCWSTR pValueName
, LPDWORD pType
,
6028 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6030 HKEY hkeyPrinter
, hkeySubkey
;
6033 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
6034 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
6037 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6041 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6043 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
6044 RegCloseKey(hkeyPrinter
);
6048 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
6049 RegCloseKey(hkeySubkey
);
6050 RegCloseKey(hkeyPrinter
);
6054 /******************************************************************************
6055 * GetPrinterDataA (WINSPOOL.@)
6057 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6058 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6060 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6061 pData
, nSize
, pcbNeeded
);
6064 /******************************************************************************
6065 * GetPrinterDataW (WINSPOOL.@)
6067 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6068 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6070 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6071 pData
, nSize
, pcbNeeded
);
6074 /*******************************************************************************
6075 * EnumPrinterDataExW [WINSPOOL.@]
6077 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6078 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6079 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6081 HKEY hkPrinter
, hkSubKey
;
6082 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6083 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6088 PPRINTER_ENUM_VALUESW ppev
;
6090 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6092 if (pKeyName
== NULL
|| *pKeyName
== 0)
6093 return ERROR_INVALID_PARAMETER
;
6095 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6096 if (ret
!= ERROR_SUCCESS
)
6098 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6103 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6104 if (ret
!= ERROR_SUCCESS
)
6106 r
= RegCloseKey (hkPrinter
);
6107 if (r
!= ERROR_SUCCESS
)
6108 WARN ("RegCloseKey returned %i\n", r
);
6109 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6110 debugstr_w (pKeyName
), ret
);
6114 ret
= RegCloseKey (hkPrinter
);
6115 if (ret
!= ERROR_SUCCESS
)
6117 ERR ("RegCloseKey returned %i\n", ret
);
6118 r
= RegCloseKey (hkSubKey
);
6119 if (r
!= ERROR_SUCCESS
)
6120 WARN ("RegCloseKey returned %i\n", r
);
6124 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6125 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6126 if (ret
!= ERROR_SUCCESS
)
6128 r
= RegCloseKey (hkSubKey
);
6129 if (r
!= ERROR_SUCCESS
)
6130 WARN ("RegCloseKey returned %i\n", r
);
6131 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6135 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6136 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6138 if (cValues
== 0) /* empty key */
6140 r
= RegCloseKey (hkSubKey
);
6141 if (r
!= ERROR_SUCCESS
)
6142 WARN ("RegCloseKey returned %i\n", r
);
6143 *pcbEnumValues
= *pnEnumValues
= 0;
6144 return ERROR_SUCCESS
;
6147 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6149 hHeap
= GetProcessHeap ();
6152 ERR ("GetProcessHeap failed\n");
6153 r
= RegCloseKey (hkSubKey
);
6154 if (r
!= ERROR_SUCCESS
)
6155 WARN ("RegCloseKey returned %i\n", r
);
6156 return ERROR_OUTOFMEMORY
;
6159 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6160 if (lpValueName
== NULL
)
6162 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6163 r
= RegCloseKey (hkSubKey
);
6164 if (r
!= ERROR_SUCCESS
)
6165 WARN ("RegCloseKey returned %i\n", r
);
6166 return ERROR_OUTOFMEMORY
;
6169 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6170 if (lpValue
== NULL
)
6172 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6173 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6174 WARN ("HeapFree failed with code %i\n", GetLastError ());
6175 r
= RegCloseKey (hkSubKey
);
6176 if (r
!= ERROR_SUCCESS
)
6177 WARN ("RegCloseKey returned %i\n", r
);
6178 return ERROR_OUTOFMEMORY
;
6181 TRACE ("pass 1: calculating buffer required for all names and values\n");
6183 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6185 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6187 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6189 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6190 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6191 NULL
, NULL
, lpValue
, &cbValueLen
);
6192 if (ret
!= ERROR_SUCCESS
)
6194 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6195 WARN ("HeapFree failed with code %i\n", GetLastError ());
6196 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6197 WARN ("HeapFree failed with code %i\n", GetLastError ());
6198 r
= RegCloseKey (hkSubKey
);
6199 if (r
!= ERROR_SUCCESS
)
6200 WARN ("RegCloseKey returned %i\n", r
);
6201 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6205 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6206 debugstr_w (lpValueName
), dwIndex
,
6207 cbValueNameLen
+ 1, cbValueLen
);
6209 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6210 cbBufSize
+= cbValueLen
;
6213 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6215 *pcbEnumValues
= cbBufSize
;
6216 *pnEnumValues
= cValues
;
6218 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6220 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6221 WARN ("HeapFree failed with code %i\n", GetLastError ());
6222 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6223 WARN ("HeapFree failed with code %i\n", GetLastError ());
6224 r
= RegCloseKey (hkSubKey
);
6225 if (r
!= ERROR_SUCCESS
)
6226 WARN ("RegCloseKey returned %i\n", r
);
6227 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6228 return ERROR_MORE_DATA
;
6231 TRACE ("pass 2: copying all names and values to buffer\n");
6233 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6234 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6236 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6238 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6239 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6240 NULL
, &dwType
, lpValue
, &cbValueLen
);
6241 if (ret
!= ERROR_SUCCESS
)
6243 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6244 WARN ("HeapFree failed with code %i\n", GetLastError ());
6245 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6246 WARN ("HeapFree failed with code %i\n", GetLastError ());
6247 r
= RegCloseKey (hkSubKey
);
6248 if (r
!= ERROR_SUCCESS
)
6249 WARN ("RegCloseKey returned %i\n", r
);
6250 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6254 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6255 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6256 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6257 pEnumValues
+= cbValueNameLen
;
6259 /* return # of *bytes* (including trailing \0), not # of chars */
6260 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6262 ppev
[dwIndex
].dwType
= dwType
;
6264 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6265 ppev
[dwIndex
].pData
= pEnumValues
;
6266 pEnumValues
+= cbValueLen
;
6268 ppev
[dwIndex
].cbData
= cbValueLen
;
6270 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6271 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6274 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6276 ret
= GetLastError ();
6277 ERR ("HeapFree failed with code %i\n", ret
);
6278 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6279 WARN ("HeapFree failed with code %i\n", GetLastError ());
6280 r
= RegCloseKey (hkSubKey
);
6281 if (r
!= ERROR_SUCCESS
)
6282 WARN ("RegCloseKey returned %i\n", r
);
6286 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6288 ret
= GetLastError ();
6289 ERR ("HeapFree failed with code %i\n", ret
);
6290 r
= RegCloseKey (hkSubKey
);
6291 if (r
!= ERROR_SUCCESS
)
6292 WARN ("RegCloseKey returned %i\n", r
);
6296 ret
= RegCloseKey (hkSubKey
);
6297 if (ret
!= ERROR_SUCCESS
)
6299 ERR ("RegCloseKey returned %i\n", ret
);
6303 return ERROR_SUCCESS
;
6306 /*******************************************************************************
6307 * EnumPrinterDataExA [WINSPOOL.@]
6309 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6310 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6311 * what Windows 2000 SP1 does.
6314 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6315 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6316 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6320 DWORD ret
, dwIndex
, dwBufSize
;
6324 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6326 if (pKeyName
== NULL
|| *pKeyName
== 0)
6327 return ERROR_INVALID_PARAMETER
;
6329 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6332 ret
= GetLastError ();
6333 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6337 hHeap
= GetProcessHeap ();
6340 ERR ("GetProcessHeap failed\n");
6341 return ERROR_OUTOFMEMORY
;
6344 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6345 if (pKeyNameW
== NULL
)
6347 ERR ("Failed to allocate %i bytes from process heap\n",
6348 (LONG
)(len
* sizeof (WCHAR
)));
6349 return ERROR_OUTOFMEMORY
;
6352 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6354 ret
= GetLastError ();
6355 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6356 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6357 WARN ("HeapFree failed with code %i\n", GetLastError ());
6361 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6362 pcbEnumValues
, pnEnumValues
);
6363 if (ret
!= ERROR_SUCCESS
)
6365 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6366 WARN ("HeapFree failed with code %i\n", GetLastError ());
6367 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6371 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6373 ret
= GetLastError ();
6374 ERR ("HeapFree failed with code %i\n", ret
);
6378 if (*pnEnumValues
== 0) /* empty key */
6379 return ERROR_SUCCESS
;
6382 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6384 PPRINTER_ENUM_VALUESW ppev
=
6385 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6387 if (dwBufSize
< ppev
->cbValueName
)
6388 dwBufSize
= ppev
->cbValueName
;
6390 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6391 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6392 dwBufSize
= ppev
->cbData
;
6395 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6397 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6398 if (pBuffer
== NULL
)
6400 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6401 return ERROR_OUTOFMEMORY
;
6404 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6406 PPRINTER_ENUM_VALUESW ppev
=
6407 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6409 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6410 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6414 ret
= GetLastError ();
6415 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6416 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6417 WARN ("HeapFree failed with code %i\n", GetLastError ());
6421 memcpy (ppev
->pValueName
, pBuffer
, len
);
6423 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6425 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6426 ppev
->dwType
!= REG_MULTI_SZ
)
6429 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6430 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6433 ret
= GetLastError ();
6434 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6435 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6436 WARN ("HeapFree failed with code %i\n", GetLastError ());
6440 memcpy (ppev
->pData
, pBuffer
, len
);
6442 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6443 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6446 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6448 ret
= GetLastError ();
6449 ERR ("HeapFree failed with code %i\n", ret
);
6453 return ERROR_SUCCESS
;
6456 /******************************************************************************
6457 * AbortPrinter (WINSPOOL.@)
6459 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6461 FIXME("(%p), stub!\n", hPrinter
);
6465 /******************************************************************************
6466 * AddPortA (WINSPOOL.@)
6471 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6473 LPWSTR nameW
= NULL
;
6474 LPWSTR monitorW
= NULL
;
6478 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6481 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6482 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6483 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6487 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6488 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6489 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6491 res
= AddPortW(nameW
, hWnd
, monitorW
);
6492 HeapFree(GetProcessHeap(), 0, nameW
);
6493 HeapFree(GetProcessHeap(), 0, monitorW
);
6497 /******************************************************************************
6498 * AddPortW (WINSPOOL.@)
6500 * Add a Port for a specific Monitor
6503 * pName [I] Servername or NULL (local Computer)
6504 * hWnd [I] Handle to parent Window for the Dialog-Box
6505 * pMonitorName [I] Name of the Monitor that manage the Port
6512 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6518 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6520 if (pName
&& pName
[0]) {
6521 SetLastError(ERROR_INVALID_PARAMETER
);
6525 if (!pMonitorName
) {
6526 SetLastError(RPC_X_NULL_REF_POINTER
);
6530 /* an empty Monitorname is Invalid */
6531 if (!pMonitorName
[0]) {
6532 SetLastError(ERROR_NOT_SUPPORTED
);
6536 pm
= monitor_load(pMonitorName
, NULL
);
6537 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6538 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6539 TRACE("got %d with %u\n", res
, GetLastError());
6544 pui
= monitor_loadui(pm
);
6545 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6546 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6547 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6548 TRACE("got %d with %u\n", res
, GetLastError());
6553 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6554 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6556 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6557 SetLastError(ERROR_NOT_SUPPORTED
);
6560 monitor_unload(pui
);
6563 TRACE("returning %d with %u\n", res
, GetLastError());
6567 /******************************************************************************
6568 * AddPortExA (WINSPOOL.@)
6573 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6576 PORT_INFO_2A
* pi2A
;
6577 LPWSTR nameW
= NULL
;
6578 LPWSTR monitorW
= NULL
;
6582 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6584 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6585 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6587 if ((level
< 1) || (level
> 2)) {
6588 SetLastError(ERROR_INVALID_LEVEL
);
6593 SetLastError(ERROR_INVALID_PARAMETER
);
6598 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6599 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6600 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6604 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6605 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6606 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6609 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6611 if (pi2A
->pPortName
) {
6612 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6613 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6614 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6618 if (pi2A
->pMonitorName
) {
6619 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6620 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6621 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6624 if (pi2A
->pDescription
) {
6625 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6626 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6627 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6629 pi2W
.fPortType
= pi2A
->fPortType
;
6630 pi2W
.Reserved
= pi2A
->Reserved
;
6633 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6635 HeapFree(GetProcessHeap(), 0, nameW
);
6636 HeapFree(GetProcessHeap(), 0, monitorW
);
6637 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6638 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6639 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6644 /******************************************************************************
6645 * AddPortExW (WINSPOOL.@)
6647 * Add a Port for a specific Monitor, without presenting a user interface
6650 * pName [I] Servername or NULL (local Computer)
6651 * level [I] Structure-Level (1 or 2) for pBuffer
6652 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6653 * pMonitorName [I] Name of the Monitor that manage the Port
6660 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6666 pi2
= (PORT_INFO_2W
*) pBuffer
;
6668 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6669 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6670 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6671 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6674 if ((level
< 1) || (level
> 2)) {
6675 SetLastError(ERROR_INVALID_LEVEL
);
6679 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6680 SetLastError(ERROR_INVALID_PARAMETER
);
6684 /* load the Monitor */
6685 pm
= monitor_load(pMonitorName
, NULL
);
6687 SetLastError(ERROR_INVALID_PARAMETER
);
6691 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6692 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6693 TRACE("got %u with %u\n", res
, GetLastError());
6697 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6703 /******************************************************************************
6704 * AddPrinterConnectionA (WINSPOOL.@)
6706 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6708 FIXME("%s\n", debugstr_a(pName
));
6712 /******************************************************************************
6713 * AddPrinterConnectionW (WINSPOOL.@)
6715 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6717 FIXME("%s\n", debugstr_w(pName
));
6721 /******************************************************************************
6722 * AddPrinterDriverExW (WINSPOOL.@)
6724 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6727 * pName [I] Servername or NULL (local Computer)
6728 * level [I] Level for the supplied DRIVER_INFO_*W struct
6729 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6730 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6737 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6739 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6741 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6743 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6744 SetLastError(ERROR_INVALID_LEVEL
);
6749 SetLastError(ERROR_INVALID_PARAMETER
);
6753 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6756 /******************************************************************************
6757 * AddPrinterDriverExA (WINSPOOL.@)
6759 * See AddPrinterDriverExW.
6762 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6764 DRIVER_INFO_8A
*diA
;
6766 LPWSTR nameW
= NULL
;
6771 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6773 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6774 ZeroMemory(&diW
, sizeof(diW
));
6776 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6777 SetLastError(ERROR_INVALID_LEVEL
);
6782 SetLastError(ERROR_INVALID_PARAMETER
);
6786 /* convert servername to unicode */
6788 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6789 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6790 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6794 diW
.cVersion
= diA
->cVersion
;
6797 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6798 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6799 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6802 if (diA
->pEnvironment
) {
6803 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6804 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6805 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6808 if (diA
->pDriverPath
) {
6809 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6810 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6811 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6814 if (diA
->pDataFile
) {
6815 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6816 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6817 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6820 if (diA
->pConfigFile
) {
6821 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6822 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6823 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6826 if ((Level
> 2) && diA
->pDependentFiles
) {
6827 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6828 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6829 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6830 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6833 if ((Level
> 2) && diA
->pMonitorName
) {
6834 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6835 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6836 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6839 if ((Level
> 3) && diA
->pDefaultDataType
) {
6840 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6841 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6842 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6845 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6846 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6847 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6848 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6849 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6852 if ((Level
> 5) && diA
->pszMfgName
) {
6853 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6854 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6855 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6858 if ((Level
> 5) && diA
->pszOEMUrl
) {
6859 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6860 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6861 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6864 if ((Level
> 5) && diA
->pszHardwareID
) {
6865 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6866 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6867 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6870 if ((Level
> 5) && diA
->pszProvider
) {
6871 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6872 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6873 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6877 FIXME("level %u is incomplete\n", Level
);
6880 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6881 TRACE("got %u with %u\n", res
, GetLastError());
6882 HeapFree(GetProcessHeap(), 0, nameW
);
6883 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6884 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6885 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6886 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6887 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6888 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6889 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6890 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6891 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6892 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6893 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6894 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6895 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6897 TRACE("=> %u with %u\n", res
, GetLastError());
6901 /******************************************************************************
6902 * ConfigurePortA (WINSPOOL.@)
6904 * See ConfigurePortW.
6907 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6909 LPWSTR nameW
= NULL
;
6910 LPWSTR portW
= NULL
;
6914 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6916 /* convert servername to unicode */
6918 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6919 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6920 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6923 /* convert portname to unicode */
6925 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6926 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6927 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6930 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6931 HeapFree(GetProcessHeap(), 0, nameW
);
6932 HeapFree(GetProcessHeap(), 0, portW
);
6936 /******************************************************************************
6937 * ConfigurePortW (WINSPOOL.@)
6939 * Display the Configuration-Dialog for a specific Port
6942 * pName [I] Servername or NULL (local Computer)
6943 * hWnd [I] Handle to parent Window for the Dialog-Box
6944 * pPortName [I] Name of the Port, that should be configured
6951 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6957 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6959 if (pName
&& pName
[0]) {
6960 SetLastError(ERROR_INVALID_PARAMETER
);
6965 SetLastError(RPC_X_NULL_REF_POINTER
);
6969 /* an empty Portname is Invalid, but can popup a Dialog */
6970 if (!pPortName
[0]) {
6971 SetLastError(ERROR_NOT_SUPPORTED
);
6975 pm
= monitor_load_by_port(pPortName
);
6976 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6977 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6978 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6979 TRACE("got %d with %u\n", res
, GetLastError());
6983 pui
= monitor_loadui(pm
);
6984 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6985 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6986 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6987 TRACE("got %d with %u\n", res
, GetLastError());
6991 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6992 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6994 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6995 SetLastError(ERROR_NOT_SUPPORTED
);
6998 monitor_unload(pui
);
7002 TRACE("returning %d with %u\n", res
, GetLastError());
7006 /******************************************************************************
7007 * ConnectToPrinterDlg (WINSPOOL.@)
7009 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7011 FIXME("%p %x\n", hWnd
, Flags
);
7015 /******************************************************************************
7016 * DeletePrinterConnectionA (WINSPOOL.@)
7018 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7020 FIXME("%s\n", debugstr_a(pName
));
7024 /******************************************************************************
7025 * DeletePrinterConnectionW (WINSPOOL.@)
7027 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7029 FIXME("%s\n", debugstr_w(pName
));
7033 /******************************************************************************
7034 * DeletePrinterDriverExW (WINSPOOL.@)
7036 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7037 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7042 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7043 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7045 if(pName
&& pName
[0])
7047 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7048 SetLastError(ERROR_INVALID_PARAMETER
);
7054 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7055 SetLastError(ERROR_INVALID_PARAMETER
);
7059 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
7063 ERR("Can't open drivers key\n");
7067 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7070 RegCloseKey(hkey_drivers
);
7075 /******************************************************************************
7076 * DeletePrinterDriverExA (WINSPOOL.@)
7078 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7079 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7081 UNICODE_STRING NameW
, EnvW
, DriverW
;
7084 asciitounicode(&NameW
, pName
);
7085 asciitounicode(&EnvW
, pEnvironment
);
7086 asciitounicode(&DriverW
, pDriverName
);
7088 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7090 RtlFreeUnicodeString(&DriverW
);
7091 RtlFreeUnicodeString(&EnvW
);
7092 RtlFreeUnicodeString(&NameW
);
7097 /******************************************************************************
7098 * DeletePrinterDataExW (WINSPOOL.@)
7100 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7103 FIXME("%p %s %s\n", hPrinter
,
7104 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7105 return ERROR_INVALID_PARAMETER
;
7108 /******************************************************************************
7109 * DeletePrinterDataExA (WINSPOOL.@)
7111 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7114 FIXME("%p %s %s\n", hPrinter
,
7115 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7116 return ERROR_INVALID_PARAMETER
;
7119 /******************************************************************************
7120 * DeletePrintProcessorA (WINSPOOL.@)
7122 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7124 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7125 debugstr_a(pPrintProcessorName
));
7129 /******************************************************************************
7130 * DeletePrintProcessorW (WINSPOOL.@)
7132 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7134 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7135 debugstr_w(pPrintProcessorName
));
7139 /******************************************************************************
7140 * DeletePrintProvidorA (WINSPOOL.@)
7142 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7144 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7145 debugstr_a(pPrintProviderName
));
7149 /******************************************************************************
7150 * DeletePrintProvidorW (WINSPOOL.@)
7152 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7154 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7155 debugstr_w(pPrintProviderName
));
7159 /******************************************************************************
7160 * EnumFormsA (WINSPOOL.@)
7162 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7163 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7165 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7166 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7170 /******************************************************************************
7171 * EnumFormsW (WINSPOOL.@)
7173 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7174 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7176 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7177 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7181 /*****************************************************************************
7182 * EnumMonitorsA [WINSPOOL.@]
7184 * See EnumMonitorsW.
7187 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7188 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7191 LPBYTE bufferW
= NULL
;
7192 LPWSTR nameW
= NULL
;
7194 DWORD numentries
= 0;
7197 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7198 cbBuf
, pcbNeeded
, pcReturned
);
7200 /* convert servername to unicode */
7202 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7203 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7204 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7206 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7207 needed
= cbBuf
* sizeof(WCHAR
);
7208 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7209 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7211 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7212 if (pcbNeeded
) needed
= *pcbNeeded
;
7213 /* HeapReAlloc return NULL, when bufferW was NULL */
7214 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7215 HeapAlloc(GetProcessHeap(), 0, needed
);
7217 /* Try again with the large Buffer */
7218 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7220 numentries
= pcReturned
? *pcReturned
: 0;
7223 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7224 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7227 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7228 DWORD entrysize
= 0;
7231 LPMONITOR_INFO_2W mi2w
;
7232 LPMONITOR_INFO_2A mi2a
;
7234 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7235 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7237 /* First pass: calculate the size for all Entries */
7238 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7239 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7241 while (index
< numentries
) {
7243 needed
+= entrysize
; /* MONITOR_INFO_?A */
7244 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7246 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7247 NULL
, 0, NULL
, NULL
);
7249 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7250 NULL
, 0, NULL
, NULL
);
7251 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7252 NULL
, 0, NULL
, NULL
);
7254 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7255 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7256 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7259 /* check for errors and quit on failure */
7260 if (cbBuf
< needed
) {
7261 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7265 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7266 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7267 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7268 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7269 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7271 /* Second Pass: Fill the User Buffer (if we have one) */
7272 while ((index
< numentries
) && pMonitors
) {
7274 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7276 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7277 ptr
, cbBuf
, NULL
, NULL
);
7281 mi2a
->pEnvironment
= ptr
;
7282 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7283 ptr
, cbBuf
, NULL
, NULL
);
7287 mi2a
->pDLLName
= ptr
;
7288 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7289 ptr
, cbBuf
, NULL
, NULL
);
7293 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7294 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7295 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7299 if (pcbNeeded
) *pcbNeeded
= needed
;
7300 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7302 HeapFree(GetProcessHeap(), 0, nameW
);
7303 HeapFree(GetProcessHeap(), 0, bufferW
);
7305 TRACE("returning %d with %d (%d byte for %d entries)\n",
7306 (res
), GetLastError(), needed
, numentries
);
7312 /*****************************************************************************
7313 * EnumMonitorsW [WINSPOOL.@]
7315 * Enumerate available Port-Monitors
7318 * pName [I] Servername or NULL (local Computer)
7319 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7320 * pMonitors [O] PTR to Buffer that receives the Result
7321 * cbBuf [I] Size of Buffer at pMonitors
7322 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7323 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7327 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7330 * Windows reads the Registry once and cache the Results.
7332 *| Language-Monitors are also installed in the same Registry-Location but
7333 *| they are filtered in Windows (not returned by EnumMonitors).
7334 *| We do no filtering to simplify our Code.
7337 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7338 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7341 DWORD numentries
= 0;
7344 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7345 cbBuf
, pcbNeeded
, pcReturned
);
7347 if (pName
&& (lstrlenW(pName
))) {
7348 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
7349 SetLastError(ERROR_ACCESS_DENIED
);
7353 /* Level is not checked in win9x */
7354 if (!Level
|| (Level
> 2)) {
7355 WARN("level (%d) is ignored in win9x\n", Level
);
7356 SetLastError(ERROR_INVALID_LEVEL
);
7360 SetLastError(RPC_X_NULL_REF_POINTER
);
7364 /* Scan all Monitor-Keys */
7366 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
7368 /* we calculated the needed buffersize. now do the error-checks */
7369 if (cbBuf
< needed
) {
7370 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7373 else if (!pMonitors
|| !pcReturned
) {
7374 SetLastError(RPC_X_NULL_REF_POINTER
);
7378 /* fill the Buffer with the Monitor-Keys */
7379 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
7383 if (pcbNeeded
) *pcbNeeded
= needed
;
7384 if (pcReturned
) *pcReturned
= numentries
;
7386 TRACE("returning %d with %d (%d byte for %d entries)\n",
7387 res
, GetLastError(), needed
, numentries
);
7392 /******************************************************************************
7393 * SpoolerInit (WINSPOOL.@)
7395 * Initialize the Spooler
7402 * The function fails on windows, when the spooler service is not running
7405 BOOL WINAPI
SpoolerInit(void)
7408 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7412 /******************************************************************************
7413 * XcvDataW (WINSPOOL.@)
7415 * Execute commands in the Printmonitor DLL
7418 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7419 * pszDataName [i] Name of the command to execute
7420 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7421 * cbInputData [i] Size in Bytes of Buffer at pInputData
7422 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7423 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7424 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7425 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7432 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7433 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7435 * Minimal List of commands, that a Printmonitor DLL should support:
7437 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7438 *| "AddPort" : Add a Port
7439 *| "DeletePort": Delete a Port
7441 * Many Printmonitors support additional commands. Examples for localspl.dll:
7442 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7443 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7446 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7447 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7448 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7450 opened_printer_t
*printer
;
7452 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7453 pInputData
, cbInputData
, pOutputData
,
7454 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7456 printer
= get_opened_printer(hXcv
);
7457 if (!printer
|| (!printer
->hXcv
)) {
7458 SetLastError(ERROR_INVALID_HANDLE
);
7462 if (!pcbOutputNeeded
) {
7463 SetLastError(ERROR_INVALID_PARAMETER
);
7467 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7468 SetLastError(RPC_X_NULL_REF_POINTER
);
7472 *pcbOutputNeeded
= 0;
7474 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
7475 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
7480 /*****************************************************************************
7481 * EnumPrinterDataA [WINSPOOL.@]
7484 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7485 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7486 DWORD cbData
, LPDWORD pcbData
)
7488 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7489 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7490 return ERROR_NO_MORE_ITEMS
;
7493 /*****************************************************************************
7494 * EnumPrinterDataW [WINSPOOL.@]
7497 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7498 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7499 DWORD cbData
, LPDWORD pcbData
)
7501 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7502 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7503 return ERROR_NO_MORE_ITEMS
;
7506 /*****************************************************************************
7507 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7510 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7511 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7512 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7514 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7515 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7516 pcbNeeded
, pcReturned
);
7520 /*****************************************************************************
7521 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7524 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7525 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7526 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7528 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7529 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7530 pcbNeeded
, pcReturned
);
7534 /*****************************************************************************
7535 * EnumPrintProcessorsA [WINSPOOL.@]
7538 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7539 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7541 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7542 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7546 /*****************************************************************************
7547 * EnumPrintProcessorsW [WINSPOOL.@]
7550 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7551 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7553 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7554 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7555 cbBuf
, pcbNeeded
, pcbReturned
);
7559 /*****************************************************************************
7560 * ExtDeviceMode [WINSPOOL.@]
7563 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7564 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7567 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7568 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7569 debugstr_a(pProfile
), fMode
);
7573 /*****************************************************************************
7574 * FindClosePrinterChangeNotification [WINSPOOL.@]
7577 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7579 FIXME("Stub: %p\n", hChange
);
7583 /*****************************************************************************
7584 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7587 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7588 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7590 FIXME("Stub: %p %x %x %p\n",
7591 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7592 return INVALID_HANDLE_VALUE
;
7595 /*****************************************************************************
7596 * FindNextPrinterChangeNotification [WINSPOOL.@]
7599 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7600 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7602 FIXME("Stub: %p %p %p %p\n",
7603 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7607 /*****************************************************************************
7608 * FreePrinterNotifyInfo [WINSPOOL.@]
7611 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7613 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7617 /*****************************************************************************
7620 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7621 * ansi depending on the unicode parameter.
7623 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7633 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7636 memcpy(ptr
, str
, *size
);
7643 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7646 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7653 /*****************************************************************************
7656 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7657 LPDWORD pcbNeeded
, BOOL unicode
)
7659 DWORD size
, left
= cbBuf
;
7660 BOOL space
= (cbBuf
> 0);
7667 ji1
->JobId
= job
->job_id
;
7670 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7671 if(space
&& size
<= left
)
7673 ji1
->pDocument
= (LPWSTR
)ptr
;
7684 /*****************************************************************************
7687 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7688 LPDWORD pcbNeeded
, BOOL unicode
)
7690 DWORD size
, left
= cbBuf
;
7691 BOOL space
= (cbBuf
> 0);
7698 ji2
->JobId
= job
->job_id
;
7701 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7702 if(space
&& size
<= left
)
7704 ji2
->pDocument
= (LPWSTR
)ptr
;
7715 /*****************************************************************************
7718 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7719 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7722 DWORD needed
= 0, size
;
7726 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7728 EnterCriticalSection(&printer_handles_cs
);
7729 job
= get_job(hPrinter
, JobId
);
7736 size
= sizeof(JOB_INFO_1W
);
7741 memset(pJob
, 0, size
);
7745 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7750 size
= sizeof(JOB_INFO_2W
);
7755 memset(pJob
, 0, size
);
7759 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7764 size
= sizeof(JOB_INFO_3
);
7768 memset(pJob
, 0, size
);
7777 SetLastError(ERROR_INVALID_LEVEL
);
7781 *pcbNeeded
= needed
;
7783 LeaveCriticalSection(&printer_handles_cs
);
7787 /*****************************************************************************
7788 * GetJobA [WINSPOOL.@]
7791 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7792 DWORD cbBuf
, LPDWORD pcbNeeded
)
7794 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7797 /*****************************************************************************
7798 * GetJobW [WINSPOOL.@]
7801 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7802 DWORD cbBuf
, LPDWORD pcbNeeded
)
7804 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7807 /*****************************************************************************
7810 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7812 char *unixname
, *queue
, *cmd
;
7813 char fmt
[] = "lpr -P%s %s";
7816 if(!(unixname
= wine_get_unix_file_name(filename
)))
7819 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7820 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7821 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7823 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7824 sprintf(cmd
, fmt
, queue
, unixname
);
7826 TRACE("printing with: %s\n", cmd
);
7829 HeapFree(GetProcessHeap(), 0, cmd
);
7830 HeapFree(GetProcessHeap(), 0, queue
);
7831 HeapFree(GetProcessHeap(), 0, unixname
);
7835 /*****************************************************************************
7838 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7840 #ifdef SONAME_LIBCUPS
7843 char *unixname
, *queue
, *doc_titleA
;
7847 if(!(unixname
= wine_get_unix_file_name(filename
)))
7850 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7851 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7852 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7854 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7855 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7856 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7858 TRACE("printing via cups\n");
7859 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7860 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7861 HeapFree(GetProcessHeap(), 0, queue
);
7862 HeapFree(GetProcessHeap(), 0, unixname
);
7868 return schedule_lpr(printer_name
, filename
);
7872 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7879 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7883 if(HIWORD(wparam
) == BN_CLICKED
)
7885 if(LOWORD(wparam
) == IDOK
)
7888 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7891 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7892 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7894 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7896 WCHAR caption
[200], message
[200];
7899 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7900 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7901 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7902 if(mb_ret
== IDCANCEL
)
7904 HeapFree(GetProcessHeap(), 0, filename
);
7908 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7909 if(hf
== INVALID_HANDLE_VALUE
)
7911 WCHAR caption
[200], message
[200];
7913 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7914 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7915 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7916 HeapFree(GetProcessHeap(), 0, filename
);
7920 DeleteFileW(filename
);
7921 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7923 EndDialog(hwnd
, IDOK
);
7926 if(LOWORD(wparam
) == IDCANCEL
)
7928 EndDialog(hwnd
, IDCANCEL
);
7937 /*****************************************************************************
7940 static BOOL
get_filename(LPWSTR
*filename
)
7942 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7943 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7946 /*****************************************************************************
7949 static BOOL
schedule_file(LPCWSTR filename
)
7951 LPWSTR output
= NULL
;
7953 if(get_filename(&output
))
7955 TRACE("copy to %s\n", debugstr_w(output
));
7956 CopyFileW(filename
, output
, FALSE
);
7957 HeapFree(GetProcessHeap(), 0, output
);
7963 /*****************************************************************************
7966 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7969 char *unixname
, *cmdA
;
7971 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7975 if(!(unixname
= wine_get_unix_file_name(filename
)))
7978 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7979 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7980 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7982 TRACE("printing with: %s\n", cmdA
);
7984 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7989 ERR("pipe() failed!\n");
7999 /* reset signals that we previously set to SIG_IGN */
8000 signal(SIGPIPE
, SIG_DFL
);
8001 signal(SIGCHLD
, SIG_DFL
);
8003 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
8007 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8008 write(fds
[1], buf
, no_read
);
8013 if(file_fd
!= -1) close(file_fd
);
8014 if(fds
[0] != -1) close(fds
[0]);
8015 if(fds
[1] != -1) close(fds
[1]);
8017 HeapFree(GetProcessHeap(), 0, cmdA
);
8018 HeapFree(GetProcessHeap(), 0, unixname
);
8025 /*****************************************************************************
8028 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8030 int in_fd
, out_fd
, no_read
;
8033 char *unixname
, *outputA
;
8036 if(!(unixname
= wine_get_unix_file_name(filename
)))
8039 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8040 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8041 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8043 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8044 in_fd
= open(unixname
, O_RDONLY
);
8045 if(out_fd
== -1 || in_fd
== -1)
8048 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8049 write(out_fd
, buf
, no_read
);
8053 if(in_fd
!= -1) close(in_fd
);
8054 if(out_fd
!= -1) close(out_fd
);
8055 HeapFree(GetProcessHeap(), 0, outputA
);
8056 HeapFree(GetProcessHeap(), 0, unixname
);
8060 /*****************************************************************************
8061 * ScheduleJob [WINSPOOL.@]
8064 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8066 opened_printer_t
*printer
;
8068 struct list
*cursor
, *cursor2
;
8070 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8071 EnterCriticalSection(&printer_handles_cs
);
8072 printer
= get_opened_printer(hPrinter
);
8076 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8078 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8081 if(job
->job_id
!= dwJobID
) continue;
8083 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8084 if(hf
!= INVALID_HANDLE_VALUE
)
8086 PRINTER_INFO_5W
*pi5
;
8090 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8091 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8093 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8094 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8095 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8096 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8097 debugstr_w(pi5
->pPortName
));
8101 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8102 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8104 DWORD type
, count
= sizeof(output
);
8105 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
8108 if(output
[0] == '|')
8110 schedule_pipe(output
+ 1, job
->filename
);
8114 schedule_unixfile(output
, job
->filename
);
8116 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
8118 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
8120 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
8122 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8124 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
8126 schedule_file(job
->filename
);
8130 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
8132 HeapFree(GetProcessHeap(), 0, pi5
);
8134 DeleteFileW(job
->filename
);
8136 list_remove(cursor
);
8137 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8138 HeapFree(GetProcessHeap(), 0, job
->filename
);
8139 HeapFree(GetProcessHeap(), 0, job
);
8144 LeaveCriticalSection(&printer_handles_cs
);
8148 /*****************************************************************************
8149 * StartDocDlgA [WINSPOOL.@]
8151 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8153 UNICODE_STRING usBuffer
;
8156 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8159 docW
.cbSize
= sizeof(docW
);
8160 if (doc
->lpszDocName
)
8162 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8163 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
8165 if (doc
->lpszOutput
)
8167 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8168 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
8170 if (doc
->lpszDatatype
)
8172 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8173 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8175 docW
.fwType
= doc
->fwType
;
8177 retW
= StartDocDlgW(hPrinter
, &docW
);
8181 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8182 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8183 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8184 HeapFree(GetProcessHeap(), 0, retW
);
8187 HeapFree(GetProcessHeap(), 0, datatypeW
);
8188 HeapFree(GetProcessHeap(), 0, outputW
);
8189 HeapFree(GetProcessHeap(), 0, docnameW
);
8194 /*****************************************************************************
8195 * StartDocDlgW [WINSPOOL.@]
8197 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8198 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8199 * port is "FILE:". Also returns the full path if passed a relative path.
8201 * The caller should free the returned string from the process heap.
8203 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8208 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8210 PRINTER_INFO_5W
*pi5
;
8211 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8212 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8214 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8215 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8216 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8218 HeapFree(GetProcessHeap(), 0, pi5
);
8221 HeapFree(GetProcessHeap(), 0, pi5
);
8224 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8228 if (get_filename(&name
))
8230 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8232 HeapFree(GetProcessHeap(), 0, name
);
8235 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8236 GetFullPathNameW(name
, len
, ret
, NULL
);
8237 HeapFree(GetProcessHeap(), 0, name
);
8242 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8245 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8246 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8248 attr
= GetFileAttributesW(ret
);
8249 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8251 HeapFree(GetProcessHeap(), 0, ret
);