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(cupsFreeDests) *pcupsFreeDests;
464 static typeof(cupsGetDests) *pcupsGetDests;
465 static typeof(cupsGetPPD) *pcupsGetPPD;
466 static typeof(cupsPrintFile) *pcupsPrintFile;
467 static void *cupshandle;
469 static BOOL CUPS_LoadPrinters(void)
472 BOOL hadprinter = FALSE, haddefault = FALSE;
474 PRINTER_INFO_2A pinfo2a;
476 HKEY hkeyPrinter, hkeyPrinters, hkey;
479 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
481 TRACE("%s\n", loaderror);
484 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
487 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
488 if (!p##x) return FALSE;
490 DYNCUPS(cupsFreeDests);
492 DYNCUPS(cupsGetDests);
493 DYNCUPS(cupsPrintFile);
496 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
498 ERR("Can't create Printers key\n");
502 nrofdests = pcupsGetDests(&dests);
503 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
504 for (i=0;i<nrofdests;i++) {
505 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
506 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
507 sprintf(port,"LPR:%s", dests[i].name);
508 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
509 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
510 sprintf(devline, "WINEPS.DRV,%s", port);
511 WriteProfileStringA("devices", dests[i].name, devline);
512 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
513 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
517 lstrcatA(devline, ",15,45");
518 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
519 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
520 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
524 HeapFree(GetProcessHeap(), 0, devline);
526 TRACE("Printer %d: %s\n", i, dests[i].name);
527 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
528 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
530 TRACE("Printer already exists\n");
531 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
532 RegCloseKey(hkeyPrinter);
534 static CHAR data_type[] = "RAW",
535 print_proc[] = "WinPrint",
536 comment[] = "WINEPS Printer using CUPS",
537 location[] = "<physical location of printer>",
538 params[] = "<parameters?>",
539 share_name[] = "<share name?>",
540 sep_file[] = "<sep file?>";
542 add_printer_driver(dests[i].name);
544 memset(&pinfo2a,0,sizeof(pinfo2a));
545 pinfo2a.pPrinterName = dests[i].name;
546 pinfo2a.pDatatype = data_type;
547 pinfo2a.pPrintProcessor = print_proc;
548 pinfo2a.pDriverName = dests[i].name;
549 pinfo2a.pComment = comment;
550 pinfo2a.pLocation = location;
551 pinfo2a.pPortName = port;
552 pinfo2a.pParameters = params;
553 pinfo2a.pShareName = share_name;
554 pinfo2a.pSepFile = sep_file;
556 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
557 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
558 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
561 HeapFree(GetProcessHeap(),0,port);
564 if (dests[i].is_default) {
565 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
569 if (hadprinter & !haddefault)
570 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
571 pcupsFreeDests(nrofdests, dests);
572 RegCloseKey(hkeyPrinters);
578 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
579 PRINTER_INFO_2A pinfo2a;
580 char *e,*s,*name,*prettyname,*devname;
581 BOOL ret = FALSE, set_default = FALSE;
582 char *port = NULL, *devline,*env_default;
583 HKEY hkeyPrinter, hkeyPrinters, hkey;
585 while (isspace(*pent)) pent++;
586 s = strchr(pent,':');
588 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
596 TRACE("name=%s entry=%s\n",name, pent);
598 if(ispunct(*name)) { /* a tc entry, not a real printer */
599 TRACE("skipping tc entry\n");
603 if(strstr(pent,":server")) { /* server only version so skip */
604 TRACE("skipping server entry\n");
608 /* Determine whether this is a postscript printer. */
611 env_default = getenv("PRINTER");
613 /* Get longest name, usually the one at the right for later display. */
614 while((s=strchr(prettyname,'|'))) {
617 while(isspace(*--e)) *e = '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname));
619 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
620 for(prettyname = s+1; isspace(*prettyname); prettyname++)
623 e = prettyname + strlen(prettyname);
624 while(isspace(*--e)) *e = '\0';
625 TRACE("\t%s\n", debugstr_a(prettyname));
626 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
628 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
629 * if it is too long, we use it as comment below. */
630 devname = prettyname;
631 if (strlen(devname)>=CCHDEVICENAME-1)
633 if (strlen(devname)>=CCHDEVICENAME-1) {
638 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
639 sprintf(port,"LPR:%s",name);
641 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
642 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
643 sprintf(devline, "WINEPS.DRV,%s", port);
644 WriteProfileStringA("devices", devname, devline);
645 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
646 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
650 lstrcatA(devline, ",15,45");
651 WriteProfileStringA("PrinterPorts", devname, devline);
652 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
653 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
657 HeapFree(GetProcessHeap(),0,devline);
659 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
661 ERR("Can't create Printers key\n");
665 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
666 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
668 TRACE("Printer already exists\n");
669 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
670 RegCloseKey(hkeyPrinter);
672 static CHAR data_type[] = "RAW",
673 print_proc[] = "WinPrint",
674 comment[] = "WINEPS Printer using LPR",
675 params[] = "<parameters?>",
676 share_name[] = "<share name?>",
677 sep_file[] = "<sep file?>";
679 add_printer_driver(devname);
681 memset(&pinfo2a,0,sizeof(pinfo2a));
682 pinfo2a.pPrinterName = devname;
683 pinfo2a.pDatatype = data_type;
684 pinfo2a.pPrintProcessor = print_proc;
685 pinfo2a.pDriverName = devname;
686 pinfo2a.pComment = comment;
687 pinfo2a.pLocation = prettyname;
688 pinfo2a.pPortName = port;
689 pinfo2a.pParameters = params;
690 pinfo2a.pShareName = share_name;
691 pinfo2a.pSepFile = sep_file;
693 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
694 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
695 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
698 RegCloseKey(hkeyPrinters);
700 if (isfirst || set_default)
701 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
704 HeapFree(GetProcessHeap(), 0, port);
705 HeapFree(GetProcessHeap(), 0, name);
710 PRINTCAP_LoadPrinters(void) {
711 BOOL hadprinter = FALSE;
715 BOOL had_bash = FALSE;
717 f = fopen("/etc/printcap","r");
721 while(fgets(buf,sizeof(buf),f)) {
724 end=strchr(buf,'\n');
728 while(isspace(*start)) start++;
729 if(*start == '#' || *start == '\0')
732 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
733 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
734 HeapFree(GetProcessHeap(),0,pent);
738 if (end && *--end == '\\') {
745 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
748 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
754 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
755 HeapFree(GetProcessHeap(),0,pent);
761 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
764 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
765 (lstrlenW(value) + 1) * sizeof(WCHAR));
767 return ERROR_FILE_NOT_FOUND;
770 /******************************************************************
771 * monitor_unload [internal]
773 * release a printmonitor and unload it from memory, when needed
776 static void monitor_unload(monitor_t * pm)
778 if (pm == NULL) return;
779 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
781 EnterCriticalSection(&monitor_handles_cs);
783 if (pm->refcount) pm->refcount--;
785 if (pm->refcount == 0) {
786 list_remove(&pm->entry);
787 FreeLibrary(pm->hdll);
788 HeapFree(GetProcessHeap(), 0, pm->name);
789 HeapFree(GetProcessHeap(), 0, pm->dllname);
790 HeapFree(GetProcessHeap(), 0, pm);
792 LeaveCriticalSection(&monitor_handles_cs);
795 /******************************************************************
796 * monitor_load [internal]
798 * load a printmonitor, get the dllname from the registry, when needed
799 * initialize the monitor and dump found function-pointers
801 * On failure, SetLastError() is called and NULL is returned
804 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
806 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
807 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
808 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
809 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
810 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
812 monitor_t * pm = NULL;
814 LPWSTR regroot = NULL;
815 LPWSTR driver = dllname;
817 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
818 /* Is the Monitor already loaded? */
819 EnterCriticalSection(&monitor_handles_cs);
822 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
824 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
832 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
833 if (pm == NULL) goto cleanup;
834 list_add_tail(&monitor_handles, &pm->entry);
838 if (pm->name == NULL) {
839 /* Load the monitor */
840 LPMONITOREX pmonitorEx;
844 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
845 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
849 lstrcpyW(regroot, MonitorsW);
850 lstrcatW(regroot, name);
851 /* Get the Driver from the Registry */
852 if (driver == NULL) {
855 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
856 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
857 &namesize) == ERROR_SUCCESS) {
858 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
859 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
866 pm->name = strdupW(name);
867 pm->dllname = strdupW(driver);
869 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
871 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
876 pm->hdll = LoadLibraryW(driver);
877 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
879 if (pm->hdll == NULL) {
881 SetLastError(ERROR_MOD_NOT_FOUND);
886 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
887 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
888 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
889 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
890 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
893 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
894 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
895 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
896 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
897 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
899 if (pInitializePrintMonitorUI != NULL) {
900 pm->monitorUI = pInitializePrintMonitorUI();
901 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
903 TRACE( "0x%08x: dwMonitorSize (%d)\n",
904 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
909 if (pInitializePrintMonitor && regroot) {
910 pmonitorEx = pInitializePrintMonitor(regroot);
911 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
912 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
915 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
916 pm->monitor = &(pmonitorEx->Monitor);
921 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
925 if (!pm->monitor && regroot) {
926 if (pInitializePrintMonitor2 != NULL) {
927 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
929 if (pInitializeMonitorEx != NULL) {
930 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
932 if (pInitializeMonitor != NULL) {
933 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
936 if (!pm->monitor && !pm->monitorUI) {
938 SetLastError(ERROR_PROC_NOT_FOUND);
943 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
947 LeaveCriticalSection(&monitor_handles_cs);
948 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
949 HeapFree(GetProcessHeap(), 0, regroot);
950 TRACE("=> %p\n", pm);
954 /******************************************************************
955 * monitor_loadui [internal]
957 * load the userinterface-dll for a given portmonitor
959 * On failure, NULL is returned
962 static monitor_t * monitor_loadui(monitor_t * pm)
964 monitor_t * pui = NULL;
965 LPWSTR buffer[MAX_PATH];
970 if (pm == NULL) return NULL;
971 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
973 /* Try the Portmonitor first; works for many monitors */
975 EnterCriticalSection(&monitor_handles_cs);
977 LeaveCriticalSection(&monitor_handles_cs);
981 /* query the userinterface-dllname from the Portmonitor */
982 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
983 /* building (",XcvMonitor %s",pm->name) not needed yet */
984 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
985 TRACE("got %u with %p\n", res, hXcv);
987 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
988 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
989 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
990 pm->monitor->pfnXcvClosePort(hXcv);
997 /******************************************************************
998 * monitor_load_by_port [internal]
1000 * load a printmonitor for a given port
1002 * On failure, NULL is returned
1005 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1010 monitor_t * pm = NULL;
1011 DWORD registered = 0;
1015 TRACE("(%s)\n", debugstr_w(portname));
1017 /* Try the Local Monitor first */
1018 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1019 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1020 /* found the portname */
1022 return monitor_load(LocalPortW, NULL);
1027 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1028 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1029 if (buffer == NULL) return NULL;
1031 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1032 EnterCriticalSection(&monitor_handles_cs);
1033 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1035 while ((pm == NULL) && (id < registered)) {
1037 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1038 TRACE("testing %s\n", debugstr_w(buffer));
1039 len = lstrlenW(buffer);
1040 lstrcatW(buffer, bs_Ports_bsW);
1041 lstrcatW(buffer, portname);
1042 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1044 buffer[len] = '\0'; /* use only the Monitor-Name */
1045 pm = monitor_load(buffer, NULL);
1049 LeaveCriticalSection(&monitor_handles_cs);
1052 HeapFree(GetProcessHeap(), 0, buffer);
1056 /******************************************************************
1057 * get_servername_from_name (internal)
1059 * for an external server, a copy of the serverpart from the full name is returned
1062 static LPWSTR get_servername_from_name(LPCWSTR name)
1066 WCHAR buffer[MAX_PATH];
1069 if (name == NULL) return NULL;
1070 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1072 server = strdupW(&name[2]); /* skip over both backslash */
1073 if (server == NULL) return NULL;
1075 /* strip '\' and the printername */
1076 ptr = strchrW(server, '\\');
1077 if (ptr) ptr[0] = '\0';
1079 TRACE("found %s\n", debugstr_w(server));
1081 len = sizeof(buffer)/sizeof(buffer[0]);
1082 if (GetComputerNameW(buffer, &len)) {
1083 if (lstrcmpW(buffer, server) == 0) {
1084 /* The requested Servername is our computername */
1085 HeapFree(GetProcessHeap(), 0, server);
1092 /******************************************************************
1093 * get_basename_from_name (internal)
1095 * skip over the serverpart from the full name
1098 static LPCWSTR get_basename_from_name(LPCWSTR name)
1100 if (name == NULL) return NULL;
1101 if ((name[0] == '\\') && (name[1] == '\\')) {
1102 /* skip over the servername and search for the following '\' */
1103 name = strchrW(&name[2], '\\');
1104 if ((name) && (name[1])) {
1105 /* found a separator ('\') followed by a name:
1106 skip over the separator and return the rest */
1111 /* no basename present (we found only a servername) */
1118 /******************************************************************
1119 * get_opened_printer_entry
1120 * Get the first place empty in the opened printer table
1123 * - pDefault is ignored
1125 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1127 UINT_PTR handle = nb_printer_handles, i;
1128 jobqueue_t *queue = NULL;
1129 opened_printer_t *printer = NULL;
1131 LPCWSTR printername;
1136 servername = get_servername_from_name(name);
1138 FIXME("server %s not supported\n", debugstr_w(servername));
1139 HeapFree(GetProcessHeap(), 0, servername);
1140 SetLastError(ERROR_INVALID_PRINTER_NAME);
1144 printername = get_basename_from_name(name);
1145 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1147 /* an empty printername is invalid */
1148 if (printername && (!printername[0])) {
1149 SetLastError(ERROR_INVALID_PARAMETER);
1153 EnterCriticalSection(&printer_handles_cs);
1155 for (i = 0; i < nb_printer_handles; i++)
1157 if (!printer_handles[i])
1159 if(handle == nb_printer_handles)
1164 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1165 queue = printer_handles[i]->queue;
1169 if (handle >= nb_printer_handles)
1171 opened_printer_t **new_array;
1172 if (printer_handles)
1173 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1174 (nb_printer_handles + 16) * sizeof(*new_array) );
1176 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1177 (nb_printer_handles + 16) * sizeof(*new_array) );
1184 printer_handles = new_array;
1185 nb_printer_handles += 16;
1188 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1195 /* clone the base name. This is NULL for the printserver */
1196 printer->printername = strdupW(printername);
1198 /* clone the full name */
1199 printer->name = strdupW(name);
1200 if (name && (!printer->name)) {
1206 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1207 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1208 /* OpenPrinter(",XcvMonitor " detected */
1209 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1210 printer->pm = monitor_load(&printername[len], NULL);
1211 if (printer->pm == NULL) {
1212 SetLastError(ERROR_UNKNOWN_PORT);
1219 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1220 if (strncmpW( printername, XcvPortW, len) == 0) {
1221 /* OpenPrinter(",XcvPort " detected */
1222 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1223 printer->pm = monitor_load_by_port(&printername[len]);
1224 if (printer->pm == NULL) {
1225 SetLastError(ERROR_UNKNOWN_PORT);
1233 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1234 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1235 pDefault ? pDefault->DesiredAccess : 0,
1238 if (printer->hXcv == NULL) {
1239 SetLastError(ERROR_INVALID_PARAMETER);
1246 /* Does the Printer exist? */
1247 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1248 ERR("Can't create Printers key\n");
1252 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1253 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1254 RegCloseKey(hkeyPrinters);
1255 SetLastError(ERROR_INVALID_PRINTER_NAME);
1259 RegCloseKey(hkeyPrinter);
1260 RegCloseKey(hkeyPrinters);
1265 TRACE("using the local printserver\n");
1269 printer->queue = queue;
1272 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1273 if (!printer->queue) {
1277 list_init(&printer->queue->jobs);
1278 printer->queue->ref = 0;
1280 InterlockedIncrement(&printer->queue->ref);
1282 printer_handles[handle] = printer;
1285 LeaveCriticalSection(&printer_handles_cs);
1286 if (!handle && printer) {
1287 /* Something failed: Free all resources */
1288 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1289 monitor_unload(printer->pm);
1290 HeapFree(GetProcessHeap(), 0, printer->printername);
1291 HeapFree(GetProcessHeap(), 0, printer->name);
1292 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1293 HeapFree(GetProcessHeap(), 0, printer);
1296 return (HANDLE)handle;
1299 /******************************************************************
1300 * get_opened_printer
1301 * Get the pointer to the opened printer referred by the handle
1303 static opened_printer_t *get_opened_printer(HANDLE hprn)
1305 UINT_PTR idx = (UINT_PTR)hprn;
1306 opened_printer_t *ret = NULL;
1308 EnterCriticalSection(&printer_handles_cs);
1310 if ((idx > 0) && (idx <= nb_printer_handles)) {
1311 ret = printer_handles[idx - 1];
1313 LeaveCriticalSection(&printer_handles_cs);
1317 /******************************************************************
1318 * get_opened_printer_name
1319 * Get the pointer to the opened printer name referred by the handle
1321 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1323 opened_printer_t *printer = get_opened_printer(hprn);
1324 if(!printer) return NULL;
1325 return printer->name;
1328 /******************************************************************
1329 * WINSPOOL_GetOpenedPrinterRegKey
1332 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1334 LPCWSTR name = get_opened_printer_name(hPrinter);
1338 if(!name) return ERROR_INVALID_HANDLE;
1340 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1344 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1346 ERR("Can't find opened printer %s in registry\n",
1348 RegCloseKey(hkeyPrinters);
1349 return ERROR_INVALID_PRINTER_NAME; /* ? */
1351 RegCloseKey(hkeyPrinters);
1352 return ERROR_SUCCESS;
1355 void WINSPOOL_LoadSystemPrinters(void)
1357 HKEY hkey, hkeyPrinters;
1359 DWORD needed, num, i;
1360 WCHAR PrinterName[256];
1363 /* This ensures that all printer entries have a valid Name value. If causes
1364 problems later if they don't. If one is found to be missed we create one
1365 and set it equal to the name of the key */
1366 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1367 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1368 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1369 for(i = 0; i < num; i++) {
1370 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1371 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1372 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1373 set_reg_szW(hkey, NameW, PrinterName);
1380 RegCloseKey(hkeyPrinters);
1383 /* We want to avoid calling AddPrinter on printers as much as
1384 possible, because on cups printers this will (eventually) lead
1385 to a call to cupsGetPPD which takes forever, even with non-cups
1386 printers AddPrinter takes a while. So we'll tag all printers that
1387 were automatically added last time around, if they still exist
1388 we'll leave them be otherwise we'll delete them. */
1389 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1391 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1392 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1393 for(i = 0; i < num; i++) {
1394 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1395 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1396 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1398 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1406 HeapFree(GetProcessHeap(), 0, pi);
1410 #ifdef SONAME_LIBCUPS
1411 done = CUPS_LoadPrinters();
1414 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1415 PRINTCAP_LoadPrinters();
1417 /* Now enumerate the list again and delete any printers that are still tagged */
1418 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1420 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1421 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1422 for(i = 0; i < num; i++) {
1423 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1424 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1425 BOOL delete_driver = FALSE;
1426 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1427 DWORD dw, type, size = sizeof(dw);
1428 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1429 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1430 DeletePrinter(hprn);
1431 delete_driver = TRUE;
1437 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1442 HeapFree(GetProcessHeap(), 0, pi);
1449 /******************************************************************
1452 * Get the pointer to the specified job.
1453 * Should hold the printer_handles_cs before calling.
1455 static job_t *get_job(HANDLE hprn, DWORD JobId)
1457 opened_printer_t *printer = get_opened_printer(hprn);
1460 if(!printer) return NULL;
1461 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1463 if(job->job_id == JobId)
1469 /***********************************************************
1472 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1475 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1478 Formname = (dmA->dmSize > off_formname);
1479 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1480 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1481 dmW->dmDeviceName, CCHDEVICENAME);
1483 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1484 dmA->dmSize - CCHDEVICENAME);
1486 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1487 off_formname - CCHDEVICENAME);
1488 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1489 dmW->dmFormName, CCHFORMNAME);
1490 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1491 (off_formname + CCHFORMNAME));
1494 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1495 dmA->dmDriverExtra);
1499 /***********************************************************
1501 * Creates an ansi copy of supplied devmode
1503 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1508 if (!dmW) return NULL;
1509 size = dmW->dmSize - CCHDEVICENAME -
1510 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1512 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1513 if (!dmA) return NULL;
1515 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1516 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1518 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1519 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1520 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1524 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1525 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1526 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1527 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1529 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1533 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1537 /******************************************************************
1538 * convert_printerinfo_W_to_A [internal]
1541 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1542 DWORD level, DWORD outlen, DWORD numentries)
1548 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1550 len = pi_sizeof[level] * numentries;
1551 ptr = (LPSTR) out + len;
1554 /* copy the numbers of all PRINTER_INFO_* first */
1555 memcpy(out, pPrintersW, len);
1557 while (id < numentries) {
1561 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1562 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1564 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1565 if (piW->pDescription) {
1566 piA->pDescription = ptr;
1567 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1568 ptr, outlen, NULL, NULL);
1574 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1575 ptr, outlen, NULL, NULL);
1579 if (piW->pComment) {
1580 piA->pComment = ptr;
1581 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1582 ptr, outlen, NULL, NULL);
1591 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1592 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1595 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1596 if (piW->pServerName) {
1597 piA->pServerName = ptr;
1598 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1599 ptr, outlen, NULL, NULL);
1603 if (piW->pPrinterName) {
1604 piA->pPrinterName = ptr;
1605 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1606 ptr, outlen, NULL, NULL);
1610 if (piW->pShareName) {
1611 piA->pShareName = ptr;
1612 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1613 ptr, outlen, NULL, NULL);
1617 if (piW->pPortName) {
1618 piA->pPortName = ptr;
1619 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1620 ptr, outlen, NULL, NULL);
1624 if (piW->pDriverName) {
1625 piA->pDriverName = ptr;
1626 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1627 ptr, outlen, NULL, NULL);
1631 if (piW->pComment) {
1632 piA->pComment = ptr;
1633 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1634 ptr, outlen, NULL, NULL);
1638 if (piW->pLocation) {
1639 piA->pLocation = ptr;
1640 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1641 ptr, outlen, NULL, NULL);
1646 dmA = DEVMODEdupWtoA(piW->pDevMode);
1648 /* align DEVMODEA to a DWORD boundary */
1649 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1653 piA->pDevMode = (LPDEVMODEA) ptr;
1654 len = dmA->dmSize + dmA->dmDriverExtra;
1655 memcpy(ptr, dmA, len);
1656 HeapFree(GetProcessHeap(), 0, dmA);
1662 if (piW->pSepFile) {
1663 piA->pSepFile = ptr;
1664 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1665 ptr, outlen, NULL, NULL);
1669 if (piW->pPrintProcessor) {
1670 piA->pPrintProcessor = ptr;
1671 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1672 ptr, outlen, NULL, NULL);
1676 if (piW->pDatatype) {
1677 piA->pDatatype = ptr;
1678 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1679 ptr, outlen, NULL, NULL);
1683 if (piW->pParameters) {
1684 piA->pParameters = ptr;
1685 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1686 ptr, outlen, NULL, NULL);
1690 if (piW->pSecurityDescriptor) {
1691 piA->pSecurityDescriptor = NULL;
1692 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1699 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1700 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1702 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1704 if (piW->pPrinterName) {
1705 piA->pPrinterName = ptr;
1706 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1707 ptr, outlen, NULL, NULL);
1711 if (piW->pServerName) {
1712 piA->pServerName = ptr;
1713 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1714 ptr, outlen, NULL, NULL);
1723 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1724 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1726 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1728 if (piW->pPrinterName) {
1729 piA->pPrinterName = ptr;
1730 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1731 ptr, outlen, NULL, NULL);
1735 if (piW->pPortName) {
1736 piA->pPortName = ptr;
1737 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1738 ptr, outlen, NULL, NULL);
1746 FIXME("for level %u\n", level);
1748 pPrintersW += pi_sizeof[level];
1749 out += pi_sizeof[level];
1754 /***********************************************************
1755 * PRINTER_INFO_2AtoW
1756 * Creates a unicode copy of PRINTER_INFO_2A on heap
1758 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1760 LPPRINTER_INFO_2W piW;
1761 UNICODE_STRING usBuffer;
1763 if(!piA) return NULL;
1764 piW = HeapAlloc(heap, 0, sizeof(*piW));
1765 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1767 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1768 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1769 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1770 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1771 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1772 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1773 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1774 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1775 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1776 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1777 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1778 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1782 /***********************************************************
1783 * FREE_PRINTER_INFO_2W
1784 * Free PRINTER_INFO_2W and all strings
1786 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1790 HeapFree(heap,0,piW->pServerName);
1791 HeapFree(heap,0,piW->pPrinterName);
1792 HeapFree(heap,0,piW->pShareName);
1793 HeapFree(heap,0,piW->pPortName);
1794 HeapFree(heap,0,piW->pDriverName);
1795 HeapFree(heap,0,piW->pComment);
1796 HeapFree(heap,0,piW->pLocation);
1797 HeapFree(heap,0,piW->pDevMode);
1798 HeapFree(heap,0,piW->pSepFile);
1799 HeapFree(heap,0,piW->pPrintProcessor);
1800 HeapFree(heap,0,piW->pDatatype);
1801 HeapFree(heap,0,piW->pParameters);
1802 HeapFree(heap,0,piW);
1806 /******************************************************************
1807 * DeviceCapabilities [WINSPOOL.@]
1808 * DeviceCapabilitiesA [WINSPOOL.@]
1811 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1812 LPSTR pOutput, LPDEVMODEA lpdm)
1816 if (!GDI_CallDeviceCapabilities16)
1818 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1820 if (!GDI_CallDeviceCapabilities16) return -1;
1822 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1824 /* If DC_PAPERSIZE map POINT16s to POINTs */
1825 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1826 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1827 POINT *pt = (POINT *)pOutput;
1829 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1830 for(i = 0; i < ret; i++, pt++)
1835 HeapFree( GetProcessHeap(), 0, tmp );
1841 /*****************************************************************************
1842 * DeviceCapabilitiesW [WINSPOOL.@]
1844 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1847 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1848 WORD fwCapability, LPWSTR pOutput,
1849 const DEVMODEW *pDevMode)
1851 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1852 LPSTR pDeviceA = strdupWtoA(pDevice);
1853 LPSTR pPortA = strdupWtoA(pPort);
1856 if(pOutput && (fwCapability == DC_BINNAMES ||
1857 fwCapability == DC_FILEDEPENDENCIES ||
1858 fwCapability == DC_PAPERNAMES)) {
1859 /* These need A -> W translation */
1862 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1866 switch(fwCapability) {
1871 case DC_FILEDEPENDENCIES:
1875 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1876 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1878 for(i = 0; i < ret; i++)
1879 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1880 pOutput + (i * size), size);
1881 HeapFree(GetProcessHeap(), 0, pOutputA);
1883 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1884 (LPSTR)pOutput, dmA);
1886 HeapFree(GetProcessHeap(),0,pPortA);
1887 HeapFree(GetProcessHeap(),0,pDeviceA);
1888 HeapFree(GetProcessHeap(),0,dmA);
1892 /******************************************************************
1893 * DocumentPropertiesA [WINSPOOL.@]
1895 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1897 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1898 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1899 LPDEVMODEA pDevModeInput,DWORD fMode )
1901 LPSTR lpName = pDeviceName;
1902 static CHAR port[] = "LPT1:";
1905 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1906 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1910 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1912 ERR("no name from hPrinter?\n");
1913 SetLastError(ERROR_INVALID_HANDLE);
1916 lpName = strdupWtoA(lpNameW);
1919 if (!GDI_CallExtDeviceMode16)
1921 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1923 if (!GDI_CallExtDeviceMode16) {
1924 ERR("No CallExtDeviceMode16?\n");
1928 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1929 pDevModeInput, NULL, fMode);
1932 HeapFree(GetProcessHeap(),0,lpName);
1937 /*****************************************************************************
1938 * DocumentPropertiesW (WINSPOOL.@)
1940 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1942 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1944 LPDEVMODEW pDevModeOutput,
1945 LPDEVMODEW pDevModeInput, DWORD fMode)
1948 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1949 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1950 LPDEVMODEA pDevModeOutputA = NULL;
1953 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1954 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1956 if(pDevModeOutput) {
1957 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1958 if(ret < 0) return ret;
1959 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1961 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1962 pDevModeInputA, fMode);
1963 if(pDevModeOutput) {
1964 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1965 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1967 if(fMode == 0 && ret > 0)
1968 ret += (CCHDEVICENAME + CCHFORMNAME);
1969 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1970 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1974 /******************************************************************
1975 * OpenPrinterA [WINSPOOL.@]
1980 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1981 LPPRINTER_DEFAULTSA pDefault)
1983 UNICODE_STRING lpPrinterNameW;
1984 UNICODE_STRING usBuffer;
1985 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1986 PWSTR pwstrPrinterNameW;
1989 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1992 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1993 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1994 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1995 pDefaultW = &DefaultW;
1997 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1999 RtlFreeUnicodeString(&usBuffer);
2000 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2002 RtlFreeUnicodeString(&lpPrinterNameW);
2006 /******************************************************************
2007 * OpenPrinterW [WINSPOOL.@]
2009 * Open a Printer / Printserver or a Printer-Object
2012 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2013 * phPrinter [O] The resulting Handle is stored here
2014 * pDefault [I] PTR to Default Printer Settings or NULL
2021 * lpPrinterName is one of:
2022 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2023 *| Printer: "PrinterName"
2024 *| Printer-Object: "PrinterName,Job xxx"
2025 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2026 *| XcvPort: "Servername,XcvPort PortName"
2029 *| Printer-Object not supported
2030 *| pDefaults is ignored
2033 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2036 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2038 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2039 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2043 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2044 SetLastError(ERROR_INVALID_PARAMETER);
2048 /* Get the unique handle of the printer or Printserver */
2049 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2050 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2051 return (*phPrinter != 0);
2054 /******************************************************************
2055 * AddMonitorA [WINSPOOL.@]
2060 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2062 LPWSTR nameW = NULL;
2065 LPMONITOR_INFO_2A mi2a;
2066 MONITOR_INFO_2W mi2w;
2068 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2069 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2070 debugstr_a(mi2a ? mi2a->pName : NULL),
2071 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2072 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2075 SetLastError(ERROR_INVALID_LEVEL);
2079 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2085 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2086 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2087 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2090 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2092 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2093 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2094 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2096 if (mi2a->pEnvironment) {
2097 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2098 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2099 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2101 if (mi2a->pDLLName) {
2102 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2103 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2104 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2107 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2109 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2110 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2111 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2113 HeapFree(GetProcessHeap(), 0, nameW);
2117 /******************************************************************************
2118 * AddMonitorW [WINSPOOL.@]
2120 * Install a Printmonitor
2123 * pName [I] Servername or NULL (local Computer)
2124 * Level [I] Structure-Level (Must be 2)
2125 * pMonitors [I] PTR to MONITOR_INFO_2
2132 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2135 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2137 LPMONITOR_INFO_2W mi2w;
2139 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2140 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2141 debugstr_w(mi2w ? mi2w->pName : NULL),
2142 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2143 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2145 if ((backend == NULL) && !load_backend()) return FALSE;
2148 SetLastError(ERROR_INVALID_LEVEL);
2152 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2157 return backend->fpAddMonitor(pName, Level, pMonitors);
2160 /******************************************************************
2161 * DeletePrinterDriverA [WINSPOOL.@]
2164 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2166 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2169 /******************************************************************
2170 * DeletePrinterDriverW [WINSPOOL.@]
2173 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2175 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2178 /******************************************************************
2179 * DeleteMonitorA [WINSPOOL.@]
2181 * See DeleteMonitorW.
2184 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2186 LPWSTR nameW = NULL;
2187 LPWSTR EnvironmentW = NULL;
2188 LPWSTR MonitorNameW = NULL;
2193 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2194 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2195 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2199 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2200 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2201 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2204 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2205 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2209 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2211 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2212 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2213 HeapFree(GetProcessHeap(), 0, nameW);
2217 /******************************************************************
2218 * DeleteMonitorW [WINSPOOL.@]
2220 * Delete a specific Printmonitor from a Printing-Environment
2223 * pName [I] Servername or NULL (local Computer)
2224 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2225 * pMonitorName [I] Name of the Monitor, that should be deleted
2232 * pEnvironment is ignored in Windows for the local Computer.
2235 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2238 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2239 debugstr_w(pMonitorName));
2241 if ((backend == NULL) && !load_backend()) return FALSE;
2243 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2247 /******************************************************************
2248 * DeletePortA [WINSPOOL.@]
2253 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2255 LPWSTR nameW = NULL;
2256 LPWSTR portW = NULL;
2260 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2262 /* convert servername to unicode */
2264 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2265 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2266 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2269 /* convert portname to unicode */
2271 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2272 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2273 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2276 res = DeletePortW(nameW, hWnd, portW);
2277 HeapFree(GetProcessHeap(), 0, nameW);
2278 HeapFree(GetProcessHeap(), 0, portW);
2282 /******************************************************************
2283 * DeletePortW [WINSPOOL.@]
2285 * Delete a specific Port
2288 * pName [I] Servername or NULL (local Computer)
2289 * hWnd [I] Handle to parent Window for the Dialog-Box
2290 * pPortName [I] Name of the Port, that should be deleted
2297 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2303 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2305 if (pName && pName[0]) {
2306 SetLastError(ERROR_INVALID_PARAMETER);
2311 SetLastError(RPC_X_NULL_REF_POINTER);
2315 /* an empty Portname is Invalid */
2316 if (!pPortName[0]) {
2317 SetLastError(ERROR_NOT_SUPPORTED);
2321 pm = monitor_load_by_port(pPortName);
2322 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2323 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2324 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2325 TRACE("got %d with %u\n", res, GetLastError());
2329 pui = monitor_loadui(pm);
2330 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2331 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2332 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2333 TRACE("got %d with %u\n", res, GetLastError());
2337 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2338 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2340 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2341 SetLastError(ERROR_NOT_SUPPORTED);
2344 monitor_unload(pui);
2348 TRACE("returning %d with %u\n", res, GetLastError());
2352 /******************************************************************************
2353 * SetPrinterW [WINSPOOL.@]
2355 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2357 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2358 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2362 /******************************************************************************
2363 * WritePrinter [WINSPOOL.@]
2365 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2367 opened_printer_t *printer;
2370 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2372 EnterCriticalSection(&printer_handles_cs);
2373 printer = get_opened_printer(hPrinter);
2376 SetLastError(ERROR_INVALID_HANDLE);
2382 SetLastError(ERROR_SPL_NO_STARTDOC);
2386 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2388 LeaveCriticalSection(&printer_handles_cs);
2392 /*****************************************************************************
2393 * AddFormA [WINSPOOL.@]
2395 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2397 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2401 /*****************************************************************************
2402 * AddFormW [WINSPOOL.@]
2404 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2406 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2410 /*****************************************************************************
2411 * AddJobA [WINSPOOL.@]
2413 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2416 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2420 SetLastError(ERROR_INVALID_LEVEL);
2424 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2427 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2428 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2429 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2430 if(*pcbNeeded > cbBuf) {
2431 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2434 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2435 addjobA->JobId = addjobW->JobId;
2436 addjobA->Path = (char *)(addjobA + 1);
2437 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2443 /*****************************************************************************
2444 * AddJobW [WINSPOOL.@]
2446 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2448 opened_printer_t *printer;
2451 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2452 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2453 WCHAR path[MAX_PATH], filename[MAX_PATH];
2455 ADDJOB_INFO_1W *addjob;
2457 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2459 EnterCriticalSection(&printer_handles_cs);
2461 printer = get_opened_printer(hPrinter);
2464 SetLastError(ERROR_INVALID_HANDLE);
2469 SetLastError(ERROR_INVALID_LEVEL);
2473 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2477 job->job_id = InterlockedIncrement(&next_job_id);
2479 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2480 if(path[len - 1] != '\\')
2482 memcpy(path + len, spool_path, sizeof(spool_path));
2483 sprintfW(filename, fmtW, path, job->job_id);
2485 len = strlenW(filename);
2486 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2487 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2488 job->document_title = strdupW(default_doc_title);
2489 list_add_tail(&printer->queue->jobs, &job->entry);
2491 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2492 if(*pcbNeeded <= cbBuf) {
2493 addjob = (ADDJOB_INFO_1W*)pData;
2494 addjob->JobId = job->job_id;
2495 addjob->Path = (WCHAR *)(addjob + 1);
2496 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2499 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2502 LeaveCriticalSection(&printer_handles_cs);
2506 /*****************************************************************************
2507 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2509 * Return the PATH for the Print-Processors
2511 * See GetPrintProcessorDirectoryW.
2515 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2516 DWORD level, LPBYTE Info,
2517 DWORD cbBuf, LPDWORD pcbNeeded)
2519 LPWSTR serverW = NULL;
2524 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2525 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2529 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2530 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2531 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2535 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2536 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2537 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2540 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2541 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2543 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2546 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2547 cbBuf, NULL, NULL) > 0;
2550 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2551 HeapFree(GetProcessHeap(), 0, envW);
2552 HeapFree(GetProcessHeap(), 0, serverW);
2556 /*****************************************************************************
2557 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2559 * Return the PATH for the Print-Processors
2562 * server [I] Servername (NT only) or NULL (local Computer)
2563 * env [I] Printing-Environment (see below) or NULL (Default)
2564 * level [I] Structure-Level (must be 1)
2565 * Info [O] PTR to Buffer that receives the Result
2566 * cbBuf [I] Size of Buffer at "Info"
2567 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2568 * required for the Buffer at "Info"
2571 * Success: TRUE and in pcbNeeded the Bytes used in Info
2572 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2573 * if cbBuf is too small
2575 * Native Values returned in Info on Success:
2576 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2577 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2578 *| win9x(Windows 4.0): "%winsysdir%"
2580 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2583 * Only NULL or "" is supported for server
2586 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2587 DWORD level, LPBYTE Info,
2588 DWORD cbBuf, LPDWORD pcbNeeded)
2591 const printenv_t * env_t;
2593 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2594 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2596 if(server != NULL && server[0]) {
2597 FIXME("server not supported: %s\n", debugstr_w(server));
2598 SetLastError(ERROR_INVALID_PARAMETER);
2602 env_t = validate_envW(env);
2603 if(!env_t) return FALSE; /* environment invalid or unsupported */
2606 WARN("(Level: %d) is ignored in win9x\n", level);
2607 SetLastError(ERROR_INVALID_LEVEL);
2611 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2612 needed = GetSystemDirectoryW(NULL, 0);
2613 /* add the Size for the Subdirectories */
2614 needed += lstrlenW(spoolprtprocsW);
2615 needed += lstrlenW(env_t->subdir);
2616 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2618 if(pcbNeeded) *pcbNeeded = needed;
2619 TRACE ("required: 0x%x/%d\n", needed, needed);
2620 if (needed > cbBuf) {
2621 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2624 if(pcbNeeded == NULL) {
2625 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2626 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2627 SetLastError(RPC_X_NULL_REF_POINTER);
2631 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2632 SetLastError(RPC_X_NULL_REF_POINTER);
2636 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2637 /* add the Subdirectories */
2638 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2639 lstrcatW((LPWSTR) Info, env_t->subdir);
2640 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2644 /*****************************************************************************
2645 * WINSPOOL_OpenDriverReg [internal]
2647 * opens the registry for the printer drivers depending on the given input
2648 * variable pEnvironment
2651 * the opened hkey on success
2654 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2658 const printenv_t * env;
2661 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2663 if (!pEnvironment || unicode) {
2664 /* pEnvironment was NULL or a Unicode-String: use it direct */
2665 env = validate_envW(pEnvironment);
2669 /* pEnvironment was an ANSI-String: convert to unicode first */
2671 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2672 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2673 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2674 env = validate_envW(buffer);
2675 HeapFree(GetProcessHeap(), 0, buffer);
2677 if (!env) return NULL;
2679 buffer = HeapAlloc( GetProcessHeap(), 0,
2680 (strlenW(DriversW) + strlenW(env->envname) +
2681 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2683 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2684 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2685 HeapFree(GetProcessHeap(), 0, buffer);
2690 /*****************************************************************************
2691 * AddPrinterW [WINSPOOL.@]
2693 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2695 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2699 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2701 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2702 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2703 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2704 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2705 statusW[] = {'S','t','a','t','u','s',0},
2706 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2708 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2711 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2712 SetLastError(ERROR_INVALID_PARAMETER);
2716 ERR("Level = %d, unsupported!\n", Level);
2717 SetLastError(ERROR_INVALID_LEVEL);
2721 SetLastError(ERROR_INVALID_PARAMETER);
2724 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2726 ERR("Can't create Printers key\n");
2729 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2730 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2731 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2732 RegCloseKey(hkeyPrinter);
2733 RegCloseKey(hkeyPrinters);
2736 RegCloseKey(hkeyPrinter);
2738 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2740 ERR("Can't create Drivers key\n");
2741 RegCloseKey(hkeyPrinters);
2744 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2746 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2747 RegCloseKey(hkeyPrinters);
2748 RegCloseKey(hkeyDrivers);
2749 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2752 RegCloseKey(hkeyDriver);
2753 RegCloseKey(hkeyDrivers);
2755 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2756 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2757 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2758 RegCloseKey(hkeyPrinters);
2762 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2764 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2765 SetLastError(ERROR_INVALID_PRINTER_NAME);
2766 RegCloseKey(hkeyPrinters);
2769 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2770 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2771 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2773 /* See if we can load the driver. We may need the devmode structure anyway
2776 * Note that DocumentPropertiesW will briefly try to open the printer we
2777 * just create to find a DEVMODEA struct (it will use the WINEPS default
2778 * one in case it is not there, so we are ok).
2780 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2783 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2784 size = sizeof(DEVMODEW);
2790 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2792 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2794 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2795 HeapFree(GetProcessHeap(),0,dmW);
2800 /* set devmode to printer name */
2801 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2805 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2806 and we support these drivers. NT writes DEVMODEW so somehow
2807 we'll need to distinguish between these when we support NT
2811 dmA = DEVMODEdupWtoA(dmW);
2812 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2813 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2814 HeapFree(GetProcessHeap(), 0, dmA);
2816 HeapFree(GetProcessHeap(), 0, dmW);
2818 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2819 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2820 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2821 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2823 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2824 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2825 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2826 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2827 (LPBYTE)&pi->Priority, sizeof(DWORD));
2828 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2829 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2830 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2831 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2832 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2833 (LPBYTE)&pi->Status, sizeof(DWORD));
2834 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2835 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2837 RegCloseKey(hkeyPrinter);
2838 RegCloseKey(hkeyPrinters);
2839 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2840 ERR("OpenPrinter failing\n");
2846 /*****************************************************************************
2847 * AddPrinterA [WINSPOOL.@]
2849 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2851 UNICODE_STRING pNameW;
2853 PRINTER_INFO_2W *piW;
2854 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2857 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2859 ERR("Level = %d, unsupported!\n", Level);
2860 SetLastError(ERROR_INVALID_LEVEL);
2863 pwstrNameW = asciitounicode(&pNameW,pName);
2864 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2866 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2868 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2869 RtlFreeUnicodeString(&pNameW);
2874 /*****************************************************************************
2875 * ClosePrinter [WINSPOOL.@]
2877 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2879 UINT_PTR i = (UINT_PTR)hPrinter;
2880 opened_printer_t *printer = NULL;
2883 TRACE("(%p)\n", hPrinter);
2885 EnterCriticalSection(&printer_handles_cs);
2887 if ((i > 0) && (i <= nb_printer_handles))
2888 printer = printer_handles[i - 1];
2893 struct list *cursor, *cursor2;
2895 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2896 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2897 printer->hXcv, debugstr_w(printer->name), printer->doc );
2900 EndDocPrinter(hPrinter);
2902 if(InterlockedDecrement(&printer->queue->ref) == 0)
2904 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2906 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2907 ScheduleJob(hPrinter, job->job_id);
2909 HeapFree(GetProcessHeap(), 0, printer->queue);
2911 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2912 monitor_unload(printer->pm);
2913 HeapFree(GetProcessHeap(), 0, printer->printername);
2914 HeapFree(GetProcessHeap(), 0, printer->name);
2915 HeapFree(GetProcessHeap(), 0, printer);
2916 printer_handles[i - 1] = NULL;
2919 LeaveCriticalSection(&printer_handles_cs);
2923 /*****************************************************************************
2924 * DeleteFormA [WINSPOOL.@]
2926 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2928 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2932 /*****************************************************************************
2933 * DeleteFormW [WINSPOOL.@]
2935 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2937 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2941 /*****************************************************************************
2942 * DeletePrinter [WINSPOOL.@]
2944 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2946 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2947 HKEY hkeyPrinters, hkey;
2950 SetLastError(ERROR_INVALID_HANDLE);
2953 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2954 RegDeleteTreeW(hkeyPrinters, lpNameW);
2955 RegCloseKey(hkeyPrinters);
2957 WriteProfileStringW(devicesW, lpNameW, NULL);
2958 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2960 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2961 RegDeleteValueW(hkey, lpNameW);
2965 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2966 RegDeleteValueW(hkey, lpNameW);
2972 /*****************************************************************************
2973 * SetPrinterA [WINSPOOL.@]
2975 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2978 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2982 /*****************************************************************************
2983 * SetJobA [WINSPOOL.@]
2985 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2986 LPBYTE pJob, DWORD Command)
2990 UNICODE_STRING usBuffer;
2992 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2994 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2995 are all ignored by SetJob, so we don't bother copying them */
3003 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3004 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3006 JobW = (LPBYTE)info1W;
3007 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3008 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3009 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3010 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3011 info1W->Status = info1A->Status;
3012 info1W->Priority = info1A->Priority;
3013 info1W->Position = info1A->Position;
3014 info1W->PagesPrinted = info1A->PagesPrinted;
3019 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3020 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3022 JobW = (LPBYTE)info2W;
3023 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3024 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3025 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3026 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3027 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3028 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3029 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3030 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3031 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3032 info2W->Status = info2A->Status;
3033 info2W->Priority = info2A->Priority;
3034 info2W->Position = info2A->Position;
3035 info2W->StartTime = info2A->StartTime;
3036 info2W->UntilTime = info2A->UntilTime;
3037 info2W->PagesPrinted = info2A->PagesPrinted;
3041 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3042 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3045 SetLastError(ERROR_INVALID_LEVEL);
3049 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3055 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3056 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3057 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3058 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3059 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3064 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3065 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3066 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3067 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3068 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3069 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3070 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3071 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3072 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3076 HeapFree(GetProcessHeap(), 0, JobW);
3081 /*****************************************************************************
3082 * SetJobW [WINSPOOL.@]
3084 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3085 LPBYTE pJob, DWORD Command)
3090 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3091 FIXME("Ignoring everything other than document title\n");
3093 EnterCriticalSection(&printer_handles_cs);
3094 job = get_job(hPrinter, JobId);
3104 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3105 HeapFree(GetProcessHeap(), 0, job->document_title);
3106 job->document_title = strdupW(info1->pDocument);
3111 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3112 HeapFree(GetProcessHeap(), 0, job->document_title);
3113 job->document_title = strdupW(info2->pDocument);
3119 SetLastError(ERROR_INVALID_LEVEL);
3124 LeaveCriticalSection(&printer_handles_cs);
3128 /*****************************************************************************
3129 * EndDocPrinter [WINSPOOL.@]
3131 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3133 opened_printer_t *printer;
3135 TRACE("(%p)\n", hPrinter);
3137 EnterCriticalSection(&printer_handles_cs);
3139 printer = get_opened_printer(hPrinter);
3142 SetLastError(ERROR_INVALID_HANDLE);
3148 SetLastError(ERROR_SPL_NO_STARTDOC);
3152 CloseHandle(printer->doc->hf);
3153 ScheduleJob(hPrinter, printer->doc->job_id);
3154 HeapFree(GetProcessHeap(), 0, printer->doc);
3155 printer->doc = NULL;
3158 LeaveCriticalSection(&printer_handles_cs);
3162 /*****************************************************************************
3163 * EndPagePrinter [WINSPOOL.@]
3165 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3167 FIXME("(%p): stub\n", hPrinter);
3171 /*****************************************************************************
3172 * StartDocPrinterA [WINSPOOL.@]
3174 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3176 UNICODE_STRING usBuffer;
3178 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3181 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3182 or one (DOC_INFO_3) extra DWORDs */
3186 doc2W.JobId = doc2->JobId;
3189 doc2W.dwMode = doc2->dwMode;
3192 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3193 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3194 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3198 SetLastError(ERROR_INVALID_LEVEL);
3202 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3204 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3205 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3206 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3211 /*****************************************************************************
3212 * StartDocPrinterW [WINSPOOL.@]
3214 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3216 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3217 opened_printer_t *printer;
3218 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3219 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3220 JOB_INFO_1W job_info;
3221 DWORD needed, ret = 0;
3225 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3226 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3227 debugstr_w(doc->pDatatype));
3229 if(Level < 1 || Level > 3)
3231 SetLastError(ERROR_INVALID_LEVEL);
3235 EnterCriticalSection(&printer_handles_cs);
3236 printer = get_opened_printer(hPrinter);
3239 SetLastError(ERROR_INVALID_HANDLE);
3245 SetLastError(ERROR_INVALID_PRINTER_STATE);
3249 /* Even if we're printing to a file we still add a print job, we'll
3250 just ignore the spool file name */
3252 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3254 ERR("AddJob failed gle %u\n", GetLastError());
3258 if(doc->pOutputFile)
3259 filename = doc->pOutputFile;
3261 filename = addjob->Path;
3263 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3264 if(hf == INVALID_HANDLE_VALUE)
3267 memset(&job_info, 0, sizeof(job_info));
3268 job_info.pDocument = doc->pDocName;
3269 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3271 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3272 printer->doc->hf = hf;
3273 ret = printer->doc->job_id = addjob->JobId;
3275 LeaveCriticalSection(&printer_handles_cs);
3280 /*****************************************************************************
3281 * StartPagePrinter [WINSPOOL.@]
3283 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3285 FIXME("(%p): stub\n", hPrinter);
3289 /*****************************************************************************
3290 * GetFormA [WINSPOOL.@]
3292 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3293 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3295 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3296 Level,pForm,cbBuf,pcbNeeded);
3300 /*****************************************************************************
3301 * GetFormW [WINSPOOL.@]
3303 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3304 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3306 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3307 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3311 /*****************************************************************************
3312 * SetFormA [WINSPOOL.@]
3314 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3317 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3321 /*****************************************************************************
3322 * SetFormW [WINSPOOL.@]
3324 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3327 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3331 /*****************************************************************************
3332 * ReadPrinter [WINSPOOL.@]
3334 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3335 LPDWORD pNoBytesRead)
3337 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3341 /*****************************************************************************
3342 * ResetPrinterA [WINSPOOL.@]
3344 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3346 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3350 /*****************************************************************************
3351 * ResetPrinterW [WINSPOOL.@]
3353 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3355 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3359 /*****************************************************************************
3360 * WINSPOOL_GetDWORDFromReg
3362 * Return DWORD associated with ValueName from hkey.
3364 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3366 DWORD sz = sizeof(DWORD), type, value = 0;
3369 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3371 if(ret != ERROR_SUCCESS) {
3372 WARN("Got ret = %d on name %s\n", ret, ValueName);
3375 if(type != REG_DWORD) {
3376 ERR("Got type %d\n", type);
3383 /*****************************************************************************
3384 * get_filename_from_reg [internal]
3386 * Get ValueName from hkey storing result in out
3387 * when the Value in the registry has only a filename, use driverdir as prefix
3388 * outlen is space left in out
3389 * String is stored either as unicode or ascii
3393 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3394 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3396 WCHAR filename[MAX_PATH];
3400 LPWSTR buffer = filename;
3404 size = sizeof(filename);
3406 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3407 if (ret == ERROR_MORE_DATA) {
3408 TRACE("need dynamic buffer: %u\n", size);
3409 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3411 /* No Memory is bad */
3415 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3418 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3419 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3425 /* do we have a full path ? */
3426 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3427 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3430 /* we must build the full Path */
3432 if ((out) && (outlen > dirlen)) {
3434 lstrcpyW((LPWSTR)out, driverdir);
3438 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3447 /* write the filename */
3449 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3450 if ((out) && (outlen >= size)) {
3451 lstrcpyW((LPWSTR)out, ptr);
3460 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3461 if ((out) && (outlen >= size)) {
3462 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3470 ptr += lstrlenW(ptr)+1;
3471 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3474 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3476 /* write the multisz-termination */
3477 if (type == REG_MULTI_SZ) {
3478 size = (unicode) ? sizeof(WCHAR) : 1;
3481 if (out && (outlen >= size)) {
3482 memset (out, 0, size);
3488 /*****************************************************************************
3489 * WINSPOOL_GetStringFromReg
3491 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3492 * String is stored either as unicode or ascii.
3493 * Bit of a hack here to get the ValueName if we want ascii.
3495 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3496 DWORD buflen, DWORD *needed,
3499 DWORD sz = buflen, type;
3503 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3505 LPSTR ValueNameA = strdupWtoA(ValueName);
3506 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3507 HeapFree(GetProcessHeap(),0,ValueNameA);
3509 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3510 WARN("Got ret = %d\n", ret);
3514 /* add space for terminating '\0' */
3515 sz += unicode ? sizeof(WCHAR) : 1;
3519 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3524 /*****************************************************************************
3525 * WINSPOOL_GetDefaultDevMode
3527 * Get a default DevMode values for wineps.
3531 static void WINSPOOL_GetDefaultDevMode(
3533 DWORD buflen, DWORD *needed,
3537 static const char szwps[] = "wineps.drv";
3539 /* fill default DEVMODE - should be read from ppd... */
3540 ZeroMemory( &dm, sizeof(dm) );
3541 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3542 dm.dmSpecVersion = DM_SPECVERSION;
3543 dm.dmDriverVersion = 1;
3544 dm.dmSize = sizeof(DEVMODEA);
3545 dm.dmDriverExtra = 0;
3547 DM_ORIENTATION | DM_PAPERSIZE |
3548 DM_PAPERLENGTH | DM_PAPERWIDTH |
3551 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3552 DM_YRESOLUTION | DM_TTOPTION;
3554 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3555 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3556 dm.u1.s1.dmPaperLength = 2970;
3557 dm.u1.s1.dmPaperWidth = 2100;
3559 dm.u1.s1.dmScale = 100;
3560 dm.u1.s1.dmCopies = 1;
3561 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3562 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3565 dm.dmYResolution = 300; /* 300dpi */
3566 dm.dmTTOption = DMTT_BITMAP;
3569 /* dm.dmLogPixels */
3570 /* dm.dmBitsPerPel */
3571 /* dm.dmPelsWidth */
3572 /* dm.dmPelsHeight */
3573 /* dm.u2.dmDisplayFlags */
3574 /* dm.dmDisplayFrequency */
3575 /* dm.dmICMMethod */
3576 /* dm.dmICMIntent */
3577 /* dm.dmMediaType */
3578 /* dm.dmDitherType */
3579 /* dm.dmReserved1 */
3580 /* dm.dmReserved2 */
3581 /* dm.dmPanningWidth */
3582 /* dm.dmPanningHeight */
3585 if(buflen >= sizeof(DEVMODEW)) {
3586 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3587 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3588 HeapFree(GetProcessHeap(),0,pdmW);
3590 *needed = sizeof(DEVMODEW);
3594 if(buflen >= sizeof(DEVMODEA)) {
3595 memcpy(ptr, &dm, sizeof(DEVMODEA));
3597 *needed = sizeof(DEVMODEA);
3601 /*****************************************************************************
3602 * WINSPOOL_GetDevModeFromReg
3604 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3605 * DevMode is stored either as unicode or ascii.
3607 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3609 DWORD buflen, DWORD *needed,
3612 DWORD sz = buflen, type;
3615 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3616 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3617 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3618 if (sz < sizeof(DEVMODEA))
3620 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3623 /* ensures that dmSize is not erratically bogus if registry is invalid */
3624 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3625 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3627 sz += (CCHDEVICENAME + CCHFORMNAME);
3629 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3630 memcpy(ptr, dmW, sz);
3631 HeapFree(GetProcessHeap(),0,dmW);
3638 /*********************************************************************
3639 * WINSPOOL_GetPrinter_1
3641 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3642 * The strings are either stored as unicode or ascii.
3644 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3645 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3648 DWORD size, left = cbBuf;
3649 BOOL space = (cbBuf > 0);
3654 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3656 if(space && size <= left) {
3657 pi1->pName = (LPWSTR)ptr;
3665 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3666 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3668 if(space && size <= left) {
3669 pi1->pDescription = (LPWSTR)ptr;
3677 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3679 if(space && size <= left) {
3680 pi1->pComment = (LPWSTR)ptr;
3688 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3690 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3691 memset(pi1, 0, sizeof(*pi1));
3695 /*********************************************************************
3696 * WINSPOOL_GetPrinter_2
3698 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3699 * The strings are either stored as unicode or ascii.
3701 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3702 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3705 DWORD size, left = cbBuf;
3706 BOOL space = (cbBuf > 0);
3711 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3713 if(space && size <= left) {
3714 pi2->pPrinterName = (LPWSTR)ptr;
3721 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3723 if(space && size <= left) {
3724 pi2->pShareName = (LPWSTR)ptr;
3731 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3733 if(space && size <= left) {
3734 pi2->pPortName = (LPWSTR)ptr;
3741 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3743 if(space && size <= left) {
3744 pi2->pDriverName = (LPWSTR)ptr;
3751 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3753 if(space && size <= left) {
3754 pi2->pComment = (LPWSTR)ptr;
3761 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3763 if(space && size <= left) {
3764 pi2->pLocation = (LPWSTR)ptr;
3771 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3773 if(space && size <= left) {
3774 pi2->pDevMode = (LPDEVMODEW)ptr;
3783 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3784 if(space && size <= left) {
3785 pi2->pDevMode = (LPDEVMODEW)ptr;
3792 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3794 if(space && size <= left) {
3795 pi2->pSepFile = (LPWSTR)ptr;
3802 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3804 if(space && size <= left) {
3805 pi2->pPrintProcessor = (LPWSTR)ptr;
3812 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3814 if(space && size <= left) {
3815 pi2->pDatatype = (LPWSTR)ptr;
3822 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3824 if(space && size <= left) {
3825 pi2->pParameters = (LPWSTR)ptr;
3833 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3834 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3835 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3836 "Default Priority");
3837 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3838 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3841 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3842 memset(pi2, 0, sizeof(*pi2));
3847 /*********************************************************************
3848 * WINSPOOL_GetPrinter_4
3850 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3852 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3853 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3856 DWORD size, left = cbBuf;
3857 BOOL space = (cbBuf > 0);
3862 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3864 if(space && size <= left) {
3865 pi4->pPrinterName = (LPWSTR)ptr;
3873 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3876 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3877 memset(pi4, 0, sizeof(*pi4));
3882 /*********************************************************************
3883 * WINSPOOL_GetPrinter_5
3885 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3887 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3888 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3891 DWORD size, left = cbBuf;
3892 BOOL space = (cbBuf > 0);
3897 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3899 if(space && size <= left) {
3900 pi5->pPrinterName = (LPWSTR)ptr;
3907 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3909 if(space && size <= left) {
3910 pi5->pPortName = (LPWSTR)ptr;
3918 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3919 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3921 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3925 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3926 memset(pi5, 0, sizeof(*pi5));
3931 /*********************************************************************
3932 * WINSPOOL_GetPrinter_7
3934 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3936 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3937 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3939 DWORD size, left = cbBuf;
3940 BOOL space = (cbBuf > 0);
3945 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3947 if (space && size <= left) {
3948 pi7->pszObjectGUID = (LPWSTR)ptr;
3956 /* We do not have a Directory Service */
3957 pi7->dwAction = DSPRINT_UNPUBLISH;
3960 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3961 memset(pi7, 0, sizeof(*pi7));
3966 /*********************************************************************
3967 * WINSPOOL_GetPrinter_9
3969 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3970 * The strings are either stored as unicode or ascii.
3972 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3973 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3976 BOOL space = (cbBuf > 0);
3980 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3981 if(space && size <= cbBuf) {
3982 pi9->pDevMode = (LPDEVMODEW)buf;
3989 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3990 if(space && size <= cbBuf) {
3991 pi9->pDevMode = (LPDEVMODEW)buf;
3997 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3998 memset(pi9, 0, sizeof(*pi9));
4003 /*****************************************************************************
4004 * WINSPOOL_GetPrinter
4006 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4007 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4008 * just a collection of pointers to strings.
4010 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4011 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4014 DWORD size, needed = 0;
4016 HKEY hkeyPrinter, hkeyPrinters;
4019 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4021 if (!(name = get_opened_printer_name(hPrinter))) {
4022 SetLastError(ERROR_INVALID_HANDLE);
4026 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4028 ERR("Can't create Printers key\n");
4031 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4033 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4034 RegCloseKey(hkeyPrinters);
4035 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4042 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4044 size = sizeof(PRINTER_INFO_2W);
4046 ptr = pPrinter + size;
4048 memset(pPrinter, 0, size);
4053 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4061 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4063 size = sizeof(PRINTER_INFO_4W);
4065 ptr = pPrinter + size;
4067 memset(pPrinter, 0, size);
4072 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4081 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4083 size = sizeof(PRINTER_INFO_5W);
4085 ptr = pPrinter + size;
4087 memset(pPrinter, 0, size);
4093 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4102 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4104 size = sizeof(PRINTER_INFO_6);
4105 if (size <= cbBuf) {
4106 /* FIXME: We do not update the status yet */
4107 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4119 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4121 size = sizeof(PRINTER_INFO_7W);
4122 if (size <= cbBuf) {
4123 ptr = pPrinter + size;
4125 memset(pPrinter, 0, size);
4131 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4139 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4141 size = sizeof(PRINTER_INFO_9W);
4143 ptr = pPrinter + size;
4145 memset(pPrinter, 0, size);
4151 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4158 FIXME("Unimplemented level %d\n", Level);
4159 SetLastError(ERROR_INVALID_LEVEL);
4160 RegCloseKey(hkeyPrinters);
4161 RegCloseKey(hkeyPrinter);
4165 RegCloseKey(hkeyPrinter);
4166 RegCloseKey(hkeyPrinters);
4168 TRACE("returning %d needed = %d\n", ret, needed);
4169 if(pcbNeeded) *pcbNeeded = needed;
4171 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4175 /*****************************************************************************
4176 * GetPrinterW [WINSPOOL.@]
4178 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4179 DWORD cbBuf, LPDWORD pcbNeeded)
4181 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4185 /*****************************************************************************
4186 * GetPrinterA [WINSPOOL.@]
4188 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4189 DWORD cbBuf, LPDWORD pcbNeeded)
4191 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4195 /*****************************************************************************
4196 * WINSPOOL_EnumPrinters
4198 * Implementation of EnumPrintersA|W
4200 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4201 DWORD dwLevel, LPBYTE lpbPrinters,
4202 DWORD cbBuf, LPDWORD lpdwNeeded,
4203 LPDWORD lpdwReturned, BOOL unicode)
4206 HKEY hkeyPrinters, hkeyPrinter;
4207 WCHAR PrinterName[255];
4208 DWORD needed = 0, number = 0;
4209 DWORD used, i, left;
4213 memset(lpbPrinters, 0, cbBuf);
4219 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4220 if(dwType == PRINTER_ENUM_DEFAULT)
4223 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4224 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4225 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4227 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4235 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4236 FIXME("dwType = %08x\n", dwType);
4237 SetLastError(ERROR_INVALID_FLAGS);
4241 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4243 ERR("Can't create Printers key\n");
4247 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4248 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4249 RegCloseKey(hkeyPrinters);
4250 ERR("Can't query Printers key\n");
4253 TRACE("Found %d printers\n", number);
4257 used = number * sizeof(PRINTER_INFO_1W);
4260 used = number * sizeof(PRINTER_INFO_2W);
4263 used = number * sizeof(PRINTER_INFO_4W);
4266 used = number * sizeof(PRINTER_INFO_5W);
4270 SetLastError(ERROR_INVALID_LEVEL);
4271 RegCloseKey(hkeyPrinters);
4274 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4276 for(i = 0; i < number; i++) {
4277 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4279 ERR("Can't enum key number %d\n", i);
4280 RegCloseKey(hkeyPrinters);
4283 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4284 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4286 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4287 RegCloseKey(hkeyPrinters);
4292 buf = lpbPrinters + used;
4293 left = cbBuf - used;
4301 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4302 left, &needed, unicode);
4304 if(pi) pi += sizeof(PRINTER_INFO_1W);
4307 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4308 left, &needed, unicode);
4310 if(pi) pi += sizeof(PRINTER_INFO_2W);
4313 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4314 left, &needed, unicode);
4316 if(pi) pi += sizeof(PRINTER_INFO_4W);
4319 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4320 left, &needed, unicode);
4322 if(pi) pi += sizeof(PRINTER_INFO_5W);
4325 ERR("Shouldn't be here!\n");
4326 RegCloseKey(hkeyPrinter);
4327 RegCloseKey(hkeyPrinters);
4330 RegCloseKey(hkeyPrinter);
4332 RegCloseKey(hkeyPrinters);
4339 memset(lpbPrinters, 0, cbBuf);
4340 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4344 *lpdwReturned = number;
4345 SetLastError(ERROR_SUCCESS);
4350 /******************************************************************
4351 * EnumPrintersW [WINSPOOL.@]
4353 * Enumerates the available printers, print servers and print
4354 * providers, depending on the specified flags, name and level.
4358 * If level is set to 1:
4359 * Returns an array of PRINTER_INFO_1 data structures in the
4360 * lpbPrinters buffer.
4362 * If level is set to 2:
4363 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4364 * Returns an array of PRINTER_INFO_2 data structures in the
4365 * lpbPrinters buffer. Note that according to MSDN also an
4366 * OpenPrinter should be performed on every remote printer.
4368 * If level is set to 4 (officially WinNT only):
4369 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4370 * Fast: Only the registry is queried to retrieve printer names,
4371 * no connection to the driver is made.
4372 * Returns an array of PRINTER_INFO_4 data structures in the
4373 * lpbPrinters buffer.
4375 * If level is set to 5 (officially WinNT4/Win9x only):
4376 * Fast: Only the registry is queried to retrieve printer names,
4377 * no connection to the driver is made.
4378 * Returns an array of PRINTER_INFO_5 data structures in the
4379 * lpbPrinters buffer.
4381 * If level set to 3 or 6+:
4382 * returns zero (failure!)
4384 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4388 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4389 * - Only levels 2, 4 and 5 are implemented at the moment.
4390 * - 16-bit printer drivers are not enumerated.
4391 * - Returned amount of bytes used/needed does not match the real Windoze
4392 * implementation (as in this implementation, all strings are part
4393 * of the buffer, whereas Win32 keeps them somewhere else)
4394 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4397 * - In a regular Wine installation, no registry settings for printers
4398 * exist, which makes this function return an empty list.
4400 BOOL WINAPI EnumPrintersW(
4401 DWORD dwType, /* [in] Types of print objects to enumerate */
4402 LPWSTR lpszName, /* [in] name of objects to enumerate */
4403 DWORD dwLevel, /* [in] type of printer info structure */
4404 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4405 DWORD cbBuf, /* [in] max size of buffer in bytes */
4406 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4407 LPDWORD lpdwReturned /* [out] number of entries returned */
4410 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4411 lpdwNeeded, lpdwReturned, TRUE);
4414 /******************************************************************
4415 * EnumPrintersA [WINSPOOL.@]
4420 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4421 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4424 UNICODE_STRING pNameU;
4428 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4429 pPrinters, cbBuf, pcbNeeded, pcReturned);
4431 pNameW = asciitounicode(&pNameU, pName);
4433 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4434 MS Office need this */
4435 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4437 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4439 RtlFreeUnicodeString(&pNameU);
4441 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4443 HeapFree(GetProcessHeap(), 0, pPrintersW);
4447 /*****************************************************************************
4448 * WINSPOOL_GetDriverInfoFromReg [internal]
4450 * Enters the information from the registry into the DRIVER_INFO struct
4453 * zero if the printer driver does not exist in the registry
4454 * (only if Level > 1) otherwise nonzero
4456 static BOOL WINSPOOL_GetDriverInfoFromReg(
4459 const printenv_t * env,
4461 LPBYTE ptr, /* DRIVER_INFO */
4462 LPBYTE pDriverStrings, /* strings buffer */
4463 DWORD cbBuf, /* size of string buffer */
4464 LPDWORD pcbNeeded, /* space needed for str. */
4465 BOOL unicode) /* type of strings */
4469 WCHAR driverdir[MAX_PATH];
4471 LPBYTE strPtr = pDriverStrings;
4472 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4474 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4475 debugstr_w(DriverName), env,
4476 Level, di, pDriverStrings, cbBuf, unicode);
4478 if (di) ZeroMemory(di, di_sizeof[Level]);
4481 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4482 if (*pcbNeeded <= cbBuf)
4483 strcpyW((LPWSTR)strPtr, DriverName);
4487 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4488 if (*pcbNeeded <= cbBuf)
4489 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4492 /* pName for level 1 has a different offset! */
4494 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4498 /* .cVersion and .pName for level > 1 */
4500 di->cVersion = env->driverversion;
4501 di->pName = (LPWSTR) strPtr;
4502 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4505 /* Reserve Space for the largest subdir and a Backslash*/
4506 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4507 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4508 /* Should never Fail */
4511 lstrcatW(driverdir, env->versionsubdir);
4512 lstrcatW(driverdir, backslashW);
4514 /* dirlen must not include the terminating zero */
4515 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4516 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4518 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4519 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4520 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4526 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4528 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4531 if (*pcbNeeded <= cbBuf) {
4533 lstrcpyW((LPWSTR)strPtr, env->envname);
4537 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4539 if (di) di->pEnvironment = (LPWSTR)strPtr;
4540 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4543 /* .pDriverPath is the Graphics rendering engine.
4544 The full Path is required to avoid a crash in some apps */
4545 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4547 if (*pcbNeeded <= cbBuf)
4548 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4550 if (di) di->pDriverPath = (LPWSTR)strPtr;
4551 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4554 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4555 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4557 if (*pcbNeeded <= cbBuf)
4558 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4560 if (di) di->pDataFile = (LPWSTR)strPtr;
4561 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4564 /* .pConfigFile is the Driver user Interface */
4565 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4567 if (*pcbNeeded <= cbBuf)
4568 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4570 if (di) di->pConfigFile = (LPWSTR)strPtr;
4571 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4575 RegCloseKey(hkeyDriver);
4576 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4581 RegCloseKey(hkeyDriver);
4582 FIXME("level 5: incomplete\n");
4587 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4589 if (*pcbNeeded <= cbBuf)
4590 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4592 if (di) di->pHelpFile = (LPWSTR)strPtr;
4593 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4596 /* .pDependentFiles */
4597 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4599 if (*pcbNeeded <= cbBuf)
4600 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4602 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4603 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4605 else if (GetVersion() & 0x80000000) {
4606 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4607 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4609 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4611 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4612 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4615 /* .pMonitorName is the optional Language Monitor */
4616 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4618 if (*pcbNeeded <= cbBuf)
4619 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4621 if (di) di->pMonitorName = (LPWSTR)strPtr;
4622 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4625 /* .pDefaultDataType */
4626 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4628 if(*pcbNeeded <= cbBuf)
4629 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4631 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4632 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4636 RegCloseKey(hkeyDriver);
4637 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4641 /* .pszzPreviousNames */
4642 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4644 if(*pcbNeeded <= cbBuf)
4645 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4647 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4648 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4652 RegCloseKey(hkeyDriver);
4653 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4657 /* support is missing, but not important enough for a FIXME */
4658 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4661 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4663 if(*pcbNeeded <= cbBuf)
4664 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4666 if (di) di->pszMfgName = (LPWSTR)strPtr;
4667 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4671 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4673 if(*pcbNeeded <= cbBuf)
4674 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4676 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4677 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4680 /* .pszHardwareID */
4681 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4683 if(*pcbNeeded <= cbBuf)
4684 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4686 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4687 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4691 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4693 if(*pcbNeeded <= cbBuf)
4694 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4696 if (di) di->pszProvider = (LPWSTR)strPtr;
4697 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4701 RegCloseKey(hkeyDriver);
4705 /* support is missing, but not important enough for a FIXME */
4706 TRACE("level 8: incomplete\n");
4708 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4709 RegCloseKey(hkeyDriver);
4713 /*****************************************************************************
4714 * WINSPOOL_GetPrinterDriver
4716 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4717 DWORD Level, LPBYTE pDriverInfo,
4718 DWORD cbBuf, LPDWORD pcbNeeded,
4722 WCHAR DriverName[100];
4723 DWORD ret, type, size, needed = 0;
4725 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4726 const printenv_t * env;
4728 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4729 Level,pDriverInfo,cbBuf, pcbNeeded);
4732 if (!(name = get_opened_printer_name(hPrinter))) {
4733 SetLastError(ERROR_INVALID_HANDLE);
4737 if (Level < 1 || Level == 7 || Level > 8) {
4738 SetLastError(ERROR_INVALID_LEVEL);
4742 env = validate_envW(pEnvironment);
4743 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4745 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4747 ERR("Can't create Printers key\n");
4750 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4752 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4753 RegCloseKey(hkeyPrinters);
4754 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4757 size = sizeof(DriverName);
4759 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4760 (LPBYTE)DriverName, &size);
4761 RegCloseKey(hkeyPrinter);
4762 RegCloseKey(hkeyPrinters);
4763 if(ret != ERROR_SUCCESS) {
4764 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4768 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4770 ERR("Can't create Drivers key\n");
4774 size = di_sizeof[Level];
4775 if ((size <= cbBuf) && pDriverInfo)
4776 ptr = pDriverInfo + size;
4778 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4779 env, Level, pDriverInfo, ptr,
4780 (cbBuf < size) ? 0 : cbBuf - size,
4781 &needed, unicode)) {
4782 RegCloseKey(hkeyDrivers);
4786 RegCloseKey(hkeyDrivers);
4788 if(pcbNeeded) *pcbNeeded = size + needed;
4789 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4790 if(cbBuf >= needed) return TRUE;
4791 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4795 /*****************************************************************************
4796 * GetPrinterDriverA [WINSPOOL.@]
4798 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4799 DWORD Level, LPBYTE pDriverInfo,
4800 DWORD cbBuf, LPDWORD pcbNeeded)
4803 UNICODE_STRING pEnvW;
4806 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4807 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4808 cbBuf, pcbNeeded, FALSE);
4809 RtlFreeUnicodeString(&pEnvW);
4812 /*****************************************************************************
4813 * GetPrinterDriverW [WINSPOOL.@]
4815 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4816 DWORD Level, LPBYTE pDriverInfo,
4817 DWORD cbBuf, LPDWORD pcbNeeded)
4819 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4820 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4823 /*****************************************************************************
4824 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4826 * Return the PATH for the Printer-Drivers (UNICODE)
4829 * pName [I] Servername (NT only) or NULL (local Computer)
4830 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4831 * Level [I] Structure-Level (must be 1)
4832 * pDriverDirectory [O] PTR to Buffer that receives the Result
4833 * cbBuf [I] Size of Buffer at pDriverDirectory
4834 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4835 * required for pDriverDirectory
4838 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4839 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4840 * if cbBuf is too small
4842 * Native Values returned in pDriverDirectory on Success:
4843 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4844 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4845 *| win9x(Windows 4.0): "%winsysdir%"
4847 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4850 *- Only NULL or "" is supported for pName
4853 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4854 DWORD Level, LPBYTE pDriverDirectory,
4855 DWORD cbBuf, LPDWORD pcbNeeded)
4857 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4858 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4860 if ((backend == NULL) && !load_backend()) return FALSE;
4863 /* (Level != 1) is ignored in win9x */
4864 SetLastError(ERROR_INVALID_LEVEL);
4867 if (pcbNeeded == NULL) {
4868 /* (pcbNeeded == NULL) is ignored in win9x */
4869 SetLastError(RPC_X_NULL_REF_POINTER);
4873 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4874 pDriverDirectory, cbBuf, pcbNeeded);
4879 /*****************************************************************************
4880 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4882 * Return the PATH for the Printer-Drivers (ANSI)
4884 * See GetPrinterDriverDirectoryW.
4887 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4890 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4891 DWORD Level, LPBYTE pDriverDirectory,
4892 DWORD cbBuf, LPDWORD pcbNeeded)
4894 UNICODE_STRING nameW, environmentW;
4897 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4898 WCHAR *driverDirectoryW = NULL;
4900 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4901 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4903 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4905 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4906 else nameW.Buffer = NULL;
4907 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4908 else environmentW.Buffer = NULL;
4910 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4911 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4914 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4915 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4917 *pcbNeeded = needed;
4918 ret = (needed <= cbBuf) ? TRUE : FALSE;
4920 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4922 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4924 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4925 RtlFreeUnicodeString(&environmentW);
4926 RtlFreeUnicodeString(&nameW);
4931 /*****************************************************************************
4932 * AddPrinterDriverA [WINSPOOL.@]
4934 * See AddPrinterDriverW.
4937 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4939 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4940 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4943 /******************************************************************************
4944 * AddPrinterDriverW (WINSPOOL.@)
4946 * Install a Printer Driver
4949 * pName [I] Servername or NULL (local Computer)
4950 * level [I] Level for the supplied DRIVER_INFO_*W struct
4951 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4958 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4960 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4961 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4964 /*****************************************************************************
4965 * AddPrintProcessorA [WINSPOOL.@]
4967 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4968 LPSTR pPrintProcessorName)
4970 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4971 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4975 /*****************************************************************************
4976 * AddPrintProcessorW [WINSPOOL.@]
4978 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4979 LPWSTR pPrintProcessorName)
4981 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4982 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4986 /*****************************************************************************
4987 * AddPrintProvidorA [WINSPOOL.@]
4989 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4991 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4995 /*****************************************************************************
4996 * AddPrintProvidorW [WINSPOOL.@]
4998 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5000 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5004 /*****************************************************************************
5005 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5007 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5008 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5010 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5011 pDevModeOutput, pDevModeInput);
5015 /*****************************************************************************
5016 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5018 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5019 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5021 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5022 pDevModeOutput, pDevModeInput);
5026 /*****************************************************************************
5027 * PrinterProperties [WINSPOOL.@]
5029 * Displays a dialog to set the properties of the printer.
5032 * nonzero on success or zero on failure
5035 * implemented as stub only
5037 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5038 HANDLE hPrinter /* [in] handle to printer object */
5040 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5041 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5045 /*****************************************************************************
5046 * EnumJobsA [WINSPOOL.@]
5049 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5050 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5053 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5054 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5056 if(pcbNeeded) *pcbNeeded = 0;
5057 if(pcReturned) *pcReturned = 0;
5062 /*****************************************************************************
5063 * EnumJobsW [WINSPOOL.@]
5066 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5067 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5070 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5071 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5073 if(pcbNeeded) *pcbNeeded = 0;
5074 if(pcReturned) *pcReturned = 0;
5078 /*****************************************************************************
5079 * WINSPOOL_EnumPrinterDrivers [internal]
5081 * Delivers information about all printer drivers installed on the
5082 * localhost or a given server
5085 * nonzero on success or zero on failure. If the buffer for the returned
5086 * information is too small the function will return an error
5089 * - only implemented for localhost, foreign hosts will return an error
5091 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5092 DWORD Level, LPBYTE pDriverInfo,
5093 DWORD cbBuf, LPDWORD pcbNeeded,
5094 LPDWORD pcReturned, BOOL unicode)
5097 DWORD i, needed, number = 0, size = 0;
5098 WCHAR DriverNameW[255];
5100 const printenv_t * env;
5102 TRACE("%s,%s,%d,%p,%d,%d\n",
5103 debugstr_w(pName), debugstr_w(pEnvironment),
5104 Level, pDriverInfo, cbBuf, unicode);
5106 /* check for local drivers */
5107 if((pName) && (pName[0])) {
5108 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5109 SetLastError(ERROR_ACCESS_DENIED);
5113 env = validate_envW(pEnvironment);
5114 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5116 /* check input parameter */
5117 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5118 SetLastError(ERROR_INVALID_LEVEL);
5122 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5123 SetLastError(RPC_X_NULL_REF_POINTER);
5127 /* initialize return values */
5129 memset( pDriverInfo, 0, cbBuf);
5133 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5135 ERR("Can't open Drivers key\n");
5139 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5140 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5141 RegCloseKey(hkeyDrivers);
5142 ERR("Can't query Drivers key\n");
5145 TRACE("Found %d Drivers\n", number);
5147 /* get size of single struct
5148 * unicode and ascii structure have the same size
5150 size = di_sizeof[Level];
5152 /* calculate required buffer size */
5153 *pcbNeeded = size * number;
5155 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5157 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5158 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5160 ERR("Can't enum key number %d\n", i);
5161 RegCloseKey(hkeyDrivers);
5164 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5166 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5167 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5168 &needed, unicode)) {
5169 RegCloseKey(hkeyDrivers);
5172 (*pcbNeeded) += needed;
5175 RegCloseKey(hkeyDrivers);
5177 if(cbBuf < *pcbNeeded){
5178 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5182 *pcReturned = number;
5186 /*****************************************************************************
5187 * EnumPrinterDriversW [WINSPOOL.@]
5189 * see function EnumPrinterDrivers for RETURNS, BUGS
5191 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5192 LPBYTE pDriverInfo, DWORD cbBuf,
5193 LPDWORD pcbNeeded, LPDWORD pcReturned)
5195 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5196 cbBuf, pcbNeeded, pcReturned, TRUE);
5199 /*****************************************************************************
5200 * EnumPrinterDriversA [WINSPOOL.@]
5202 * see function EnumPrinterDrivers for RETURNS, BUGS
5204 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5205 LPBYTE pDriverInfo, DWORD cbBuf,
5206 LPDWORD pcbNeeded, LPDWORD pcReturned)
5208 UNICODE_STRING pNameW, pEnvironmentW;
5209 PWSTR pwstrNameW, pwstrEnvironmentW;
5211 pwstrNameW = asciitounicode(&pNameW, pName);
5212 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5214 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5215 Level, pDriverInfo, cbBuf, pcbNeeded,
5217 RtlFreeUnicodeString(&pNameW);
5218 RtlFreeUnicodeString(&pEnvironmentW);
5223 /******************************************************************************
5224 * EnumPortsA (WINSPOOL.@)
5229 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5230 LPDWORD pcbNeeded, LPDWORD pcReturned)
5233 LPBYTE bufferW = NULL;
5234 LPWSTR nameW = NULL;
5236 DWORD numentries = 0;
5239 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5240 cbBuf, pcbNeeded, pcReturned);
5242 /* convert servername to unicode */
5244 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5245 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5246 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5248 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5249 needed = cbBuf * sizeof(WCHAR);
5250 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5251 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5253 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5254 if (pcbNeeded) needed = *pcbNeeded;
5255 /* HeapReAlloc return NULL, when bufferW was NULL */
5256 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5257 HeapAlloc(GetProcessHeap(), 0, needed);
5259 /* Try again with the large Buffer */
5260 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5262 needed = pcbNeeded ? *pcbNeeded : 0;
5263 numentries = pcReturned ? *pcReturned : 0;
5266 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5267 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5270 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5271 DWORD entrysize = 0;
5274 LPPORT_INFO_2W pi2w;
5275 LPPORT_INFO_2A pi2a;
5278 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5280 /* First pass: calculate the size for all Entries */
5281 pi2w = (LPPORT_INFO_2W) bufferW;
5282 pi2a = (LPPORT_INFO_2A) pPorts;
5284 while (index < numentries) {
5286 needed += entrysize; /* PORT_INFO_?A */
5287 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5289 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5290 NULL, 0, NULL, NULL);
5292 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5293 NULL, 0, NULL, NULL);
5294 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5295 NULL, 0, NULL, NULL);
5297 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5298 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5299 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5302 /* check for errors and quit on failure */
5303 if (cbBuf < needed) {
5304 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5308 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5309 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5310 cbBuf -= len ; /* free Bytes in the user-Buffer */
5311 pi2w = (LPPORT_INFO_2W) bufferW;
5312 pi2a = (LPPORT_INFO_2A) pPorts;
5314 /* Second Pass: Fill the User Buffer (if we have one) */
5315 while ((index < numentries) && pPorts) {
5317 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5318 pi2a->pPortName = ptr;
5319 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5320 ptr, cbBuf , NULL, NULL);
5324 pi2a->pMonitorName = ptr;
5325 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5326 ptr, cbBuf, NULL, NULL);
5330 pi2a->pDescription = ptr;
5331 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5332 ptr, cbBuf, NULL, NULL);
5336 pi2a->fPortType = pi2w->fPortType;
5337 pi2a->Reserved = 0; /* documented: "must be zero" */
5340 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5341 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5342 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5347 if (pcbNeeded) *pcbNeeded = needed;
5348 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5350 HeapFree(GetProcessHeap(), 0, nameW);
5351 HeapFree(GetProcessHeap(), 0, bufferW);
5353 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5354 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5360 /******************************************************************************
5361 * EnumPortsW (WINSPOOL.@)
5363 * Enumerate available Ports
5366 * pName [I] Servername or NULL (local Computer)
5367 * Level [I] Structure-Level (1 or 2)
5368 * pPorts [O] PTR to Buffer that receives the Result
5369 * cbBuf [I] Size of Buffer at pPorts
5370 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5371 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5375 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5378 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5381 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5382 cbBuf, pcbNeeded, pcReturned);
5384 if ((backend == NULL) && !load_backend()) return FALSE;
5386 /* Level is not checked in win9x */
5387 if (!Level || (Level > 2)) {
5388 WARN("level (%d) is ignored in win9x\n", Level);
5389 SetLastError(ERROR_INVALID_LEVEL);
5392 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5393 SetLastError(RPC_X_NULL_REF_POINTER);
5397 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5400 /******************************************************************************
5401 * GetDefaultPrinterW (WINSPOOL.@)
5404 * This function must read the value from data 'device' of key
5405 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5407 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5411 WCHAR *buffer, *ptr;
5415 SetLastError(ERROR_INVALID_PARAMETER);
5419 /* make the buffer big enough for the stuff from the profile/registry,
5420 * the content must fit into the local buffer to compute the correct
5421 * size even if the extern buffer is too small or not given.
5422 * (20 for ,driver,port) */
5424 len = max(100, (insize + 20));
5425 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5427 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5429 SetLastError (ERROR_FILE_NOT_FOUND);
5433 TRACE("%s\n", debugstr_w(buffer));
5435 if ((ptr = strchrW(buffer, ',')) == NULL)
5437 SetLastError(ERROR_INVALID_NAME);
5443 *namesize = strlenW(buffer) + 1;
5444 if(!name || (*namesize > insize))
5446 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5450 strcpyW(name, buffer);
5453 HeapFree( GetProcessHeap(), 0, buffer);
5458 /******************************************************************************
5459 * GetDefaultPrinterA (WINSPOOL.@)
5461 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5465 WCHAR *bufferW = NULL;
5469 SetLastError(ERROR_INVALID_PARAMETER);
5473 if(name && *namesize) {
5475 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5478 if(!GetDefaultPrinterW( bufferW, namesize)) {
5483 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5487 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5490 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5493 HeapFree( GetProcessHeap(), 0, bufferW);
5498 /******************************************************************************
5499 * SetDefaultPrinterW (WINSPOOL.204)
5501 * Set the Name of the Default Printer
5504 * pszPrinter [I] Name of the Printer or NULL
5511 * When the Parameter is NULL or points to an Empty String and
5512 * a Default Printer was already present, then this Function changes nothing.
5513 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5514 * the First enumerated local Printer is used.
5517 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5520 TRACE("(%s)\n", debugstr_w(pszPrinter));
5522 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5526 /******************************************************************************
5527 * SetDefaultPrinterA (WINSPOOL.202)
5529 * See SetDefaultPrinterW.
5532 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5535 TRACE("(%s)\n", debugstr_a(pszPrinter));
5537 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5542 /******************************************************************************
5543 * SetPrinterDataExA (WINSPOOL.@)
5545 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5546 LPCSTR pValueName, DWORD Type,
5547 LPBYTE pData, DWORD cbData)
5549 HKEY hkeyPrinter, hkeySubkey;
5552 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5553 debugstr_a(pValueName), Type, pData, cbData);
5555 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5559 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5561 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5562 RegCloseKey(hkeyPrinter);
5565 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5566 RegCloseKey(hkeySubkey);
5567 RegCloseKey(hkeyPrinter);
5571 /******************************************************************************
5572 * SetPrinterDataExW (WINSPOOL.@)
5574 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5575 LPCWSTR pValueName, DWORD Type,
5576 LPBYTE pData, DWORD cbData)
5578 HKEY hkeyPrinter, hkeySubkey;
5581 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5582 debugstr_w(pValueName), Type, pData, cbData);
5584 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5588 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5590 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5591 RegCloseKey(hkeyPrinter);
5594 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5595 RegCloseKey(hkeySubkey);
5596 RegCloseKey(hkeyPrinter);
5600 /******************************************************************************
5601 * SetPrinterDataA (WINSPOOL.@)
5603 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5604 LPBYTE pData, DWORD cbData)
5606 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5610 /******************************************************************************
5611 * SetPrinterDataW (WINSPOOL.@)
5613 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5614 LPBYTE pData, DWORD cbData)
5616 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5620 /******************************************************************************
5621 * GetPrinterDataExA (WINSPOOL.@)
5623 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5624 LPCSTR pValueName, LPDWORD pType,
5625 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5627 HKEY hkeyPrinter, hkeySubkey;
5630 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5631 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5634 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5638 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5640 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5641 RegCloseKey(hkeyPrinter);
5645 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5646 RegCloseKey(hkeySubkey);
5647 RegCloseKey(hkeyPrinter);
5651 /******************************************************************************
5652 * GetPrinterDataExW (WINSPOOL.@)
5654 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5655 LPCWSTR pValueName, LPDWORD pType,
5656 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5658 HKEY hkeyPrinter, hkeySubkey;
5661 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5662 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5665 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5669 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5671 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5672 RegCloseKey(hkeyPrinter);
5676 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5677 RegCloseKey(hkeySubkey);
5678 RegCloseKey(hkeyPrinter);
5682 /******************************************************************************
5683 * GetPrinterDataA (WINSPOOL.@)
5685 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5686 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5688 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5689 pData, nSize, pcbNeeded);
5692 /******************************************************************************
5693 * GetPrinterDataW (WINSPOOL.@)
5695 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5696 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5698 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5699 pData, nSize, pcbNeeded);
5702 /*******************************************************************************
5703 * EnumPrinterDataExW [WINSPOOL.@]
5705 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5706 LPBYTE pEnumValues, DWORD cbEnumValues,
5707 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5709 HKEY hkPrinter, hkSubKey;
5710 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5711 cbValueNameLen, cbMaxValueLen, cbValueLen,
5716 PPRINTER_ENUM_VALUESW ppev;
5718 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5720 if (pKeyName == NULL || *pKeyName == 0)
5721 return ERROR_INVALID_PARAMETER;
5723 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5724 if (ret != ERROR_SUCCESS)
5726 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5731 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5732 if (ret != ERROR_SUCCESS)
5734 r = RegCloseKey (hkPrinter);
5735 if (r != ERROR_SUCCESS)
5736 WARN ("RegCloseKey returned %i\n", r);
5737 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5738 debugstr_w (pKeyName), ret);
5742 ret = RegCloseKey (hkPrinter);
5743 if (ret != ERROR_SUCCESS)
5745 ERR ("RegCloseKey returned %i\n", ret);
5746 r = RegCloseKey (hkSubKey);
5747 if (r != ERROR_SUCCESS)
5748 WARN ("RegCloseKey returned %i\n", r);
5752 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5753 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5754 if (ret != ERROR_SUCCESS)
5756 r = RegCloseKey (hkSubKey);
5757 if (r != ERROR_SUCCESS)
5758 WARN ("RegCloseKey returned %i\n", r);
5759 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5763 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5764 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5766 if (cValues == 0) /* empty key */
5768 r = RegCloseKey (hkSubKey);
5769 if (r != ERROR_SUCCESS)
5770 WARN ("RegCloseKey returned %i\n", r);
5771 *pcbEnumValues = *pnEnumValues = 0;
5772 return ERROR_SUCCESS;
5775 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5777 hHeap = GetProcessHeap ();
5780 ERR ("GetProcessHeap failed\n");
5781 r = RegCloseKey (hkSubKey);
5782 if (r != ERROR_SUCCESS)
5783 WARN ("RegCloseKey returned %i\n", r);
5784 return ERROR_OUTOFMEMORY;
5787 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5788 if (lpValueName == NULL)
5790 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5791 r = RegCloseKey (hkSubKey);
5792 if (r != ERROR_SUCCESS)
5793 WARN ("RegCloseKey returned %i\n", r);
5794 return ERROR_OUTOFMEMORY;
5797 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5798 if (lpValue == NULL)
5800 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5801 if (HeapFree (hHeap, 0, lpValueName) == 0)
5802 WARN ("HeapFree failed with code %i\n", GetLastError ());
5803 r = RegCloseKey (hkSubKey);
5804 if (r != ERROR_SUCCESS)
5805 WARN ("RegCloseKey returned %i\n", r);
5806 return ERROR_OUTOFMEMORY;
5809 TRACE ("pass 1: calculating buffer required for all names and values\n");
5811 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5813 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5815 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5817 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5818 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5819 NULL, NULL, lpValue, &cbValueLen);
5820 if (ret != ERROR_SUCCESS)
5822 if (HeapFree (hHeap, 0, lpValue) == 0)
5823 WARN ("HeapFree failed with code %i\n", GetLastError ());
5824 if (HeapFree (hHeap, 0, lpValueName) == 0)
5825 WARN ("HeapFree failed with code %i\n", GetLastError ());
5826 r = RegCloseKey (hkSubKey);
5827 if (r != ERROR_SUCCESS)
5828 WARN ("RegCloseKey returned %i\n", r);
5829 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5833 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5834 debugstr_w (lpValueName), dwIndex,
5835 cbValueNameLen + 1, cbValueLen);
5837 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5838 cbBufSize += cbValueLen;
5841 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5843 *pcbEnumValues = cbBufSize;
5844 *pnEnumValues = cValues;
5846 if (cbEnumValues < cbBufSize) /* buffer too small */
5848 if (HeapFree (hHeap, 0, lpValue) == 0)
5849 WARN ("HeapFree failed with code %i\n", GetLastError ());
5850 if (HeapFree (hHeap, 0, lpValueName) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5852 r = RegCloseKey (hkSubKey);
5853 if (r != ERROR_SUCCESS)
5854 WARN ("RegCloseKey returned %i\n", r);
5855 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5856 return ERROR_MORE_DATA;
5859 TRACE ("pass 2: copying all names and values to buffer\n");
5861 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5862 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5864 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5866 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5867 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5868 NULL, &dwType, lpValue, &cbValueLen);
5869 if (ret != ERROR_SUCCESS)
5871 if (HeapFree (hHeap, 0, lpValue) == 0)
5872 WARN ("HeapFree failed with code %i\n", GetLastError ());
5873 if (HeapFree (hHeap, 0, lpValueName) == 0)
5874 WARN ("HeapFree failed with code %i\n", GetLastError ());
5875 r = RegCloseKey (hkSubKey);
5876 if (r != ERROR_SUCCESS)
5877 WARN ("RegCloseKey returned %i\n", r);
5878 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5882 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5883 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5884 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5885 pEnumValues += cbValueNameLen;
5887 /* return # of *bytes* (including trailing \0), not # of chars */
5888 ppev[dwIndex].cbValueName = cbValueNameLen;
5890 ppev[dwIndex].dwType = dwType;
5892 memcpy (pEnumValues, lpValue, cbValueLen);
5893 ppev[dwIndex].pData = pEnumValues;
5894 pEnumValues += cbValueLen;
5896 ppev[dwIndex].cbData = cbValueLen;
5898 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5899 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5902 if (HeapFree (hHeap, 0, lpValue) == 0)
5904 ret = GetLastError ();
5905 ERR ("HeapFree failed with code %i\n", ret);
5906 if (HeapFree (hHeap, 0, lpValueName) == 0)
5907 WARN ("HeapFree failed with code %i\n", GetLastError ());
5908 r = RegCloseKey (hkSubKey);
5909 if (r != ERROR_SUCCESS)
5910 WARN ("RegCloseKey returned %i\n", r);
5914 if (HeapFree (hHeap, 0, lpValueName) == 0)
5916 ret = GetLastError ();
5917 ERR ("HeapFree failed with code %i\n", ret);
5918 r = RegCloseKey (hkSubKey);
5919 if (r != ERROR_SUCCESS)
5920 WARN ("RegCloseKey returned %i\n", r);
5924 ret = RegCloseKey (hkSubKey);
5925 if (ret != ERROR_SUCCESS)
5927 ERR ("RegCloseKey returned %i\n", ret);
5931 return ERROR_SUCCESS;
5934 /*******************************************************************************
5935 * EnumPrinterDataExA [WINSPOOL.@]
5937 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5938 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5939 * what Windows 2000 SP1 does.
5942 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5943 LPBYTE pEnumValues, DWORD cbEnumValues,
5944 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5948 DWORD ret, dwIndex, dwBufSize;
5952 TRACE ("%p %s\n", hPrinter, pKeyName);
5954 if (pKeyName == NULL || *pKeyName == 0)
5955 return ERROR_INVALID_PARAMETER;
5957 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5960 ret = GetLastError ();
5961 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5965 hHeap = GetProcessHeap ();
5968 ERR ("GetProcessHeap failed\n");
5969 return ERROR_OUTOFMEMORY;
5972 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5973 if (pKeyNameW == NULL)
5975 ERR ("Failed to allocate %i bytes from process heap\n",
5976 (LONG)(len * sizeof (WCHAR)));
5977 return ERROR_OUTOFMEMORY;
5980 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5982 ret = GetLastError ();
5983 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5984 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5985 WARN ("HeapFree failed with code %i\n", GetLastError ());
5989 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5990 pcbEnumValues, pnEnumValues);
5991 if (ret != ERROR_SUCCESS)
5993 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5994 WARN ("HeapFree failed with code %i\n", GetLastError ());
5995 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5999 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6001 ret = GetLastError ();
6002 ERR ("HeapFree failed with code %i\n", ret);
6006 if (*pnEnumValues == 0) /* empty key */
6007 return ERROR_SUCCESS;
6010 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6012 PPRINTER_ENUM_VALUESW ppev =
6013 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6015 if (dwBufSize < ppev->cbValueName)
6016 dwBufSize = ppev->cbValueName;
6018 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6019 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6020 dwBufSize = ppev->cbData;
6023 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6025 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6026 if (pBuffer == NULL)
6028 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6029 return ERROR_OUTOFMEMORY;
6032 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6034 PPRINTER_ENUM_VALUESW ppev =
6035 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6037 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6038 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6042 ret = GetLastError ();
6043 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6044 if (HeapFree (hHeap, 0, pBuffer) == 0)
6045 WARN ("HeapFree failed with code %i\n", GetLastError ());
6049 memcpy (ppev->pValueName, pBuffer, len);
6051 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6053 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6054 ppev->dwType != REG_MULTI_SZ)
6057 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6058 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6061 ret = GetLastError ();
6062 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6063 if (HeapFree (hHeap, 0, pBuffer) == 0)
6064 WARN ("HeapFree failed with code %i\n", GetLastError ());
6068 memcpy (ppev->pData, pBuffer, len);
6070 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6071 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6074 if (HeapFree (hHeap, 0, pBuffer) == 0)
6076 ret = GetLastError ();
6077 ERR ("HeapFree failed with code %i\n", ret);
6081 return ERROR_SUCCESS;
6084 /******************************************************************************
6085 * AbortPrinter (WINSPOOL.@)
6087 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6089 FIXME("(%p), stub!\n", hPrinter);
6093 /******************************************************************************
6094 * AddPortA (WINSPOOL.@)
6099 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6101 LPWSTR nameW = NULL;
6102 LPWSTR monitorW = NULL;
6106 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6109 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6110 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6111 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6115 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6116 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6117 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6119 res = AddPortW(nameW, hWnd, monitorW);
6120 HeapFree(GetProcessHeap(), 0, nameW);
6121 HeapFree(GetProcessHeap(), 0, monitorW);
6125 /******************************************************************************
6126 * AddPortW (WINSPOOL.@)
6128 * Add a Port for a specific Monitor
6131 * pName [I] Servername or NULL (local Computer)
6132 * hWnd [I] Handle to parent Window for the Dialog-Box
6133 * pMonitorName [I] Name of the Monitor that manage the Port
6140 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6146 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6148 if (pName && pName[0]) {
6149 SetLastError(ERROR_INVALID_PARAMETER);
6153 if (!pMonitorName) {
6154 SetLastError(RPC_X_NULL_REF_POINTER);
6158 /* an empty Monitorname is Invalid */
6159 if (!pMonitorName[0]) {
6160 SetLastError(ERROR_NOT_SUPPORTED);
6164 pm = monitor_load(pMonitorName, NULL);
6165 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6166 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6167 TRACE("got %d with %u\n", res, GetLastError());
6172 pui = monitor_loadui(pm);
6173 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6174 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6175 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6176 TRACE("got %d with %u\n", res, GetLastError());
6181 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6182 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6184 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6185 SetLastError(ERROR_NOT_SUPPORTED);
6188 monitor_unload(pui);
6191 TRACE("returning %d with %u\n", res, GetLastError());
6195 /******************************************************************************
6196 * AddPortExA (WINSPOOL.@)
6201 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6204 PORT_INFO_2A * pi2A;
6205 LPWSTR nameW = NULL;
6206 LPWSTR monitorW = NULL;
6210 pi2A = (PORT_INFO_2A *) pBuffer;
6212 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6213 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6215 if ((level < 1) || (level > 2)) {
6216 SetLastError(ERROR_INVALID_LEVEL);
6221 SetLastError(ERROR_INVALID_PARAMETER);
6226 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6227 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6228 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6232 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6233 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6234 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6237 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6239 if (pi2A->pPortName) {
6240 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6241 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6242 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6246 if (pi2A->pMonitorName) {
6247 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6248 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6249 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6252 if (pi2A->pDescription) {
6253 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6254 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6255 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6257 pi2W.fPortType = pi2A->fPortType;
6258 pi2W.Reserved = pi2A->Reserved;
6261 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6263 HeapFree(GetProcessHeap(), 0, nameW);
6264 HeapFree(GetProcessHeap(), 0, monitorW);
6265 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6266 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6267 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6272 /******************************************************************************
6273 * AddPortExW (WINSPOOL.@)
6275 * Add a Port for a specific Monitor, without presenting a user interface
6278 * pName [I] Servername or NULL (local Computer)
6279 * level [I] Structure-Level (1 or 2) for pBuffer
6280 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6281 * pMonitorName [I] Name of the Monitor that manage the Port
6288 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6294 pi2 = (PORT_INFO_2W *) pBuffer;
6296 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6297 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6298 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6299 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6302 if ((level < 1) || (level > 2)) {
6303 SetLastError(ERROR_INVALID_LEVEL);
6307 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6308 SetLastError(ERROR_INVALID_PARAMETER);
6312 /* load the Monitor */
6313 pm = monitor_load(pMonitorName, NULL);
6315 SetLastError(ERROR_INVALID_PARAMETER);
6319 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6320 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6321 TRACE("got %u with %u\n", res, GetLastError());
6325 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6331 /******************************************************************************
6332 * AddPrinterConnectionA (WINSPOOL.@)
6334 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6336 FIXME("%s\n", debugstr_a(pName));
6340 /******************************************************************************
6341 * AddPrinterConnectionW (WINSPOOL.@)
6343 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6345 FIXME("%s\n", debugstr_w(pName));
6349 /******************************************************************************
6350 * AddPrinterDriverExW (WINSPOOL.@)
6352 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6355 * pName [I] Servername or NULL (local Computer)
6356 * level [I] Level for the supplied DRIVER_INFO_*W struct
6357 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6358 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6365 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6367 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6369 if ((backend == NULL) && !load_backend()) return FALSE;
6371 if (level < 2 || level == 5 || level == 7 || level > 8) {
6372 SetLastError(ERROR_INVALID_LEVEL);
6377 SetLastError(ERROR_INVALID_PARAMETER);
6381 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6384 /******************************************************************************
6385 * AddPrinterDriverExA (WINSPOOL.@)
6387 * See AddPrinterDriverExW.
6390 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6392 DRIVER_INFO_8A *diA;
6394 LPWSTR nameW = NULL;
6399 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6401 diA = (DRIVER_INFO_8A *) pDriverInfo;
6402 ZeroMemory(&diW, sizeof(diW));
6404 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6405 SetLastError(ERROR_INVALID_LEVEL);
6410 SetLastError(ERROR_INVALID_PARAMETER);
6414 /* convert servername to unicode */
6416 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6417 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6418 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6422 diW.cVersion = diA->cVersion;
6425 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6426 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6427 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6430 if (diA->pEnvironment) {
6431 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6432 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6433 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6436 if (diA->pDriverPath) {
6437 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6438 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6439 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6442 if (diA->pDataFile) {
6443 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6444 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6445 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6448 if (diA->pConfigFile) {
6449 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6450 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6451 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6454 if ((Level > 2) && diA->pDependentFiles) {
6455 lenA = multi_sz_lenA(diA->pDependentFiles);
6456 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6457 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6458 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6461 if ((Level > 2) && diA->pMonitorName) {
6462 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6463 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6464 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6467 if ((Level > 3) && diA->pDefaultDataType) {
6468 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6469 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6470 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6473 if ((Level > 3) && diA->pszzPreviousNames) {
6474 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6475 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6476 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6477 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6480 if ((Level > 5) && diA->pszMfgName) {
6481 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6482 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6483 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6486 if ((Level > 5) && diA->pszOEMUrl) {
6487 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6488 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6489 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6492 if ((Level > 5) && diA->pszHardwareID) {
6493 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6494 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6495 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6498 if ((Level > 5) && diA->pszProvider) {
6499 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6500 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6501 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6505 FIXME("level %u is incomplete\n", Level);
6508 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6509 TRACE("got %u with %u\n", res, GetLastError());
6510 HeapFree(GetProcessHeap(), 0, nameW);
6511 HeapFree(GetProcessHeap(), 0, diW.pName);
6512 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6513 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6514 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6515 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6516 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6517 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6518 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6519 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6520 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6521 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6522 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6523 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6525 TRACE("=> %u with %u\n", res, GetLastError());
6529 /******************************************************************************
6530 * ConfigurePortA (WINSPOOL.@)
6532 * See ConfigurePortW.
6535 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6537 LPWSTR nameW = NULL;
6538 LPWSTR portW = NULL;
6542 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6544 /* convert servername to unicode */
6546 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6547 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6548 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6551 /* convert portname to unicode */
6553 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6554 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6555 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6558 res = ConfigurePortW(nameW, hWnd, portW);
6559 HeapFree(GetProcessHeap(), 0, nameW);
6560 HeapFree(GetProcessHeap(), 0, portW);
6564 /******************************************************************************
6565 * ConfigurePortW (WINSPOOL.@)
6567 * Display the Configuration-Dialog for a specific Port
6570 * pName [I] Servername or NULL (local Computer)
6571 * hWnd [I] Handle to parent Window for the Dialog-Box
6572 * pPortName [I] Name of the Port, that should be configured
6579 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6585 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6587 if (pName && pName[0]) {
6588 SetLastError(ERROR_INVALID_PARAMETER);
6593 SetLastError(RPC_X_NULL_REF_POINTER);
6597 /* an empty Portname is Invalid, but can popup a Dialog */
6598 if (!pPortName[0]) {
6599 SetLastError(ERROR_NOT_SUPPORTED);
6603 pm = monitor_load_by_port(pPortName);
6604 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6605 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6606 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6607 TRACE("got %d with %u\n", res, GetLastError());
6611 pui = monitor_loadui(pm);
6612 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6613 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6614 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6615 TRACE("got %d with %u\n", res, GetLastError());
6619 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6620 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6622 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6623 SetLastError(ERROR_NOT_SUPPORTED);
6626 monitor_unload(pui);
6630 TRACE("returning %d with %u\n", res, GetLastError());
6634 /******************************************************************************
6635 * ConnectToPrinterDlg (WINSPOOL.@)
6637 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6639 FIXME("%p %x\n", hWnd, Flags);
6643 /******************************************************************************
6644 * DeletePrinterConnectionA (WINSPOOL.@)
6646 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6648 FIXME("%s\n", debugstr_a(pName));
6652 /******************************************************************************
6653 * DeletePrinterConnectionW (WINSPOOL.@)
6655 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6657 FIXME("%s\n", debugstr_w(pName));
6661 /******************************************************************************
6662 * DeletePrinterDriverExW (WINSPOOL.@)
6664 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6665 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6670 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6671 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6673 if(pName && pName[0])
6675 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6676 SetLastError(ERROR_INVALID_PARAMETER);
6682 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6683 SetLastError(ERROR_INVALID_PARAMETER);
6687 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6691 ERR("Can't open drivers key\n");
6695 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6698 RegCloseKey(hkey_drivers);
6703 /******************************************************************************
6704 * DeletePrinterDriverExA (WINSPOOL.@)
6706 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6707 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6709 UNICODE_STRING NameW, EnvW, DriverW;
6712 asciitounicode(&NameW, pName);
6713 asciitounicode(&EnvW, pEnvironment);
6714 asciitounicode(&DriverW, pDriverName);
6716 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6718 RtlFreeUnicodeString(&DriverW);
6719 RtlFreeUnicodeString(&EnvW);
6720 RtlFreeUnicodeString(&NameW);
6725 /******************************************************************************
6726 * DeletePrinterDataExW (WINSPOOL.@)
6728 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6731 FIXME("%p %s %s\n", hPrinter,
6732 debugstr_w(pKeyName), debugstr_w(pValueName));
6733 return ERROR_INVALID_PARAMETER;
6736 /******************************************************************************
6737 * DeletePrinterDataExA (WINSPOOL.@)
6739 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6742 FIXME("%p %s %s\n", hPrinter,
6743 debugstr_a(pKeyName), debugstr_a(pValueName));
6744 return ERROR_INVALID_PARAMETER;
6747 /******************************************************************************
6748 * DeletePrintProcessorA (WINSPOOL.@)
6750 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6752 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6753 debugstr_a(pPrintProcessorName));
6757 /******************************************************************************
6758 * DeletePrintProcessorW (WINSPOOL.@)
6760 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6762 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6763 debugstr_w(pPrintProcessorName));
6767 /******************************************************************************
6768 * DeletePrintProvidorA (WINSPOOL.@)
6770 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6772 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6773 debugstr_a(pPrintProviderName));
6777 /******************************************************************************
6778 * DeletePrintProvidorW (WINSPOOL.@)
6780 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6782 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6783 debugstr_w(pPrintProviderName));
6787 /******************************************************************************
6788 * EnumFormsA (WINSPOOL.@)
6790 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6791 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6793 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6794 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6798 /******************************************************************************
6799 * EnumFormsW (WINSPOOL.@)
6801 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6802 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6804 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6805 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6809 /*****************************************************************************
6810 * EnumMonitorsA [WINSPOOL.@]
6812 * See EnumMonitorsW.
6815 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6816 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6819 LPBYTE bufferW = NULL;
6820 LPWSTR nameW = NULL;
6822 DWORD numentries = 0;
6825 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6826 cbBuf, pcbNeeded, pcReturned);
6828 /* convert servername to unicode */
6830 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6831 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6832 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6834 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6835 needed = cbBuf * sizeof(WCHAR);
6836 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6837 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6839 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6840 if (pcbNeeded) needed = *pcbNeeded;
6841 /* HeapReAlloc return NULL, when bufferW was NULL */
6842 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6843 HeapAlloc(GetProcessHeap(), 0, needed);
6845 /* Try again with the large Buffer */
6846 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6848 numentries = pcReturned ? *pcReturned : 0;
6851 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6852 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6855 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6856 DWORD entrysize = 0;
6859 LPMONITOR_INFO_2W mi2w;
6860 LPMONITOR_INFO_2A mi2a;
6862 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6863 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6865 /* First pass: calculate the size for all Entries */
6866 mi2w = (LPMONITOR_INFO_2W) bufferW;
6867 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6869 while (index < numentries) {
6871 needed += entrysize; /* MONITOR_INFO_?A */
6872 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6874 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6875 NULL, 0, NULL, NULL);
6877 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6878 NULL, 0, NULL, NULL);
6879 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6880 NULL, 0, NULL, NULL);
6882 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6883 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6884 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6887 /* check for errors and quit on failure */
6888 if (cbBuf < needed) {
6889 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6893 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6894 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6895 cbBuf -= len ; /* free Bytes in the user-Buffer */
6896 mi2w = (LPMONITOR_INFO_2W) bufferW;
6897 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6899 /* Second Pass: Fill the User Buffer (if we have one) */
6900 while ((index < numentries) && pMonitors) {
6902 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6904 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6905 ptr, cbBuf , NULL, NULL);
6909 mi2a->pEnvironment = ptr;
6910 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6911 ptr, cbBuf, NULL, NULL);
6915 mi2a->pDLLName = ptr;
6916 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6917 ptr, cbBuf, NULL, NULL);
6921 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6922 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6923 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6927 if (pcbNeeded) *pcbNeeded = needed;
6928 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6930 HeapFree(GetProcessHeap(), 0, nameW);
6931 HeapFree(GetProcessHeap(), 0, bufferW);
6933 TRACE("returning %d with %d (%d byte for %d entries)\n",
6934 (res), GetLastError(), needed, numentries);
6940 /*****************************************************************************
6941 * EnumMonitorsW [WINSPOOL.@]
6943 * Enumerate available Port-Monitors
6946 * pName [I] Servername or NULL (local Computer)
6947 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6948 * pMonitors [O] PTR to Buffer that receives the Result
6949 * cbBuf [I] Size of Buffer at pMonitors
6950 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6951 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6955 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6958 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6959 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6962 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6963 cbBuf, pcbNeeded, pcReturned);
6965 if ((backend == NULL) && !load_backend()) return FALSE;
6967 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6968 SetLastError(RPC_X_NULL_REF_POINTER);
6972 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6975 /******************************************************************************
6976 * SpoolerInit (WINSPOOL.@)
6978 * Initialize the Spooler
6985 * The function fails on windows, when the spooler service is not running
6988 BOOL WINAPI SpoolerInit(void)
6991 if ((backend == NULL) && !load_backend()) return FALSE;
6995 /******************************************************************************
6996 * XcvDataW (WINSPOOL.@)
6998 * Execute commands in the Printmonitor DLL
7001 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7002 * pszDataName [i] Name of the command to execute
7003 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7004 * cbInputData [i] Size in Bytes of Buffer at pInputData
7005 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7006 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7007 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7008 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7015 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7016 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7018 * Minimal List of commands, that a Printmonitor DLL should support:
7020 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7021 *| "AddPort" : Add a Port
7022 *| "DeletePort": Delete a Port
7024 * Many Printmonitors support additional commands. Examples for localspl.dll:
7025 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7026 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7029 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7030 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7031 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7033 opened_printer_t *printer;
7035 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7036 pInputData, cbInputData, pOutputData,
7037 cbOutputData, pcbOutputNeeded, pdwStatus);
7039 printer = get_opened_printer(hXcv);
7040 if (!printer || (!printer->hXcv)) {
7041 SetLastError(ERROR_INVALID_HANDLE);
7045 if (!pcbOutputNeeded) {
7046 SetLastError(ERROR_INVALID_PARAMETER);
7050 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7051 SetLastError(RPC_X_NULL_REF_POINTER);
7055 *pcbOutputNeeded = 0;
7057 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7058 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7063 /*****************************************************************************
7064 * EnumPrinterDataA [WINSPOOL.@]
7067 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7068 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7069 DWORD cbData, LPDWORD pcbData )
7071 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7072 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7073 return ERROR_NO_MORE_ITEMS;
7076 /*****************************************************************************
7077 * EnumPrinterDataW [WINSPOOL.@]
7080 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7081 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7082 DWORD cbData, LPDWORD pcbData )
7084 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7085 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7086 return ERROR_NO_MORE_ITEMS;
7089 /*****************************************************************************
7090 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7093 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7094 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7095 LPDWORD pcbNeeded, LPDWORD pcReturned)
7097 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7098 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7099 pcbNeeded, pcReturned);
7103 /*****************************************************************************
7104 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7107 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7108 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7109 LPDWORD pcbNeeded, LPDWORD pcReturned)
7111 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7112 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7113 pcbNeeded, pcReturned);
7117 /*****************************************************************************
7118 * EnumPrintProcessorsA [WINSPOOL.@]
7121 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7122 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7124 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7125 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7129 /*****************************************************************************
7130 * EnumPrintProcessorsW [WINSPOOL.@]
7133 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7134 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7136 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7137 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7138 cbBuf, pcbNeeded, pcbReturned);
7142 /*****************************************************************************
7143 * ExtDeviceMode [WINSPOOL.@]
7146 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7147 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7150 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7151 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7152 debugstr_a(pProfile), fMode);
7156 /*****************************************************************************
7157 * FindClosePrinterChangeNotification [WINSPOOL.@]
7160 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7162 FIXME("Stub: %p\n", hChange);
7166 /*****************************************************************************
7167 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7170 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7171 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7173 FIXME("Stub: %p %x %x %p\n",
7174 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7175 return INVALID_HANDLE_VALUE;
7178 /*****************************************************************************
7179 * FindNextPrinterChangeNotification [WINSPOOL.@]
7182 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7183 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7185 FIXME("Stub: %p %p %p %p\n",
7186 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7190 /*****************************************************************************
7191 * FreePrinterNotifyInfo [WINSPOOL.@]
7194 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7196 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7200 /*****************************************************************************
7203 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7204 * ansi depending on the unicode parameter.
7206 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7216 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7219 memcpy(ptr, str, *size);
7226 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7229 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7236 /*****************************************************************************
7239 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7240 LPDWORD pcbNeeded, BOOL unicode)
7242 DWORD size, left = cbBuf;
7243 BOOL space = (cbBuf > 0);
7250 ji1->JobId = job->job_id;
7253 string_to_buf(job->document_title, ptr, left, &size, unicode);
7254 if(space && size <= left)
7256 ji1->pDocument = (LPWSTR)ptr;
7267 /*****************************************************************************
7270 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7271 LPDWORD pcbNeeded, BOOL unicode)
7273 DWORD size, left = cbBuf;
7274 BOOL space = (cbBuf > 0);
7281 ji2->JobId = job->job_id;
7284 string_to_buf(job->document_title, ptr, left, &size, unicode);
7285 if(space && size <= left)
7287 ji2->pDocument = (LPWSTR)ptr;
7298 /*****************************************************************************
7301 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7302 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7305 DWORD needed = 0, size;
7309 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7311 EnterCriticalSection(&printer_handles_cs);
7312 job = get_job(hPrinter, JobId);
7319 size = sizeof(JOB_INFO_1W);
7324 memset(pJob, 0, size);
7328 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7333 size = sizeof(JOB_INFO_2W);
7338 memset(pJob, 0, size);
7342 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7347 size = sizeof(JOB_INFO_3);
7351 memset(pJob, 0, size);
7360 SetLastError(ERROR_INVALID_LEVEL);
7364 *pcbNeeded = needed;
7366 LeaveCriticalSection(&printer_handles_cs);
7370 /*****************************************************************************
7371 * GetJobA [WINSPOOL.@]
7374 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7375 DWORD cbBuf, LPDWORD pcbNeeded)
7377 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7380 /*****************************************************************************
7381 * GetJobW [WINSPOOL.@]
7384 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7385 DWORD cbBuf, LPDWORD pcbNeeded)
7387 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7390 /*****************************************************************************
7393 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7395 char *unixname, *queue, *cmd;
7396 char fmt[] = "lpr -P%s %s";
7400 if(!(unixname = wine_get_unix_file_name(filename)))
7403 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7404 queue = HeapAlloc(GetProcessHeap(), 0, len);
7405 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7407 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7408 sprintf(cmd, fmt, queue, unixname);
7410 TRACE("printing with: %s\n", cmd);
7413 HeapFree(GetProcessHeap(), 0, cmd);
7414 HeapFree(GetProcessHeap(), 0, queue);
7415 HeapFree(GetProcessHeap(), 0, unixname);
7419 /*****************************************************************************
7422 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7424 #ifdef SONAME_LIBCUPS
7427 char *unixname, *queue, *unix_doc_title;
7431 if(!(unixname = wine_get_unix_file_name(filename)))
7434 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7435 queue = HeapAlloc(GetProcessHeap(), 0, len);
7436 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7438 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7439 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7440 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7442 TRACE("printing via cups\n");
7443 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7444 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7445 HeapFree(GetProcessHeap(), 0, queue);
7446 HeapFree(GetProcessHeap(), 0, unixname);
7452 return schedule_lpr(printer_name, filename);
7456 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7463 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7467 if(HIWORD(wparam) == BN_CLICKED)
7469 if(LOWORD(wparam) == IDOK)
7472 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7475 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7476 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7478 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7480 WCHAR caption[200], message[200];
7483 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7484 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7485 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7486 if(mb_ret == IDCANCEL)
7488 HeapFree(GetProcessHeap(), 0, filename);
7492 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7493 if(hf == INVALID_HANDLE_VALUE)
7495 WCHAR caption[200], message[200];
7497 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7498 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7499 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7500 HeapFree(GetProcessHeap(), 0, filename);
7504 DeleteFileW(filename);
7505 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7507 EndDialog(hwnd, IDOK);
7510 if(LOWORD(wparam) == IDCANCEL)
7512 EndDialog(hwnd, IDCANCEL);
7521 /*****************************************************************************
7524 static BOOL get_filename(LPWSTR *filename)
7526 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7527 file_dlg_proc, (LPARAM)filename) == IDOK;
7530 /*****************************************************************************
7533 static BOOL schedule_file(LPCWSTR filename)
7535 LPWSTR output = NULL;
7537 if(get_filename(&output))
7540 TRACE("copy to %s\n", debugstr_w(output));
7541 r = CopyFileW(filename, output, FALSE);
7542 HeapFree(GetProcessHeap(), 0, output);
7548 /*****************************************************************************
7551 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7554 char *unixname, *cmdA;
7556 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7560 if(!(unixname = wine_get_unix_file_name(filename)))
7563 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7564 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7565 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7567 TRACE("printing with: %s\n", cmdA);
7569 if((file_fd = open(unixname, O_RDONLY)) == -1)
7574 ERR("pipe() failed!\n");
7584 /* reset signals that we previously set to SIG_IGN */
7585 signal(SIGPIPE, SIG_DFL);
7586 signal(SIGCHLD, SIG_DFL);
7588 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7592 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7593 write(fds[1], buf, no_read);
7598 if(file_fd != -1) close(file_fd);
7599 if(fds[0] != -1) close(fds[0]);
7600 if(fds[1] != -1) close(fds[1]);
7602 HeapFree(GetProcessHeap(), 0, cmdA);
7603 HeapFree(GetProcessHeap(), 0, unixname);
7610 /*****************************************************************************
7613 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7615 int in_fd, out_fd, no_read;
7618 char *unixname, *outputA;
7621 if(!(unixname = wine_get_unix_file_name(filename)))
7624 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7625 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7626 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7628 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7629 in_fd = open(unixname, O_RDONLY);
7630 if(out_fd == -1 || in_fd == -1)
7633 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7634 write(out_fd, buf, no_read);
7638 if(in_fd != -1) close(in_fd);
7639 if(out_fd != -1) close(out_fd);
7640 HeapFree(GetProcessHeap(), 0, outputA);
7641 HeapFree(GetProcessHeap(), 0, unixname);
7645 /*****************************************************************************
7646 * ScheduleJob [WINSPOOL.@]
7649 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7651 opened_printer_t *printer;
7653 struct list *cursor, *cursor2;
7655 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7656 EnterCriticalSection(&printer_handles_cs);
7657 printer = get_opened_printer(hPrinter);
7661 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7663 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7666 if(job->job_id != dwJobID) continue;
7668 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7669 if(hf != INVALID_HANDLE_VALUE)
7671 PRINTER_INFO_5W *pi5;
7675 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7676 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7678 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7679 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7680 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7681 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7682 debugstr_w(pi5->pPortName));
7686 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7687 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7689 DWORD type, count = sizeof(output);
7690 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7693 if(output[0] == '|')
7695 ret = schedule_pipe(output + 1, job->filename);
7699 ret = schedule_unixfile(output, job->filename);
7701 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7703 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7705 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7707 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7709 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7711 ret = schedule_file(job->filename);
7715 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7717 HeapFree(GetProcessHeap(), 0, pi5);
7719 DeleteFileW(job->filename);
7721 list_remove(cursor);
7722 HeapFree(GetProcessHeap(), 0, job->document_title);
7723 HeapFree(GetProcessHeap(), 0, job->filename);
7724 HeapFree(GetProcessHeap(), 0, job);
7728 LeaveCriticalSection(&printer_handles_cs);
7732 /*****************************************************************************
7733 * StartDocDlgA [WINSPOOL.@]
7735 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7737 UNICODE_STRING usBuffer;
7740 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7743 docW.cbSize = sizeof(docW);
7744 if (doc->lpszDocName)
7746 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7747 if (!(docW.lpszDocName = docnameW)) return NULL;
7749 if (doc->lpszOutput)
7751 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7752 if (!(docW.lpszOutput = outputW)) return NULL;
7754 if (doc->lpszDatatype)
7756 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7757 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7759 docW.fwType = doc->fwType;
7761 retW = StartDocDlgW(hPrinter, &docW);
7765 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7766 ret = HeapAlloc(GetProcessHeap(), 0, len);
7767 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7768 HeapFree(GetProcessHeap(), 0, retW);
7771 HeapFree(GetProcessHeap(), 0, datatypeW);
7772 HeapFree(GetProcessHeap(), 0, outputW);
7773 HeapFree(GetProcessHeap(), 0, docnameW);
7778 /*****************************************************************************
7779 * StartDocDlgW [WINSPOOL.@]
7781 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7782 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7783 * port is "FILE:". Also returns the full path if passed a relative path.
7785 * The caller should free the returned string from the process heap.
7787 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7792 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7794 PRINTER_INFO_5W *pi5;
7795 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7796 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7798 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7799 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7800 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7802 HeapFree(GetProcessHeap(), 0, pi5);
7805 HeapFree(GetProcessHeap(), 0, pi5);
7808 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7812 if (get_filename(&name))
7814 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7816 HeapFree(GetProcessHeap(), 0, name);
7819 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7820 GetFullPathNameW(name, len, ret, NULL);
7821 HeapFree(GetProcessHeap(), 0, name);
7826 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7829 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7830 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7832 attr = GetFileAttributesW(ret);
7833 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7835 HeapFree(GetProcessHeap(), 0, ret);