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-2009 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_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
199 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
200 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
201 static const WCHAR subdir_x64W[] = {'x','6','4',0};
202 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
203 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
204 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
205 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
206 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
208 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
209 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
211 static const WCHAR backslashW[] = {'\\',0};
212 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
213 'i','o','n',' ','F','i','l','e',0};
214 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
215 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
216 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
217 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
218 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
219 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
220 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
221 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
222 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
223 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
224 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
225 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
226 static const WCHAR NameW[] = {'N','a','m','e',0};
227 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
228 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
229 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
230 static const WCHAR PortW[] = {'P','o','r','t',0};
231 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
232 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
233 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
234 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
235 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
236 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
237 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
238 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
239 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
240 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
241 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
242 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
243 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
244 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
245 static const WCHAR emptyStringW[] = {0};
246 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
247 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
249 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
251 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
252 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
253 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
255 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
256 'D','o','c','u','m','e','n','t',0};
258 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
259 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
260 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
261 0, sizeof(DRIVER_INFO_8W)};
264 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
265 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
266 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
267 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
268 sizeof(PRINTER_INFO_9W)};
270 /******************************************************************
271 * validate the user-supplied printing-environment [internal]
274 * env [I] PTR to Environment-String or NULL
278 * Success: PTR to printenv_t
281 * An empty string is handled the same way as NULL.
282 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
286 static const printenv_t * validate_envW(LPCWSTR env)
288 static const printenv_t env_x64 = {envname_x64W, subdir_x64W,
289 3, Version3_RegPathW, Version3_SubdirW};
290 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
291 3, Version3_RegPathW, Version3_SubdirW};
292 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
293 0, Version0_RegPathW, Version0_SubdirW};
295 static const printenv_t * const all_printenv[]={&env_x86, &env_x64, &env_win40};
297 const printenv_t *result = NULL;
300 TRACE("testing %s\n", debugstr_w(env));
303 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
305 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
307 result = all_printenv[i];
312 if (result == NULL) {
313 FIXME("unsupported Environment: %s\n", debugstr_w(env));
314 SetLastError(ERROR_INVALID_ENVIRONMENT);
316 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
320 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
322 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
328 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
329 if passed a NULL string. This returns NULLs to the result.
331 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
335 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
336 return usBufferPtr->Buffer;
338 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
342 static LPWSTR strdupW(LPCWSTR p)
348 len = (strlenW(p) + 1) * sizeof(WCHAR);
349 ret = HeapAlloc(GetProcessHeap(), 0, len);
354 static LPSTR strdupWtoA( LPCWSTR str )
359 if (!str) return NULL;
360 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
361 ret = HeapAlloc( GetProcessHeap(), 0, len );
362 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
366 /******************************************************************
367 * Return the number of bytes for an multi_sz string.
368 * The result includes all \0s
369 * (specifically the extra \0, that is needed as multi_sz terminator).
372 static int multi_sz_lenW(const WCHAR *str)
374 const WCHAR *ptr = str;
378 ptr += lstrlenW(ptr) + 1;
381 return (ptr - str + 1) * sizeof(WCHAR);
384 /* ################################ */
386 static int multi_sz_lenA(const char *str)
388 const char *ptr = str;
392 ptr += lstrlenA(ptr) + 1;
395 return ptr - str + 1;
399 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
402 /* If forcing, or no profile string entry for device yet, set the entry
404 * The always change entry if not WINEPS yet is discussable.
407 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
409 !strstr(qbuf,"WINEPS.DRV")
411 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
414 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
415 WriteProfileStringA("windows","device",buf);
416 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
417 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
420 HeapFree(GetProcessHeap(),0,buf);
424 static BOOL add_printer_driver(const char *name)
428 static char driver_9x[] = "wineps16.drv",
429 driver_nt[] = "wineps.drv",
430 env_9x[] = "Windows 4.0",
431 env_nt[] = "Windows NT x86",
432 data_file[] = "generic.ppd",
433 default_data_type[] = "RAW";
435 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
437 di3a.pName = (char *)name;
438 di3a.pEnvironment = env_nt;
439 di3a.pDriverPath = driver_nt;
440 di3a.pDataFile = data_file;
441 di3a.pConfigFile = driver_nt;
442 di3a.pDefaultDataType = default_data_type;
444 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
445 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
448 di3a.pEnvironment = env_9x;
449 di3a.pDriverPath = driver_9x;
450 di3a.pConfigFile = driver_9x;
451 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
452 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
457 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
458 debugstr_a(di3a.pEnvironment), GetLastError());
462 #ifdef SONAME_LIBCUPS
463 static typeof(cupsGetDests) *pcupsGetDests;
464 static typeof(cupsGetPPD) *pcupsGetPPD;
465 static typeof(cupsPrintFile) *pcupsPrintFile;
466 static void *cupshandle;
468 static BOOL CUPS_LoadPrinters(void)
471 BOOL hadprinter = FALSE, haddefault = FALSE;
473 PRINTER_INFO_2A pinfo2a;
475 HKEY hkeyPrinter, hkeyPrinters, hkey;
478 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
480 TRACE("%s\n", loaderror);
483 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
486 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
487 if (!p##x) return FALSE;
490 DYNCUPS(cupsGetDests);
491 DYNCUPS(cupsPrintFile);
494 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
496 ERR("Can't create Printers key\n");
500 nrofdests = pcupsGetDests(&dests);
501 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
502 for (i=0;i<nrofdests;i++) {
503 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
504 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
505 sprintf(port,"LPR:%s", dests[i].name);
506 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
507 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
508 sprintf(devline, "WINEPS.DRV,%s", port);
509 WriteProfileStringA("devices", dests[i].name, devline);
510 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
511 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
515 lstrcatA(devline, ",15,45");
516 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
517 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
518 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
522 HeapFree(GetProcessHeap(), 0, devline);
524 TRACE("Printer %d: %s\n", i, dests[i].name);
525 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
526 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
528 TRACE("Printer already exists\n");
529 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
530 RegCloseKey(hkeyPrinter);
532 static CHAR data_type[] = "RAW",
533 print_proc[] = "WinPrint",
534 comment[] = "WINEPS Printer using CUPS",
535 location[] = "<physical location of printer>",
536 params[] = "<parameters?>",
537 share_name[] = "<share name?>",
538 sep_file[] = "<sep file?>";
540 add_printer_driver(dests[i].name);
542 memset(&pinfo2a,0,sizeof(pinfo2a));
543 pinfo2a.pPrinterName = dests[i].name;
544 pinfo2a.pDatatype = data_type;
545 pinfo2a.pPrintProcessor = print_proc;
546 pinfo2a.pDriverName = dests[i].name;
547 pinfo2a.pComment = comment;
548 pinfo2a.pLocation = location;
549 pinfo2a.pPortName = port;
550 pinfo2a.pParameters = params;
551 pinfo2a.pShareName = share_name;
552 pinfo2a.pSepFile = sep_file;
554 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
555 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
556 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
559 HeapFree(GetProcessHeap(),0,port);
562 if (dests[i].is_default) {
563 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
567 if (hadprinter & !haddefault)
568 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
569 RegCloseKey(hkeyPrinters);
575 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
576 PRINTER_INFO_2A pinfo2a;
577 char *e,*s,*name,*prettyname,*devname;
578 BOOL ret = FALSE, set_default = FALSE;
579 char *port = NULL, *devline,*env_default;
580 HKEY hkeyPrinter, hkeyPrinters, hkey;
582 while (isspace(*pent)) pent++;
583 s = strchr(pent,':');
585 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
593 TRACE("name=%s entry=%s\n",name, pent);
595 if(ispunct(*name)) { /* a tc entry, not a real printer */
596 TRACE("skipping tc entry\n");
600 if(strstr(pent,":server")) { /* server only version so skip */
601 TRACE("skipping server entry\n");
605 /* Determine whether this is a postscript printer. */
608 env_default = getenv("PRINTER");
610 /* Get longest name, usually the one at the right for later display. */
611 while((s=strchr(prettyname,'|'))) {
614 while(isspace(*--e)) *e = '\0';
615 TRACE("\t%s\n", debugstr_a(prettyname));
616 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
617 for(prettyname = s+1; isspace(*prettyname); prettyname++)
620 e = prettyname + strlen(prettyname);
621 while(isspace(*--e)) *e = '\0';
622 TRACE("\t%s\n", debugstr_a(prettyname));
623 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
625 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
626 * if it is too long, we use it as comment below. */
627 devname = prettyname;
628 if (strlen(devname)>=CCHDEVICENAME-1)
630 if (strlen(devname)>=CCHDEVICENAME-1) {
635 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
636 sprintf(port,"LPR:%s",name);
638 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
639 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
640 sprintf(devline, "WINEPS.DRV,%s", port);
641 WriteProfileStringA("devices", devname, devline);
642 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
643 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
647 lstrcatA(devline, ",15,45");
648 WriteProfileStringA("PrinterPorts", devname, devline);
649 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
650 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
654 HeapFree(GetProcessHeap(),0,devline);
656 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
658 ERR("Can't create Printers key\n");
662 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
663 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
665 TRACE("Printer already exists\n");
666 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
667 RegCloseKey(hkeyPrinter);
669 static CHAR data_type[] = "RAW",
670 print_proc[] = "WinPrint",
671 comment[] = "WINEPS Printer using LPR",
672 params[] = "<parameters?>",
673 share_name[] = "<share name?>",
674 sep_file[] = "<sep file?>";
676 add_printer_driver(devname);
678 memset(&pinfo2a,0,sizeof(pinfo2a));
679 pinfo2a.pPrinterName = devname;
680 pinfo2a.pDatatype = data_type;
681 pinfo2a.pPrintProcessor = print_proc;
682 pinfo2a.pDriverName = devname;
683 pinfo2a.pComment = comment;
684 pinfo2a.pLocation = prettyname;
685 pinfo2a.pPortName = port;
686 pinfo2a.pParameters = params;
687 pinfo2a.pShareName = share_name;
688 pinfo2a.pSepFile = sep_file;
690 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
691 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
692 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
695 RegCloseKey(hkeyPrinters);
697 if (isfirst || set_default)
698 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
701 HeapFree(GetProcessHeap(), 0, port);
702 HeapFree(GetProcessHeap(), 0, name);
707 PRINTCAP_LoadPrinters(void) {
708 BOOL hadprinter = FALSE;
712 BOOL had_bash = FALSE;
714 f = fopen("/etc/printcap","r");
718 while(fgets(buf,sizeof(buf),f)) {
721 end=strchr(buf,'\n');
725 while(isspace(*start)) start++;
726 if(*start == '#' || *start == '\0')
729 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
730 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
731 HeapFree(GetProcessHeap(),0,pent);
735 if (end && *--end == '\\') {
742 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
745 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
751 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
752 HeapFree(GetProcessHeap(),0,pent);
758 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
761 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
762 (lstrlenW(value) + 1) * sizeof(WCHAR));
764 return ERROR_FILE_NOT_FOUND;
767 /******************************************************************
768 * monitor_unload [internal]
770 * release a printmonitor and unload it from memory, when needed
773 static void monitor_unload(monitor_t * pm)
775 if (pm == NULL) return;
776 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
778 EnterCriticalSection(&monitor_handles_cs);
780 if (pm->refcount) pm->refcount--;
782 if (pm->refcount == 0) {
783 list_remove(&pm->entry);
784 FreeLibrary(pm->hdll);
785 HeapFree(GetProcessHeap(), 0, pm->name);
786 HeapFree(GetProcessHeap(), 0, pm->dllname);
787 HeapFree(GetProcessHeap(), 0, pm);
789 LeaveCriticalSection(&monitor_handles_cs);
792 /******************************************************************
793 * monitor_load [internal]
795 * load a printmonitor, get the dllname from the registry, when needed
796 * initialize the monitor and dump found function-pointers
798 * On failure, SetLastError() is called and NULL is returned
801 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
803 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
804 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
805 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
806 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
807 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
809 monitor_t * pm = NULL;
811 LPWSTR regroot = NULL;
812 LPWSTR driver = dllname;
814 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
815 /* Is the Monitor already loaded? */
816 EnterCriticalSection(&monitor_handles_cs);
819 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
821 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
829 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
830 if (pm == NULL) goto cleanup;
831 list_add_tail(&monitor_handles, &pm->entry);
835 if (pm->name == NULL) {
836 /* Load the monitor */
837 LPMONITOREX pmonitorEx;
841 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
842 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
846 lstrcpyW(regroot, MonitorsW);
847 lstrcatW(regroot, name);
848 /* Get the Driver from the Registry */
849 if (driver == NULL) {
852 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
853 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
854 &namesize) == ERROR_SUCCESS) {
855 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
856 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
863 pm->name = strdupW(name);
864 pm->dllname = strdupW(driver);
866 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
868 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
873 pm->hdll = LoadLibraryW(driver);
874 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
876 if (pm->hdll == NULL) {
878 SetLastError(ERROR_MOD_NOT_FOUND);
883 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
884 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
885 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
886 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
887 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
890 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
891 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
892 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
893 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
894 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
896 if (pInitializePrintMonitorUI != NULL) {
897 pm->monitorUI = pInitializePrintMonitorUI();
898 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
900 TRACE( "0x%08x: dwMonitorSize (%d)\n",
901 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
906 if (pInitializePrintMonitor && regroot) {
907 pmonitorEx = pInitializePrintMonitor(regroot);
908 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
909 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
912 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
913 pm->monitor = &(pmonitorEx->Monitor);
918 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
922 if (!pm->monitor && regroot) {
923 if (pInitializePrintMonitor2 != NULL) {
924 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
926 if (pInitializeMonitorEx != NULL) {
927 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
929 if (pInitializeMonitor != NULL) {
930 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
933 if (!pm->monitor && !pm->monitorUI) {
935 SetLastError(ERROR_PROC_NOT_FOUND);
940 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
944 LeaveCriticalSection(&monitor_handles_cs);
945 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
946 HeapFree(GetProcessHeap(), 0, regroot);
947 TRACE("=> %p\n", pm);
951 /******************************************************************
952 * monitor_loadui [internal]
954 * load the userinterface-dll for a given portmonitor
956 * On failure, NULL is returned
959 static monitor_t * monitor_loadui(monitor_t * pm)
961 monitor_t * pui = NULL;
962 LPWSTR buffer[MAX_PATH];
967 if (pm == NULL) return NULL;
968 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
970 /* Try the Portmonitor first; works for many monitors */
972 EnterCriticalSection(&monitor_handles_cs);
974 LeaveCriticalSection(&monitor_handles_cs);
978 /* query the userinterface-dllname from the Portmonitor */
979 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
980 /* building (",XcvMonitor %s",pm->name) not needed yet */
981 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
982 TRACE("got %u with %p\n", res, hXcv);
984 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
985 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
986 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
987 pm->monitor->pfnXcvClosePort(hXcv);
994 /******************************************************************
995 * monitor_load_by_port [internal]
997 * load a printmonitor for a given port
999 * On failure, NULL is returned
1002 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1007 monitor_t * pm = NULL;
1008 DWORD registered = 0;
1012 TRACE("(%s)\n", debugstr_w(portname));
1014 /* Try the Local Monitor first */
1015 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1016 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1017 /* found the portname */
1019 return monitor_load(LocalPortW, NULL);
1024 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1025 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1026 if (buffer == NULL) return NULL;
1028 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1029 EnterCriticalSection(&monitor_handles_cs);
1030 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1032 while ((pm == NULL) && (id < registered)) {
1034 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1035 TRACE("testing %s\n", debugstr_w(buffer));
1036 len = lstrlenW(buffer);
1037 lstrcatW(buffer, bs_Ports_bsW);
1038 lstrcatW(buffer, portname);
1039 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1041 buffer[len] = '\0'; /* use only the Monitor-Name */
1042 pm = monitor_load(buffer, NULL);
1046 LeaveCriticalSection(&monitor_handles_cs);
1049 HeapFree(GetProcessHeap(), 0, buffer);
1053 /******************************************************************
1054 * get_servername_from_name (internal)
1056 * for an external server, a copy of the serverpart from the full name is returned
1059 static LPWSTR get_servername_from_name(LPCWSTR name)
1063 WCHAR buffer[MAX_PATH];
1066 if (name == NULL) return NULL;
1067 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1069 server = strdupW(&name[2]); /* skip over both backslash */
1070 if (server == NULL) return NULL;
1072 /* strip '\' and the printername */
1073 ptr = strchrW(server, '\\');
1074 if (ptr) ptr[0] = '\0';
1076 TRACE("found %s\n", debugstr_w(server));
1078 len = sizeof(buffer)/sizeof(buffer[0]);
1079 if (GetComputerNameW(buffer, &len)) {
1080 if (lstrcmpW(buffer, server) == 0) {
1081 /* The requested Servername is our computername */
1082 HeapFree(GetProcessHeap(), 0, server);
1089 /******************************************************************
1090 * get_basename_from_name (internal)
1092 * skip over the serverpart from the full name
1095 static LPCWSTR get_basename_from_name(LPCWSTR name)
1097 if (name == NULL) return NULL;
1098 if ((name[0] == '\\') && (name[1] == '\\')) {
1099 /* skip over the servername and search for the following '\' */
1100 name = strchrW(&name[2], '\\');
1101 if ((name) && (name[1])) {
1102 /* found a separator ('\') followed by a name:
1103 skip over the separator and return the rest */
1108 /* no basename present (we found only a servername) */
1115 /******************************************************************
1116 * get_opened_printer_entry
1117 * Get the first place empty in the opened printer table
1120 * - pDefault is ignored
1122 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1124 UINT_PTR handle = nb_printer_handles, i;
1125 jobqueue_t *queue = NULL;
1126 opened_printer_t *printer = NULL;
1128 LPCWSTR printername;
1133 servername = get_servername_from_name(name);
1135 FIXME("server %s not supported\n", debugstr_w(servername));
1136 HeapFree(GetProcessHeap(), 0, servername);
1137 SetLastError(ERROR_INVALID_PRINTER_NAME);
1141 printername = get_basename_from_name(name);
1142 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1144 /* an empty printername is invalid */
1145 if (printername && (!printername[0])) {
1146 SetLastError(ERROR_INVALID_PARAMETER);
1150 EnterCriticalSection(&printer_handles_cs);
1152 for (i = 0; i < nb_printer_handles; i++)
1154 if (!printer_handles[i])
1156 if(handle == nb_printer_handles)
1161 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1162 queue = printer_handles[i]->queue;
1166 if (handle >= nb_printer_handles)
1168 opened_printer_t **new_array;
1169 if (printer_handles)
1170 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1171 (nb_printer_handles + 16) * sizeof(*new_array) );
1173 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1174 (nb_printer_handles + 16) * sizeof(*new_array) );
1181 printer_handles = new_array;
1182 nb_printer_handles += 16;
1185 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1192 /* clone the base name. This is NULL for the printserver */
1193 printer->printername = strdupW(printername);
1195 /* clone the full name */
1196 printer->name = strdupW(name);
1197 if (name && (!printer->name)) {
1203 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1204 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1205 /* OpenPrinter(",XcvMonitor " detected */
1206 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1207 printer->pm = monitor_load(&printername[len], NULL);
1208 if (printer->pm == NULL) {
1209 SetLastError(ERROR_UNKNOWN_PORT);
1216 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1217 if (strncmpW( printername, XcvPortW, len) == 0) {
1218 /* OpenPrinter(",XcvPort " detected */
1219 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1220 printer->pm = monitor_load_by_port(&printername[len]);
1221 if (printer->pm == NULL) {
1222 SetLastError(ERROR_UNKNOWN_PORT);
1230 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1231 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1232 pDefault ? pDefault->DesiredAccess : 0,
1235 if (printer->hXcv == NULL) {
1236 SetLastError(ERROR_INVALID_PARAMETER);
1243 /* Does the Printer exist? */
1244 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1245 ERR("Can't create Printers key\n");
1249 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1250 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1251 RegCloseKey(hkeyPrinters);
1252 SetLastError(ERROR_INVALID_PRINTER_NAME);
1256 RegCloseKey(hkeyPrinter);
1257 RegCloseKey(hkeyPrinters);
1262 TRACE("using the local printserver\n");
1266 printer->queue = queue;
1269 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1270 if (!printer->queue) {
1274 list_init(&printer->queue->jobs);
1275 printer->queue->ref = 0;
1277 InterlockedIncrement(&printer->queue->ref);
1279 printer_handles[handle] = printer;
1282 LeaveCriticalSection(&printer_handles_cs);
1283 if (!handle && printer) {
1284 /* Something failed: Free all resources */
1285 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1286 monitor_unload(printer->pm);
1287 HeapFree(GetProcessHeap(), 0, printer->printername);
1288 HeapFree(GetProcessHeap(), 0, printer->name);
1289 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1290 HeapFree(GetProcessHeap(), 0, printer);
1293 return (HANDLE)handle;
1296 /******************************************************************
1297 * get_opened_printer
1298 * Get the pointer to the opened printer referred by the handle
1300 static opened_printer_t *get_opened_printer(HANDLE hprn)
1302 UINT_PTR idx = (UINT_PTR)hprn;
1303 opened_printer_t *ret = NULL;
1305 EnterCriticalSection(&printer_handles_cs);
1307 if ((idx > 0) && (idx <= nb_printer_handles)) {
1308 ret = printer_handles[idx - 1];
1310 LeaveCriticalSection(&printer_handles_cs);
1314 /******************************************************************
1315 * get_opened_printer_name
1316 * Get the pointer to the opened printer name referred by the handle
1318 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1320 opened_printer_t *printer = get_opened_printer(hprn);
1321 if(!printer) return NULL;
1322 return printer->name;
1325 /******************************************************************
1326 * WINSPOOL_GetOpenedPrinterRegKey
1329 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1331 LPCWSTR name = get_opened_printer_name(hPrinter);
1335 if(!name) return ERROR_INVALID_HANDLE;
1337 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1341 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1343 ERR("Can't find opened printer %s in registry\n",
1345 RegCloseKey(hkeyPrinters);
1346 return ERROR_INVALID_PRINTER_NAME; /* ? */
1348 RegCloseKey(hkeyPrinters);
1349 return ERROR_SUCCESS;
1352 void WINSPOOL_LoadSystemPrinters(void)
1354 HKEY hkey, hkeyPrinters;
1356 DWORD needed, num, i;
1357 WCHAR PrinterName[256];
1360 /* This ensures that all printer entries have a valid Name value. If causes
1361 problems later if they don't. If one is found to be missed we create one
1362 and set it equal to the name of the key */
1363 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1364 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1365 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1366 for(i = 0; i < num; i++) {
1367 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1368 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1369 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1370 set_reg_szW(hkey, NameW, PrinterName);
1377 RegCloseKey(hkeyPrinters);
1380 /* We want to avoid calling AddPrinter on printers as much as
1381 possible, because on cups printers this will (eventually) lead
1382 to a call to cupsGetPPD which takes forever, even with non-cups
1383 printers AddPrinter takes a while. So we'll tag all printers that
1384 were automatically added last time around, if they still exist
1385 we'll leave them be otherwise we'll delete them. */
1386 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1388 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1389 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1390 for(i = 0; i < num; i++) {
1391 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1392 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1393 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1395 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1403 HeapFree(GetProcessHeap(), 0, pi);
1407 #ifdef SONAME_LIBCUPS
1408 done = CUPS_LoadPrinters();
1411 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1412 PRINTCAP_LoadPrinters();
1414 /* Now enumerate the list again and delete any printers that are still tagged */
1415 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1417 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1418 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1419 for(i = 0; i < num; i++) {
1420 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1421 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1422 BOOL delete_driver = FALSE;
1423 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1424 DWORD dw, type, size = sizeof(dw);
1425 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1426 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1427 DeletePrinter(hprn);
1428 delete_driver = TRUE;
1434 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1439 HeapFree(GetProcessHeap(), 0, pi);
1446 /******************************************************************
1449 * Get the pointer to the specified job.
1450 * Should hold the printer_handles_cs before calling.
1452 static job_t *get_job(HANDLE hprn, DWORD JobId)
1454 opened_printer_t *printer = get_opened_printer(hprn);
1457 if(!printer) return NULL;
1458 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1460 if(job->job_id == JobId)
1466 /***********************************************************
1469 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1472 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1475 Formname = (dmA->dmSize > off_formname);
1476 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1477 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1478 dmW->dmDeviceName, CCHDEVICENAME);
1480 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1481 dmA->dmSize - CCHDEVICENAME);
1483 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1484 off_formname - CCHDEVICENAME);
1485 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1486 dmW->dmFormName, CCHFORMNAME);
1487 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1488 (off_formname + CCHFORMNAME));
1491 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1492 dmA->dmDriverExtra);
1496 /***********************************************************
1498 * Creates an ansi copy of supplied devmode
1500 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1505 if (!dmW) return NULL;
1506 size = dmW->dmSize - CCHDEVICENAME -
1507 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1509 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1510 if (!dmA) return NULL;
1512 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1513 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1515 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1516 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1517 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1521 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1522 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1523 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1524 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1526 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1530 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1534 /******************************************************************
1535 * convert_printerinfo_W_to_A [internal]
1538 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1539 DWORD level, DWORD outlen, DWORD numentries)
1545 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1547 len = pi_sizeof[level] * numentries;
1548 ptr = (LPSTR) out + len;
1551 /* copy the numbers of all PRINTER_INFO_* first */
1552 memcpy(out, pPrintersW, len);
1554 while (id < numentries) {
1558 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1559 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1561 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1562 if (piW->pDescription) {
1563 piA->pDescription = ptr;
1564 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1565 ptr, outlen, NULL, NULL);
1571 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1572 ptr, outlen, NULL, NULL);
1576 if (piW->pComment) {
1577 piA->pComment = ptr;
1578 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1579 ptr, outlen, NULL, NULL);
1588 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1589 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1592 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1593 if (piW->pServerName) {
1594 piA->pServerName = ptr;
1595 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1596 ptr, outlen, NULL, NULL);
1600 if (piW->pPrinterName) {
1601 piA->pPrinterName = ptr;
1602 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1603 ptr, outlen, NULL, NULL);
1607 if (piW->pShareName) {
1608 piA->pShareName = ptr;
1609 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1610 ptr, outlen, NULL, NULL);
1614 if (piW->pPortName) {
1615 piA->pPortName = ptr;
1616 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1617 ptr, outlen, NULL, NULL);
1621 if (piW->pDriverName) {
1622 piA->pDriverName = ptr;
1623 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1624 ptr, outlen, NULL, NULL);
1628 if (piW->pComment) {
1629 piA->pComment = ptr;
1630 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1631 ptr, outlen, NULL, NULL);
1635 if (piW->pLocation) {
1636 piA->pLocation = ptr;
1637 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1638 ptr, outlen, NULL, NULL);
1643 dmA = DEVMODEdupWtoA(piW->pDevMode);
1645 /* align DEVMODEA to a DWORD boundary */
1646 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1650 piA->pDevMode = (LPDEVMODEA) ptr;
1651 len = dmA->dmSize + dmA->dmDriverExtra;
1652 memcpy(ptr, dmA, len);
1653 HeapFree(GetProcessHeap(), 0, dmA);
1659 if (piW->pSepFile) {
1660 piA->pSepFile = ptr;
1661 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1662 ptr, outlen, NULL, NULL);
1666 if (piW->pPrintProcessor) {
1667 piA->pPrintProcessor = ptr;
1668 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1669 ptr, outlen, NULL, NULL);
1673 if (piW->pDatatype) {
1674 piA->pDatatype = ptr;
1675 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1676 ptr, outlen, NULL, NULL);
1680 if (piW->pParameters) {
1681 piA->pParameters = ptr;
1682 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1683 ptr, outlen, NULL, NULL);
1687 if (piW->pSecurityDescriptor) {
1688 piA->pSecurityDescriptor = NULL;
1689 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1696 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1697 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1699 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1701 if (piW->pPrinterName) {
1702 piA->pPrinterName = ptr;
1703 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1704 ptr, outlen, NULL, NULL);
1708 if (piW->pServerName) {
1709 piA->pServerName = ptr;
1710 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1711 ptr, outlen, NULL, NULL);
1720 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1721 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1723 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1725 if (piW->pPrinterName) {
1726 piA->pPrinterName = ptr;
1727 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1728 ptr, outlen, NULL, NULL);
1732 if (piW->pPortName) {
1733 piA->pPortName = ptr;
1734 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1735 ptr, outlen, NULL, NULL);
1743 FIXME("for level %u\n", level);
1745 pPrintersW += pi_sizeof[level];
1746 out += pi_sizeof[level];
1751 /***********************************************************
1752 * PRINTER_INFO_2AtoW
1753 * Creates a unicode copy of PRINTER_INFO_2A on heap
1755 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1757 LPPRINTER_INFO_2W piW;
1758 UNICODE_STRING usBuffer;
1760 if(!piA) return NULL;
1761 piW = HeapAlloc(heap, 0, sizeof(*piW));
1762 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1764 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1765 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1766 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1767 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1768 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1769 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1770 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1771 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1772 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1773 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1774 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1775 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1779 /***********************************************************
1780 * FREE_PRINTER_INFO_2W
1781 * Free PRINTER_INFO_2W and all strings
1783 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1787 HeapFree(heap,0,piW->pServerName);
1788 HeapFree(heap,0,piW->pPrinterName);
1789 HeapFree(heap,0,piW->pShareName);
1790 HeapFree(heap,0,piW->pPortName);
1791 HeapFree(heap,0,piW->pDriverName);
1792 HeapFree(heap,0,piW->pComment);
1793 HeapFree(heap,0,piW->pLocation);
1794 HeapFree(heap,0,piW->pDevMode);
1795 HeapFree(heap,0,piW->pSepFile);
1796 HeapFree(heap,0,piW->pPrintProcessor);
1797 HeapFree(heap,0,piW->pDatatype);
1798 HeapFree(heap,0,piW->pParameters);
1799 HeapFree(heap,0,piW);
1803 /******************************************************************
1804 * DeviceCapabilities [WINSPOOL.@]
1805 * DeviceCapabilitiesA [WINSPOOL.@]
1808 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1809 LPSTR pOutput, LPDEVMODEA lpdm)
1813 if (!GDI_CallDeviceCapabilities16)
1815 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1817 if (!GDI_CallDeviceCapabilities16) return -1;
1819 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1821 /* If DC_PAPERSIZE map POINT16s to POINTs */
1822 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1823 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1824 POINT *pt = (POINT *)pOutput;
1826 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1827 for(i = 0; i < ret; i++, pt++)
1832 HeapFree( GetProcessHeap(), 0, tmp );
1838 /*****************************************************************************
1839 * DeviceCapabilitiesW [WINSPOOL.@]
1841 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1844 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1845 WORD fwCapability, LPWSTR pOutput,
1846 const DEVMODEW *pDevMode)
1848 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1849 LPSTR pDeviceA = strdupWtoA(pDevice);
1850 LPSTR pPortA = strdupWtoA(pPort);
1853 if(pOutput && (fwCapability == DC_BINNAMES ||
1854 fwCapability == DC_FILEDEPENDENCIES ||
1855 fwCapability == DC_PAPERNAMES)) {
1856 /* These need A -> W translation */
1859 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1863 switch(fwCapability) {
1868 case DC_FILEDEPENDENCIES:
1872 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1873 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1875 for(i = 0; i < ret; i++)
1876 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1877 pOutput + (i * size), size);
1878 HeapFree(GetProcessHeap(), 0, pOutputA);
1880 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1881 (LPSTR)pOutput, dmA);
1883 HeapFree(GetProcessHeap(),0,pPortA);
1884 HeapFree(GetProcessHeap(),0,pDeviceA);
1885 HeapFree(GetProcessHeap(),0,dmA);
1889 /******************************************************************
1890 * DocumentPropertiesA [WINSPOOL.@]
1892 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1894 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1895 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1896 LPDEVMODEA pDevModeInput,DWORD fMode )
1898 LPSTR lpName = pDeviceName;
1899 static CHAR port[] = "LPT1:";
1902 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1903 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1907 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1909 ERR("no name from hPrinter?\n");
1910 SetLastError(ERROR_INVALID_HANDLE);
1913 lpName = strdupWtoA(lpNameW);
1916 if (!GDI_CallExtDeviceMode16)
1918 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1920 if (!GDI_CallExtDeviceMode16) {
1921 ERR("No CallExtDeviceMode16?\n");
1925 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1926 pDevModeInput, NULL, fMode);
1929 HeapFree(GetProcessHeap(),0,lpName);
1934 /*****************************************************************************
1935 * DocumentPropertiesW (WINSPOOL.@)
1937 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1939 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1941 LPDEVMODEW pDevModeOutput,
1942 LPDEVMODEW pDevModeInput, DWORD fMode)
1945 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1946 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1947 LPDEVMODEA pDevModeOutputA = NULL;
1950 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1951 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1953 if(pDevModeOutput) {
1954 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1955 if(ret < 0) return ret;
1956 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1958 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1959 pDevModeInputA, fMode);
1960 if(pDevModeOutput) {
1961 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1962 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1964 if(fMode == 0 && ret > 0)
1965 ret += (CCHDEVICENAME + CCHFORMNAME);
1966 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1967 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1971 /******************************************************************
1972 * OpenPrinterA [WINSPOOL.@]
1977 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1978 LPPRINTER_DEFAULTSA pDefault)
1980 UNICODE_STRING lpPrinterNameW;
1981 UNICODE_STRING usBuffer;
1982 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1983 PWSTR pwstrPrinterNameW;
1986 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1989 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1990 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1991 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1992 pDefaultW = &DefaultW;
1994 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1996 RtlFreeUnicodeString(&usBuffer);
1997 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1999 RtlFreeUnicodeString(&lpPrinterNameW);
2003 /******************************************************************
2004 * OpenPrinterW [WINSPOOL.@]
2006 * Open a Printer / Printserver or a Printer-Object
2009 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2010 * phPrinter [O] The resulting Handle is stored here
2011 * pDefault [I] PTR to Default Printer Settings or NULL
2018 * lpPrinterName is one of:
2019 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2020 *| Printer: "PrinterName"
2021 *| Printer-Object: "PrinterName,Job xxx"
2022 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2023 *| XcvPort: "Servername,XcvPort PortName"
2026 *| Printer-Object not supported
2027 *| pDefaults is ignored
2030 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2033 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2035 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2036 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2040 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2041 SetLastError(ERROR_INVALID_PARAMETER);
2045 /* Get the unique handle of the printer or Printserver */
2046 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2047 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2048 return (*phPrinter != 0);
2051 /******************************************************************
2052 * AddMonitorA [WINSPOOL.@]
2057 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2059 LPWSTR nameW = NULL;
2062 LPMONITOR_INFO_2A mi2a;
2063 MONITOR_INFO_2W mi2w;
2065 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2066 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2067 debugstr_a(mi2a ? mi2a->pName : NULL),
2068 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2069 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2072 SetLastError(ERROR_INVALID_LEVEL);
2076 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2082 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2083 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2084 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2087 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2089 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2090 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2091 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2093 if (mi2a->pEnvironment) {
2094 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2095 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2096 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2098 if (mi2a->pDLLName) {
2099 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2100 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2101 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2104 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2106 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2107 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2108 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2110 HeapFree(GetProcessHeap(), 0, nameW);
2114 /******************************************************************************
2115 * AddMonitorW [WINSPOOL.@]
2117 * Install a Printmonitor
2120 * pName [I] Servername or NULL (local Computer)
2121 * Level [I] Structure-Level (Must be 2)
2122 * pMonitors [I] PTR to MONITOR_INFO_2
2129 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2132 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2134 LPMONITOR_INFO_2W mi2w;
2136 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2137 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2138 debugstr_w(mi2w ? mi2w->pName : NULL),
2139 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2140 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2142 if ((backend == NULL) && !load_backend()) return FALSE;
2145 SetLastError(ERROR_INVALID_LEVEL);
2149 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2154 return backend->fpAddMonitor(pName, Level, pMonitors);
2157 /******************************************************************
2158 * DeletePrinterDriverA [WINSPOOL.@]
2161 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2163 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2166 /******************************************************************
2167 * DeletePrinterDriverW [WINSPOOL.@]
2170 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2172 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2175 /******************************************************************
2176 * DeleteMonitorA [WINSPOOL.@]
2178 * See DeleteMonitorW.
2181 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2183 LPWSTR nameW = NULL;
2184 LPWSTR EnvironmentW = NULL;
2185 LPWSTR MonitorNameW = NULL;
2190 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2191 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2192 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2196 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2197 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2198 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2201 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2202 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2203 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2206 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2208 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2209 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2210 HeapFree(GetProcessHeap(), 0, nameW);
2214 /******************************************************************
2215 * DeleteMonitorW [WINSPOOL.@]
2217 * Delete a specific Printmonitor from a Printing-Environment
2220 * pName [I] Servername or NULL (local Computer)
2221 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2222 * pMonitorName [I] Name of the Monitor, that should be deleted
2229 * pEnvironment is ignored in Windows for the local Computer.
2232 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2235 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2236 debugstr_w(pMonitorName));
2238 if ((backend == NULL) && !load_backend()) return FALSE;
2240 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2244 /******************************************************************
2245 * DeletePortA [WINSPOOL.@]
2250 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2252 LPWSTR nameW = NULL;
2253 LPWSTR portW = NULL;
2257 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2259 /* convert servername to unicode */
2261 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2262 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2263 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2266 /* convert portname to unicode */
2268 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2269 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2270 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2273 res = DeletePortW(nameW, hWnd, portW);
2274 HeapFree(GetProcessHeap(), 0, nameW);
2275 HeapFree(GetProcessHeap(), 0, portW);
2279 /******************************************************************
2280 * DeletePortW [WINSPOOL.@]
2282 * Delete a specific Port
2285 * pName [I] Servername or NULL (local Computer)
2286 * hWnd [I] Handle to parent Window for the Dialog-Box
2287 * pPortName [I] Name of the Port, that should be deleted
2294 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2300 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2302 if (pName && pName[0]) {
2303 SetLastError(ERROR_INVALID_PARAMETER);
2308 SetLastError(RPC_X_NULL_REF_POINTER);
2312 /* an empty Portname is Invalid */
2313 if (!pPortName[0]) {
2314 SetLastError(ERROR_NOT_SUPPORTED);
2318 pm = monitor_load_by_port(pPortName);
2319 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2320 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2321 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2322 TRACE("got %d with %u\n", res, GetLastError());
2326 pui = monitor_loadui(pm);
2327 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2328 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2329 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2330 TRACE("got %d with %u\n", res, GetLastError());
2334 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2335 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2337 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2338 SetLastError(ERROR_NOT_SUPPORTED);
2341 monitor_unload(pui);
2345 TRACE("returning %d with %u\n", res, GetLastError());
2349 /******************************************************************************
2350 * SetPrinterW [WINSPOOL.@]
2352 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2354 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2355 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2359 /******************************************************************************
2360 * WritePrinter [WINSPOOL.@]
2362 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2364 opened_printer_t *printer;
2367 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2369 EnterCriticalSection(&printer_handles_cs);
2370 printer = get_opened_printer(hPrinter);
2373 SetLastError(ERROR_INVALID_HANDLE);
2379 SetLastError(ERROR_SPL_NO_STARTDOC);
2383 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2385 LeaveCriticalSection(&printer_handles_cs);
2389 /*****************************************************************************
2390 * AddFormA [WINSPOOL.@]
2392 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2394 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2398 /*****************************************************************************
2399 * AddFormW [WINSPOOL.@]
2401 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2403 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2407 /*****************************************************************************
2408 * AddJobA [WINSPOOL.@]
2410 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2413 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2417 SetLastError(ERROR_INVALID_LEVEL);
2421 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2424 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2425 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2426 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2427 if(*pcbNeeded > cbBuf) {
2428 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2431 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2432 addjobA->JobId = addjobW->JobId;
2433 addjobA->Path = (char *)(addjobA + 1);
2434 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2440 /*****************************************************************************
2441 * AddJobW [WINSPOOL.@]
2443 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2445 opened_printer_t *printer;
2448 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2449 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2450 WCHAR path[MAX_PATH], filename[MAX_PATH];
2452 ADDJOB_INFO_1W *addjob;
2454 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2456 EnterCriticalSection(&printer_handles_cs);
2458 printer = get_opened_printer(hPrinter);
2461 SetLastError(ERROR_INVALID_HANDLE);
2466 SetLastError(ERROR_INVALID_LEVEL);
2470 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2474 job->job_id = InterlockedIncrement(&next_job_id);
2476 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2477 if(path[len - 1] != '\\')
2479 memcpy(path + len, spool_path, sizeof(spool_path));
2480 sprintfW(filename, fmtW, path, job->job_id);
2482 len = strlenW(filename);
2483 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2484 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2485 job->document_title = strdupW(default_doc_title);
2486 list_add_tail(&printer->queue->jobs, &job->entry);
2488 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2489 if(*pcbNeeded <= cbBuf) {
2490 addjob = (ADDJOB_INFO_1W*)pData;
2491 addjob->JobId = job->job_id;
2492 addjob->Path = (WCHAR *)(addjob + 1);
2493 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2496 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2499 LeaveCriticalSection(&printer_handles_cs);
2503 /*****************************************************************************
2504 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2506 * Return the PATH for the Print-Processors
2508 * See GetPrintProcessorDirectoryW.
2512 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2513 DWORD level, LPBYTE Info,
2514 DWORD cbBuf, LPDWORD pcbNeeded)
2516 LPWSTR serverW = NULL;
2521 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2522 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2526 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2527 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2528 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2532 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2533 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2534 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2537 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2538 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2540 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2543 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2544 cbBuf, NULL, NULL) > 0;
2547 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2548 HeapFree(GetProcessHeap(), 0, envW);
2549 HeapFree(GetProcessHeap(), 0, serverW);
2553 /*****************************************************************************
2554 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2556 * Return the PATH for the Print-Processors
2559 * server [I] Servername (NT only) or NULL (local Computer)
2560 * env [I] Printing-Environment (see below) or NULL (Default)
2561 * level [I] Structure-Level (must be 1)
2562 * Info [O] PTR to Buffer that receives the Result
2563 * cbBuf [I] Size of Buffer at "Info"
2564 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2565 * required for the Buffer at "Info"
2568 * Success: TRUE and in pcbNeeded the Bytes used in Info
2569 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2570 * if cbBuf is too small
2572 * Native Values returned in Info on Success:
2573 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2574 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2575 *| win9x(Windows 4.0): "%winsysdir%"
2577 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2580 * Only NULL or "" is supported for server
2583 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2584 DWORD level, LPBYTE Info,
2585 DWORD cbBuf, LPDWORD pcbNeeded)
2588 const printenv_t * env_t;
2590 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2591 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2593 if(server != NULL && server[0]) {
2594 FIXME("server not supported: %s\n", debugstr_w(server));
2595 SetLastError(ERROR_INVALID_PARAMETER);
2599 env_t = validate_envW(env);
2600 if(!env_t) return FALSE; /* environment invalid or unsupported */
2603 WARN("(Level: %d) is ignored in win9x\n", level);
2604 SetLastError(ERROR_INVALID_LEVEL);
2608 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2609 needed = GetSystemDirectoryW(NULL, 0);
2610 /* add the Size for the Subdirectories */
2611 needed += lstrlenW(spoolprtprocsW);
2612 needed += lstrlenW(env_t->subdir);
2613 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2615 if(pcbNeeded) *pcbNeeded = needed;
2616 TRACE ("required: 0x%x/%d\n", needed, needed);
2617 if (needed > cbBuf) {
2618 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2621 if(pcbNeeded == NULL) {
2622 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2623 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2624 SetLastError(RPC_X_NULL_REF_POINTER);
2628 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2629 SetLastError(RPC_X_NULL_REF_POINTER);
2633 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2634 /* add the Subdirectories */
2635 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2636 lstrcatW((LPWSTR) Info, env_t->subdir);
2637 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2641 /*****************************************************************************
2642 * WINSPOOL_OpenDriverReg [internal]
2644 * opens the registry for the printer drivers depending on the given input
2645 * variable pEnvironment
2648 * the opened hkey on success
2651 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2655 const printenv_t * env;
2658 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2660 if (!pEnvironment || unicode) {
2661 /* pEnvironment was NULL or a Unicode-String: use it direct */
2662 env = validate_envW(pEnvironment);
2666 /* pEnvironment was an ANSI-String: convert to unicode first */
2668 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2669 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2670 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2671 env = validate_envW(buffer);
2672 HeapFree(GetProcessHeap(), 0, buffer);
2674 if (!env) return NULL;
2676 buffer = HeapAlloc( GetProcessHeap(), 0,
2677 (strlenW(DriversW) + strlenW(env->envname) +
2678 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2680 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2681 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2682 HeapFree(GetProcessHeap(), 0, buffer);
2687 /*****************************************************************************
2688 * AddPrinterW [WINSPOOL.@]
2690 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2692 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2696 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2698 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2699 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2700 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2701 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2702 statusW[] = {'S','t','a','t','u','s',0},
2703 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2705 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2708 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2709 SetLastError(ERROR_INVALID_PARAMETER);
2713 ERR("Level = %d, unsupported!\n", Level);
2714 SetLastError(ERROR_INVALID_LEVEL);
2718 SetLastError(ERROR_INVALID_PARAMETER);
2721 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2723 ERR("Can't create Printers key\n");
2726 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2727 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2728 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2729 RegCloseKey(hkeyPrinter);
2730 RegCloseKey(hkeyPrinters);
2733 RegCloseKey(hkeyPrinter);
2735 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2737 ERR("Can't create Drivers key\n");
2738 RegCloseKey(hkeyPrinters);
2741 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2743 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2744 RegCloseKey(hkeyPrinters);
2745 RegCloseKey(hkeyDrivers);
2746 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2749 RegCloseKey(hkeyDriver);
2750 RegCloseKey(hkeyDrivers);
2752 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2753 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2754 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2755 RegCloseKey(hkeyPrinters);
2759 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2761 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2762 SetLastError(ERROR_INVALID_PRINTER_NAME);
2763 RegCloseKey(hkeyPrinters);
2766 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2767 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2768 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2770 /* See if we can load the driver. We may need the devmode structure anyway
2773 * Note that DocumentPropertiesW will briefly try to open the printer we
2774 * just create to find a DEVMODEA struct (it will use the WINEPS default
2775 * one in case it is not there, so we are ok).
2777 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2780 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2781 size = sizeof(DEVMODEW);
2787 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2789 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2791 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2792 HeapFree(GetProcessHeap(),0,dmW);
2797 /* set devmode to printer name */
2798 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2802 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2803 and we support these drivers. NT writes DEVMODEW so somehow
2804 we'll need to distinguish between these when we support NT
2808 dmA = DEVMODEdupWtoA(dmW);
2809 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2810 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2811 HeapFree(GetProcessHeap(), 0, dmA);
2813 HeapFree(GetProcessHeap(), 0, dmW);
2815 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2816 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2817 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2818 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2820 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2821 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2822 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2823 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2824 (LPBYTE)&pi->Priority, sizeof(DWORD));
2825 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2826 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2827 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2828 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2829 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2830 (LPBYTE)&pi->Status, sizeof(DWORD));
2831 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2832 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2834 RegCloseKey(hkeyPrinter);
2835 RegCloseKey(hkeyPrinters);
2836 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2837 ERR("OpenPrinter failing\n");
2843 /*****************************************************************************
2844 * AddPrinterA [WINSPOOL.@]
2846 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2848 UNICODE_STRING pNameW;
2850 PRINTER_INFO_2W *piW;
2851 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2854 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2856 ERR("Level = %d, unsupported!\n", Level);
2857 SetLastError(ERROR_INVALID_LEVEL);
2860 pwstrNameW = asciitounicode(&pNameW,pName);
2861 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2863 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2865 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2866 RtlFreeUnicodeString(&pNameW);
2871 /*****************************************************************************
2872 * ClosePrinter [WINSPOOL.@]
2874 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2876 UINT_PTR i = (UINT_PTR)hPrinter;
2877 opened_printer_t *printer = NULL;
2880 TRACE("(%p)\n", hPrinter);
2882 EnterCriticalSection(&printer_handles_cs);
2884 if ((i > 0) && (i <= nb_printer_handles))
2885 printer = printer_handles[i - 1];
2890 struct list *cursor, *cursor2;
2892 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2893 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2894 printer->hXcv, debugstr_w(printer->name), printer->doc );
2897 EndDocPrinter(hPrinter);
2899 if(InterlockedDecrement(&printer->queue->ref) == 0)
2901 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2903 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2904 ScheduleJob(hPrinter, job->job_id);
2906 HeapFree(GetProcessHeap(), 0, printer->queue);
2908 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2909 monitor_unload(printer->pm);
2910 HeapFree(GetProcessHeap(), 0, printer->printername);
2911 HeapFree(GetProcessHeap(), 0, printer->name);
2912 HeapFree(GetProcessHeap(), 0, printer);
2913 printer_handles[i - 1] = NULL;
2916 LeaveCriticalSection(&printer_handles_cs);
2920 /*****************************************************************************
2921 * DeleteFormA [WINSPOOL.@]
2923 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2925 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2929 /*****************************************************************************
2930 * DeleteFormW [WINSPOOL.@]
2932 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2934 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2938 /*****************************************************************************
2939 * DeletePrinter [WINSPOOL.@]
2941 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2943 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2944 HKEY hkeyPrinters, hkey;
2947 SetLastError(ERROR_INVALID_HANDLE);
2950 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2951 RegDeleteTreeW(hkeyPrinters, lpNameW);
2952 RegCloseKey(hkeyPrinters);
2954 WriteProfileStringW(devicesW, lpNameW, NULL);
2955 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2957 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2958 RegDeleteValueW(hkey, lpNameW);
2962 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2963 RegDeleteValueW(hkey, lpNameW);
2969 /*****************************************************************************
2970 * SetPrinterA [WINSPOOL.@]
2972 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2975 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2979 /*****************************************************************************
2980 * SetJobA [WINSPOOL.@]
2982 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2983 LPBYTE pJob, DWORD Command)
2987 UNICODE_STRING usBuffer;
2989 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2991 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2992 are all ignored by SetJob, so we don't bother copying them */
3000 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3001 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3003 JobW = (LPBYTE)info1W;
3004 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3005 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3006 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3007 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3008 info1W->Status = info1A->Status;
3009 info1W->Priority = info1A->Priority;
3010 info1W->Position = info1A->Position;
3011 info1W->PagesPrinted = info1A->PagesPrinted;
3016 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3017 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3019 JobW = (LPBYTE)info2W;
3020 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3021 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3022 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3023 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3024 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3025 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3026 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3027 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3028 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3029 info2W->Status = info2A->Status;
3030 info2W->Priority = info2A->Priority;
3031 info2W->Position = info2A->Position;
3032 info2W->StartTime = info2A->StartTime;
3033 info2W->UntilTime = info2A->UntilTime;
3034 info2W->PagesPrinted = info2A->PagesPrinted;
3038 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3039 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3042 SetLastError(ERROR_INVALID_LEVEL);
3046 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3052 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3053 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3054 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3055 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3056 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3061 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3062 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3063 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3064 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3065 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3066 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3067 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3068 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3069 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3073 HeapFree(GetProcessHeap(), 0, JobW);
3078 /*****************************************************************************
3079 * SetJobW [WINSPOOL.@]
3081 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3082 LPBYTE pJob, DWORD Command)
3087 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3088 FIXME("Ignoring everything other than document title\n");
3090 EnterCriticalSection(&printer_handles_cs);
3091 job = get_job(hPrinter, JobId);
3101 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3102 HeapFree(GetProcessHeap(), 0, job->document_title);
3103 job->document_title = strdupW(info1->pDocument);
3108 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3109 HeapFree(GetProcessHeap(), 0, job->document_title);
3110 job->document_title = strdupW(info2->pDocument);
3116 SetLastError(ERROR_INVALID_LEVEL);
3121 LeaveCriticalSection(&printer_handles_cs);
3125 /*****************************************************************************
3126 * EndDocPrinter [WINSPOOL.@]
3128 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3130 opened_printer_t *printer;
3132 TRACE("(%p)\n", hPrinter);
3134 EnterCriticalSection(&printer_handles_cs);
3136 printer = get_opened_printer(hPrinter);
3139 SetLastError(ERROR_INVALID_HANDLE);
3145 SetLastError(ERROR_SPL_NO_STARTDOC);
3149 CloseHandle(printer->doc->hf);
3150 ScheduleJob(hPrinter, printer->doc->job_id);
3151 HeapFree(GetProcessHeap(), 0, printer->doc);
3152 printer->doc = NULL;
3155 LeaveCriticalSection(&printer_handles_cs);
3159 /*****************************************************************************
3160 * EndPagePrinter [WINSPOOL.@]
3162 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3164 FIXME("(%p): stub\n", hPrinter);
3168 /*****************************************************************************
3169 * StartDocPrinterA [WINSPOOL.@]
3171 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3173 UNICODE_STRING usBuffer;
3175 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3178 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3179 or one (DOC_INFO_3) extra DWORDs */
3183 doc2W.JobId = doc2->JobId;
3186 doc2W.dwMode = doc2->dwMode;
3189 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3190 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3191 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3195 SetLastError(ERROR_INVALID_LEVEL);
3199 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3201 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3202 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3203 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3208 /*****************************************************************************
3209 * StartDocPrinterW [WINSPOOL.@]
3211 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3213 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3214 opened_printer_t *printer;
3215 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3216 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3217 JOB_INFO_1W job_info;
3218 DWORD needed, ret = 0;
3222 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3223 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3224 debugstr_w(doc->pDatatype));
3226 if(Level < 1 || Level > 3)
3228 SetLastError(ERROR_INVALID_LEVEL);
3232 EnterCriticalSection(&printer_handles_cs);
3233 printer = get_opened_printer(hPrinter);
3236 SetLastError(ERROR_INVALID_HANDLE);
3242 SetLastError(ERROR_INVALID_PRINTER_STATE);
3246 /* Even if we're printing to a file we still add a print job, we'll
3247 just ignore the spool file name */
3249 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3251 ERR("AddJob failed gle %u\n", GetLastError());
3255 if(doc->pOutputFile)
3256 filename = doc->pOutputFile;
3258 filename = addjob->Path;
3260 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3261 if(hf == INVALID_HANDLE_VALUE)
3264 memset(&job_info, 0, sizeof(job_info));
3265 job_info.pDocument = doc->pDocName;
3266 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3268 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3269 printer->doc->hf = hf;
3270 ret = printer->doc->job_id = addjob->JobId;
3272 LeaveCriticalSection(&printer_handles_cs);
3277 /*****************************************************************************
3278 * StartPagePrinter [WINSPOOL.@]
3280 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3282 FIXME("(%p): stub\n", hPrinter);
3286 /*****************************************************************************
3287 * GetFormA [WINSPOOL.@]
3289 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3290 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3292 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3293 Level,pForm,cbBuf,pcbNeeded);
3297 /*****************************************************************************
3298 * GetFormW [WINSPOOL.@]
3300 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3301 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3303 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3304 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3308 /*****************************************************************************
3309 * SetFormA [WINSPOOL.@]
3311 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3314 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3318 /*****************************************************************************
3319 * SetFormW [WINSPOOL.@]
3321 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3324 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3328 /*****************************************************************************
3329 * ReadPrinter [WINSPOOL.@]
3331 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3332 LPDWORD pNoBytesRead)
3334 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3338 /*****************************************************************************
3339 * ResetPrinterA [WINSPOOL.@]
3341 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3343 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3347 /*****************************************************************************
3348 * ResetPrinterW [WINSPOOL.@]
3350 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3352 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3356 /*****************************************************************************
3357 * WINSPOOL_GetDWORDFromReg
3359 * Return DWORD associated with ValueName from hkey.
3361 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3363 DWORD sz = sizeof(DWORD), type, value = 0;
3366 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3368 if(ret != ERROR_SUCCESS) {
3369 WARN("Got ret = %d on name %s\n", ret, ValueName);
3372 if(type != REG_DWORD) {
3373 ERR("Got type %d\n", type);
3380 /*****************************************************************************
3381 * get_filename_from_reg [internal]
3383 * Get ValueName from hkey storing result in out
3384 * when the Value in the registry has only a filename, use driverdir as prefix
3385 * outlen is space left in out
3386 * String is stored either as unicode or ascii
3390 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3391 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3393 WCHAR filename[MAX_PATH];
3397 LPWSTR buffer = filename;
3401 size = sizeof(filename);
3403 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3404 if (ret == ERROR_MORE_DATA) {
3405 TRACE("need dynamic buffer: %u\n", size);
3406 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3408 /* No Memory is bad */
3412 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3415 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3416 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3422 /* do we have a full path ? */
3423 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3424 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3427 /* we must build the full Path */
3429 if ((out) && (outlen > dirlen)) {
3431 lstrcpyW((LPWSTR)out, driverdir);
3435 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3444 /* write the filename */
3446 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3447 if ((out) && (outlen >= size)) {
3448 lstrcpyW((LPWSTR)out, ptr);
3457 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3458 if ((out) && (outlen >= size)) {
3459 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3467 ptr += lstrlenW(ptr)+1;
3468 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3471 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3473 /* write the multisz-termination */
3474 if (type == REG_MULTI_SZ) {
3475 size = (unicode) ? sizeof(WCHAR) : 1;
3478 if (out && (outlen >= size)) {
3479 memset (out, 0, size);
3485 /*****************************************************************************
3486 * WINSPOOL_GetStringFromReg
3488 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3489 * String is stored either as unicode or ascii.
3490 * Bit of a hack here to get the ValueName if we want ascii.
3492 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3493 DWORD buflen, DWORD *needed,
3496 DWORD sz = buflen, type;
3500 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3502 LPSTR ValueNameA = strdupWtoA(ValueName);
3503 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3504 HeapFree(GetProcessHeap(),0,ValueNameA);
3506 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3507 WARN("Got ret = %d\n", ret);
3511 /* add space for terminating '\0' */
3512 sz += unicode ? sizeof(WCHAR) : 1;
3516 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3521 /*****************************************************************************
3522 * WINSPOOL_GetDefaultDevMode
3524 * Get a default DevMode values for wineps.
3528 static void WINSPOOL_GetDefaultDevMode(
3530 DWORD buflen, DWORD *needed,
3534 static const char szwps[] = "wineps.drv";
3536 /* fill default DEVMODE - should be read from ppd... */
3537 ZeroMemory( &dm, sizeof(dm) );
3538 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3539 dm.dmSpecVersion = DM_SPECVERSION;
3540 dm.dmDriverVersion = 1;
3541 dm.dmSize = sizeof(DEVMODEA);
3542 dm.dmDriverExtra = 0;
3544 DM_ORIENTATION | DM_PAPERSIZE |
3545 DM_PAPERLENGTH | DM_PAPERWIDTH |
3548 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3549 DM_YRESOLUTION | DM_TTOPTION;
3551 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3552 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3553 dm.u1.s1.dmPaperLength = 2970;
3554 dm.u1.s1.dmPaperWidth = 2100;
3556 dm.u1.s1.dmScale = 100;
3557 dm.u1.s1.dmCopies = 1;
3558 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3559 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3562 dm.dmYResolution = 300; /* 300dpi */
3563 dm.dmTTOption = DMTT_BITMAP;
3566 /* dm.dmLogPixels */
3567 /* dm.dmBitsPerPel */
3568 /* dm.dmPelsWidth */
3569 /* dm.dmPelsHeight */
3570 /* dm.u2.dmDisplayFlags */
3571 /* dm.dmDisplayFrequency */
3572 /* dm.dmICMMethod */
3573 /* dm.dmICMIntent */
3574 /* dm.dmMediaType */
3575 /* dm.dmDitherType */
3576 /* dm.dmReserved1 */
3577 /* dm.dmReserved2 */
3578 /* dm.dmPanningWidth */
3579 /* dm.dmPanningHeight */
3582 if(buflen >= sizeof(DEVMODEW)) {
3583 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3584 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3585 HeapFree(GetProcessHeap(),0,pdmW);
3587 *needed = sizeof(DEVMODEW);
3591 if(buflen >= sizeof(DEVMODEA)) {
3592 memcpy(ptr, &dm, sizeof(DEVMODEA));
3594 *needed = sizeof(DEVMODEA);
3598 /*****************************************************************************
3599 * WINSPOOL_GetDevModeFromReg
3601 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3602 * DevMode is stored either as unicode or ascii.
3604 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3606 DWORD buflen, DWORD *needed,
3609 DWORD sz = buflen, type;
3612 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3613 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3614 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3615 if (sz < sizeof(DEVMODEA))
3617 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3620 /* ensures that dmSize is not erratically bogus if registry is invalid */
3621 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3622 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3624 sz += (CCHDEVICENAME + CCHFORMNAME);
3626 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3627 memcpy(ptr, dmW, sz);
3628 HeapFree(GetProcessHeap(),0,dmW);
3635 /*********************************************************************
3636 * WINSPOOL_GetPrinter_1
3638 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3639 * The strings are either stored as unicode or ascii.
3641 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3642 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3645 DWORD size, left = cbBuf;
3646 BOOL space = (cbBuf > 0);
3651 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3653 if(space && size <= left) {
3654 pi1->pName = (LPWSTR)ptr;
3662 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3665 if(space && size <= left) {
3666 pi1->pDescription = (LPWSTR)ptr;
3674 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3676 if(space && size <= left) {
3677 pi1->pComment = (LPWSTR)ptr;
3685 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3687 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3688 memset(pi1, 0, sizeof(*pi1));
3692 /*********************************************************************
3693 * WINSPOOL_GetPrinter_2
3695 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3696 * The strings are either stored as unicode or ascii.
3698 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3699 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3702 DWORD size, left = cbBuf;
3703 BOOL space = (cbBuf > 0);
3708 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3710 if(space && size <= left) {
3711 pi2->pPrinterName = (LPWSTR)ptr;
3718 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3720 if(space && size <= left) {
3721 pi2->pShareName = (LPWSTR)ptr;
3728 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3730 if(space && size <= left) {
3731 pi2->pPortName = (LPWSTR)ptr;
3738 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3740 if(space && size <= left) {
3741 pi2->pDriverName = (LPWSTR)ptr;
3748 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3750 if(space && size <= left) {
3751 pi2->pComment = (LPWSTR)ptr;
3758 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3760 if(space && size <= left) {
3761 pi2->pLocation = (LPWSTR)ptr;
3768 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3770 if(space && size <= left) {
3771 pi2->pDevMode = (LPDEVMODEW)ptr;
3780 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3781 if(space && size <= left) {
3782 pi2->pDevMode = (LPDEVMODEW)ptr;
3789 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3791 if(space && size <= left) {
3792 pi2->pSepFile = (LPWSTR)ptr;
3799 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3801 if(space && size <= left) {
3802 pi2->pPrintProcessor = (LPWSTR)ptr;
3809 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3811 if(space && size <= left) {
3812 pi2->pDatatype = (LPWSTR)ptr;
3819 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3821 if(space && size <= left) {
3822 pi2->pParameters = (LPWSTR)ptr;
3830 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3831 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3832 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3833 "Default Priority");
3834 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3835 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3838 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3839 memset(pi2, 0, sizeof(*pi2));
3844 /*********************************************************************
3845 * WINSPOOL_GetPrinter_4
3847 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3849 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3850 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3853 DWORD size, left = cbBuf;
3854 BOOL space = (cbBuf > 0);
3859 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3861 if(space && size <= left) {
3862 pi4->pPrinterName = (LPWSTR)ptr;
3870 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3873 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3874 memset(pi4, 0, sizeof(*pi4));
3879 /*********************************************************************
3880 * WINSPOOL_GetPrinter_5
3882 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3884 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3885 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3888 DWORD size, left = cbBuf;
3889 BOOL space = (cbBuf > 0);
3894 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3896 if(space && size <= left) {
3897 pi5->pPrinterName = (LPWSTR)ptr;
3904 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3906 if(space && size <= left) {
3907 pi5->pPortName = (LPWSTR)ptr;
3915 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3916 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3918 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3922 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3923 memset(pi5, 0, sizeof(*pi5));
3928 /*********************************************************************
3929 * WINSPOOL_GetPrinter_7
3931 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3933 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3934 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3936 DWORD size, left = cbBuf;
3937 BOOL space = (cbBuf > 0);
3942 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3944 if (space && size <= left) {
3945 pi7->pszObjectGUID = (LPWSTR)ptr;
3953 /* We do not have a Directory Service */
3954 pi7->dwAction = DSPRINT_UNPUBLISH;
3957 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3958 memset(pi7, 0, sizeof(*pi7));
3963 /*********************************************************************
3964 * WINSPOOL_GetPrinter_9
3966 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3967 * The strings are either stored as unicode or ascii.
3969 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3970 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3973 BOOL space = (cbBuf > 0);
3977 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3978 if(space && size <= cbBuf) {
3979 pi9->pDevMode = (LPDEVMODEW)buf;
3986 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3987 if(space && size <= cbBuf) {
3988 pi9->pDevMode = (LPDEVMODEW)buf;
3994 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3995 memset(pi9, 0, sizeof(*pi9));
4000 /*****************************************************************************
4001 * WINSPOOL_GetPrinter
4003 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4004 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4005 * just a collection of pointers to strings.
4007 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4008 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4011 DWORD size, needed = 0;
4013 HKEY hkeyPrinter, hkeyPrinters;
4016 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4018 if (!(name = get_opened_printer_name(hPrinter))) {
4019 SetLastError(ERROR_INVALID_HANDLE);
4023 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4025 ERR("Can't create Printers key\n");
4028 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4030 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4031 RegCloseKey(hkeyPrinters);
4032 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4039 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4041 size = sizeof(PRINTER_INFO_2W);
4043 ptr = pPrinter + size;
4045 memset(pPrinter, 0, size);
4050 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4058 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4060 size = sizeof(PRINTER_INFO_4W);
4062 ptr = pPrinter + size;
4064 memset(pPrinter, 0, size);
4069 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4078 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4080 size = sizeof(PRINTER_INFO_5W);
4082 ptr = pPrinter + size;
4084 memset(pPrinter, 0, size);
4090 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4099 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4101 size = sizeof(PRINTER_INFO_6);
4102 if (size <= cbBuf) {
4103 /* FIXME: We do not update the status yet */
4104 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4116 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4118 size = sizeof(PRINTER_INFO_7W);
4119 if (size <= cbBuf) {
4120 ptr = pPrinter + size;
4122 memset(pPrinter, 0, size);
4128 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4136 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4138 size = sizeof(PRINTER_INFO_9W);
4140 ptr = pPrinter + size;
4142 memset(pPrinter, 0, size);
4148 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4155 FIXME("Unimplemented level %d\n", Level);
4156 SetLastError(ERROR_INVALID_LEVEL);
4157 RegCloseKey(hkeyPrinters);
4158 RegCloseKey(hkeyPrinter);
4162 RegCloseKey(hkeyPrinter);
4163 RegCloseKey(hkeyPrinters);
4165 TRACE("returning %d needed = %d\n", ret, needed);
4166 if(pcbNeeded) *pcbNeeded = needed;
4168 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4172 /*****************************************************************************
4173 * GetPrinterW [WINSPOOL.@]
4175 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4176 DWORD cbBuf, LPDWORD pcbNeeded)
4178 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4182 /*****************************************************************************
4183 * GetPrinterA [WINSPOOL.@]
4185 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4186 DWORD cbBuf, LPDWORD pcbNeeded)
4188 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4192 /*****************************************************************************
4193 * WINSPOOL_EnumPrinters
4195 * Implementation of EnumPrintersA|W
4197 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4198 DWORD dwLevel, LPBYTE lpbPrinters,
4199 DWORD cbBuf, LPDWORD lpdwNeeded,
4200 LPDWORD lpdwReturned, BOOL unicode)
4203 HKEY hkeyPrinters, hkeyPrinter;
4204 WCHAR PrinterName[255];
4205 DWORD needed = 0, number = 0;
4206 DWORD used, i, left;
4210 memset(lpbPrinters, 0, cbBuf);
4216 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4217 if(dwType == PRINTER_ENUM_DEFAULT)
4220 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4221 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4222 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4224 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4232 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4233 FIXME("dwType = %08x\n", dwType);
4234 SetLastError(ERROR_INVALID_FLAGS);
4238 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4240 ERR("Can't create Printers key\n");
4244 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4245 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4246 RegCloseKey(hkeyPrinters);
4247 ERR("Can't query Printers key\n");
4250 TRACE("Found %d printers\n", number);
4254 used = number * sizeof(PRINTER_INFO_1W);
4257 used = number * sizeof(PRINTER_INFO_2W);
4260 used = number * sizeof(PRINTER_INFO_4W);
4263 used = number * sizeof(PRINTER_INFO_5W);
4267 SetLastError(ERROR_INVALID_LEVEL);
4268 RegCloseKey(hkeyPrinters);
4271 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4273 for(i = 0; i < number; i++) {
4274 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4276 ERR("Can't enum key number %d\n", i);
4277 RegCloseKey(hkeyPrinters);
4280 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4281 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4283 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4284 RegCloseKey(hkeyPrinters);
4289 buf = lpbPrinters + used;
4290 left = cbBuf - used;
4298 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4299 left, &needed, unicode);
4301 if(pi) pi += sizeof(PRINTER_INFO_1W);
4304 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4305 left, &needed, unicode);
4307 if(pi) pi += sizeof(PRINTER_INFO_2W);
4310 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4311 left, &needed, unicode);
4313 if(pi) pi += sizeof(PRINTER_INFO_4W);
4316 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4317 left, &needed, unicode);
4319 if(pi) pi += sizeof(PRINTER_INFO_5W);
4322 ERR("Shouldn't be here!\n");
4323 RegCloseKey(hkeyPrinter);
4324 RegCloseKey(hkeyPrinters);
4327 RegCloseKey(hkeyPrinter);
4329 RegCloseKey(hkeyPrinters);
4336 memset(lpbPrinters, 0, cbBuf);
4337 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4341 *lpdwReturned = number;
4342 SetLastError(ERROR_SUCCESS);
4347 /******************************************************************
4348 * EnumPrintersW [WINSPOOL.@]
4350 * Enumerates the available printers, print servers and print
4351 * providers, depending on the specified flags, name and level.
4355 * If level is set to 1:
4356 * Returns an array of PRINTER_INFO_1 data structures in the
4357 * lpbPrinters buffer.
4359 * If level is set to 2:
4360 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4361 * Returns an array of PRINTER_INFO_2 data structures in the
4362 * lpbPrinters buffer. Note that according to MSDN also an
4363 * OpenPrinter should be performed on every remote printer.
4365 * If level is set to 4 (officially WinNT only):
4366 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4367 * Fast: Only the registry is queried to retrieve printer names,
4368 * no connection to the driver is made.
4369 * Returns an array of PRINTER_INFO_4 data structures in the
4370 * lpbPrinters buffer.
4372 * If level is set to 5 (officially WinNT4/Win9x only):
4373 * Fast: Only the registry is queried to retrieve printer names,
4374 * no connection to the driver is made.
4375 * Returns an array of PRINTER_INFO_5 data structures in the
4376 * lpbPrinters buffer.
4378 * If level set to 3 or 6+:
4379 * returns zero (failure!)
4381 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4385 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4386 * - Only levels 2, 4 and 5 are implemented at the moment.
4387 * - 16-bit printer drivers are not enumerated.
4388 * - Returned amount of bytes used/needed does not match the real Windoze
4389 * implementation (as in this implementation, all strings are part
4390 * of the buffer, whereas Win32 keeps them somewhere else)
4391 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4394 * - In a regular Wine installation, no registry settings for printers
4395 * exist, which makes this function return an empty list.
4397 BOOL WINAPI EnumPrintersW(
4398 DWORD dwType, /* [in] Types of print objects to enumerate */
4399 LPWSTR lpszName, /* [in] name of objects to enumerate */
4400 DWORD dwLevel, /* [in] type of printer info structure */
4401 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4402 DWORD cbBuf, /* [in] max size of buffer in bytes */
4403 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4404 LPDWORD lpdwReturned /* [out] number of entries returned */
4407 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4408 lpdwNeeded, lpdwReturned, TRUE);
4411 /******************************************************************
4412 * EnumPrintersA [WINSPOOL.@]
4417 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4418 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4421 UNICODE_STRING pNameU;
4425 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4426 pPrinters, cbBuf, pcbNeeded, pcReturned);
4428 pNameW = asciitounicode(&pNameU, pName);
4430 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4431 MS Office need this */
4432 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4434 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4436 RtlFreeUnicodeString(&pNameU);
4438 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4440 HeapFree(GetProcessHeap(), 0, pPrintersW);
4444 /*****************************************************************************
4445 * WINSPOOL_GetDriverInfoFromReg [internal]
4447 * Enters the information from the registry into the DRIVER_INFO struct
4450 * zero if the printer driver does not exist in the registry
4451 * (only if Level > 1) otherwise nonzero
4453 static BOOL WINSPOOL_GetDriverInfoFromReg(
4456 const printenv_t * env,
4458 LPBYTE ptr, /* DRIVER_INFO */
4459 LPBYTE pDriverStrings, /* strings buffer */
4460 DWORD cbBuf, /* size of string buffer */
4461 LPDWORD pcbNeeded, /* space needed for str. */
4462 BOOL unicode) /* type of strings */
4466 WCHAR driverdir[MAX_PATH];
4468 LPBYTE strPtr = pDriverStrings;
4469 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4471 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4472 debugstr_w(DriverName), env,
4473 Level, di, pDriverStrings, cbBuf, unicode);
4475 if (di) ZeroMemory(di, di_sizeof[Level]);
4478 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4479 if (*pcbNeeded <= cbBuf)
4480 strcpyW((LPWSTR)strPtr, DriverName);
4484 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4485 if (*pcbNeeded <= cbBuf)
4486 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4489 /* pName for level 1 has a different offset! */
4491 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4495 /* .cVersion and .pName for level > 1 */
4497 di->cVersion = env->driverversion;
4498 di->pName = (LPWSTR) strPtr;
4499 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4502 /* Reserve Space for the largest subdir and a Backslash*/
4503 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4504 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4505 /* Should never Fail */
4508 lstrcatW(driverdir, env->versionsubdir);
4509 lstrcatW(driverdir, backslashW);
4511 /* dirlen must not include the terminating zero */
4512 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4513 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4515 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4516 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4517 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4523 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4525 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4528 if (*pcbNeeded <= cbBuf) {
4530 lstrcpyW((LPWSTR)strPtr, env->envname);
4534 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4536 if (di) di->pEnvironment = (LPWSTR)strPtr;
4537 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4540 /* .pDriverPath is the Graphics rendering engine.
4541 The full Path is required to avoid a crash in some apps */
4542 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4544 if (*pcbNeeded <= cbBuf)
4545 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4547 if (di) di->pDriverPath = (LPWSTR)strPtr;
4548 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4551 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4552 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4554 if (*pcbNeeded <= cbBuf)
4555 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4557 if (di) di->pDataFile = (LPWSTR)strPtr;
4558 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4561 /* .pConfigFile is the Driver user Interface */
4562 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4564 if (*pcbNeeded <= cbBuf)
4565 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4567 if (di) di->pConfigFile = (LPWSTR)strPtr;
4568 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4572 RegCloseKey(hkeyDriver);
4573 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4578 RegCloseKey(hkeyDriver);
4579 FIXME("level 5: incomplete\n");
4584 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4586 if (*pcbNeeded <= cbBuf)
4587 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4589 if (di) di->pHelpFile = (LPWSTR)strPtr;
4590 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4593 /* .pDependentFiles */
4594 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4596 if (*pcbNeeded <= cbBuf)
4597 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4599 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4600 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4602 else if (GetVersion() & 0x80000000) {
4603 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4604 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4606 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4608 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4609 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4612 /* .pMonitorName is the optional Language Monitor */
4613 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4615 if (*pcbNeeded <= cbBuf)
4616 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4618 if (di) di->pMonitorName = (LPWSTR)strPtr;
4619 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4622 /* .pDefaultDataType */
4623 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4625 if(*pcbNeeded <= cbBuf)
4626 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4628 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4629 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4633 RegCloseKey(hkeyDriver);
4634 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4638 /* .pszzPreviousNames */
4639 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4641 if(*pcbNeeded <= cbBuf)
4642 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4644 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4645 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4649 RegCloseKey(hkeyDriver);
4650 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4654 /* support is missing, but not important enough for a FIXME */
4655 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4658 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4660 if(*pcbNeeded <= cbBuf)
4661 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4663 if (di) di->pszMfgName = (LPWSTR)strPtr;
4664 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4668 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4670 if(*pcbNeeded <= cbBuf)
4671 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4673 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4674 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4677 /* .pszHardwareID */
4678 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4680 if(*pcbNeeded <= cbBuf)
4681 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4683 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4684 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4688 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4690 if(*pcbNeeded <= cbBuf)
4691 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4693 if (di) di->pszProvider = (LPWSTR)strPtr;
4694 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4698 RegCloseKey(hkeyDriver);
4702 /* support is missing, but not important enough for a FIXME */
4703 TRACE("level 8: incomplete\n");
4705 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4706 RegCloseKey(hkeyDriver);
4710 /*****************************************************************************
4711 * WINSPOOL_GetPrinterDriver
4713 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4714 DWORD Level, LPBYTE pDriverInfo,
4715 DWORD cbBuf, LPDWORD pcbNeeded,
4719 WCHAR DriverName[100];
4720 DWORD ret, type, size, needed = 0;
4722 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4723 const printenv_t * env;
4725 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4726 Level,pDriverInfo,cbBuf, pcbNeeded);
4729 if (!(name = get_opened_printer_name(hPrinter))) {
4730 SetLastError(ERROR_INVALID_HANDLE);
4734 if (Level < 1 || Level == 7 || Level > 8) {
4735 SetLastError(ERROR_INVALID_LEVEL);
4739 env = validate_envW(pEnvironment);
4740 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4742 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4744 ERR("Can't create Printers key\n");
4747 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4749 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4750 RegCloseKey(hkeyPrinters);
4751 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4754 size = sizeof(DriverName);
4756 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4757 (LPBYTE)DriverName, &size);
4758 RegCloseKey(hkeyPrinter);
4759 RegCloseKey(hkeyPrinters);
4760 if(ret != ERROR_SUCCESS) {
4761 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4765 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4767 ERR("Can't create Drivers key\n");
4771 size = di_sizeof[Level];
4772 if ((size <= cbBuf) && pDriverInfo)
4773 ptr = pDriverInfo + size;
4775 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4776 env, Level, pDriverInfo, ptr,
4777 (cbBuf < size) ? 0 : cbBuf - size,
4778 &needed, unicode)) {
4779 RegCloseKey(hkeyDrivers);
4783 RegCloseKey(hkeyDrivers);
4785 if(pcbNeeded) *pcbNeeded = size + needed;
4786 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4787 if(cbBuf >= needed) return TRUE;
4788 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4792 /*****************************************************************************
4793 * GetPrinterDriverA [WINSPOOL.@]
4795 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4796 DWORD Level, LPBYTE pDriverInfo,
4797 DWORD cbBuf, LPDWORD pcbNeeded)
4800 UNICODE_STRING pEnvW;
4803 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4804 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4805 cbBuf, pcbNeeded, FALSE);
4806 RtlFreeUnicodeString(&pEnvW);
4809 /*****************************************************************************
4810 * GetPrinterDriverW [WINSPOOL.@]
4812 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4813 DWORD Level, LPBYTE pDriverInfo,
4814 DWORD cbBuf, LPDWORD pcbNeeded)
4816 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4817 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4820 /*****************************************************************************
4821 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4823 * Return the PATH for the Printer-Drivers (UNICODE)
4826 * pName [I] Servername (NT only) or NULL (local Computer)
4827 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4828 * Level [I] Structure-Level (must be 1)
4829 * pDriverDirectory [O] PTR to Buffer that receives the Result
4830 * cbBuf [I] Size of Buffer at pDriverDirectory
4831 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4832 * required for pDriverDirectory
4835 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4836 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4837 * if cbBuf is too small
4839 * Native Values returned in pDriverDirectory on Success:
4840 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4841 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4842 *| win9x(Windows 4.0): "%winsysdir%"
4844 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4847 *- Only NULL or "" is supported for pName
4850 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4851 DWORD Level, LPBYTE pDriverDirectory,
4852 DWORD cbBuf, LPDWORD pcbNeeded)
4854 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4855 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4857 if ((backend == NULL) && !load_backend()) return FALSE;
4860 /* (Level != 1) is ignored in win9x */
4861 SetLastError(ERROR_INVALID_LEVEL);
4864 if (pcbNeeded == NULL) {
4865 /* (pcbNeeded == NULL) is ignored in win9x */
4866 SetLastError(RPC_X_NULL_REF_POINTER);
4870 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4871 pDriverDirectory, cbBuf, pcbNeeded);
4876 /*****************************************************************************
4877 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4879 * Return the PATH for the Printer-Drivers (ANSI)
4881 * See GetPrinterDriverDirectoryW.
4884 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4887 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4888 DWORD Level, LPBYTE pDriverDirectory,
4889 DWORD cbBuf, LPDWORD pcbNeeded)
4891 UNICODE_STRING nameW, environmentW;
4894 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4895 WCHAR *driverDirectoryW = NULL;
4897 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4898 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4900 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4902 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4903 else nameW.Buffer = NULL;
4904 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4905 else environmentW.Buffer = NULL;
4907 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4908 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4911 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4912 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4914 *pcbNeeded = needed;
4915 ret = (needed <= cbBuf) ? TRUE : FALSE;
4917 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4919 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4921 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4922 RtlFreeUnicodeString(&environmentW);
4923 RtlFreeUnicodeString(&nameW);
4928 /*****************************************************************************
4929 * AddPrinterDriverA [WINSPOOL.@]
4931 * See AddPrinterDriverW.
4934 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4936 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4937 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4940 /******************************************************************************
4941 * AddPrinterDriverW (WINSPOOL.@)
4943 * Install a Printer Driver
4946 * pName [I] Servername or NULL (local Computer)
4947 * level [I] Level for the supplied DRIVER_INFO_*W struct
4948 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4955 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4957 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4958 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4961 /*****************************************************************************
4962 * AddPrintProcessorA [WINSPOOL.@]
4964 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4965 LPSTR pPrintProcessorName)
4967 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4968 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4972 /*****************************************************************************
4973 * AddPrintProcessorW [WINSPOOL.@]
4975 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4976 LPWSTR pPrintProcessorName)
4978 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4979 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4983 /*****************************************************************************
4984 * AddPrintProvidorA [WINSPOOL.@]
4986 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4988 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4992 /*****************************************************************************
4993 * AddPrintProvidorW [WINSPOOL.@]
4995 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4997 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5001 /*****************************************************************************
5002 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5004 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5005 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5007 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5008 pDevModeOutput, pDevModeInput);
5012 /*****************************************************************************
5013 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5015 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5016 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5018 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5019 pDevModeOutput, pDevModeInput);
5023 /*****************************************************************************
5024 * PrinterProperties [WINSPOOL.@]
5026 * Displays a dialog to set the properties of the printer.
5029 * nonzero on success or zero on failure
5032 * implemented as stub only
5034 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5035 HANDLE hPrinter /* [in] handle to printer object */
5037 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5038 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5042 /*****************************************************************************
5043 * EnumJobsA [WINSPOOL.@]
5046 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5047 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5050 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5051 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5053 if(pcbNeeded) *pcbNeeded = 0;
5054 if(pcReturned) *pcReturned = 0;
5059 /*****************************************************************************
5060 * EnumJobsW [WINSPOOL.@]
5063 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5064 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5067 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5068 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5070 if(pcbNeeded) *pcbNeeded = 0;
5071 if(pcReturned) *pcReturned = 0;
5075 /*****************************************************************************
5076 * WINSPOOL_EnumPrinterDrivers [internal]
5078 * Delivers information about all printer drivers installed on the
5079 * localhost or a given server
5082 * nonzero on success or zero on failure. If the buffer for the returned
5083 * information is too small the function will return an error
5086 * - only implemented for localhost, foreign hosts will return an error
5088 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5089 DWORD Level, LPBYTE pDriverInfo,
5090 DWORD cbBuf, LPDWORD pcbNeeded,
5091 LPDWORD pcReturned, BOOL unicode)
5094 DWORD i, needed, number = 0, size = 0;
5095 WCHAR DriverNameW[255];
5097 const printenv_t * env;
5099 TRACE("%s,%s,%d,%p,%d,%d\n",
5100 debugstr_w(pName), debugstr_w(pEnvironment),
5101 Level, pDriverInfo, cbBuf, unicode);
5103 /* check for local drivers */
5104 if((pName) && (pName[0])) {
5105 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5106 SetLastError(ERROR_ACCESS_DENIED);
5110 env = validate_envW(pEnvironment);
5111 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5113 /* check input parameter */
5114 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5115 SetLastError(ERROR_INVALID_LEVEL);
5119 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5120 SetLastError(RPC_X_NULL_REF_POINTER);
5124 /* initialize return values */
5126 memset( pDriverInfo, 0, cbBuf);
5130 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5132 ERR("Can't open Drivers key\n");
5136 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5137 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5138 RegCloseKey(hkeyDrivers);
5139 ERR("Can't query Drivers key\n");
5142 TRACE("Found %d Drivers\n", number);
5144 /* get size of single struct
5145 * unicode and ascii structure have the same size
5147 size = di_sizeof[Level];
5149 /* calculate required buffer size */
5150 *pcbNeeded = size * number;
5152 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5154 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5155 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5157 ERR("Can't enum key number %d\n", i);
5158 RegCloseKey(hkeyDrivers);
5161 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5163 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5164 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5165 &needed, unicode)) {
5166 RegCloseKey(hkeyDrivers);
5169 (*pcbNeeded) += needed;
5172 RegCloseKey(hkeyDrivers);
5174 if(cbBuf < *pcbNeeded){
5175 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5179 *pcReturned = number;
5183 /*****************************************************************************
5184 * EnumPrinterDriversW [WINSPOOL.@]
5186 * see function EnumPrinterDrivers for RETURNS, BUGS
5188 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5189 LPBYTE pDriverInfo, DWORD cbBuf,
5190 LPDWORD pcbNeeded, LPDWORD pcReturned)
5192 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5193 cbBuf, pcbNeeded, pcReturned, TRUE);
5196 /*****************************************************************************
5197 * EnumPrinterDriversA [WINSPOOL.@]
5199 * see function EnumPrinterDrivers for RETURNS, BUGS
5201 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5202 LPBYTE pDriverInfo, DWORD cbBuf,
5203 LPDWORD pcbNeeded, LPDWORD pcReturned)
5205 UNICODE_STRING pNameW, pEnvironmentW;
5206 PWSTR pwstrNameW, pwstrEnvironmentW;
5208 pwstrNameW = asciitounicode(&pNameW, pName);
5209 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5211 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5212 Level, pDriverInfo, cbBuf, pcbNeeded,
5214 RtlFreeUnicodeString(&pNameW);
5215 RtlFreeUnicodeString(&pEnvironmentW);
5220 /******************************************************************************
5221 * EnumPortsA (WINSPOOL.@)
5226 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5227 LPDWORD pcbNeeded, LPDWORD pcReturned)
5230 LPBYTE bufferW = NULL;
5231 LPWSTR nameW = NULL;
5233 DWORD numentries = 0;
5236 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5237 cbBuf, pcbNeeded, pcReturned);
5239 /* convert servername to unicode */
5241 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5242 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5243 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5245 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5246 needed = cbBuf * sizeof(WCHAR);
5247 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5248 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5250 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5251 if (pcbNeeded) needed = *pcbNeeded;
5252 /* HeapReAlloc return NULL, when bufferW was NULL */
5253 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5254 HeapAlloc(GetProcessHeap(), 0, needed);
5256 /* Try again with the large Buffer */
5257 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5259 needed = pcbNeeded ? *pcbNeeded : 0;
5260 numentries = pcReturned ? *pcReturned : 0;
5263 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5264 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5267 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5268 DWORD entrysize = 0;
5271 LPPORT_INFO_2W pi2w;
5272 LPPORT_INFO_2A pi2a;
5275 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5277 /* First pass: calculate the size for all Entries */
5278 pi2w = (LPPORT_INFO_2W) bufferW;
5279 pi2a = (LPPORT_INFO_2A) pPorts;
5281 while (index < numentries) {
5283 needed += entrysize; /* PORT_INFO_?A */
5284 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5286 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5287 NULL, 0, NULL, NULL);
5289 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5290 NULL, 0, NULL, NULL);
5291 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5292 NULL, 0, NULL, NULL);
5294 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5295 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5296 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5299 /* check for errors and quit on failure */
5300 if (cbBuf < needed) {
5301 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5305 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5306 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5307 cbBuf -= len ; /* free Bytes in the user-Buffer */
5308 pi2w = (LPPORT_INFO_2W) bufferW;
5309 pi2a = (LPPORT_INFO_2A) pPorts;
5311 /* Second Pass: Fill the User Buffer (if we have one) */
5312 while ((index < numentries) && pPorts) {
5314 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5315 pi2a->pPortName = ptr;
5316 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5317 ptr, cbBuf , NULL, NULL);
5321 pi2a->pMonitorName = ptr;
5322 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5323 ptr, cbBuf, NULL, NULL);
5327 pi2a->pDescription = ptr;
5328 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5329 ptr, cbBuf, NULL, NULL);
5333 pi2a->fPortType = pi2w->fPortType;
5334 pi2a->Reserved = 0; /* documented: "must be zero" */
5337 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5338 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5339 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5344 if (pcbNeeded) *pcbNeeded = needed;
5345 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5347 HeapFree(GetProcessHeap(), 0, nameW);
5348 HeapFree(GetProcessHeap(), 0, bufferW);
5350 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5351 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5357 /******************************************************************************
5358 * EnumPortsW (WINSPOOL.@)
5360 * Enumerate available Ports
5363 * pName [I] Servername or NULL (local Computer)
5364 * Level [I] Structure-Level (1 or 2)
5365 * pPorts [O] PTR to Buffer that receives the Result
5366 * cbBuf [I] Size of Buffer at pPorts
5367 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5368 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5372 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5375 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5378 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5379 cbBuf, pcbNeeded, pcReturned);
5381 if ((backend == NULL) && !load_backend()) return FALSE;
5383 /* Level is not checked in win9x */
5384 if (!Level || (Level > 2)) {
5385 WARN("level (%d) is ignored in win9x\n", Level);
5386 SetLastError(ERROR_INVALID_LEVEL);
5389 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5390 SetLastError(RPC_X_NULL_REF_POINTER);
5394 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5397 /******************************************************************************
5398 * GetDefaultPrinterW (WINSPOOL.@)
5401 * This function must read the value from data 'device' of key
5402 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5404 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5408 WCHAR *buffer, *ptr;
5412 SetLastError(ERROR_INVALID_PARAMETER);
5416 /* make the buffer big enough for the stuff from the profile/registry,
5417 * the content must fit into the local buffer to compute the correct
5418 * size even if the extern buffer is too small or not given.
5419 * (20 for ,driver,port) */
5421 len = max(100, (insize + 20));
5422 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5424 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5426 SetLastError (ERROR_FILE_NOT_FOUND);
5430 TRACE("%s\n", debugstr_w(buffer));
5432 if ((ptr = strchrW(buffer, ',')) == NULL)
5434 SetLastError(ERROR_INVALID_NAME);
5440 *namesize = strlenW(buffer) + 1;
5441 if(!name || (*namesize > insize))
5443 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5447 strcpyW(name, buffer);
5450 HeapFree( GetProcessHeap(), 0, buffer);
5455 /******************************************************************************
5456 * GetDefaultPrinterA (WINSPOOL.@)
5458 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5462 WCHAR *bufferW = NULL;
5466 SetLastError(ERROR_INVALID_PARAMETER);
5470 if(name && *namesize) {
5472 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5475 if(!GetDefaultPrinterW( bufferW, namesize)) {
5480 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5484 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5487 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5490 HeapFree( GetProcessHeap(), 0, bufferW);
5495 /******************************************************************************
5496 * SetDefaultPrinterW (WINSPOOL.204)
5498 * Set the Name of the Default Printer
5501 * pszPrinter [I] Name of the Printer or NULL
5508 * When the Parameter is NULL or points to an Empty String and
5509 * a Default Printer was already present, then this Function changes nothing.
5510 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5511 * the First enumerated local Printer is used.
5514 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5517 TRACE("(%s)\n", debugstr_w(pszPrinter));
5519 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5523 /******************************************************************************
5524 * SetDefaultPrinterA (WINSPOOL.202)
5526 * See SetDefaultPrinterW.
5529 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5532 TRACE("(%s)\n", debugstr_a(pszPrinter));
5534 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5539 /******************************************************************************
5540 * SetPrinterDataExA (WINSPOOL.@)
5542 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5543 LPCSTR pValueName, DWORD Type,
5544 LPBYTE pData, DWORD cbData)
5546 HKEY hkeyPrinter, hkeySubkey;
5549 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5550 debugstr_a(pValueName), Type, pData, cbData);
5552 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5556 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5558 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5559 RegCloseKey(hkeyPrinter);
5562 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5563 RegCloseKey(hkeySubkey);
5564 RegCloseKey(hkeyPrinter);
5568 /******************************************************************************
5569 * SetPrinterDataExW (WINSPOOL.@)
5571 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5572 LPCWSTR pValueName, DWORD Type,
5573 LPBYTE pData, DWORD cbData)
5575 HKEY hkeyPrinter, hkeySubkey;
5578 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5579 debugstr_w(pValueName), Type, pData, cbData);
5581 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5585 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5587 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5588 RegCloseKey(hkeyPrinter);
5591 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5592 RegCloseKey(hkeySubkey);
5593 RegCloseKey(hkeyPrinter);
5597 /******************************************************************************
5598 * SetPrinterDataA (WINSPOOL.@)
5600 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5601 LPBYTE pData, DWORD cbData)
5603 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5607 /******************************************************************************
5608 * SetPrinterDataW (WINSPOOL.@)
5610 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5611 LPBYTE pData, DWORD cbData)
5613 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5617 /******************************************************************************
5618 * GetPrinterDataExA (WINSPOOL.@)
5620 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5621 LPCSTR pValueName, LPDWORD pType,
5622 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5624 HKEY hkeyPrinter, hkeySubkey;
5627 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5628 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5631 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5635 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5637 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5638 RegCloseKey(hkeyPrinter);
5642 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5643 RegCloseKey(hkeySubkey);
5644 RegCloseKey(hkeyPrinter);
5648 /******************************************************************************
5649 * GetPrinterDataExW (WINSPOOL.@)
5651 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5652 LPCWSTR pValueName, LPDWORD pType,
5653 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5655 HKEY hkeyPrinter, hkeySubkey;
5658 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5659 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5662 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5666 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5668 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5669 RegCloseKey(hkeyPrinter);
5673 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5674 RegCloseKey(hkeySubkey);
5675 RegCloseKey(hkeyPrinter);
5679 /******************************************************************************
5680 * GetPrinterDataA (WINSPOOL.@)
5682 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5683 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5685 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5686 pData, nSize, pcbNeeded);
5689 /******************************************************************************
5690 * GetPrinterDataW (WINSPOOL.@)
5692 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5693 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5695 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5696 pData, nSize, pcbNeeded);
5699 /*******************************************************************************
5700 * EnumPrinterDataExW [WINSPOOL.@]
5702 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5703 LPBYTE pEnumValues, DWORD cbEnumValues,
5704 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5706 HKEY hkPrinter, hkSubKey;
5707 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5708 cbValueNameLen, cbMaxValueLen, cbValueLen,
5713 PPRINTER_ENUM_VALUESW ppev;
5715 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5717 if (pKeyName == NULL || *pKeyName == 0)
5718 return ERROR_INVALID_PARAMETER;
5720 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5721 if (ret != ERROR_SUCCESS)
5723 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5728 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5729 if (ret != ERROR_SUCCESS)
5731 r = RegCloseKey (hkPrinter);
5732 if (r != ERROR_SUCCESS)
5733 WARN ("RegCloseKey returned %i\n", r);
5734 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5735 debugstr_w (pKeyName), ret);
5739 ret = RegCloseKey (hkPrinter);
5740 if (ret != ERROR_SUCCESS)
5742 ERR ("RegCloseKey returned %i\n", ret);
5743 r = RegCloseKey (hkSubKey);
5744 if (r != ERROR_SUCCESS)
5745 WARN ("RegCloseKey returned %i\n", r);
5749 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5750 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5751 if (ret != ERROR_SUCCESS)
5753 r = RegCloseKey (hkSubKey);
5754 if (r != ERROR_SUCCESS)
5755 WARN ("RegCloseKey returned %i\n", r);
5756 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5760 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5761 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5763 if (cValues == 0) /* empty key */
5765 r = RegCloseKey (hkSubKey);
5766 if (r != ERROR_SUCCESS)
5767 WARN ("RegCloseKey returned %i\n", r);
5768 *pcbEnumValues = *pnEnumValues = 0;
5769 return ERROR_SUCCESS;
5772 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5774 hHeap = GetProcessHeap ();
5777 ERR ("GetProcessHeap failed\n");
5778 r = RegCloseKey (hkSubKey);
5779 if (r != ERROR_SUCCESS)
5780 WARN ("RegCloseKey returned %i\n", r);
5781 return ERROR_OUTOFMEMORY;
5784 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5785 if (lpValueName == NULL)
5787 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5788 r = RegCloseKey (hkSubKey);
5789 if (r != ERROR_SUCCESS)
5790 WARN ("RegCloseKey returned %i\n", r);
5791 return ERROR_OUTOFMEMORY;
5794 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5795 if (lpValue == NULL)
5797 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5798 if (HeapFree (hHeap, 0, lpValueName) == 0)
5799 WARN ("HeapFree failed with code %i\n", GetLastError ());
5800 r = RegCloseKey (hkSubKey);
5801 if (r != ERROR_SUCCESS)
5802 WARN ("RegCloseKey returned %i\n", r);
5803 return ERROR_OUTOFMEMORY;
5806 TRACE ("pass 1: calculating buffer required for all names and values\n");
5808 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5810 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5812 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5814 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5815 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5816 NULL, NULL, lpValue, &cbValueLen);
5817 if (ret != ERROR_SUCCESS)
5819 if (HeapFree (hHeap, 0, lpValue) == 0)
5820 WARN ("HeapFree failed with code %i\n", GetLastError ());
5821 if (HeapFree (hHeap, 0, lpValueName) == 0)
5822 WARN ("HeapFree failed with code %i\n", GetLastError ());
5823 r = RegCloseKey (hkSubKey);
5824 if (r != ERROR_SUCCESS)
5825 WARN ("RegCloseKey returned %i\n", r);
5826 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5830 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5831 debugstr_w (lpValueName), dwIndex,
5832 cbValueNameLen + 1, cbValueLen);
5834 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5835 cbBufSize += cbValueLen;
5838 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5840 *pcbEnumValues = cbBufSize;
5841 *pnEnumValues = cValues;
5843 if (cbEnumValues < cbBufSize) /* buffer too small */
5845 if (HeapFree (hHeap, 0, lpValue) == 0)
5846 WARN ("HeapFree failed with code %i\n", GetLastError ());
5847 if (HeapFree (hHeap, 0, lpValueName) == 0)
5848 WARN ("HeapFree failed with code %i\n", GetLastError ());
5849 r = RegCloseKey (hkSubKey);
5850 if (r != ERROR_SUCCESS)
5851 WARN ("RegCloseKey returned %i\n", r);
5852 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5853 return ERROR_MORE_DATA;
5856 TRACE ("pass 2: copying all names and values to buffer\n");
5858 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5859 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5861 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5863 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5864 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5865 NULL, &dwType, lpValue, &cbValueLen);
5866 if (ret != ERROR_SUCCESS)
5868 if (HeapFree (hHeap, 0, lpValue) == 0)
5869 WARN ("HeapFree failed with code %i\n", GetLastError ());
5870 if (HeapFree (hHeap, 0, lpValueName) == 0)
5871 WARN ("HeapFree failed with code %i\n", GetLastError ());
5872 r = RegCloseKey (hkSubKey);
5873 if (r != ERROR_SUCCESS)
5874 WARN ("RegCloseKey returned %i\n", r);
5875 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5879 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5880 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5881 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5882 pEnumValues += cbValueNameLen;
5884 /* return # of *bytes* (including trailing \0), not # of chars */
5885 ppev[dwIndex].cbValueName = cbValueNameLen;
5887 ppev[dwIndex].dwType = dwType;
5889 memcpy (pEnumValues, lpValue, cbValueLen);
5890 ppev[dwIndex].pData = pEnumValues;
5891 pEnumValues += cbValueLen;
5893 ppev[dwIndex].cbData = cbValueLen;
5895 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5896 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5899 if (HeapFree (hHeap, 0, lpValue) == 0)
5901 ret = GetLastError ();
5902 ERR ("HeapFree failed with code %i\n", ret);
5903 if (HeapFree (hHeap, 0, lpValueName) == 0)
5904 WARN ("HeapFree failed with code %i\n", GetLastError ());
5905 r = RegCloseKey (hkSubKey);
5906 if (r != ERROR_SUCCESS)
5907 WARN ("RegCloseKey returned %i\n", r);
5911 if (HeapFree (hHeap, 0, lpValueName) == 0)
5913 ret = GetLastError ();
5914 ERR ("HeapFree failed with code %i\n", ret);
5915 r = RegCloseKey (hkSubKey);
5916 if (r != ERROR_SUCCESS)
5917 WARN ("RegCloseKey returned %i\n", r);
5921 ret = RegCloseKey (hkSubKey);
5922 if (ret != ERROR_SUCCESS)
5924 ERR ("RegCloseKey returned %i\n", ret);
5928 return ERROR_SUCCESS;
5931 /*******************************************************************************
5932 * EnumPrinterDataExA [WINSPOOL.@]
5934 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5935 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5936 * what Windows 2000 SP1 does.
5939 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5940 LPBYTE pEnumValues, DWORD cbEnumValues,
5941 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5945 DWORD ret, dwIndex, dwBufSize;
5949 TRACE ("%p %s\n", hPrinter, pKeyName);
5951 if (pKeyName == NULL || *pKeyName == 0)
5952 return ERROR_INVALID_PARAMETER;
5954 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5957 ret = GetLastError ();
5958 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5962 hHeap = GetProcessHeap ();
5965 ERR ("GetProcessHeap failed\n");
5966 return ERROR_OUTOFMEMORY;
5969 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5970 if (pKeyNameW == NULL)
5972 ERR ("Failed to allocate %i bytes from process heap\n",
5973 (LONG)(len * sizeof (WCHAR)));
5974 return ERROR_OUTOFMEMORY;
5977 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5979 ret = GetLastError ();
5980 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5981 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5982 WARN ("HeapFree failed with code %i\n", GetLastError ());
5986 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5987 pcbEnumValues, pnEnumValues);
5988 if (ret != ERROR_SUCCESS)
5990 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5991 WARN ("HeapFree failed with code %i\n", GetLastError ());
5992 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5996 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5998 ret = GetLastError ();
5999 ERR ("HeapFree failed with code %i\n", ret);
6003 if (*pnEnumValues == 0) /* empty key */
6004 return ERROR_SUCCESS;
6007 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6009 PPRINTER_ENUM_VALUESW ppev =
6010 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6012 if (dwBufSize < ppev->cbValueName)
6013 dwBufSize = ppev->cbValueName;
6015 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6016 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6017 dwBufSize = ppev->cbData;
6020 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6022 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6023 if (pBuffer == NULL)
6025 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6026 return ERROR_OUTOFMEMORY;
6029 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6031 PPRINTER_ENUM_VALUESW ppev =
6032 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6034 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6035 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6039 ret = GetLastError ();
6040 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6041 if (HeapFree (hHeap, 0, pBuffer) == 0)
6042 WARN ("HeapFree failed with code %i\n", GetLastError ());
6046 memcpy (ppev->pValueName, pBuffer, len);
6048 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6050 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6051 ppev->dwType != REG_MULTI_SZ)
6054 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6055 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6058 ret = GetLastError ();
6059 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6060 if (HeapFree (hHeap, 0, pBuffer) == 0)
6061 WARN ("HeapFree failed with code %i\n", GetLastError ());
6065 memcpy (ppev->pData, pBuffer, len);
6067 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6068 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6071 if (HeapFree (hHeap, 0, pBuffer) == 0)
6073 ret = GetLastError ();
6074 ERR ("HeapFree failed with code %i\n", ret);
6078 return ERROR_SUCCESS;
6081 /******************************************************************************
6082 * AbortPrinter (WINSPOOL.@)
6084 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6086 FIXME("(%p), stub!\n", hPrinter);
6090 /******************************************************************************
6091 * AddPortA (WINSPOOL.@)
6096 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6098 LPWSTR nameW = NULL;
6099 LPWSTR monitorW = NULL;
6103 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6106 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6107 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6108 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6112 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6113 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6114 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6116 res = AddPortW(nameW, hWnd, monitorW);
6117 HeapFree(GetProcessHeap(), 0, nameW);
6118 HeapFree(GetProcessHeap(), 0, monitorW);
6122 /******************************************************************************
6123 * AddPortW (WINSPOOL.@)
6125 * Add a Port for a specific Monitor
6128 * pName [I] Servername or NULL (local Computer)
6129 * hWnd [I] Handle to parent Window for the Dialog-Box
6130 * pMonitorName [I] Name of the Monitor that manage the Port
6137 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6143 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6145 if (pName && pName[0]) {
6146 SetLastError(ERROR_INVALID_PARAMETER);
6150 if (!pMonitorName) {
6151 SetLastError(RPC_X_NULL_REF_POINTER);
6155 /* an empty Monitorname is Invalid */
6156 if (!pMonitorName[0]) {
6157 SetLastError(ERROR_NOT_SUPPORTED);
6161 pm = monitor_load(pMonitorName, NULL);
6162 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6163 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6164 TRACE("got %d with %u\n", res, GetLastError());
6169 pui = monitor_loadui(pm);
6170 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6171 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6172 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6173 TRACE("got %d with %u\n", res, GetLastError());
6178 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6179 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6181 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6182 SetLastError(ERROR_NOT_SUPPORTED);
6185 monitor_unload(pui);
6188 TRACE("returning %d with %u\n", res, GetLastError());
6192 /******************************************************************************
6193 * AddPortExA (WINSPOOL.@)
6198 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6201 PORT_INFO_2A * pi2A;
6202 LPWSTR nameW = NULL;
6203 LPWSTR monitorW = NULL;
6207 pi2A = (PORT_INFO_2A *) pBuffer;
6209 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6210 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6212 if ((level < 1) || (level > 2)) {
6213 SetLastError(ERROR_INVALID_LEVEL);
6218 SetLastError(ERROR_INVALID_PARAMETER);
6223 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6224 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6225 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6229 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6230 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6231 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6234 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6236 if (pi2A->pPortName) {
6237 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6238 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6239 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6243 if (pi2A->pMonitorName) {
6244 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6245 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6246 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6249 if (pi2A->pDescription) {
6250 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6251 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6252 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6254 pi2W.fPortType = pi2A->fPortType;
6255 pi2W.Reserved = pi2A->Reserved;
6258 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6260 HeapFree(GetProcessHeap(), 0, nameW);
6261 HeapFree(GetProcessHeap(), 0, monitorW);
6262 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6263 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6264 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6269 /******************************************************************************
6270 * AddPortExW (WINSPOOL.@)
6272 * Add a Port for a specific Monitor, without presenting a user interface
6275 * pName [I] Servername or NULL (local Computer)
6276 * level [I] Structure-Level (1 or 2) for pBuffer
6277 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6278 * pMonitorName [I] Name of the Monitor that manage the Port
6285 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6291 pi2 = (PORT_INFO_2W *) pBuffer;
6293 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6294 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6295 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6296 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6299 if ((level < 1) || (level > 2)) {
6300 SetLastError(ERROR_INVALID_LEVEL);
6304 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6305 SetLastError(ERROR_INVALID_PARAMETER);
6309 /* load the Monitor */
6310 pm = monitor_load(pMonitorName, NULL);
6312 SetLastError(ERROR_INVALID_PARAMETER);
6316 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6317 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6318 TRACE("got %u with %u\n", res, GetLastError());
6322 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6328 /******************************************************************************
6329 * AddPrinterConnectionA (WINSPOOL.@)
6331 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6333 FIXME("%s\n", debugstr_a(pName));
6337 /******************************************************************************
6338 * AddPrinterConnectionW (WINSPOOL.@)
6340 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6342 FIXME("%s\n", debugstr_w(pName));
6346 /******************************************************************************
6347 * AddPrinterDriverExW (WINSPOOL.@)
6349 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6352 * pName [I] Servername or NULL (local Computer)
6353 * level [I] Level for the supplied DRIVER_INFO_*W struct
6354 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6355 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6362 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6364 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6366 if ((backend == NULL) && !load_backend()) return FALSE;
6368 if (level < 2 || level == 5 || level == 7 || level > 8) {
6369 SetLastError(ERROR_INVALID_LEVEL);
6374 SetLastError(ERROR_INVALID_PARAMETER);
6378 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6381 /******************************************************************************
6382 * AddPrinterDriverExA (WINSPOOL.@)
6384 * See AddPrinterDriverExW.
6387 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6389 DRIVER_INFO_8A *diA;
6391 LPWSTR nameW = NULL;
6396 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6398 diA = (DRIVER_INFO_8A *) pDriverInfo;
6399 ZeroMemory(&diW, sizeof(diW));
6401 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6402 SetLastError(ERROR_INVALID_LEVEL);
6407 SetLastError(ERROR_INVALID_PARAMETER);
6411 /* convert servername to unicode */
6413 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6414 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6415 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6419 diW.cVersion = diA->cVersion;
6422 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6423 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6424 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6427 if (diA->pEnvironment) {
6428 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6429 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6430 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6433 if (diA->pDriverPath) {
6434 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6435 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6436 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6439 if (diA->pDataFile) {
6440 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6441 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6442 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6445 if (diA->pConfigFile) {
6446 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6447 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6448 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6451 if ((Level > 2) && diA->pDependentFiles) {
6452 lenA = multi_sz_lenA(diA->pDependentFiles);
6453 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6454 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6455 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6458 if ((Level > 2) && diA->pMonitorName) {
6459 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6460 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6461 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6464 if ((Level > 3) && diA->pDefaultDataType) {
6465 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6466 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6467 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6470 if ((Level > 3) && diA->pszzPreviousNames) {
6471 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6472 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6473 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6474 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6477 if ((Level > 5) && diA->pszMfgName) {
6478 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6479 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6480 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6483 if ((Level > 5) && diA->pszOEMUrl) {
6484 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6485 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6486 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6489 if ((Level > 5) && diA->pszHardwareID) {
6490 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6491 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6492 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6495 if ((Level > 5) && diA->pszProvider) {
6496 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6497 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6498 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6502 FIXME("level %u is incomplete\n", Level);
6505 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6506 TRACE("got %u with %u\n", res, GetLastError());
6507 HeapFree(GetProcessHeap(), 0, nameW);
6508 HeapFree(GetProcessHeap(), 0, diW.pName);
6509 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6510 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6511 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6512 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6513 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6514 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6515 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6516 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6517 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6518 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6519 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6520 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6522 TRACE("=> %u with %u\n", res, GetLastError());
6526 /******************************************************************************
6527 * ConfigurePortA (WINSPOOL.@)
6529 * See ConfigurePortW.
6532 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6534 LPWSTR nameW = NULL;
6535 LPWSTR portW = NULL;
6539 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6541 /* convert servername to unicode */
6543 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6544 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6545 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6548 /* convert portname to unicode */
6550 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6551 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6552 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6555 res = ConfigurePortW(nameW, hWnd, portW);
6556 HeapFree(GetProcessHeap(), 0, nameW);
6557 HeapFree(GetProcessHeap(), 0, portW);
6561 /******************************************************************************
6562 * ConfigurePortW (WINSPOOL.@)
6564 * Display the Configuration-Dialog for a specific Port
6567 * pName [I] Servername or NULL (local Computer)
6568 * hWnd [I] Handle to parent Window for the Dialog-Box
6569 * pPortName [I] Name of the Port, that should be configured
6576 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6582 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6584 if (pName && pName[0]) {
6585 SetLastError(ERROR_INVALID_PARAMETER);
6590 SetLastError(RPC_X_NULL_REF_POINTER);
6594 /* an empty Portname is Invalid, but can popup a Dialog */
6595 if (!pPortName[0]) {
6596 SetLastError(ERROR_NOT_SUPPORTED);
6600 pm = monitor_load_by_port(pPortName);
6601 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6602 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6603 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6604 TRACE("got %d with %u\n", res, GetLastError());
6608 pui = monitor_loadui(pm);
6609 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6610 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6611 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6612 TRACE("got %d with %u\n", res, GetLastError());
6616 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6617 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6619 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6620 SetLastError(ERROR_NOT_SUPPORTED);
6623 monitor_unload(pui);
6627 TRACE("returning %d with %u\n", res, GetLastError());
6631 /******************************************************************************
6632 * ConnectToPrinterDlg (WINSPOOL.@)
6634 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6636 FIXME("%p %x\n", hWnd, Flags);
6640 /******************************************************************************
6641 * DeletePrinterConnectionA (WINSPOOL.@)
6643 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6645 FIXME("%s\n", debugstr_a(pName));
6649 /******************************************************************************
6650 * DeletePrinterConnectionW (WINSPOOL.@)
6652 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6654 FIXME("%s\n", debugstr_w(pName));
6658 /******************************************************************************
6659 * DeletePrinterDriverExW (WINSPOOL.@)
6661 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6662 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6667 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6668 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6670 if(pName && pName[0])
6672 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6673 SetLastError(ERROR_INVALID_PARAMETER);
6679 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6680 SetLastError(ERROR_INVALID_PARAMETER);
6684 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6688 ERR("Can't open drivers key\n");
6692 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6695 RegCloseKey(hkey_drivers);
6700 /******************************************************************************
6701 * DeletePrinterDriverExA (WINSPOOL.@)
6703 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6704 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6706 UNICODE_STRING NameW, EnvW, DriverW;
6709 asciitounicode(&NameW, pName);
6710 asciitounicode(&EnvW, pEnvironment);
6711 asciitounicode(&DriverW, pDriverName);
6713 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6715 RtlFreeUnicodeString(&DriverW);
6716 RtlFreeUnicodeString(&EnvW);
6717 RtlFreeUnicodeString(&NameW);
6722 /******************************************************************************
6723 * DeletePrinterDataExW (WINSPOOL.@)
6725 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6728 FIXME("%p %s %s\n", hPrinter,
6729 debugstr_w(pKeyName), debugstr_w(pValueName));
6730 return ERROR_INVALID_PARAMETER;
6733 /******************************************************************************
6734 * DeletePrinterDataExA (WINSPOOL.@)
6736 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6739 FIXME("%p %s %s\n", hPrinter,
6740 debugstr_a(pKeyName), debugstr_a(pValueName));
6741 return ERROR_INVALID_PARAMETER;
6744 /******************************************************************************
6745 * DeletePrintProcessorA (WINSPOOL.@)
6747 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6749 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6750 debugstr_a(pPrintProcessorName));
6754 /******************************************************************************
6755 * DeletePrintProcessorW (WINSPOOL.@)
6757 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6759 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6760 debugstr_w(pPrintProcessorName));
6764 /******************************************************************************
6765 * DeletePrintProvidorA (WINSPOOL.@)
6767 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6769 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6770 debugstr_a(pPrintProviderName));
6774 /******************************************************************************
6775 * DeletePrintProvidorW (WINSPOOL.@)
6777 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6779 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6780 debugstr_w(pPrintProviderName));
6784 /******************************************************************************
6785 * EnumFormsA (WINSPOOL.@)
6787 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6788 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6790 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6791 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6795 /******************************************************************************
6796 * EnumFormsW (WINSPOOL.@)
6798 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6799 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6801 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6802 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6806 /*****************************************************************************
6807 * EnumMonitorsA [WINSPOOL.@]
6809 * See EnumMonitorsW.
6812 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6813 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6816 LPBYTE bufferW = NULL;
6817 LPWSTR nameW = NULL;
6819 DWORD numentries = 0;
6822 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6823 cbBuf, pcbNeeded, pcReturned);
6825 /* convert servername to unicode */
6827 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6828 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6829 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6831 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6832 needed = cbBuf * sizeof(WCHAR);
6833 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6834 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6836 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6837 if (pcbNeeded) needed = *pcbNeeded;
6838 /* HeapReAlloc return NULL, when bufferW was NULL */
6839 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6840 HeapAlloc(GetProcessHeap(), 0, needed);
6842 /* Try again with the large Buffer */
6843 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6845 numentries = pcReturned ? *pcReturned : 0;
6848 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6849 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6852 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6853 DWORD entrysize = 0;
6856 LPMONITOR_INFO_2W mi2w;
6857 LPMONITOR_INFO_2A mi2a;
6859 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6860 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6862 /* First pass: calculate the size for all Entries */
6863 mi2w = (LPMONITOR_INFO_2W) bufferW;
6864 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6866 while (index < numentries) {
6868 needed += entrysize; /* MONITOR_INFO_?A */
6869 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6871 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6872 NULL, 0, NULL, NULL);
6874 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6875 NULL, 0, NULL, NULL);
6876 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6877 NULL, 0, NULL, NULL);
6879 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6880 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6881 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6884 /* check for errors and quit on failure */
6885 if (cbBuf < needed) {
6886 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6890 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6891 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6892 cbBuf -= len ; /* free Bytes in the user-Buffer */
6893 mi2w = (LPMONITOR_INFO_2W) bufferW;
6894 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6896 /* Second Pass: Fill the User Buffer (if we have one) */
6897 while ((index < numentries) && pMonitors) {
6899 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6901 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6902 ptr, cbBuf , NULL, NULL);
6906 mi2a->pEnvironment = ptr;
6907 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6908 ptr, cbBuf, NULL, NULL);
6912 mi2a->pDLLName = ptr;
6913 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6914 ptr, cbBuf, NULL, NULL);
6918 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6919 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6920 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6924 if (pcbNeeded) *pcbNeeded = needed;
6925 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6927 HeapFree(GetProcessHeap(), 0, nameW);
6928 HeapFree(GetProcessHeap(), 0, bufferW);
6930 TRACE("returning %d with %d (%d byte for %d entries)\n",
6931 (res), GetLastError(), needed, numentries);
6937 /*****************************************************************************
6938 * EnumMonitorsW [WINSPOOL.@]
6940 * Enumerate available Port-Monitors
6943 * pName [I] Servername or NULL (local Computer)
6944 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6945 * pMonitors [O] PTR to Buffer that receives the Result
6946 * cbBuf [I] Size of Buffer at pMonitors
6947 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6948 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6952 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6955 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6956 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6959 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6960 cbBuf, pcbNeeded, pcReturned);
6962 if ((backend == NULL) && !load_backend()) return FALSE;
6964 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6965 SetLastError(RPC_X_NULL_REF_POINTER);
6969 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6972 /******************************************************************************
6973 * SpoolerInit (WINSPOOL.@)
6975 * Initialize the Spooler
6982 * The function fails on windows, when the spooler service is not running
6985 BOOL WINAPI SpoolerInit(void)
6988 if ((backend == NULL) && !load_backend()) return FALSE;
6992 /******************************************************************************
6993 * XcvDataW (WINSPOOL.@)
6995 * Execute commands in the Printmonitor DLL
6998 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6999 * pszDataName [i] Name of the command to execute
7000 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7001 * cbInputData [i] Size in Bytes of Buffer at pInputData
7002 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7003 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7004 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7005 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7012 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7013 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7015 * Minimal List of commands, that a Printmonitor DLL should support:
7017 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7018 *| "AddPort" : Add a Port
7019 *| "DeletePort": Delete a Port
7021 * Many Printmonitors support additional commands. Examples for localspl.dll:
7022 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7023 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7026 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7027 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7028 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7030 opened_printer_t *printer;
7032 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7033 pInputData, cbInputData, pOutputData,
7034 cbOutputData, pcbOutputNeeded, pdwStatus);
7036 printer = get_opened_printer(hXcv);
7037 if (!printer || (!printer->hXcv)) {
7038 SetLastError(ERROR_INVALID_HANDLE);
7042 if (!pcbOutputNeeded) {
7043 SetLastError(ERROR_INVALID_PARAMETER);
7047 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7048 SetLastError(RPC_X_NULL_REF_POINTER);
7052 *pcbOutputNeeded = 0;
7054 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7055 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7060 /*****************************************************************************
7061 * EnumPrinterDataA [WINSPOOL.@]
7064 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7065 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7066 DWORD cbData, LPDWORD pcbData )
7068 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7069 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7070 return ERROR_NO_MORE_ITEMS;
7073 /*****************************************************************************
7074 * EnumPrinterDataW [WINSPOOL.@]
7077 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7078 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7079 DWORD cbData, LPDWORD pcbData )
7081 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7082 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7083 return ERROR_NO_MORE_ITEMS;
7086 /*****************************************************************************
7087 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7090 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7091 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7092 LPDWORD pcbNeeded, LPDWORD pcReturned)
7094 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7095 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7096 pcbNeeded, pcReturned);
7100 /*****************************************************************************
7101 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7104 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7105 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7106 LPDWORD pcbNeeded, LPDWORD pcReturned)
7108 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7109 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7110 pcbNeeded, pcReturned);
7114 /*****************************************************************************
7115 * EnumPrintProcessorsA [WINSPOOL.@]
7118 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7119 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7121 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7122 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7126 /*****************************************************************************
7127 * EnumPrintProcessorsW [WINSPOOL.@]
7130 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7131 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7133 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7134 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7135 cbBuf, pcbNeeded, pcbReturned);
7139 /*****************************************************************************
7140 * ExtDeviceMode [WINSPOOL.@]
7143 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7144 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7147 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7148 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7149 debugstr_a(pProfile), fMode);
7153 /*****************************************************************************
7154 * FindClosePrinterChangeNotification [WINSPOOL.@]
7157 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7159 FIXME("Stub: %p\n", hChange);
7163 /*****************************************************************************
7164 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7167 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7168 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7170 FIXME("Stub: %p %x %x %p\n",
7171 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7172 return INVALID_HANDLE_VALUE;
7175 /*****************************************************************************
7176 * FindNextPrinterChangeNotification [WINSPOOL.@]
7179 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7180 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7182 FIXME("Stub: %p %p %p %p\n",
7183 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7187 /*****************************************************************************
7188 * FreePrinterNotifyInfo [WINSPOOL.@]
7191 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7193 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7197 /*****************************************************************************
7200 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7201 * ansi depending on the unicode parameter.
7203 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7213 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7216 memcpy(ptr, str, *size);
7223 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7226 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7233 /*****************************************************************************
7236 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7237 LPDWORD pcbNeeded, BOOL unicode)
7239 DWORD size, left = cbBuf;
7240 BOOL space = (cbBuf > 0);
7247 ji1->JobId = job->job_id;
7250 string_to_buf(job->document_title, ptr, left, &size, unicode);
7251 if(space && size <= left)
7253 ji1->pDocument = (LPWSTR)ptr;
7264 /*****************************************************************************
7267 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7268 LPDWORD pcbNeeded, BOOL unicode)
7270 DWORD size, left = cbBuf;
7271 BOOL space = (cbBuf > 0);
7278 ji2->JobId = job->job_id;
7281 string_to_buf(job->document_title, ptr, left, &size, unicode);
7282 if(space && size <= left)
7284 ji2->pDocument = (LPWSTR)ptr;
7295 /*****************************************************************************
7298 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7299 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7302 DWORD needed = 0, size;
7306 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7308 EnterCriticalSection(&printer_handles_cs);
7309 job = get_job(hPrinter, JobId);
7316 size = sizeof(JOB_INFO_1W);
7321 memset(pJob, 0, size);
7325 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7330 size = sizeof(JOB_INFO_2W);
7335 memset(pJob, 0, size);
7339 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7344 size = sizeof(JOB_INFO_3);
7348 memset(pJob, 0, size);
7357 SetLastError(ERROR_INVALID_LEVEL);
7361 *pcbNeeded = needed;
7363 LeaveCriticalSection(&printer_handles_cs);
7367 /*****************************************************************************
7368 * GetJobA [WINSPOOL.@]
7371 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7372 DWORD cbBuf, LPDWORD pcbNeeded)
7374 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7377 /*****************************************************************************
7378 * GetJobW [WINSPOOL.@]
7381 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7382 DWORD cbBuf, LPDWORD pcbNeeded)
7384 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7387 /*****************************************************************************
7390 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7392 char *unixname, *queue, *cmd;
7393 char fmt[] = "lpr -P%s %s";
7397 if(!(unixname = wine_get_unix_file_name(filename)))
7400 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7401 queue = HeapAlloc(GetProcessHeap(), 0, len);
7402 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7404 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7405 sprintf(cmd, fmt, queue, unixname);
7407 TRACE("printing with: %s\n", cmd);
7410 HeapFree(GetProcessHeap(), 0, cmd);
7411 HeapFree(GetProcessHeap(), 0, queue);
7412 HeapFree(GetProcessHeap(), 0, unixname);
7416 /*****************************************************************************
7419 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7421 #ifdef SONAME_LIBCUPS
7424 char *unixname, *queue, *unix_doc_title;
7428 if(!(unixname = wine_get_unix_file_name(filename)))
7431 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7432 queue = HeapAlloc(GetProcessHeap(), 0, len);
7433 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7435 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7436 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7437 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7439 TRACE("printing via cups\n");
7440 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7441 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7442 HeapFree(GetProcessHeap(), 0, queue);
7443 HeapFree(GetProcessHeap(), 0, unixname);
7449 return schedule_lpr(printer_name, filename);
7453 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7460 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7464 if(HIWORD(wparam) == BN_CLICKED)
7466 if(LOWORD(wparam) == IDOK)
7469 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7472 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7473 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7475 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7477 WCHAR caption[200], message[200];
7480 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7481 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7482 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7483 if(mb_ret == IDCANCEL)
7485 HeapFree(GetProcessHeap(), 0, filename);
7489 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7490 if(hf == INVALID_HANDLE_VALUE)
7492 WCHAR caption[200], message[200];
7494 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7495 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7496 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7497 HeapFree(GetProcessHeap(), 0, filename);
7501 DeleteFileW(filename);
7502 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7504 EndDialog(hwnd, IDOK);
7507 if(LOWORD(wparam) == IDCANCEL)
7509 EndDialog(hwnd, IDCANCEL);
7518 /*****************************************************************************
7521 static BOOL get_filename(LPWSTR *filename)
7523 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7524 file_dlg_proc, (LPARAM)filename) == IDOK;
7527 /*****************************************************************************
7530 static BOOL schedule_file(LPCWSTR filename)
7532 LPWSTR output = NULL;
7534 if(get_filename(&output))
7537 TRACE("copy to %s\n", debugstr_w(output));
7538 r = CopyFileW(filename, output, FALSE);
7539 HeapFree(GetProcessHeap(), 0, output);
7545 /*****************************************************************************
7548 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7551 char *unixname, *cmdA;
7553 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7557 if(!(unixname = wine_get_unix_file_name(filename)))
7560 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7561 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7562 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7564 TRACE("printing with: %s\n", cmdA);
7566 if((file_fd = open(unixname, O_RDONLY)) == -1)
7571 ERR("pipe() failed!\n");
7581 /* reset signals that we previously set to SIG_IGN */
7582 signal(SIGPIPE, SIG_DFL);
7583 signal(SIGCHLD, SIG_DFL);
7585 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7589 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7590 write(fds[1], buf, no_read);
7595 if(file_fd != -1) close(file_fd);
7596 if(fds[0] != -1) close(fds[0]);
7597 if(fds[1] != -1) close(fds[1]);
7599 HeapFree(GetProcessHeap(), 0, cmdA);
7600 HeapFree(GetProcessHeap(), 0, unixname);
7607 /*****************************************************************************
7610 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7612 int in_fd, out_fd, no_read;
7615 char *unixname, *outputA;
7618 if(!(unixname = wine_get_unix_file_name(filename)))
7621 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7622 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7623 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7625 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7626 in_fd = open(unixname, O_RDONLY);
7627 if(out_fd == -1 || in_fd == -1)
7630 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7631 write(out_fd, buf, no_read);
7635 if(in_fd != -1) close(in_fd);
7636 if(out_fd != -1) close(out_fd);
7637 HeapFree(GetProcessHeap(), 0, outputA);
7638 HeapFree(GetProcessHeap(), 0, unixname);
7642 /*****************************************************************************
7643 * ScheduleJob [WINSPOOL.@]
7646 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7648 opened_printer_t *printer;
7650 struct list *cursor, *cursor2;
7652 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7653 EnterCriticalSection(&printer_handles_cs);
7654 printer = get_opened_printer(hPrinter);
7658 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7660 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7663 if(job->job_id != dwJobID) continue;
7665 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7666 if(hf != INVALID_HANDLE_VALUE)
7668 PRINTER_INFO_5W *pi5;
7672 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7673 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7675 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7676 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7677 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7678 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7679 debugstr_w(pi5->pPortName));
7683 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7684 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7686 DWORD type, count = sizeof(output);
7687 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7690 if(output[0] == '|')
7692 ret = schedule_pipe(output + 1, job->filename);
7696 ret = schedule_unixfile(output, job->filename);
7698 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7700 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7702 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7704 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7706 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7708 ret = schedule_file(job->filename);
7712 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7714 HeapFree(GetProcessHeap(), 0, pi5);
7716 DeleteFileW(job->filename);
7718 list_remove(cursor);
7719 HeapFree(GetProcessHeap(), 0, job->document_title);
7720 HeapFree(GetProcessHeap(), 0, job->filename);
7721 HeapFree(GetProcessHeap(), 0, job);
7725 LeaveCriticalSection(&printer_handles_cs);
7729 /*****************************************************************************
7730 * StartDocDlgA [WINSPOOL.@]
7732 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7734 UNICODE_STRING usBuffer;
7737 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7740 docW.cbSize = sizeof(docW);
7741 if (doc->lpszDocName)
7743 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7744 if (!(docW.lpszDocName = docnameW)) return NULL;
7746 if (doc->lpszOutput)
7748 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7749 if (!(docW.lpszOutput = outputW)) return NULL;
7751 if (doc->lpszDatatype)
7753 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7754 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7756 docW.fwType = doc->fwType;
7758 retW = StartDocDlgW(hPrinter, &docW);
7762 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7763 ret = HeapAlloc(GetProcessHeap(), 0, len);
7764 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7765 HeapFree(GetProcessHeap(), 0, retW);
7768 HeapFree(GetProcessHeap(), 0, datatypeW);
7769 HeapFree(GetProcessHeap(), 0, outputW);
7770 HeapFree(GetProcessHeap(), 0, docnameW);
7775 /*****************************************************************************
7776 * StartDocDlgW [WINSPOOL.@]
7778 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7779 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7780 * port is "FILE:". Also returns the full path if passed a relative path.
7782 * The caller should free the returned string from the process heap.
7784 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7789 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7791 PRINTER_INFO_5W *pi5;
7792 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7793 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7795 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7796 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7797 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7799 HeapFree(GetProcessHeap(), 0, pi5);
7802 HeapFree(GetProcessHeap(), 0, pi5);
7805 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7809 if (get_filename(&name))
7811 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7813 HeapFree(GetProcessHeap(), 0, name);
7816 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7817 GetFullPathNameW(name, len, ret, NULL);
7818 HeapFree(GetProcessHeap(), 0, name);
7823 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7826 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7827 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7829 attr = GetFileAttributesW(ret);
7830 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7832 HeapFree(GetProcessHeap(), 0, ret);