4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2008 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
122 WCHAR *document_title;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
191 'M','i','c','r','o','s','o','f','t','\\',
192 'W','i','n','d','o','w','s',' ','N','T','\\',
193 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
194 'P','r','i','n','t','e','r','P','o','r','t','s',0};
196 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
197 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
198 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
200 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
201 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
202 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
203 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
204 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
206 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
207 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
209 static const WCHAR backslashW[] = {'\\',0};
210 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
211 'i','o','n',' ','F','i','l','e',0};
212 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
213 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
214 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
215 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
216 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
217 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
218 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
219 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
220 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
221 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
222 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
223 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
224 static const WCHAR NameW[] = {'N','a','m','e',0};
225 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
226 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
227 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
228 static const WCHAR PortW[] = {'P','o','r','t',0};
229 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
230 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
231 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
232 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
233 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
234 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
235 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW[] = {0};
244 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
245 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
247 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
249 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
250 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
251 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
253 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
254 'D','o','c','u','m','e','n','t',0};
256 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
257 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
258 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
259 0, sizeof(DRIVER_INFO_8W)};
262 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
263 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
264 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
265 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
266 sizeof(PRINTER_INFO_9W)};
268 /******************************************************************
269 * validate the user-supplied printing-environment [internal]
272 * env [I] PTR to Environment-String or NULL
276 * Success: PTR to printenv_t
279 * An empty string is handled the same way as NULL.
280 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
284 static const printenv_t * validate_envW(LPCWSTR env)
286 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
287 3, Version3_RegPathW, Version3_SubdirW};
288 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
289 0, Version0_RegPathW, Version0_SubdirW};
291 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
293 const printenv_t *result = NULL;
296 TRACE("testing %s\n", debugstr_w(env));
299 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
301 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
303 result = all_printenv[i];
308 if (result == NULL) {
309 FIXME("unsupported Environment: %s\n", debugstr_w(env));
310 SetLastError(ERROR_INVALID_ENVIRONMENT);
312 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
316 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
318 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
324 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
325 if passed a NULL string. This returns NULLs to the result.
327 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
331 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
332 return usBufferPtr->Buffer;
334 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
338 static LPWSTR strdupW(LPCWSTR p)
344 len = (strlenW(p) + 1) * sizeof(WCHAR);
345 ret = HeapAlloc(GetProcessHeap(), 0, len);
350 static LPSTR strdupWtoA( LPCWSTR str )
355 if (!str) return NULL;
356 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
357 ret = HeapAlloc( GetProcessHeap(), 0, len );
358 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
362 /******************************************************************
363 * Return the number of bytes for an multi_sz string.
364 * The result includes all \0s
365 * (specifically the extra \0, that is needed as multi_sz terminator).
368 static int multi_sz_lenW(const WCHAR *str)
370 const WCHAR *ptr = str;
374 ptr += lstrlenW(ptr) + 1;
377 return (ptr - str + 1) * sizeof(WCHAR);
380 /* ################################ */
382 static int multi_sz_lenA(const char *str)
384 const char *ptr = str;
388 ptr += lstrlenA(ptr) + 1;
391 return ptr - str + 1;
395 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
398 /* If forcing, or no profile string entry for device yet, set the entry
400 * The always change entry if not WINEPS yet is discussable.
403 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
405 !strstr(qbuf,"WINEPS.DRV")
407 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
410 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
411 WriteProfileStringA("windows","device",buf);
412 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
413 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
416 HeapFree(GetProcessHeap(),0,buf);
420 static BOOL add_printer_driver(const char *name)
424 static char driver_9x[] = "wineps16.drv",
425 driver_nt[] = "wineps.drv",
426 env_9x[] = "Windows 4.0",
427 env_nt[] = "Windows NT x86",
428 data_file[] = "generic.ppd",
429 default_data_type[] = "RAW";
431 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
433 di3a.pName = (char *)name;
434 di3a.pEnvironment = env_nt;
435 di3a.pDriverPath = driver_nt;
436 di3a.pDataFile = data_file;
437 di3a.pConfigFile = driver_nt;
438 di3a.pDefaultDataType = default_data_type;
440 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
441 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
444 di3a.pEnvironment = env_9x;
445 di3a.pDriverPath = driver_9x;
446 di3a.pConfigFile = driver_9x;
447 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
448 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
453 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
454 debugstr_a(di3a.pEnvironment), GetLastError());
458 #ifdef SONAME_LIBCUPS
459 static typeof(cupsGetDests) *pcupsGetDests;
460 static typeof(cupsGetPPD) *pcupsGetPPD;
461 static typeof(cupsPrintFile) *pcupsPrintFile;
462 static void *cupshandle;
464 static BOOL CUPS_LoadPrinters(void)
467 BOOL hadprinter = FALSE, haddefault = FALSE;
469 PRINTER_INFO_2A pinfo2a;
471 HKEY hkeyPrinter, hkeyPrinters, hkey;
474 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
476 TRACE("%s\n", loaderror);
479 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
482 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
483 if (!p##x) return FALSE;
486 DYNCUPS(cupsGetDests);
487 DYNCUPS(cupsPrintFile);
490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
492 ERR("Can't create Printers key\n");
496 nrofdests = pcupsGetDests(&dests);
497 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
498 for (i=0;i<nrofdests;i++) {
499 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
500 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
501 sprintf(port,"LPR:%s", dests[i].name);
502 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
503 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
504 sprintf(devline, "WINEPS.DRV,%s", port);
505 WriteProfileStringA("devices", dests[i].name, devline);
506 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
507 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
511 lstrcatA(devline, ",15,45");
512 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
513 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
514 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
518 HeapFree(GetProcessHeap(), 0, devline);
520 TRACE("Printer %d: %s\n", i, dests[i].name);
521 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
522 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
524 TRACE("Printer already exists\n");
525 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
526 RegCloseKey(hkeyPrinter);
528 static CHAR data_type[] = "RAW",
529 print_proc[] = "WinPrint",
530 comment[] = "WINEPS Printer using CUPS",
531 location[] = "<physical location of printer>",
532 params[] = "<parameters?>",
533 share_name[] = "<share name?>",
534 sep_file[] = "<sep file?>";
536 add_printer_driver(dests[i].name);
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = dests[i].name;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = dests[i].name;
543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = location;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
555 HeapFree(GetProcessHeap(),0,port);
558 if (dests[i].is_default) {
559 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
563 if (hadprinter & !haddefault)
564 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
565 RegCloseKey(hkeyPrinters);
571 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
572 PRINTER_INFO_2A pinfo2a;
573 char *e,*s,*name,*prettyname,*devname;
574 BOOL ret = FALSE, set_default = FALSE;
575 char *port = NULL, *devline,*env_default;
576 HKEY hkeyPrinter, hkeyPrinters, hkey;
578 while (isspace(*pent)) pent++;
579 s = strchr(pent,':');
581 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
589 TRACE("name=%s entry=%s\n",name, pent);
591 if(ispunct(*name)) { /* a tc entry, not a real printer */
592 TRACE("skipping tc entry\n");
596 if(strstr(pent,":server")) { /* server only version so skip */
597 TRACE("skipping server entry\n");
601 /* Determine whether this is a postscript printer. */
604 env_default = getenv("PRINTER");
606 /* Get longest name, usually the one at the right for later display. */
607 while((s=strchr(prettyname,'|'))) {
610 while(isspace(*--e)) *e = '\0';
611 TRACE("\t%s\n", debugstr_a(prettyname));
612 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
613 for(prettyname = s+1; isspace(*prettyname); prettyname++)
616 e = prettyname + strlen(prettyname);
617 while(isspace(*--e)) *e = '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname));
619 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
621 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
622 * if it is too long, we use it as comment below. */
623 devname = prettyname;
624 if (strlen(devname)>=CCHDEVICENAME-1)
626 if (strlen(devname)>=CCHDEVICENAME-1) {
631 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
632 sprintf(port,"LPR:%s",name);
634 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
635 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
636 sprintf(devline, "WINEPS.DRV,%s", port);
637 WriteProfileStringA("devices", devname, devline);
638 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
639 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
643 lstrcatA(devline, ",15,45");
644 WriteProfileStringA("PrinterPorts", devname, devline);
645 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
646 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
650 HeapFree(GetProcessHeap(),0,devline);
652 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
654 ERR("Can't create Printers key\n");
658 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
659 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
661 TRACE("Printer already exists\n");
662 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
663 RegCloseKey(hkeyPrinter);
665 static CHAR data_type[] = "RAW",
666 print_proc[] = "WinPrint",
667 comment[] = "WINEPS Printer using LPR",
668 params[] = "<parameters?>",
669 share_name[] = "<share name?>",
670 sep_file[] = "<sep file?>";
672 add_printer_driver(devname);
674 memset(&pinfo2a,0,sizeof(pinfo2a));
675 pinfo2a.pPrinterName = devname;
676 pinfo2a.pDatatype = data_type;
677 pinfo2a.pPrintProcessor = print_proc;
678 pinfo2a.pDriverName = devname;
679 pinfo2a.pComment = comment;
680 pinfo2a.pLocation = prettyname;
681 pinfo2a.pPortName = port;
682 pinfo2a.pParameters = params;
683 pinfo2a.pShareName = share_name;
684 pinfo2a.pSepFile = sep_file;
686 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
687 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
688 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
691 RegCloseKey(hkeyPrinters);
693 if (isfirst || set_default)
694 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
697 HeapFree(GetProcessHeap(), 0, port);
698 HeapFree(GetProcessHeap(), 0, name);
703 PRINTCAP_LoadPrinters(void) {
704 BOOL hadprinter = FALSE;
708 BOOL had_bash = FALSE;
710 f = fopen("/etc/printcap","r");
714 while(fgets(buf,sizeof(buf),f)) {
717 end=strchr(buf,'\n');
721 while(isspace(*start)) start++;
722 if(*start == '#' || *start == '\0')
725 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
726 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
727 HeapFree(GetProcessHeap(),0,pent);
731 if (end && *--end == '\\') {
738 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
741 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
747 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
748 HeapFree(GetProcessHeap(),0,pent);
754 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
757 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
758 (lstrlenW(value) + 1) * sizeof(WCHAR));
760 return ERROR_FILE_NOT_FOUND;
763 /******************************************************************
764 * monitor_unload [internal]
766 * release a printmonitor and unload it from memory, when needed
769 static void monitor_unload(monitor_t * pm)
771 if (pm == NULL) return;
772 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
774 EnterCriticalSection(&monitor_handles_cs);
776 if (pm->refcount) pm->refcount--;
778 if (pm->refcount == 0) {
779 list_remove(&pm->entry);
780 FreeLibrary(pm->hdll);
781 HeapFree(GetProcessHeap(), 0, pm->name);
782 HeapFree(GetProcessHeap(), 0, pm->dllname);
783 HeapFree(GetProcessHeap(), 0, pm);
785 LeaveCriticalSection(&monitor_handles_cs);
788 /******************************************************************
789 * monitor_unloadall [internal]
791 * release all printmonitors and unload them from memory, when needed
794 static void monitor_unloadall(void)
799 EnterCriticalSection(&monitor_handles_cs);
800 /* iterate through the list, with safety against removal */
801 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
805 LeaveCriticalSection(&monitor_handles_cs);
808 /******************************************************************
809 * monitor_load [internal]
811 * load a printmonitor, get the dllname from the registry, when needed
812 * initialize the monitor and dump found function-pointers
814 * On failure, SetLastError() is called and NULL is returned
817 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
819 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
820 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
821 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
822 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
823 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
825 monitor_t * pm = NULL;
827 LPWSTR regroot = NULL;
828 LPWSTR driver = dllname;
830 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
831 /* Is the Monitor already loaded? */
832 EnterCriticalSection(&monitor_handles_cs);
835 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
837 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
845 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
846 if (pm == NULL) goto cleanup;
847 list_add_tail(&monitor_handles, &pm->entry);
851 if (pm->name == NULL) {
852 /* Load the monitor */
853 LPMONITOREX pmonitorEx;
857 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
858 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
862 lstrcpyW(regroot, MonitorsW);
863 lstrcatW(regroot, name);
864 /* Get the Driver from the Registry */
865 if (driver == NULL) {
868 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
869 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
870 &namesize) == ERROR_SUCCESS) {
871 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
872 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
879 pm->name = strdupW(name);
880 pm->dllname = strdupW(driver);
882 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
884 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
889 pm->hdll = LoadLibraryW(driver);
890 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
892 if (pm->hdll == NULL) {
894 SetLastError(ERROR_MOD_NOT_FOUND);
899 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
900 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
901 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
902 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
903 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
906 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
907 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
908 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
909 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
910 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
912 if (pInitializePrintMonitorUI != NULL) {
913 pm->monitorUI = pInitializePrintMonitorUI();
914 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
916 TRACE( "0x%08x: dwMonitorSize (%d)\n",
917 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
922 if (pInitializePrintMonitor && regroot) {
923 pmonitorEx = pInitializePrintMonitor(regroot);
924 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
925 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
928 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
929 pm->monitor = &(pmonitorEx->Monitor);
934 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
938 if (!pm->monitor && regroot) {
939 if (pInitializePrintMonitor2 != NULL) {
940 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
942 if (pInitializeMonitorEx != NULL) {
943 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
945 if (pInitializeMonitor != NULL) {
946 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
949 if (!pm->monitor && !pm->monitorUI) {
951 SetLastError(ERROR_PROC_NOT_FOUND);
956 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
960 LeaveCriticalSection(&monitor_handles_cs);
961 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
962 HeapFree(GetProcessHeap(), 0, regroot);
963 TRACE("=> %p\n", pm);
967 /******************************************************************
968 * monitor_loadall [internal]
970 * Load all registered monitors
973 static DWORD monitor_loadall(void)
976 DWORD registered = 0;
979 WCHAR buffer[MAX_PATH];
982 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
983 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
984 NULL, NULL, NULL, NULL, NULL);
986 TRACE("%d monitors registered\n", registered);
988 EnterCriticalSection(&monitor_handles_cs);
989 while (id < registered) {
991 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
992 pm = monitor_load(buffer, NULL);
996 LeaveCriticalSection(&monitor_handles_cs);
997 RegCloseKey(hmonitors);
999 TRACE("%d monitors loaded\n", loaded);
1003 /******************************************************************
1004 * monitor_loadui [internal]
1006 * load the userinterface-dll for a given portmonitor
1008 * On failure, NULL is returned
1011 static monitor_t * monitor_loadui(monitor_t * pm)
1013 monitor_t * pui = NULL;
1014 LPWSTR buffer[MAX_PATH];
1019 if (pm == NULL) return NULL;
1020 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1022 /* Try the Portmonitor first; works for many monitors */
1023 if (pm->monitorUI) {
1024 EnterCriticalSection(&monitor_handles_cs);
1026 LeaveCriticalSection(&monitor_handles_cs);
1030 /* query the userinterface-dllname from the Portmonitor */
1031 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1032 /* building (",XcvMonitor %s",pm->name) not needed yet */
1033 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1034 TRACE("got %u with %p\n", res, hXcv);
1036 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1037 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1038 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1039 pm->monitor->pfnXcvClosePort(hXcv);
1046 /******************************************************************
1047 * monitor_load_by_port [internal]
1049 * load a printmonitor for a given port
1051 * On failure, NULL is returned
1054 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1059 monitor_t * pm = NULL;
1060 DWORD registered = 0;
1064 TRACE("(%s)\n", debugstr_w(portname));
1066 /* Try the Local Monitor first */
1067 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1068 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1069 /* found the portname */
1071 return monitor_load(LocalPortW, NULL);
1076 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1077 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1078 if (buffer == NULL) return NULL;
1080 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1081 EnterCriticalSection(&monitor_handles_cs);
1082 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1084 while ((pm == NULL) && (id < registered)) {
1086 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1087 TRACE("testing %s\n", debugstr_w(buffer));
1088 len = lstrlenW(buffer);
1089 lstrcatW(buffer, bs_Ports_bsW);
1090 lstrcatW(buffer, portname);
1091 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1093 buffer[len] = '\0'; /* use only the Monitor-Name */
1094 pm = monitor_load(buffer, NULL);
1098 LeaveCriticalSection(&monitor_handles_cs);
1101 HeapFree(GetProcessHeap(), 0, buffer);
1105 /******************************************************************
1106 * enumerate the local Ports from all loaded monitors (internal)
1108 * returns the needed size (in bytes) for pPorts
1109 * and *lpreturned is set to number of entries returned in pPorts
1112 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1116 LPPORT_INFO_2W cache;
1118 LPBYTE pi_buffer = NULL;
1119 DWORD pi_allocated = 0;
1130 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1131 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1133 numentries = *lpreturned; /* this is 0, when we scan the registry */
1134 needed = entrysize * numentries;
1135 ptr = (LPWSTR) &pPorts[needed];
1140 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1142 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1145 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1146 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1147 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1148 HeapFree(GetProcessHeap(), 0, pi_buffer);
1149 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1150 pi_allocated = (pi_buffer) ? pi_needed : 0;
1151 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1153 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1154 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1156 numentries += pi_returned;
1157 needed += pi_needed;
1159 /* fill the output-buffer (pPorts), if we have one */
1160 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1162 while (pi_returned > pi_index) {
1163 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1164 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1165 out->pPortName = ptr;
1166 lstrcpyW(ptr, cache->pPortName);
1167 ptr += (lstrlenW(ptr)+1);
1169 out->pMonitorName = ptr;
1170 lstrcpyW(ptr, cache->pMonitorName);
1171 ptr += (lstrlenW(ptr)+1);
1173 out->pDescription = ptr;
1174 lstrcpyW(ptr, cache->pDescription);
1175 ptr += (lstrlenW(ptr)+1);
1176 out->fPortType = cache->fPortType;
1177 out->Reserved = cache->Reserved;
1185 /* the temporary portinfo-buffer is no longer needed */
1186 HeapFree(GetProcessHeap(), 0, pi_buffer);
1188 *lpreturned = numentries;
1189 TRACE("need %d byte for %d entries\n", needed, numentries);
1193 /******************************************************************
1194 * get_servername_from_name (internal)
1196 * for an external server, a copy of the serverpart from the full name is returned
1199 static LPWSTR get_servername_from_name(LPCWSTR name)
1203 WCHAR buffer[MAX_PATH];
1206 if (name == NULL) return NULL;
1207 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1209 server = strdupW(&name[2]); /* skip over both backslash */
1210 if (server == NULL) return NULL;
1212 /* strip '\' and the printername */
1213 ptr = strchrW(server, '\\');
1214 if (ptr) ptr[0] = '\0';
1216 TRACE("found %s\n", debugstr_w(server));
1218 len = sizeof(buffer)/sizeof(buffer[0]);
1219 if (GetComputerNameW(buffer, &len)) {
1220 if (lstrcmpW(buffer, server) == 0) {
1221 /* The requested Servername is our computername */
1222 HeapFree(GetProcessHeap(), 0, server);
1229 /******************************************************************
1230 * get_basename_from_name (internal)
1232 * skip over the serverpart from the full name
1235 static LPCWSTR get_basename_from_name(LPCWSTR name)
1237 if (name == NULL) return NULL;
1238 if ((name[0] == '\\') && (name[1] == '\\')) {
1239 /* skip over the servername and search for the following '\' */
1240 name = strchrW(&name[2], '\\');
1241 if ((name) && (name[1])) {
1242 /* found a separator ('\') followed by a name:
1243 skip over the separator and return the rest */
1248 /* no basename present (we found only a servername) */
1255 /******************************************************************
1256 * get_opened_printer_entry
1257 * Get the first place empty in the opened printer table
1260 * - pDefault is ignored
1262 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1264 UINT_PTR handle = nb_printer_handles, i;
1265 jobqueue_t *queue = NULL;
1266 opened_printer_t *printer = NULL;
1268 LPCWSTR printername;
1273 servername = get_servername_from_name(name);
1275 FIXME("server %s not supported\n", debugstr_w(servername));
1276 HeapFree(GetProcessHeap(), 0, servername);
1277 SetLastError(ERROR_INVALID_PRINTER_NAME);
1281 printername = get_basename_from_name(name);
1282 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1284 /* an empty printername is invalid */
1285 if (printername && (!printername[0])) {
1286 SetLastError(ERROR_INVALID_PARAMETER);
1290 EnterCriticalSection(&printer_handles_cs);
1292 for (i = 0; i < nb_printer_handles; i++)
1294 if (!printer_handles[i])
1296 if(handle == nb_printer_handles)
1301 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1302 queue = printer_handles[i]->queue;
1306 if (handle >= nb_printer_handles)
1308 opened_printer_t **new_array;
1309 if (printer_handles)
1310 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1311 (nb_printer_handles + 16) * sizeof(*new_array) );
1313 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1314 (nb_printer_handles + 16) * sizeof(*new_array) );
1321 printer_handles = new_array;
1322 nb_printer_handles += 16;
1325 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1332 /* clone the base name. This is NULL for the printserver */
1333 printer->printername = strdupW(printername);
1335 /* clone the full name */
1336 printer->name = strdupW(name);
1337 if (name && (!printer->name)) {
1343 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1344 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1345 /* OpenPrinter(",XcvMonitor " detected */
1346 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1347 printer->pm = monitor_load(&printername[len], NULL);
1348 if (printer->pm == NULL) {
1349 SetLastError(ERROR_UNKNOWN_PORT);
1356 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1357 if (strncmpW( printername, XcvPortW, len) == 0) {
1358 /* OpenPrinter(",XcvPort " detected */
1359 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1360 printer->pm = monitor_load_by_port(&printername[len]);
1361 if (printer->pm == NULL) {
1362 SetLastError(ERROR_UNKNOWN_PORT);
1370 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1371 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1372 pDefault ? pDefault->DesiredAccess : 0,
1375 if (printer->hXcv == NULL) {
1376 SetLastError(ERROR_INVALID_PARAMETER);
1383 /* Does the Printer exist? */
1384 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1385 ERR("Can't create Printers key\n");
1389 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1390 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1391 RegCloseKey(hkeyPrinters);
1392 SetLastError(ERROR_INVALID_PRINTER_NAME);
1396 RegCloseKey(hkeyPrinter);
1397 RegCloseKey(hkeyPrinters);
1402 TRACE("using the local printserver\n");
1406 printer->queue = queue;
1409 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1410 if (!printer->queue) {
1414 list_init(&printer->queue->jobs);
1415 printer->queue->ref = 0;
1417 InterlockedIncrement(&printer->queue->ref);
1419 printer_handles[handle] = printer;
1422 LeaveCriticalSection(&printer_handles_cs);
1423 if (!handle && printer) {
1424 /* Something failed: Free all resources */
1425 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1426 monitor_unload(printer->pm);
1427 HeapFree(GetProcessHeap(), 0, printer->printername);
1428 HeapFree(GetProcessHeap(), 0, printer->name);
1429 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1430 HeapFree(GetProcessHeap(), 0, printer);
1433 return (HANDLE)handle;
1436 /******************************************************************
1437 * get_opened_printer
1438 * Get the pointer to the opened printer referred by the handle
1440 static opened_printer_t *get_opened_printer(HANDLE hprn)
1442 UINT_PTR idx = (UINT_PTR)hprn;
1443 opened_printer_t *ret = NULL;
1445 EnterCriticalSection(&printer_handles_cs);
1447 if ((idx > 0) && (idx <= nb_printer_handles)) {
1448 ret = printer_handles[idx - 1];
1450 LeaveCriticalSection(&printer_handles_cs);
1454 /******************************************************************
1455 * get_opened_printer_name
1456 * Get the pointer to the opened printer name referred by the handle
1458 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1460 opened_printer_t *printer = get_opened_printer(hprn);
1461 if(!printer) return NULL;
1462 return printer->name;
1465 /******************************************************************
1466 * WINSPOOL_GetOpenedPrinterRegKey
1469 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1471 LPCWSTR name = get_opened_printer_name(hPrinter);
1475 if(!name) return ERROR_INVALID_HANDLE;
1477 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1481 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1483 ERR("Can't find opened printer %s in registry\n",
1485 RegCloseKey(hkeyPrinters);
1486 return ERROR_INVALID_PRINTER_NAME; /* ? */
1488 RegCloseKey(hkeyPrinters);
1489 return ERROR_SUCCESS;
1492 void WINSPOOL_LoadSystemPrinters(void)
1494 HKEY hkey, hkeyPrinters;
1496 DWORD needed, num, i;
1497 WCHAR PrinterName[256];
1500 /* This ensures that all printer entries have a valid Name value. If causes
1501 problems later if they don't. If one is found to be missed we create one
1502 and set it equal to the name of the key */
1503 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1504 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1505 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1506 for(i = 0; i < num; i++) {
1507 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1508 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1509 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1510 set_reg_szW(hkey, NameW, PrinterName);
1517 RegCloseKey(hkeyPrinters);
1520 /* We want to avoid calling AddPrinter on printers as much as
1521 possible, because on cups printers this will (eventually) lead
1522 to a call to cupsGetPPD which takes forever, even with non-cups
1523 printers AddPrinter takes a while. So we'll tag all printers that
1524 were automatically added last time around, if they still exist
1525 we'll leave them be otherwise we'll delete them. */
1526 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1528 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1529 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1530 for(i = 0; i < num; i++) {
1531 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1532 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1533 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1535 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1543 HeapFree(GetProcessHeap(), 0, pi);
1547 #ifdef SONAME_LIBCUPS
1548 done = CUPS_LoadPrinters();
1551 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1552 PRINTCAP_LoadPrinters();
1554 /* Now enumerate the list again and delete any printers that are still tagged */
1555 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1557 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1558 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1559 for(i = 0; i < num; i++) {
1560 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1561 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1562 BOOL delete_driver = FALSE;
1563 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1564 DWORD dw, type, size = sizeof(dw);
1565 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1566 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1567 DeletePrinter(hprn);
1568 delete_driver = TRUE;
1574 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1579 HeapFree(GetProcessHeap(), 0, pi);
1586 /******************************************************************
1589 * Get the pointer to the specified job.
1590 * Should hold the printer_handles_cs before calling.
1592 static job_t *get_job(HANDLE hprn, DWORD JobId)
1594 opened_printer_t *printer = get_opened_printer(hprn);
1597 if(!printer) return NULL;
1598 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1600 if(job->job_id == JobId)
1606 /***********************************************************
1609 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1612 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1615 Formname = (dmA->dmSize > off_formname);
1616 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1617 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1618 dmW->dmDeviceName, CCHDEVICENAME);
1620 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1621 dmA->dmSize - CCHDEVICENAME);
1623 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1624 off_formname - CCHDEVICENAME);
1625 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1626 dmW->dmFormName, CCHFORMNAME);
1627 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1628 (off_formname + CCHFORMNAME));
1631 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1632 dmA->dmDriverExtra);
1636 /***********************************************************
1638 * Creates an ansi copy of supplied devmode
1640 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1645 if (!dmW) return NULL;
1646 size = dmW->dmSize - CCHDEVICENAME -
1647 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1649 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1650 if (!dmA) return NULL;
1652 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1653 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1655 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1656 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1657 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1661 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1662 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1663 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1664 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1666 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1670 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1674 /******************************************************************
1675 * convert_printerinfo_W_to_A [internal]
1678 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1679 DWORD level, DWORD outlen, DWORD numentries)
1685 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1687 len = pi_sizeof[level] * numentries;
1688 ptr = (LPSTR) out + len;
1691 /* copy the numbers of all PRINTER_INFO_* first */
1692 memcpy(out, pPrintersW, len);
1694 while (id < numentries) {
1698 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1699 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1701 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1702 if (piW->pDescription) {
1703 piA->pDescription = ptr;
1704 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1705 ptr, outlen, NULL, NULL);
1711 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1712 ptr, outlen, NULL, NULL);
1716 if (piW->pComment) {
1717 piA->pComment = ptr;
1718 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1719 ptr, outlen, NULL, NULL);
1728 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1729 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1732 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1733 if (piW->pServerName) {
1734 piA->pServerName = ptr;
1735 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1736 ptr, outlen, NULL, NULL);
1740 if (piW->pPrinterName) {
1741 piA->pPrinterName = ptr;
1742 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1743 ptr, outlen, NULL, NULL);
1747 if (piW->pShareName) {
1748 piA->pShareName = ptr;
1749 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1750 ptr, outlen, NULL, NULL);
1754 if (piW->pPortName) {
1755 piA->pPortName = ptr;
1756 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1757 ptr, outlen, NULL, NULL);
1761 if (piW->pDriverName) {
1762 piA->pDriverName = ptr;
1763 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1764 ptr, outlen, NULL, NULL);
1768 if (piW->pComment) {
1769 piA->pComment = ptr;
1770 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1771 ptr, outlen, NULL, NULL);
1775 if (piW->pLocation) {
1776 piA->pLocation = ptr;
1777 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1778 ptr, outlen, NULL, NULL);
1783 dmA = DEVMODEdupWtoA(piW->pDevMode);
1785 /* align DEVMODEA to a DWORD boundary */
1786 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1790 piA->pDevMode = (LPDEVMODEA) ptr;
1791 len = dmA->dmSize + dmA->dmDriverExtra;
1792 memcpy(ptr, dmA, len);
1793 HeapFree(GetProcessHeap(), 0, dmA);
1799 if (piW->pSepFile) {
1800 piA->pSepFile = ptr;
1801 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1802 ptr, outlen, NULL, NULL);
1806 if (piW->pPrintProcessor) {
1807 piA->pPrintProcessor = ptr;
1808 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1809 ptr, outlen, NULL, NULL);
1813 if (piW->pDatatype) {
1814 piA->pDatatype = ptr;
1815 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1816 ptr, outlen, NULL, NULL);
1820 if (piW->pParameters) {
1821 piA->pParameters = ptr;
1822 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1823 ptr, outlen, NULL, NULL);
1827 if (piW->pSecurityDescriptor) {
1828 piA->pSecurityDescriptor = NULL;
1829 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1836 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1837 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1839 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1841 if (piW->pPrinterName) {
1842 piA->pPrinterName = ptr;
1843 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1844 ptr, outlen, NULL, NULL);
1848 if (piW->pServerName) {
1849 piA->pServerName = ptr;
1850 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1851 ptr, outlen, NULL, NULL);
1860 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1861 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1863 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1865 if (piW->pPrinterName) {
1866 piA->pPrinterName = ptr;
1867 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1868 ptr, outlen, NULL, NULL);
1872 if (piW->pPortName) {
1873 piA->pPortName = ptr;
1874 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1875 ptr, outlen, NULL, NULL);
1883 FIXME("for level %u\n", level);
1885 pPrintersW += pi_sizeof[level];
1886 out += pi_sizeof[level];
1891 /***********************************************************
1892 * PRINTER_INFO_2AtoW
1893 * Creates a unicode copy of PRINTER_INFO_2A on heap
1895 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1897 LPPRINTER_INFO_2W piW;
1898 UNICODE_STRING usBuffer;
1900 if(!piA) return NULL;
1901 piW = HeapAlloc(heap, 0, sizeof(*piW));
1902 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1904 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1905 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1906 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1907 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1908 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1909 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1910 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1911 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1912 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1913 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1914 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1915 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1919 /***********************************************************
1920 * FREE_PRINTER_INFO_2W
1921 * Free PRINTER_INFO_2W and all strings
1923 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1927 HeapFree(heap,0,piW->pServerName);
1928 HeapFree(heap,0,piW->pPrinterName);
1929 HeapFree(heap,0,piW->pShareName);
1930 HeapFree(heap,0,piW->pPortName);
1931 HeapFree(heap,0,piW->pDriverName);
1932 HeapFree(heap,0,piW->pComment);
1933 HeapFree(heap,0,piW->pLocation);
1934 HeapFree(heap,0,piW->pDevMode);
1935 HeapFree(heap,0,piW->pSepFile);
1936 HeapFree(heap,0,piW->pPrintProcessor);
1937 HeapFree(heap,0,piW->pDatatype);
1938 HeapFree(heap,0,piW->pParameters);
1939 HeapFree(heap,0,piW);
1943 /******************************************************************
1944 * DeviceCapabilities [WINSPOOL.@]
1945 * DeviceCapabilitiesA [WINSPOOL.@]
1948 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1949 LPSTR pOutput, LPDEVMODEA lpdm)
1953 if (!GDI_CallDeviceCapabilities16)
1955 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1957 if (!GDI_CallDeviceCapabilities16) return -1;
1959 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1961 /* If DC_PAPERSIZE map POINT16s to POINTs */
1962 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1963 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1964 POINT *pt = (POINT *)pOutput;
1966 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1967 for(i = 0; i < ret; i++, pt++)
1972 HeapFree( GetProcessHeap(), 0, tmp );
1978 /*****************************************************************************
1979 * DeviceCapabilitiesW [WINSPOOL.@]
1981 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1984 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1985 WORD fwCapability, LPWSTR pOutput,
1986 const DEVMODEW *pDevMode)
1988 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1989 LPSTR pDeviceA = strdupWtoA(pDevice);
1990 LPSTR pPortA = strdupWtoA(pPort);
1993 if(pOutput && (fwCapability == DC_BINNAMES ||
1994 fwCapability == DC_FILEDEPENDENCIES ||
1995 fwCapability == DC_PAPERNAMES)) {
1996 /* These need A -> W translation */
1999 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2003 switch(fwCapability) {
2008 case DC_FILEDEPENDENCIES:
2012 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2013 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2015 for(i = 0; i < ret; i++)
2016 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2017 pOutput + (i * size), size);
2018 HeapFree(GetProcessHeap(), 0, pOutputA);
2020 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2021 (LPSTR)pOutput, dmA);
2023 HeapFree(GetProcessHeap(),0,pPortA);
2024 HeapFree(GetProcessHeap(),0,pDeviceA);
2025 HeapFree(GetProcessHeap(),0,dmA);
2029 /******************************************************************
2030 * DocumentPropertiesA [WINSPOOL.@]
2032 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2034 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2035 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2036 LPDEVMODEA pDevModeInput,DWORD fMode )
2038 LPSTR lpName = pDeviceName;
2039 static CHAR port[] = "LPT1:";
2042 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2043 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2047 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2049 ERR("no name from hPrinter?\n");
2050 SetLastError(ERROR_INVALID_HANDLE);
2053 lpName = strdupWtoA(lpNameW);
2056 if (!GDI_CallExtDeviceMode16)
2058 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2060 if (!GDI_CallExtDeviceMode16) {
2061 ERR("No CallExtDeviceMode16?\n");
2065 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2066 pDevModeInput, NULL, fMode);
2069 HeapFree(GetProcessHeap(),0,lpName);
2074 /*****************************************************************************
2075 * DocumentPropertiesW (WINSPOOL.@)
2077 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2079 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2081 LPDEVMODEW pDevModeOutput,
2082 LPDEVMODEW pDevModeInput, DWORD fMode)
2085 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2086 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2087 LPDEVMODEA pDevModeOutputA = NULL;
2090 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2091 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2093 if(pDevModeOutput) {
2094 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2095 if(ret < 0) return ret;
2096 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2098 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2099 pDevModeInputA, fMode);
2100 if(pDevModeOutput) {
2101 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2102 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2104 if(fMode == 0 && ret > 0)
2105 ret += (CCHDEVICENAME + CCHFORMNAME);
2106 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2107 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2111 /******************************************************************
2112 * OpenPrinterA [WINSPOOL.@]
2117 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2118 LPPRINTER_DEFAULTSA pDefault)
2120 UNICODE_STRING lpPrinterNameW;
2121 UNICODE_STRING usBuffer;
2122 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2123 PWSTR pwstrPrinterNameW;
2126 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2129 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2130 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2131 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2132 pDefaultW = &DefaultW;
2134 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2136 RtlFreeUnicodeString(&usBuffer);
2137 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2139 RtlFreeUnicodeString(&lpPrinterNameW);
2143 /******************************************************************
2144 * OpenPrinterW [WINSPOOL.@]
2146 * Open a Printer / Printserver or a Printer-Object
2149 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2150 * phPrinter [O] The resulting Handle is stored here
2151 * pDefault [I] PTR to Default Printer Settings or NULL
2158 * lpPrinterName is one of:
2159 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2160 *| Printer: "PrinterName"
2161 *| Printer-Object: "PrinterName,Job xxx"
2162 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2163 *| XcvPort: "Servername,XcvPort PortName"
2166 *| Printer-Object not supported
2167 *| pDefaults is ignored
2170 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2173 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2175 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2176 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2180 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2181 SetLastError(ERROR_INVALID_PARAMETER);
2185 /* Get the unique handle of the printer or Printserver */
2186 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2187 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2188 return (*phPrinter != 0);
2191 /******************************************************************
2192 * AddMonitorA [WINSPOOL.@]
2197 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2199 LPWSTR nameW = NULL;
2202 LPMONITOR_INFO_2A mi2a;
2203 MONITOR_INFO_2W mi2w;
2205 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2206 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2207 debugstr_a(mi2a ? mi2a->pName : NULL),
2208 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2209 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2212 SetLastError(ERROR_INVALID_LEVEL);
2216 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2222 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2223 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2224 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2227 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2229 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2230 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2231 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2233 if (mi2a->pEnvironment) {
2234 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2235 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2236 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2238 if (mi2a->pDLLName) {
2239 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2240 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2241 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2244 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2246 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2247 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2248 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2250 HeapFree(GetProcessHeap(), 0, nameW);
2254 /******************************************************************************
2255 * AddMonitorW [WINSPOOL.@]
2257 * Install a Printmonitor
2260 * pName [I] Servername or NULL (local Computer)
2261 * Level [I] Structure-Level (Must be 2)
2262 * pMonitors [I] PTR to MONITOR_INFO_2
2269 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2272 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2274 LPMONITOR_INFO_2W mi2w;
2276 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2277 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2278 debugstr_w(mi2w ? mi2w->pName : NULL),
2279 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2280 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2282 if ((backend == NULL) && !load_backend()) return FALSE;
2285 SetLastError(ERROR_INVALID_LEVEL);
2289 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2294 return backend->fpAddMonitor(pName, Level, pMonitors);
2297 /******************************************************************
2298 * DeletePrinterDriverA [WINSPOOL.@]
2301 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2303 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2306 /******************************************************************
2307 * DeletePrinterDriverW [WINSPOOL.@]
2310 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2312 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2315 /******************************************************************
2316 * DeleteMonitorA [WINSPOOL.@]
2318 * See DeleteMonitorW.
2321 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2323 LPWSTR nameW = NULL;
2324 LPWSTR EnvironmentW = NULL;
2325 LPWSTR MonitorNameW = NULL;
2330 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2331 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2332 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2336 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2337 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2338 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2341 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2342 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2343 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2346 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2348 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2349 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2350 HeapFree(GetProcessHeap(), 0, nameW);
2354 /******************************************************************
2355 * DeleteMonitorW [WINSPOOL.@]
2357 * Delete a specific Printmonitor from a Printing-Environment
2360 * pName [I] Servername or NULL (local Computer)
2361 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2362 * pMonitorName [I] Name of the Monitor, that should be deleted
2369 * pEnvironment is ignored in Windows for the local Computer.
2372 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2375 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2376 debugstr_w(pMonitorName));
2378 if ((backend == NULL) && !load_backend()) return FALSE;
2380 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2384 /******************************************************************
2385 * DeletePortA [WINSPOOL.@]
2390 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2392 LPWSTR nameW = NULL;
2393 LPWSTR portW = NULL;
2397 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2399 /* convert servername to unicode */
2401 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2402 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2403 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2406 /* convert portname to unicode */
2408 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2409 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2410 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2413 res = DeletePortW(nameW, hWnd, portW);
2414 HeapFree(GetProcessHeap(), 0, nameW);
2415 HeapFree(GetProcessHeap(), 0, portW);
2419 /******************************************************************
2420 * DeletePortW [WINSPOOL.@]
2422 * Delete a specific Port
2425 * pName [I] Servername or NULL (local Computer)
2426 * hWnd [I] Handle to parent Window for the Dialog-Box
2427 * pPortName [I] Name of the Port, that should be deleted
2434 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2440 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2442 if (pName && pName[0]) {
2443 SetLastError(ERROR_INVALID_PARAMETER);
2448 SetLastError(RPC_X_NULL_REF_POINTER);
2452 /* an empty Portname is Invalid */
2453 if (!pPortName[0]) {
2454 SetLastError(ERROR_NOT_SUPPORTED);
2458 pm = monitor_load_by_port(pPortName);
2459 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2460 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2461 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2462 TRACE("got %d with %u\n", res, GetLastError());
2466 pui = monitor_loadui(pm);
2467 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2468 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2469 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2470 TRACE("got %d with %u\n", res, GetLastError());
2474 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2475 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2477 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2478 SetLastError(ERROR_NOT_SUPPORTED);
2481 monitor_unload(pui);
2485 TRACE("returning %d with %u\n", res, GetLastError());
2489 /******************************************************************************
2490 * SetPrinterW [WINSPOOL.@]
2492 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2494 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2495 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2499 /******************************************************************************
2500 * WritePrinter [WINSPOOL.@]
2502 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2504 opened_printer_t *printer;
2507 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2509 EnterCriticalSection(&printer_handles_cs);
2510 printer = get_opened_printer(hPrinter);
2513 SetLastError(ERROR_INVALID_HANDLE);
2519 SetLastError(ERROR_SPL_NO_STARTDOC);
2523 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2525 LeaveCriticalSection(&printer_handles_cs);
2529 /*****************************************************************************
2530 * AddFormA [WINSPOOL.@]
2532 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2534 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2538 /*****************************************************************************
2539 * AddFormW [WINSPOOL.@]
2541 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2543 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2547 /*****************************************************************************
2548 * AddJobA [WINSPOOL.@]
2550 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2553 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2557 SetLastError(ERROR_INVALID_LEVEL);
2561 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2564 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2565 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2566 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2567 if(*pcbNeeded > cbBuf) {
2568 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2571 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2572 addjobA->JobId = addjobW->JobId;
2573 addjobA->Path = (char *)(addjobA + 1);
2574 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2580 /*****************************************************************************
2581 * AddJobW [WINSPOOL.@]
2583 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2585 opened_printer_t *printer;
2588 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2589 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2590 WCHAR path[MAX_PATH], filename[MAX_PATH];
2592 ADDJOB_INFO_1W *addjob;
2594 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2596 EnterCriticalSection(&printer_handles_cs);
2598 printer = get_opened_printer(hPrinter);
2601 SetLastError(ERROR_INVALID_HANDLE);
2606 SetLastError(ERROR_INVALID_LEVEL);
2610 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2614 job->job_id = InterlockedIncrement(&next_job_id);
2616 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2617 if(path[len - 1] != '\\')
2619 memcpy(path + len, spool_path, sizeof(spool_path));
2620 sprintfW(filename, fmtW, path, job->job_id);
2622 len = strlenW(filename);
2623 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2624 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2625 job->document_title = strdupW(default_doc_title);
2626 list_add_tail(&printer->queue->jobs, &job->entry);
2628 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2629 if(*pcbNeeded <= cbBuf) {
2630 addjob = (ADDJOB_INFO_1W*)pData;
2631 addjob->JobId = job->job_id;
2632 addjob->Path = (WCHAR *)(addjob + 1);
2633 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2636 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2639 LeaveCriticalSection(&printer_handles_cs);
2643 /*****************************************************************************
2644 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2646 * Return the PATH for the Print-Processors
2648 * See GetPrintProcessorDirectoryW.
2652 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2653 DWORD level, LPBYTE Info,
2654 DWORD cbBuf, LPDWORD pcbNeeded)
2656 LPWSTR serverW = NULL;
2661 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2662 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2666 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2667 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2668 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2672 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2673 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2674 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2677 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2678 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2680 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2683 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2684 cbBuf, NULL, NULL) > 0;
2687 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2688 HeapFree(GetProcessHeap(), 0, envW);
2689 HeapFree(GetProcessHeap(), 0, serverW);
2693 /*****************************************************************************
2694 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2696 * Return the PATH for the Print-Processors
2699 * server [I] Servername (NT only) or NULL (local Computer)
2700 * env [I] Printing-Environment (see below) or NULL (Default)
2701 * level [I] Structure-Level (must be 1)
2702 * Info [O] PTR to Buffer that receives the Result
2703 * cbBuf [I] Size of Buffer at "Info"
2704 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2705 * required for the Buffer at "Info"
2708 * Success: TRUE and in pcbNeeded the Bytes used in Info
2709 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2710 * if cbBuf is too small
2712 * Native Values returned in Info on Success:
2713 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2714 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2715 *| win9x(Windows 4.0): "%winsysdir%"
2717 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2720 * Only NULL or "" is supported for server
2723 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2724 DWORD level, LPBYTE Info,
2725 DWORD cbBuf, LPDWORD pcbNeeded)
2728 const printenv_t * env_t;
2730 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2731 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2733 if(server != NULL && server[0]) {
2734 FIXME("server not supported: %s\n", debugstr_w(server));
2735 SetLastError(ERROR_INVALID_PARAMETER);
2739 env_t = validate_envW(env);
2740 if(!env_t) return FALSE; /* environment invalid or unsupported */
2743 WARN("(Level: %d) is ignored in win9x\n", level);
2744 SetLastError(ERROR_INVALID_LEVEL);
2748 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2749 needed = GetSystemDirectoryW(NULL, 0);
2750 /* add the Size for the Subdirectories */
2751 needed += lstrlenW(spoolprtprocsW);
2752 needed += lstrlenW(env_t->subdir);
2753 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2755 if(pcbNeeded) *pcbNeeded = needed;
2756 TRACE ("required: 0x%x/%d\n", needed, needed);
2757 if (needed > cbBuf) {
2758 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2761 if(pcbNeeded == NULL) {
2762 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2763 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2764 SetLastError(RPC_X_NULL_REF_POINTER);
2768 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2769 SetLastError(RPC_X_NULL_REF_POINTER);
2773 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2774 /* add the Subdirectories */
2775 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2776 lstrcatW((LPWSTR) Info, env_t->subdir);
2777 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2781 /*****************************************************************************
2782 * WINSPOOL_OpenDriverReg [internal]
2784 * opens the registry for the printer drivers depending on the given input
2785 * variable pEnvironment
2788 * the opened hkey on success
2791 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2795 const printenv_t * env;
2798 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2800 if (!pEnvironment || unicode) {
2801 /* pEnvironment was NULL or a Unicode-String: use it direct */
2802 env = validate_envW(pEnvironment);
2806 /* pEnvironment was an ANSI-String: convert to unicode first */
2808 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2809 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2810 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2811 env = validate_envW(buffer);
2812 HeapFree(GetProcessHeap(), 0, buffer);
2814 if (!env) return NULL;
2816 buffer = HeapAlloc( GetProcessHeap(), 0,
2817 (strlenW(DriversW) + strlenW(env->envname) +
2818 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2820 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2821 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2822 HeapFree(GetProcessHeap(), 0, buffer);
2827 /*****************************************************************************
2828 * AddPrinterW [WINSPOOL.@]
2830 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2832 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2836 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2838 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2839 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2840 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2841 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2842 statusW[] = {'S','t','a','t','u','s',0},
2843 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2845 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2848 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2849 SetLastError(ERROR_INVALID_PARAMETER);
2853 ERR("Level = %d, unsupported!\n", Level);
2854 SetLastError(ERROR_INVALID_LEVEL);
2858 SetLastError(ERROR_INVALID_PARAMETER);
2861 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2863 ERR("Can't create Printers key\n");
2866 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2867 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2868 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2869 RegCloseKey(hkeyPrinter);
2870 RegCloseKey(hkeyPrinters);
2873 RegCloseKey(hkeyPrinter);
2875 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2877 ERR("Can't create Drivers key\n");
2878 RegCloseKey(hkeyPrinters);
2881 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2883 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2884 RegCloseKey(hkeyPrinters);
2885 RegCloseKey(hkeyDrivers);
2886 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2889 RegCloseKey(hkeyDriver);
2890 RegCloseKey(hkeyDrivers);
2892 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2893 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2894 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2895 RegCloseKey(hkeyPrinters);
2899 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2901 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2902 SetLastError(ERROR_INVALID_PRINTER_NAME);
2903 RegCloseKey(hkeyPrinters);
2906 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2907 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2908 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2910 /* See if we can load the driver. We may need the devmode structure anyway
2913 * Note that DocumentPropertiesW will briefly try to open the printer we
2914 * just create to find a DEVMODEA struct (it will use the WINEPS default
2915 * one in case it is not there, so we are ok).
2917 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2920 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2921 size = sizeof(DEVMODEW);
2927 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2929 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2931 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2932 HeapFree(GetProcessHeap(),0,dmW);
2937 /* set devmode to printer name */
2938 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2942 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2943 and we support these drivers. NT writes DEVMODEW so somehow
2944 we'll need to distinguish between these when we support NT
2948 dmA = DEVMODEdupWtoA(dmW);
2949 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2950 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2951 HeapFree(GetProcessHeap(), 0, dmA);
2953 HeapFree(GetProcessHeap(), 0, dmW);
2955 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2956 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2957 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2958 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2960 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2961 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2962 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2963 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2964 (LPBYTE)&pi->Priority, sizeof(DWORD));
2965 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2966 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2967 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2968 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2969 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2970 (LPBYTE)&pi->Status, sizeof(DWORD));
2971 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2972 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2974 RegCloseKey(hkeyPrinter);
2975 RegCloseKey(hkeyPrinters);
2976 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2977 ERR("OpenPrinter failing\n");
2983 /*****************************************************************************
2984 * AddPrinterA [WINSPOOL.@]
2986 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2988 UNICODE_STRING pNameW;
2990 PRINTER_INFO_2W *piW;
2991 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2994 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2996 ERR("Level = %d, unsupported!\n", Level);
2997 SetLastError(ERROR_INVALID_LEVEL);
3000 pwstrNameW = asciitounicode(&pNameW,pName);
3001 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3003 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3005 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3006 RtlFreeUnicodeString(&pNameW);
3011 /*****************************************************************************
3012 * ClosePrinter [WINSPOOL.@]
3014 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3016 UINT_PTR i = (UINT_PTR)hPrinter;
3017 opened_printer_t *printer = NULL;
3020 TRACE("(%p)\n", hPrinter);
3022 EnterCriticalSection(&printer_handles_cs);
3024 if ((i > 0) && (i <= nb_printer_handles))
3025 printer = printer_handles[i - 1];
3030 struct list *cursor, *cursor2;
3032 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3033 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3034 printer->hXcv, debugstr_w(printer->name), printer->doc );
3037 EndDocPrinter(hPrinter);
3039 if(InterlockedDecrement(&printer->queue->ref) == 0)
3041 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3043 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3044 ScheduleJob(hPrinter, job->job_id);
3046 HeapFree(GetProcessHeap(), 0, printer->queue);
3048 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3049 monitor_unload(printer->pm);
3050 HeapFree(GetProcessHeap(), 0, printer->printername);
3051 HeapFree(GetProcessHeap(), 0, printer->name);
3052 HeapFree(GetProcessHeap(), 0, printer);
3053 printer_handles[i - 1] = NULL;
3056 LeaveCriticalSection(&printer_handles_cs);
3060 /*****************************************************************************
3061 * DeleteFormA [WINSPOOL.@]
3063 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3065 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3069 /*****************************************************************************
3070 * DeleteFormW [WINSPOOL.@]
3072 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3074 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3078 /*****************************************************************************
3079 * DeletePrinter [WINSPOOL.@]
3081 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3083 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3084 HKEY hkeyPrinters, hkey;
3087 SetLastError(ERROR_INVALID_HANDLE);
3090 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3091 RegDeleteTreeW(hkeyPrinters, lpNameW);
3092 RegCloseKey(hkeyPrinters);
3094 WriteProfileStringW(devicesW, lpNameW, NULL);
3095 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3097 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3098 RegDeleteValueW(hkey, lpNameW);
3102 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3103 RegDeleteValueW(hkey, lpNameW);
3109 /*****************************************************************************
3110 * SetPrinterA [WINSPOOL.@]
3112 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3115 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3119 /*****************************************************************************
3120 * SetJobA [WINSPOOL.@]
3122 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3123 LPBYTE pJob, DWORD Command)
3127 UNICODE_STRING usBuffer;
3129 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3131 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3132 are all ignored by SetJob, so we don't bother copying them */
3140 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3141 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3143 JobW = (LPBYTE)info1W;
3144 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3145 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3146 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3147 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3148 info1W->Status = info1A->Status;
3149 info1W->Priority = info1A->Priority;
3150 info1W->Position = info1A->Position;
3151 info1W->PagesPrinted = info1A->PagesPrinted;
3156 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3157 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3159 JobW = (LPBYTE)info2W;
3160 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3161 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3162 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3163 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3164 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3165 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3166 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3167 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3168 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3169 info2W->Status = info2A->Status;
3170 info2W->Priority = info2A->Priority;
3171 info2W->Position = info2A->Position;
3172 info2W->StartTime = info2A->StartTime;
3173 info2W->UntilTime = info2A->UntilTime;
3174 info2W->PagesPrinted = info2A->PagesPrinted;
3178 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3179 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3182 SetLastError(ERROR_INVALID_LEVEL);
3186 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3192 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3193 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3194 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3195 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3196 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3201 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3202 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3203 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3204 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3205 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3206 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3207 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3208 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3209 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3213 HeapFree(GetProcessHeap(), 0, JobW);
3218 /*****************************************************************************
3219 * SetJobW [WINSPOOL.@]
3221 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3222 LPBYTE pJob, DWORD Command)
3227 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3228 FIXME("Ignoring everything other than document title\n");
3230 EnterCriticalSection(&printer_handles_cs);
3231 job = get_job(hPrinter, JobId);
3241 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3242 HeapFree(GetProcessHeap(), 0, job->document_title);
3243 job->document_title = strdupW(info1->pDocument);
3248 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3249 HeapFree(GetProcessHeap(), 0, job->document_title);
3250 job->document_title = strdupW(info2->pDocument);
3256 SetLastError(ERROR_INVALID_LEVEL);
3261 LeaveCriticalSection(&printer_handles_cs);
3265 /*****************************************************************************
3266 * EndDocPrinter [WINSPOOL.@]
3268 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3270 opened_printer_t *printer;
3272 TRACE("(%p)\n", hPrinter);
3274 EnterCriticalSection(&printer_handles_cs);
3276 printer = get_opened_printer(hPrinter);
3279 SetLastError(ERROR_INVALID_HANDLE);
3285 SetLastError(ERROR_SPL_NO_STARTDOC);
3289 CloseHandle(printer->doc->hf);
3290 ScheduleJob(hPrinter, printer->doc->job_id);
3291 HeapFree(GetProcessHeap(), 0, printer->doc);
3292 printer->doc = NULL;
3295 LeaveCriticalSection(&printer_handles_cs);
3299 /*****************************************************************************
3300 * EndPagePrinter [WINSPOOL.@]
3302 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3304 FIXME("(%p): stub\n", hPrinter);
3308 /*****************************************************************************
3309 * StartDocPrinterA [WINSPOOL.@]
3311 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3313 UNICODE_STRING usBuffer;
3315 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3318 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3319 or one (DOC_INFO_3) extra DWORDs */
3323 doc2W.JobId = doc2->JobId;
3326 doc2W.dwMode = doc2->dwMode;
3329 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3330 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3331 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3335 SetLastError(ERROR_INVALID_LEVEL);
3339 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3341 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3342 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3343 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3348 /*****************************************************************************
3349 * StartDocPrinterW [WINSPOOL.@]
3351 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3353 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3354 opened_printer_t *printer;
3355 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3356 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3357 JOB_INFO_1W job_info;
3358 DWORD needed, ret = 0;
3362 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3363 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3364 debugstr_w(doc->pDatatype));
3366 if(Level < 1 || Level > 3)
3368 SetLastError(ERROR_INVALID_LEVEL);
3372 EnterCriticalSection(&printer_handles_cs);
3373 printer = get_opened_printer(hPrinter);
3376 SetLastError(ERROR_INVALID_HANDLE);
3382 SetLastError(ERROR_INVALID_PRINTER_STATE);
3386 /* Even if we're printing to a file we still add a print job, we'll
3387 just ignore the spool file name */
3389 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3391 ERR("AddJob failed gle %u\n", GetLastError());
3395 if(doc->pOutputFile)
3396 filename = doc->pOutputFile;
3398 filename = addjob->Path;
3400 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3401 if(hf == INVALID_HANDLE_VALUE)
3404 memset(&job_info, 0, sizeof(job_info));
3405 job_info.pDocument = doc->pDocName;
3406 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3408 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3409 printer->doc->hf = hf;
3410 ret = printer->doc->job_id = addjob->JobId;
3412 LeaveCriticalSection(&printer_handles_cs);
3417 /*****************************************************************************
3418 * StartPagePrinter [WINSPOOL.@]
3420 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3422 FIXME("(%p): stub\n", hPrinter);
3426 /*****************************************************************************
3427 * GetFormA [WINSPOOL.@]
3429 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3430 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3432 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3433 Level,pForm,cbBuf,pcbNeeded);
3437 /*****************************************************************************
3438 * GetFormW [WINSPOOL.@]
3440 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3441 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3443 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3444 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3448 /*****************************************************************************
3449 * SetFormA [WINSPOOL.@]
3451 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3454 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3458 /*****************************************************************************
3459 * SetFormW [WINSPOOL.@]
3461 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3464 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3468 /*****************************************************************************
3469 * ReadPrinter [WINSPOOL.@]
3471 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3472 LPDWORD pNoBytesRead)
3474 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3478 /*****************************************************************************
3479 * ResetPrinterA [WINSPOOL.@]
3481 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3483 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3487 /*****************************************************************************
3488 * ResetPrinterW [WINSPOOL.@]
3490 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3492 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3496 /*****************************************************************************
3497 * WINSPOOL_GetDWORDFromReg
3499 * Return DWORD associated with ValueName from hkey.
3501 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3503 DWORD sz = sizeof(DWORD), type, value = 0;
3506 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3508 if(ret != ERROR_SUCCESS) {
3509 WARN("Got ret = %d on name %s\n", ret, ValueName);
3512 if(type != REG_DWORD) {
3513 ERR("Got type %d\n", type);
3520 /*****************************************************************************
3521 * get_filename_from_reg [internal]
3523 * Get ValueName from hkey storing result in out
3524 * when the Value in the registry has only a filename, use driverdir as prefix
3525 * outlen is space left in out
3526 * String is stored either as unicode or ascii
3530 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3531 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3533 WCHAR filename[MAX_PATH];
3537 LPWSTR buffer = filename;
3541 size = sizeof(filename);
3543 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3544 if (ret == ERROR_MORE_DATA) {
3545 TRACE("need dynamic buffer: %u\n", size);
3546 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3548 /* No Memory is bad */
3552 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3555 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3556 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3562 /* do we have a full path ? */
3563 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3564 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3567 /* we must build the full Path */
3569 if ((out) && (outlen > dirlen)) {
3571 lstrcpyW((LPWSTR)out, driverdir);
3575 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3584 /* write the filename */
3586 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3587 if ((out) && (outlen >= size)) {
3588 lstrcpyW((LPWSTR)out, ptr);
3597 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3598 if ((out) && (outlen >= size)) {
3599 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3607 ptr += lstrlenW(ptr)+1;
3608 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3611 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3613 /* write the multisz-termination */
3614 if (type == REG_MULTI_SZ) {
3615 size = (unicode) ? sizeof(WCHAR) : 1;
3618 if (out && (outlen >= size)) {
3619 memset (out, 0, size);
3625 /*****************************************************************************
3626 * WINSPOOL_GetStringFromReg
3628 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3629 * String is stored either as unicode or ascii.
3630 * Bit of a hack here to get the ValueName if we want ascii.
3632 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3633 DWORD buflen, DWORD *needed,
3636 DWORD sz = buflen, type;
3640 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3642 LPSTR ValueNameA = strdupWtoA(ValueName);
3643 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3644 HeapFree(GetProcessHeap(),0,ValueNameA);
3646 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3647 WARN("Got ret = %d\n", ret);
3651 /* add space for terminating '\0' */
3652 sz += unicode ? sizeof(WCHAR) : 1;
3656 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3661 /*****************************************************************************
3662 * WINSPOOL_GetDefaultDevMode
3664 * Get a default DevMode values for wineps.
3668 static void WINSPOOL_GetDefaultDevMode(
3670 DWORD buflen, DWORD *needed,
3674 static const char szwps[] = "wineps.drv";
3676 /* fill default DEVMODE - should be read from ppd... */
3677 ZeroMemory( &dm, sizeof(dm) );
3678 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3679 dm.dmSpecVersion = DM_SPECVERSION;
3680 dm.dmDriverVersion = 1;
3681 dm.dmSize = sizeof(DEVMODEA);
3682 dm.dmDriverExtra = 0;
3684 DM_ORIENTATION | DM_PAPERSIZE |
3685 DM_PAPERLENGTH | DM_PAPERWIDTH |
3688 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3689 DM_YRESOLUTION | DM_TTOPTION;
3691 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3692 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3693 dm.u1.s1.dmPaperLength = 2970;
3694 dm.u1.s1.dmPaperWidth = 2100;
3696 dm.u1.s1.dmScale = 100;
3697 dm.u1.s1.dmCopies = 1;
3698 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3699 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3702 dm.dmYResolution = 300; /* 300dpi */
3703 dm.dmTTOption = DMTT_BITMAP;
3706 /* dm.dmLogPixels */
3707 /* dm.dmBitsPerPel */
3708 /* dm.dmPelsWidth */
3709 /* dm.dmPelsHeight */
3710 /* dm.u2.dmDisplayFlags */
3711 /* dm.dmDisplayFrequency */
3712 /* dm.dmICMMethod */
3713 /* dm.dmICMIntent */
3714 /* dm.dmMediaType */
3715 /* dm.dmDitherType */
3716 /* dm.dmReserved1 */
3717 /* dm.dmReserved2 */
3718 /* dm.dmPanningWidth */
3719 /* dm.dmPanningHeight */
3722 if(buflen >= sizeof(DEVMODEW)) {
3723 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3724 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3725 HeapFree(GetProcessHeap(),0,pdmW);
3727 *needed = sizeof(DEVMODEW);
3731 if(buflen >= sizeof(DEVMODEA)) {
3732 memcpy(ptr, &dm, sizeof(DEVMODEA));
3734 *needed = sizeof(DEVMODEA);
3738 /*****************************************************************************
3739 * WINSPOOL_GetDevModeFromReg
3741 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3742 * DevMode is stored either as unicode or ascii.
3744 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3746 DWORD buflen, DWORD *needed,
3749 DWORD sz = buflen, type;
3752 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3753 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3754 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3755 if (sz < sizeof(DEVMODEA))
3757 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3760 /* ensures that dmSize is not erratically bogus if registry is invalid */
3761 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3762 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3764 sz += (CCHDEVICENAME + CCHFORMNAME);
3766 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3767 memcpy(ptr, dmW, sz);
3768 HeapFree(GetProcessHeap(),0,dmW);
3775 /*********************************************************************
3776 * WINSPOOL_GetPrinter_1
3778 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3779 * The strings are either stored as unicode or ascii.
3781 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3782 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3785 DWORD size, left = cbBuf;
3786 BOOL space = (cbBuf > 0);
3791 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3793 if(space && size <= left) {
3794 pi1->pName = (LPWSTR)ptr;
3802 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3803 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3805 if(space && size <= left) {
3806 pi1->pDescription = (LPWSTR)ptr;
3814 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3816 if(space && size <= left) {
3817 pi1->pComment = (LPWSTR)ptr;
3825 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3827 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3828 memset(pi1, 0, sizeof(*pi1));
3832 /*********************************************************************
3833 * WINSPOOL_GetPrinter_2
3835 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3836 * The strings are either stored as unicode or ascii.
3838 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3839 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3842 DWORD size, left = cbBuf;
3843 BOOL space = (cbBuf > 0);
3848 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3850 if(space && size <= left) {
3851 pi2->pPrinterName = (LPWSTR)ptr;
3858 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3860 if(space && size <= left) {
3861 pi2->pShareName = (LPWSTR)ptr;
3868 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3870 if(space && size <= left) {
3871 pi2->pPortName = (LPWSTR)ptr;
3878 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3880 if(space && size <= left) {
3881 pi2->pDriverName = (LPWSTR)ptr;
3888 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3890 if(space && size <= left) {
3891 pi2->pComment = (LPWSTR)ptr;
3898 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3900 if(space && size <= left) {
3901 pi2->pLocation = (LPWSTR)ptr;
3908 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3910 if(space && size <= left) {
3911 pi2->pDevMode = (LPDEVMODEW)ptr;
3920 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3921 if(space && size <= left) {
3922 pi2->pDevMode = (LPDEVMODEW)ptr;
3929 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3931 if(space && size <= left) {
3932 pi2->pSepFile = (LPWSTR)ptr;
3939 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3941 if(space && size <= left) {
3942 pi2->pPrintProcessor = (LPWSTR)ptr;
3949 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3951 if(space && size <= left) {
3952 pi2->pDatatype = (LPWSTR)ptr;
3959 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3961 if(space && size <= left) {
3962 pi2->pParameters = (LPWSTR)ptr;
3970 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3971 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3972 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3973 "Default Priority");
3974 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3975 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3978 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3979 memset(pi2, 0, sizeof(*pi2));
3984 /*********************************************************************
3985 * WINSPOOL_GetPrinter_4
3987 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3989 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3990 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3993 DWORD size, left = cbBuf;
3994 BOOL space = (cbBuf > 0);
3999 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4001 if(space && size <= left) {
4002 pi4->pPrinterName = (LPWSTR)ptr;
4010 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4013 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4014 memset(pi4, 0, sizeof(*pi4));
4019 /*********************************************************************
4020 * WINSPOOL_GetPrinter_5
4022 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4024 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4025 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4028 DWORD size, left = cbBuf;
4029 BOOL space = (cbBuf > 0);
4034 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4036 if(space && size <= left) {
4037 pi5->pPrinterName = (LPWSTR)ptr;
4044 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4046 if(space && size <= left) {
4047 pi5->pPortName = (LPWSTR)ptr;
4055 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4056 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4058 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4062 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4063 memset(pi5, 0, sizeof(*pi5));
4068 /*********************************************************************
4069 * WINSPOOL_GetPrinter_7
4071 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4073 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4074 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4076 DWORD size, left = cbBuf;
4077 BOOL space = (cbBuf > 0);
4082 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4084 if (space && size <= left) {
4085 pi7->pszObjectGUID = (LPWSTR)ptr;
4093 /* We do not have a Directory Service */
4094 pi7->dwAction = DSPRINT_UNPUBLISH;
4097 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4098 memset(pi7, 0, sizeof(*pi7));
4103 /*********************************************************************
4104 * WINSPOOL_GetPrinter_9
4106 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4107 * The strings are either stored as unicode or ascii.
4109 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4110 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4113 BOOL space = (cbBuf > 0);
4117 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4118 if(space && size <= cbBuf) {
4119 pi9->pDevMode = (LPDEVMODEW)buf;
4126 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4127 if(space && size <= cbBuf) {
4128 pi9->pDevMode = (LPDEVMODEW)buf;
4134 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4135 memset(pi9, 0, sizeof(*pi9));
4140 /*****************************************************************************
4141 * WINSPOOL_GetPrinter
4143 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4144 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4145 * just a collection of pointers to strings.
4147 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4148 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4151 DWORD size, needed = 0;
4153 HKEY hkeyPrinter, hkeyPrinters;
4156 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4158 if (!(name = get_opened_printer_name(hPrinter))) {
4159 SetLastError(ERROR_INVALID_HANDLE);
4163 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4165 ERR("Can't create Printers key\n");
4168 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4170 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4171 RegCloseKey(hkeyPrinters);
4172 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4179 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4181 size = sizeof(PRINTER_INFO_2W);
4183 ptr = pPrinter + size;
4185 memset(pPrinter, 0, size);
4190 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4198 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4200 size = sizeof(PRINTER_INFO_4W);
4202 ptr = pPrinter + size;
4204 memset(pPrinter, 0, size);
4209 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4218 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4220 size = sizeof(PRINTER_INFO_5W);
4222 ptr = pPrinter + size;
4224 memset(pPrinter, 0, size);
4230 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4239 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4241 size = sizeof(PRINTER_INFO_6);
4242 if (size <= cbBuf) {
4243 /* FIXME: We do not update the status yet */
4244 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4256 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4258 size = sizeof(PRINTER_INFO_7W);
4259 if (size <= cbBuf) {
4260 ptr = pPrinter + size;
4262 memset(pPrinter, 0, size);
4268 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4276 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4278 size = sizeof(PRINTER_INFO_9W);
4280 ptr = pPrinter + size;
4282 memset(pPrinter, 0, size);
4288 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4295 FIXME("Unimplemented level %d\n", Level);
4296 SetLastError(ERROR_INVALID_LEVEL);
4297 RegCloseKey(hkeyPrinters);
4298 RegCloseKey(hkeyPrinter);
4302 RegCloseKey(hkeyPrinter);
4303 RegCloseKey(hkeyPrinters);
4305 TRACE("returning %d needed = %d\n", ret, needed);
4306 if(pcbNeeded) *pcbNeeded = needed;
4308 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4312 /*****************************************************************************
4313 * GetPrinterW [WINSPOOL.@]
4315 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4316 DWORD cbBuf, LPDWORD pcbNeeded)
4318 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4322 /*****************************************************************************
4323 * GetPrinterA [WINSPOOL.@]
4325 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4326 DWORD cbBuf, LPDWORD pcbNeeded)
4328 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4332 /*****************************************************************************
4333 * WINSPOOL_EnumPrinters
4335 * Implementation of EnumPrintersA|W
4337 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4338 DWORD dwLevel, LPBYTE lpbPrinters,
4339 DWORD cbBuf, LPDWORD lpdwNeeded,
4340 LPDWORD lpdwReturned, BOOL unicode)
4343 HKEY hkeyPrinters, hkeyPrinter;
4344 WCHAR PrinterName[255];
4345 DWORD needed = 0, number = 0;
4346 DWORD used, i, left;
4350 memset(lpbPrinters, 0, cbBuf);
4356 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4357 if(dwType == PRINTER_ENUM_DEFAULT)
4360 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4361 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4362 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4364 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4372 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4373 FIXME("dwType = %08x\n", dwType);
4374 SetLastError(ERROR_INVALID_FLAGS);
4378 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4380 ERR("Can't create Printers key\n");
4384 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4385 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4386 RegCloseKey(hkeyPrinters);
4387 ERR("Can't query Printers key\n");
4390 TRACE("Found %d printers\n", number);
4394 used = number * sizeof(PRINTER_INFO_1W);
4397 used = number * sizeof(PRINTER_INFO_2W);
4400 used = number * sizeof(PRINTER_INFO_4W);
4403 used = number * sizeof(PRINTER_INFO_5W);
4407 SetLastError(ERROR_INVALID_LEVEL);
4408 RegCloseKey(hkeyPrinters);
4411 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4413 for(i = 0; i < number; i++) {
4414 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4416 ERR("Can't enum key number %d\n", i);
4417 RegCloseKey(hkeyPrinters);
4420 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4421 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4423 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4424 RegCloseKey(hkeyPrinters);
4429 buf = lpbPrinters + used;
4430 left = cbBuf - used;
4438 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4439 left, &needed, unicode);
4441 if(pi) pi += sizeof(PRINTER_INFO_1W);
4444 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4445 left, &needed, unicode);
4447 if(pi) pi += sizeof(PRINTER_INFO_2W);
4450 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4451 left, &needed, unicode);
4453 if(pi) pi += sizeof(PRINTER_INFO_4W);
4456 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4457 left, &needed, unicode);
4459 if(pi) pi += sizeof(PRINTER_INFO_5W);
4462 ERR("Shouldn't be here!\n");
4463 RegCloseKey(hkeyPrinter);
4464 RegCloseKey(hkeyPrinters);
4467 RegCloseKey(hkeyPrinter);
4469 RegCloseKey(hkeyPrinters);
4476 memset(lpbPrinters, 0, cbBuf);
4477 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4481 *lpdwReturned = number;
4482 SetLastError(ERROR_SUCCESS);
4487 /******************************************************************
4488 * EnumPrintersW [WINSPOOL.@]
4490 * Enumerates the available printers, print servers and print
4491 * providers, depending on the specified flags, name and level.
4495 * If level is set to 1:
4496 * Returns an array of PRINTER_INFO_1 data structures in the
4497 * lpbPrinters buffer.
4499 * If level is set to 2:
4500 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4501 * Returns an array of PRINTER_INFO_2 data structures in the
4502 * lpbPrinters buffer. Note that according to MSDN also an
4503 * OpenPrinter should be performed on every remote printer.
4505 * If level is set to 4 (officially WinNT only):
4506 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4507 * Fast: Only the registry is queried to retrieve printer names,
4508 * no connection to the driver is made.
4509 * Returns an array of PRINTER_INFO_4 data structures in the
4510 * lpbPrinters buffer.
4512 * If level is set to 5 (officially WinNT4/Win9x only):
4513 * Fast: Only the registry is queried to retrieve printer names,
4514 * no connection to the driver is made.
4515 * Returns an array of PRINTER_INFO_5 data structures in the
4516 * lpbPrinters buffer.
4518 * If level set to 3 or 6+:
4519 * returns zero (failure!)
4521 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4525 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4526 * - Only levels 2, 4 and 5 are implemented at the moment.
4527 * - 16-bit printer drivers are not enumerated.
4528 * - Returned amount of bytes used/needed does not match the real Windoze
4529 * implementation (as in this implementation, all strings are part
4530 * of the buffer, whereas Win32 keeps them somewhere else)
4531 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4534 * - In a regular Wine installation, no registry settings for printers
4535 * exist, which makes this function return an empty list.
4537 BOOL WINAPI EnumPrintersW(
4538 DWORD dwType, /* [in] Types of print objects to enumerate */
4539 LPWSTR lpszName, /* [in] name of objects to enumerate */
4540 DWORD dwLevel, /* [in] type of printer info structure */
4541 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4542 DWORD cbBuf, /* [in] max size of buffer in bytes */
4543 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4544 LPDWORD lpdwReturned /* [out] number of entries returned */
4547 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4548 lpdwNeeded, lpdwReturned, TRUE);
4551 /******************************************************************
4552 * EnumPrintersA [WINSPOOL.@]
4557 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4558 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4561 UNICODE_STRING pNameU;
4565 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4566 pPrinters, cbBuf, pcbNeeded, pcReturned);
4568 pNameW = asciitounicode(&pNameU, pName);
4570 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4571 MS Office need this */
4572 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4574 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4576 RtlFreeUnicodeString(&pNameU);
4578 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4580 HeapFree(GetProcessHeap(), 0, pPrintersW);
4584 /*****************************************************************************
4585 * WINSPOOL_GetDriverInfoFromReg [internal]
4587 * Enters the information from the registry into the DRIVER_INFO struct
4590 * zero if the printer driver does not exist in the registry
4591 * (only if Level > 1) otherwise nonzero
4593 static BOOL WINSPOOL_GetDriverInfoFromReg(
4596 const printenv_t * env,
4598 LPBYTE ptr, /* DRIVER_INFO */
4599 LPBYTE pDriverStrings, /* strings buffer */
4600 DWORD cbBuf, /* size of string buffer */
4601 LPDWORD pcbNeeded, /* space needed for str. */
4602 BOOL unicode) /* type of strings */
4606 WCHAR driverdir[MAX_PATH];
4608 LPBYTE strPtr = pDriverStrings;
4609 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4611 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4612 debugstr_w(DriverName), env,
4613 Level, di, pDriverStrings, cbBuf, unicode);
4615 if (di) ZeroMemory(di, di_sizeof[Level]);
4618 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4619 if (*pcbNeeded <= cbBuf)
4620 strcpyW((LPWSTR)strPtr, DriverName);
4624 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4625 if (*pcbNeeded <= cbBuf)
4626 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4629 /* pName for level 1 has a different offset! */
4631 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4635 /* .cVersion and .pName for level > 1 */
4637 di->cVersion = env->driverversion;
4638 di->pName = (LPWSTR) strPtr;
4639 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4642 /* Reserve Space for the largest subdir and a Backslash*/
4643 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4644 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4645 /* Should never Fail */
4648 lstrcatW(driverdir, env->versionsubdir);
4649 lstrcatW(driverdir, backslashW);
4651 /* dirlen must not include the terminating zero */
4652 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4653 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4655 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4656 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4657 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4663 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4665 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4668 if (*pcbNeeded <= cbBuf) {
4670 lstrcpyW((LPWSTR)strPtr, env->envname);
4674 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4676 if (di) di->pEnvironment = (LPWSTR)strPtr;
4677 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4680 /* .pDriverPath is the Graphics rendering engine.
4681 The full Path is required to avoid a crash in some apps */
4682 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4684 if (*pcbNeeded <= cbBuf)
4685 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4687 if (di) di->pDriverPath = (LPWSTR)strPtr;
4688 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4691 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4692 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4694 if (*pcbNeeded <= cbBuf)
4695 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4697 if (di) di->pDataFile = (LPWSTR)strPtr;
4698 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4701 /* .pConfigFile is the Driver user Interface */
4702 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4704 if (*pcbNeeded <= cbBuf)
4705 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4707 if (di) di->pConfigFile = (LPWSTR)strPtr;
4708 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4712 RegCloseKey(hkeyDriver);
4713 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4718 RegCloseKey(hkeyDriver);
4719 FIXME("level 5: incomplete\n");
4724 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4726 if (*pcbNeeded <= cbBuf)
4727 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4729 if (di) di->pHelpFile = (LPWSTR)strPtr;
4730 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4733 /* .pDependentFiles */
4734 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4736 if (*pcbNeeded <= cbBuf)
4737 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4739 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4740 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4742 else if (GetVersion() & 0x80000000) {
4743 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4744 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4746 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4748 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4749 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4752 /* .pMonitorName is the optional Language Monitor */
4753 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4755 if (*pcbNeeded <= cbBuf)
4756 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4758 if (di) di->pMonitorName = (LPWSTR)strPtr;
4759 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4762 /* .pDefaultDataType */
4763 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4765 if(*pcbNeeded <= cbBuf)
4766 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4768 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4769 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4773 RegCloseKey(hkeyDriver);
4774 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4778 /* .pszzPreviousNames */
4779 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4781 if(*pcbNeeded <= cbBuf)
4782 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4784 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4785 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4789 RegCloseKey(hkeyDriver);
4790 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4794 /* support is missing, but not important enough for a FIXME */
4795 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4798 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4800 if(*pcbNeeded <= cbBuf)
4801 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4803 if (di) di->pszMfgName = (LPWSTR)strPtr;
4804 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4808 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4810 if(*pcbNeeded <= cbBuf)
4811 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4813 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4814 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4817 /* .pszHardwareID */
4818 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4820 if(*pcbNeeded <= cbBuf)
4821 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4823 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4824 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4828 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4830 if(*pcbNeeded <= cbBuf)
4831 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4833 if (di) di->pszProvider = (LPWSTR)strPtr;
4834 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4838 RegCloseKey(hkeyDriver);
4842 /* support is missing, but not important enough for a FIXME */
4843 TRACE("level 8: incomplete\n");
4845 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4846 RegCloseKey(hkeyDriver);
4850 /*****************************************************************************
4851 * WINSPOOL_GetPrinterDriver
4853 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4854 DWORD Level, LPBYTE pDriverInfo,
4855 DWORD cbBuf, LPDWORD pcbNeeded,
4859 WCHAR DriverName[100];
4860 DWORD ret, type, size, needed = 0;
4862 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4863 const printenv_t * env;
4865 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4866 Level,pDriverInfo,cbBuf, pcbNeeded);
4869 if (!(name = get_opened_printer_name(hPrinter))) {
4870 SetLastError(ERROR_INVALID_HANDLE);
4874 if (Level < 1 || Level == 7 || Level > 8) {
4875 SetLastError(ERROR_INVALID_LEVEL);
4879 env = validate_envW(pEnvironment);
4880 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4882 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4884 ERR("Can't create Printers key\n");
4887 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4889 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4890 RegCloseKey(hkeyPrinters);
4891 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4894 size = sizeof(DriverName);
4896 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4897 (LPBYTE)DriverName, &size);
4898 RegCloseKey(hkeyPrinter);
4899 RegCloseKey(hkeyPrinters);
4900 if(ret != ERROR_SUCCESS) {
4901 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4905 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4907 ERR("Can't create Drivers key\n");
4911 size = di_sizeof[Level];
4912 if ((size <= cbBuf) && pDriverInfo)
4913 ptr = pDriverInfo + size;
4915 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4916 env, Level, pDriverInfo, ptr,
4917 (cbBuf < size) ? 0 : cbBuf - size,
4918 &needed, unicode)) {
4919 RegCloseKey(hkeyDrivers);
4923 RegCloseKey(hkeyDrivers);
4925 if(pcbNeeded) *pcbNeeded = size + needed;
4926 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4927 if(cbBuf >= needed) return TRUE;
4928 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4932 /*****************************************************************************
4933 * GetPrinterDriverA [WINSPOOL.@]
4935 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4936 DWORD Level, LPBYTE pDriverInfo,
4937 DWORD cbBuf, LPDWORD pcbNeeded)
4940 UNICODE_STRING pEnvW;
4943 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4944 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4945 cbBuf, pcbNeeded, FALSE);
4946 RtlFreeUnicodeString(&pEnvW);
4949 /*****************************************************************************
4950 * GetPrinterDriverW [WINSPOOL.@]
4952 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4953 DWORD Level, LPBYTE pDriverInfo,
4954 DWORD cbBuf, LPDWORD pcbNeeded)
4956 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4957 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4960 /*****************************************************************************
4961 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4963 * Return the PATH for the Printer-Drivers (UNICODE)
4966 * pName [I] Servername (NT only) or NULL (local Computer)
4967 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4968 * Level [I] Structure-Level (must be 1)
4969 * pDriverDirectory [O] PTR to Buffer that receives the Result
4970 * cbBuf [I] Size of Buffer at pDriverDirectory
4971 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4972 * required for pDriverDirectory
4975 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4976 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4977 * if cbBuf is too small
4979 * Native Values returned in pDriverDirectory on Success:
4980 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4981 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4982 *| win9x(Windows 4.0): "%winsysdir%"
4984 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4987 *- Only NULL or "" is supported for pName
4990 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4991 DWORD Level, LPBYTE pDriverDirectory,
4992 DWORD cbBuf, LPDWORD pcbNeeded)
4994 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4995 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4997 if ((backend == NULL) && !load_backend()) return FALSE;
5000 /* (Level != 1) is ignored in win9x */
5001 SetLastError(ERROR_INVALID_LEVEL);
5004 if (pcbNeeded == NULL) {
5005 /* (pcbNeeded == NULL) is ignored in win9x */
5006 SetLastError(RPC_X_NULL_REF_POINTER);
5010 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5011 pDriverDirectory, cbBuf, pcbNeeded);
5016 /*****************************************************************************
5017 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5019 * Return the PATH for the Printer-Drivers (ANSI)
5021 * See GetPrinterDriverDirectoryW.
5024 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5027 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5028 DWORD Level, LPBYTE pDriverDirectory,
5029 DWORD cbBuf, LPDWORD pcbNeeded)
5031 UNICODE_STRING nameW, environmentW;
5034 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5035 WCHAR *driverDirectoryW = NULL;
5037 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5038 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5040 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5042 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5043 else nameW.Buffer = NULL;
5044 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5045 else environmentW.Buffer = NULL;
5047 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5048 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5051 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5052 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5054 *pcbNeeded = needed;
5055 ret = (needed <= cbBuf) ? TRUE : FALSE;
5057 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5059 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5061 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5062 RtlFreeUnicodeString(&environmentW);
5063 RtlFreeUnicodeString(&nameW);
5068 /*****************************************************************************
5069 * AddPrinterDriverA [WINSPOOL.@]
5071 * See AddPrinterDriverW.
5074 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5076 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5077 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5080 /******************************************************************************
5081 * AddPrinterDriverW (WINSPOOL.@)
5083 * Install a Printer Driver
5086 * pName [I] Servername or NULL (local Computer)
5087 * level [I] Level for the supplied DRIVER_INFO_*W struct
5088 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5095 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5097 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5098 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5101 /*****************************************************************************
5102 * AddPrintProcessorA [WINSPOOL.@]
5104 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5105 LPSTR pPrintProcessorName)
5107 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5108 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5112 /*****************************************************************************
5113 * AddPrintProcessorW [WINSPOOL.@]
5115 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5116 LPWSTR pPrintProcessorName)
5118 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5119 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5123 /*****************************************************************************
5124 * AddPrintProvidorA [WINSPOOL.@]
5126 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5128 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5132 /*****************************************************************************
5133 * AddPrintProvidorW [WINSPOOL.@]
5135 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5137 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5141 /*****************************************************************************
5142 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5144 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5145 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5147 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5148 pDevModeOutput, pDevModeInput);
5152 /*****************************************************************************
5153 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5155 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5156 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5158 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5159 pDevModeOutput, pDevModeInput);
5163 /*****************************************************************************
5164 * PrinterProperties [WINSPOOL.@]
5166 * Displays a dialog to set the properties of the printer.
5169 * nonzero on success or zero on failure
5172 * implemented as stub only
5174 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5175 HANDLE hPrinter /* [in] handle to printer object */
5177 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5178 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5182 /*****************************************************************************
5183 * EnumJobsA [WINSPOOL.@]
5186 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5187 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5190 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5191 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5193 if(pcbNeeded) *pcbNeeded = 0;
5194 if(pcReturned) *pcReturned = 0;
5199 /*****************************************************************************
5200 * EnumJobsW [WINSPOOL.@]
5203 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5204 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5207 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5208 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5210 if(pcbNeeded) *pcbNeeded = 0;
5211 if(pcReturned) *pcReturned = 0;
5215 /*****************************************************************************
5216 * WINSPOOL_EnumPrinterDrivers [internal]
5218 * Delivers information about all printer drivers installed on the
5219 * localhost or a given server
5222 * nonzero on success or zero on failure. If the buffer for the returned
5223 * information is too small the function will return an error
5226 * - only implemented for localhost, foreign hosts will return an error
5228 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5229 DWORD Level, LPBYTE pDriverInfo,
5230 DWORD cbBuf, LPDWORD pcbNeeded,
5231 LPDWORD pcReturned, BOOL unicode)
5234 DWORD i, needed, number = 0, size = 0;
5235 WCHAR DriverNameW[255];
5237 const printenv_t * env;
5239 TRACE("%s,%s,%d,%p,%d,%d\n",
5240 debugstr_w(pName), debugstr_w(pEnvironment),
5241 Level, pDriverInfo, cbBuf, unicode);
5243 /* check for local drivers */
5244 if((pName) && (pName[0])) {
5245 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5246 SetLastError(ERROR_ACCESS_DENIED);
5250 env = validate_envW(pEnvironment);
5251 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5253 /* check input parameter */
5254 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5255 SetLastError(ERROR_INVALID_LEVEL);
5259 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5260 SetLastError(RPC_X_NULL_REF_POINTER);
5264 /* initialize return values */
5266 memset( pDriverInfo, 0, cbBuf);
5270 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5272 ERR("Can't open Drivers key\n");
5276 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5277 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5278 RegCloseKey(hkeyDrivers);
5279 ERR("Can't query Drivers key\n");
5282 TRACE("Found %d Drivers\n", number);
5284 /* get size of single struct
5285 * unicode and ascii structure have the same size
5287 size = di_sizeof[Level];
5289 /* calculate required buffer size */
5290 *pcbNeeded = size * number;
5292 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5294 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5295 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5297 ERR("Can't enum key number %d\n", i);
5298 RegCloseKey(hkeyDrivers);
5301 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5303 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5304 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5305 &needed, unicode)) {
5306 RegCloseKey(hkeyDrivers);
5309 (*pcbNeeded) += needed;
5312 RegCloseKey(hkeyDrivers);
5314 if(cbBuf < *pcbNeeded){
5315 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5319 *pcReturned = number;
5323 /*****************************************************************************
5324 * EnumPrinterDriversW [WINSPOOL.@]
5326 * see function EnumPrinterDrivers for RETURNS, BUGS
5328 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5329 LPBYTE pDriverInfo, DWORD cbBuf,
5330 LPDWORD pcbNeeded, LPDWORD pcReturned)
5332 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5333 cbBuf, pcbNeeded, pcReturned, TRUE);
5336 /*****************************************************************************
5337 * EnumPrinterDriversA [WINSPOOL.@]
5339 * see function EnumPrinterDrivers for RETURNS, BUGS
5341 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5342 LPBYTE pDriverInfo, DWORD cbBuf,
5343 LPDWORD pcbNeeded, LPDWORD pcReturned)
5345 UNICODE_STRING pNameW, pEnvironmentW;
5346 PWSTR pwstrNameW, pwstrEnvironmentW;
5348 pwstrNameW = asciitounicode(&pNameW, pName);
5349 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5351 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5352 Level, pDriverInfo, cbBuf, pcbNeeded,
5354 RtlFreeUnicodeString(&pNameW);
5355 RtlFreeUnicodeString(&pEnvironmentW);
5360 /******************************************************************************
5361 * EnumPortsA (WINSPOOL.@)
5366 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5367 LPDWORD pcbNeeded, LPDWORD pcReturned)
5370 LPBYTE bufferW = NULL;
5371 LPWSTR nameW = NULL;
5373 DWORD numentries = 0;
5376 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5377 cbBuf, pcbNeeded, pcReturned);
5379 /* convert servername to unicode */
5381 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5382 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5383 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5385 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5386 needed = cbBuf * sizeof(WCHAR);
5387 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5388 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5390 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5391 if (pcbNeeded) needed = *pcbNeeded;
5392 /* HeapReAlloc return NULL, when bufferW was NULL */
5393 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5394 HeapAlloc(GetProcessHeap(), 0, needed);
5396 /* Try again with the large Buffer */
5397 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5399 needed = pcbNeeded ? *pcbNeeded : 0;
5400 numentries = pcReturned ? *pcReturned : 0;
5403 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5404 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5407 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5408 DWORD entrysize = 0;
5411 LPPORT_INFO_2W pi2w;
5412 LPPORT_INFO_2A pi2a;
5415 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5417 /* First pass: calculate the size for all Entries */
5418 pi2w = (LPPORT_INFO_2W) bufferW;
5419 pi2a = (LPPORT_INFO_2A) pPorts;
5421 while (index < numentries) {
5423 needed += entrysize; /* PORT_INFO_?A */
5424 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5426 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5427 NULL, 0, NULL, NULL);
5429 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5430 NULL, 0, NULL, NULL);
5431 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5432 NULL, 0, NULL, NULL);
5434 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5435 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5436 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5439 /* check for errors and quit on failure */
5440 if (cbBuf < needed) {
5441 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5445 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5446 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5447 cbBuf -= len ; /* free Bytes in the user-Buffer */
5448 pi2w = (LPPORT_INFO_2W) bufferW;
5449 pi2a = (LPPORT_INFO_2A) pPorts;
5451 /* Second Pass: Fill the User Buffer (if we have one) */
5452 while ((index < numentries) && pPorts) {
5454 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5455 pi2a->pPortName = ptr;
5456 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5457 ptr, cbBuf , NULL, NULL);
5461 pi2a->pMonitorName = ptr;
5462 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5463 ptr, cbBuf, NULL, NULL);
5467 pi2a->pDescription = ptr;
5468 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5469 ptr, cbBuf, NULL, NULL);
5473 pi2a->fPortType = pi2w->fPortType;
5474 pi2a->Reserved = 0; /* documented: "must be zero" */
5477 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5478 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5479 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5484 if (pcbNeeded) *pcbNeeded = needed;
5485 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5487 HeapFree(GetProcessHeap(), 0, nameW);
5488 HeapFree(GetProcessHeap(), 0, bufferW);
5490 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5491 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5497 /******************************************************************************
5498 * EnumPortsW (WINSPOOL.@)
5500 * Enumerate available Ports
5503 * name [I] Servername or NULL (local Computer)
5504 * level [I] Structure-Level (1 or 2)
5505 * buffer [O] PTR to Buffer that receives the Result
5506 * bufsize [I] Size of Buffer at buffer
5507 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5508 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5512 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5516 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5519 DWORD numentries = 0;
5522 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5523 cbBuf, pcbNeeded, pcReturned);
5525 if (pName && (pName[0])) {
5526 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5527 SetLastError(ERROR_ACCESS_DENIED);
5531 /* Level is not checked in win9x */
5532 if (!Level || (Level > 2)) {
5533 WARN("level (%d) is ignored in win9x\n", Level);
5534 SetLastError(ERROR_INVALID_LEVEL);
5538 SetLastError(RPC_X_NULL_REF_POINTER);
5542 EnterCriticalSection(&monitor_handles_cs);
5545 /* Scan all local Ports */
5547 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5549 /* we calculated the needed buffersize. now do the error-checks */
5550 if (cbBuf < needed) {
5551 monitor_unloadall();
5552 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5553 goto emP_cleanup_cs;
5555 else if (!pPorts || !pcReturned) {
5556 monitor_unloadall();
5557 SetLastError(RPC_X_NULL_REF_POINTER);
5558 goto emP_cleanup_cs;
5561 /* Fill the Buffer */
5562 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5564 monitor_unloadall();
5567 LeaveCriticalSection(&monitor_handles_cs);
5570 if (pcbNeeded) *pcbNeeded = needed;
5571 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5573 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5574 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5579 /******************************************************************************
5580 * GetDefaultPrinterW (WINSPOOL.@)
5583 * This function must read the value from data 'device' of key
5584 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5586 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5590 WCHAR *buffer, *ptr;
5594 SetLastError(ERROR_INVALID_PARAMETER);
5598 /* make the buffer big enough for the stuff from the profile/registry,
5599 * the content must fit into the local buffer to compute the correct
5600 * size even if the extern buffer is too small or not given.
5601 * (20 for ,driver,port) */
5603 len = max(100, (insize + 20));
5604 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5606 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5608 SetLastError (ERROR_FILE_NOT_FOUND);
5612 TRACE("%s\n", debugstr_w(buffer));
5614 if ((ptr = strchrW(buffer, ',')) == NULL)
5616 SetLastError(ERROR_INVALID_NAME);
5622 *namesize = strlenW(buffer) + 1;
5623 if(!name || (*namesize > insize))
5625 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5629 strcpyW(name, buffer);
5632 HeapFree( GetProcessHeap(), 0, buffer);
5637 /******************************************************************************
5638 * GetDefaultPrinterA (WINSPOOL.@)
5640 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5644 WCHAR *bufferW = NULL;
5648 SetLastError(ERROR_INVALID_PARAMETER);
5652 if(name && *namesize) {
5654 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5657 if(!GetDefaultPrinterW( bufferW, namesize)) {
5662 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5666 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5669 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5672 HeapFree( GetProcessHeap(), 0, bufferW);
5677 /******************************************************************************
5678 * SetDefaultPrinterW (WINSPOOL.204)
5680 * Set the Name of the Default Printer
5683 * pszPrinter [I] Name of the Printer or NULL
5690 * When the Parameter is NULL or points to an Empty String and
5691 * a Default Printer was already present, then this Function changes nothing.
5692 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5693 * the First enumerated local Printer is used.
5696 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5699 TRACE("(%s)\n", debugstr_w(pszPrinter));
5701 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5705 /******************************************************************************
5706 * SetDefaultPrinterA (WINSPOOL.202)
5708 * See SetDefaultPrinterW.
5711 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5714 TRACE("(%s)\n", debugstr_a(pszPrinter));
5716 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5721 /******************************************************************************
5722 * SetPrinterDataExA (WINSPOOL.@)
5724 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5725 LPCSTR pValueName, DWORD Type,
5726 LPBYTE pData, DWORD cbData)
5728 HKEY hkeyPrinter, hkeySubkey;
5731 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5732 debugstr_a(pValueName), Type, pData, cbData);
5734 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5738 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5740 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5741 RegCloseKey(hkeyPrinter);
5744 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5745 RegCloseKey(hkeySubkey);
5746 RegCloseKey(hkeyPrinter);
5750 /******************************************************************************
5751 * SetPrinterDataExW (WINSPOOL.@)
5753 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5754 LPCWSTR pValueName, DWORD Type,
5755 LPBYTE pData, DWORD cbData)
5757 HKEY hkeyPrinter, hkeySubkey;
5760 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5761 debugstr_w(pValueName), Type, pData, cbData);
5763 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5767 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5769 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5770 RegCloseKey(hkeyPrinter);
5773 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5774 RegCloseKey(hkeySubkey);
5775 RegCloseKey(hkeyPrinter);
5779 /******************************************************************************
5780 * SetPrinterDataA (WINSPOOL.@)
5782 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5783 LPBYTE pData, DWORD cbData)
5785 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5789 /******************************************************************************
5790 * SetPrinterDataW (WINSPOOL.@)
5792 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5793 LPBYTE pData, DWORD cbData)
5795 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5799 /******************************************************************************
5800 * GetPrinterDataExA (WINSPOOL.@)
5802 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5803 LPCSTR pValueName, LPDWORD pType,
5804 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5806 HKEY hkeyPrinter, hkeySubkey;
5809 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5810 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5813 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5817 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5819 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5820 RegCloseKey(hkeyPrinter);
5824 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5825 RegCloseKey(hkeySubkey);
5826 RegCloseKey(hkeyPrinter);
5830 /******************************************************************************
5831 * GetPrinterDataExW (WINSPOOL.@)
5833 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5834 LPCWSTR pValueName, LPDWORD pType,
5835 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5837 HKEY hkeyPrinter, hkeySubkey;
5840 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5841 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5844 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5848 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5850 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5851 RegCloseKey(hkeyPrinter);
5855 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5856 RegCloseKey(hkeySubkey);
5857 RegCloseKey(hkeyPrinter);
5861 /******************************************************************************
5862 * GetPrinterDataA (WINSPOOL.@)
5864 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5865 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5867 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5868 pData, nSize, pcbNeeded);
5871 /******************************************************************************
5872 * GetPrinterDataW (WINSPOOL.@)
5874 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5875 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5877 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5878 pData, nSize, pcbNeeded);
5881 /*******************************************************************************
5882 * EnumPrinterDataExW [WINSPOOL.@]
5884 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5885 LPBYTE pEnumValues, DWORD cbEnumValues,
5886 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5888 HKEY hkPrinter, hkSubKey;
5889 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5890 cbValueNameLen, cbMaxValueLen, cbValueLen,
5895 PPRINTER_ENUM_VALUESW ppev;
5897 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5899 if (pKeyName == NULL || *pKeyName == 0)
5900 return ERROR_INVALID_PARAMETER;
5902 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5903 if (ret != ERROR_SUCCESS)
5905 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5910 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5911 if (ret != ERROR_SUCCESS)
5913 r = RegCloseKey (hkPrinter);
5914 if (r != ERROR_SUCCESS)
5915 WARN ("RegCloseKey returned %i\n", r);
5916 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5917 debugstr_w (pKeyName), ret);
5921 ret = RegCloseKey (hkPrinter);
5922 if (ret != ERROR_SUCCESS)
5924 ERR ("RegCloseKey returned %i\n", ret);
5925 r = RegCloseKey (hkSubKey);
5926 if (r != ERROR_SUCCESS)
5927 WARN ("RegCloseKey returned %i\n", r);
5931 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5932 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5933 if (ret != ERROR_SUCCESS)
5935 r = RegCloseKey (hkSubKey);
5936 if (r != ERROR_SUCCESS)
5937 WARN ("RegCloseKey returned %i\n", r);
5938 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5942 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5943 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5945 if (cValues == 0) /* empty key */
5947 r = RegCloseKey (hkSubKey);
5948 if (r != ERROR_SUCCESS)
5949 WARN ("RegCloseKey returned %i\n", r);
5950 *pcbEnumValues = *pnEnumValues = 0;
5951 return ERROR_SUCCESS;
5954 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5956 hHeap = GetProcessHeap ();
5959 ERR ("GetProcessHeap failed\n");
5960 r = RegCloseKey (hkSubKey);
5961 if (r != ERROR_SUCCESS)
5962 WARN ("RegCloseKey returned %i\n", r);
5963 return ERROR_OUTOFMEMORY;
5966 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5967 if (lpValueName == NULL)
5969 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5970 r = RegCloseKey (hkSubKey);
5971 if (r != ERROR_SUCCESS)
5972 WARN ("RegCloseKey returned %i\n", r);
5973 return ERROR_OUTOFMEMORY;
5976 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5977 if (lpValue == NULL)
5979 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5980 if (HeapFree (hHeap, 0, lpValueName) == 0)
5981 WARN ("HeapFree failed with code %i\n", GetLastError ());
5982 r = RegCloseKey (hkSubKey);
5983 if (r != ERROR_SUCCESS)
5984 WARN ("RegCloseKey returned %i\n", r);
5985 return ERROR_OUTOFMEMORY;
5988 TRACE ("pass 1: calculating buffer required for all names and values\n");
5990 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5992 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5994 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5996 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5997 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5998 NULL, NULL, lpValue, &cbValueLen);
5999 if (ret != ERROR_SUCCESS)
6001 if (HeapFree (hHeap, 0, lpValue) == 0)
6002 WARN ("HeapFree failed with code %i\n", GetLastError ());
6003 if (HeapFree (hHeap, 0, lpValueName) == 0)
6004 WARN ("HeapFree failed with code %i\n", GetLastError ());
6005 r = RegCloseKey (hkSubKey);
6006 if (r != ERROR_SUCCESS)
6007 WARN ("RegCloseKey returned %i\n", r);
6008 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6012 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6013 debugstr_w (lpValueName), dwIndex,
6014 cbValueNameLen + 1, cbValueLen);
6016 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6017 cbBufSize += cbValueLen;
6020 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6022 *pcbEnumValues = cbBufSize;
6023 *pnEnumValues = cValues;
6025 if (cbEnumValues < cbBufSize) /* buffer too small */
6027 if (HeapFree (hHeap, 0, lpValue) == 0)
6028 WARN ("HeapFree failed with code %i\n", GetLastError ());
6029 if (HeapFree (hHeap, 0, lpValueName) == 0)
6030 WARN ("HeapFree failed with code %i\n", GetLastError ());
6031 r = RegCloseKey (hkSubKey);
6032 if (r != ERROR_SUCCESS)
6033 WARN ("RegCloseKey returned %i\n", r);
6034 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6035 return ERROR_MORE_DATA;
6038 TRACE ("pass 2: copying all names and values to buffer\n");
6040 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6041 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6043 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6045 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6046 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6047 NULL, &dwType, lpValue, &cbValueLen);
6048 if (ret != ERROR_SUCCESS)
6050 if (HeapFree (hHeap, 0, lpValue) == 0)
6051 WARN ("HeapFree failed with code %i\n", GetLastError ());
6052 if (HeapFree (hHeap, 0, lpValueName) == 0)
6053 WARN ("HeapFree failed with code %i\n", GetLastError ());
6054 r = RegCloseKey (hkSubKey);
6055 if (r != ERROR_SUCCESS)
6056 WARN ("RegCloseKey returned %i\n", r);
6057 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6061 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6062 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6063 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6064 pEnumValues += cbValueNameLen;
6066 /* return # of *bytes* (including trailing \0), not # of chars */
6067 ppev[dwIndex].cbValueName = cbValueNameLen;
6069 ppev[dwIndex].dwType = dwType;
6071 memcpy (pEnumValues, lpValue, cbValueLen);
6072 ppev[dwIndex].pData = pEnumValues;
6073 pEnumValues += cbValueLen;
6075 ppev[dwIndex].cbData = cbValueLen;
6077 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6078 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6081 if (HeapFree (hHeap, 0, lpValue) == 0)
6083 ret = GetLastError ();
6084 ERR ("HeapFree failed with code %i\n", ret);
6085 if (HeapFree (hHeap, 0, lpValueName) == 0)
6086 WARN ("HeapFree failed with code %i\n", GetLastError ());
6087 r = RegCloseKey (hkSubKey);
6088 if (r != ERROR_SUCCESS)
6089 WARN ("RegCloseKey returned %i\n", r);
6093 if (HeapFree (hHeap, 0, lpValueName) == 0)
6095 ret = GetLastError ();
6096 ERR ("HeapFree failed with code %i\n", ret);
6097 r = RegCloseKey (hkSubKey);
6098 if (r != ERROR_SUCCESS)
6099 WARN ("RegCloseKey returned %i\n", r);
6103 ret = RegCloseKey (hkSubKey);
6104 if (ret != ERROR_SUCCESS)
6106 ERR ("RegCloseKey returned %i\n", ret);
6110 return ERROR_SUCCESS;
6113 /*******************************************************************************
6114 * EnumPrinterDataExA [WINSPOOL.@]
6116 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6117 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6118 * what Windows 2000 SP1 does.
6121 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6122 LPBYTE pEnumValues, DWORD cbEnumValues,
6123 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6127 DWORD ret, dwIndex, dwBufSize;
6131 TRACE ("%p %s\n", hPrinter, pKeyName);
6133 if (pKeyName == NULL || *pKeyName == 0)
6134 return ERROR_INVALID_PARAMETER;
6136 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6139 ret = GetLastError ();
6140 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6144 hHeap = GetProcessHeap ();
6147 ERR ("GetProcessHeap failed\n");
6148 return ERROR_OUTOFMEMORY;
6151 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6152 if (pKeyNameW == NULL)
6154 ERR ("Failed to allocate %i bytes from process heap\n",
6155 (LONG)(len * sizeof (WCHAR)));
6156 return ERROR_OUTOFMEMORY;
6159 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6161 ret = GetLastError ();
6162 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6163 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6164 WARN ("HeapFree failed with code %i\n", GetLastError ());
6168 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6169 pcbEnumValues, pnEnumValues);
6170 if (ret != ERROR_SUCCESS)
6172 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6173 WARN ("HeapFree failed with code %i\n", GetLastError ());
6174 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6178 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6180 ret = GetLastError ();
6181 ERR ("HeapFree failed with code %i\n", ret);
6185 if (*pnEnumValues == 0) /* empty key */
6186 return ERROR_SUCCESS;
6189 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6191 PPRINTER_ENUM_VALUESW ppev =
6192 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6194 if (dwBufSize < ppev->cbValueName)
6195 dwBufSize = ppev->cbValueName;
6197 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6198 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6199 dwBufSize = ppev->cbData;
6202 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6204 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6205 if (pBuffer == NULL)
6207 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6208 return ERROR_OUTOFMEMORY;
6211 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6213 PPRINTER_ENUM_VALUESW ppev =
6214 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6216 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6217 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6221 ret = GetLastError ();
6222 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6223 if (HeapFree (hHeap, 0, pBuffer) == 0)
6224 WARN ("HeapFree failed with code %i\n", GetLastError ());
6228 memcpy (ppev->pValueName, pBuffer, len);
6230 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6232 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6233 ppev->dwType != REG_MULTI_SZ)
6236 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6237 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6240 ret = GetLastError ();
6241 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6242 if (HeapFree (hHeap, 0, pBuffer) == 0)
6243 WARN ("HeapFree failed with code %i\n", GetLastError ());
6247 memcpy (ppev->pData, pBuffer, len);
6249 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6250 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6253 if (HeapFree (hHeap, 0, pBuffer) == 0)
6255 ret = GetLastError ();
6256 ERR ("HeapFree failed with code %i\n", ret);
6260 return ERROR_SUCCESS;
6263 /******************************************************************************
6264 * AbortPrinter (WINSPOOL.@)
6266 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6268 FIXME("(%p), stub!\n", hPrinter);
6272 /******************************************************************************
6273 * AddPortA (WINSPOOL.@)
6278 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6280 LPWSTR nameW = NULL;
6281 LPWSTR monitorW = NULL;
6285 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6288 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6289 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6290 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6294 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6295 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6296 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6298 res = AddPortW(nameW, hWnd, monitorW);
6299 HeapFree(GetProcessHeap(), 0, nameW);
6300 HeapFree(GetProcessHeap(), 0, monitorW);
6304 /******************************************************************************
6305 * AddPortW (WINSPOOL.@)
6307 * Add a Port for a specific Monitor
6310 * pName [I] Servername or NULL (local Computer)
6311 * hWnd [I] Handle to parent Window for the Dialog-Box
6312 * pMonitorName [I] Name of the Monitor that manage the Port
6319 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6325 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6327 if (pName && pName[0]) {
6328 SetLastError(ERROR_INVALID_PARAMETER);
6332 if (!pMonitorName) {
6333 SetLastError(RPC_X_NULL_REF_POINTER);
6337 /* an empty Monitorname is Invalid */
6338 if (!pMonitorName[0]) {
6339 SetLastError(ERROR_NOT_SUPPORTED);
6343 pm = monitor_load(pMonitorName, NULL);
6344 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6345 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6346 TRACE("got %d with %u\n", res, GetLastError());
6351 pui = monitor_loadui(pm);
6352 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6353 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6354 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6355 TRACE("got %d with %u\n", res, GetLastError());
6360 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6361 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6363 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6364 SetLastError(ERROR_NOT_SUPPORTED);
6367 monitor_unload(pui);
6370 TRACE("returning %d with %u\n", res, GetLastError());
6374 /******************************************************************************
6375 * AddPortExA (WINSPOOL.@)
6380 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6383 PORT_INFO_2A * pi2A;
6384 LPWSTR nameW = NULL;
6385 LPWSTR monitorW = NULL;
6389 pi2A = (PORT_INFO_2A *) pBuffer;
6391 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6392 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6394 if ((level < 1) || (level > 2)) {
6395 SetLastError(ERROR_INVALID_LEVEL);
6400 SetLastError(ERROR_INVALID_PARAMETER);
6405 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6406 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6407 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6411 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6412 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6413 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6416 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6418 if (pi2A->pPortName) {
6419 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6420 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6421 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6425 if (pi2A->pMonitorName) {
6426 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6427 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6428 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6431 if (pi2A->pDescription) {
6432 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6433 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6434 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6436 pi2W.fPortType = pi2A->fPortType;
6437 pi2W.Reserved = pi2A->Reserved;
6440 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6442 HeapFree(GetProcessHeap(), 0, nameW);
6443 HeapFree(GetProcessHeap(), 0, monitorW);
6444 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6445 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6446 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6451 /******************************************************************************
6452 * AddPortExW (WINSPOOL.@)
6454 * Add a Port for a specific Monitor, without presenting a user interface
6457 * pName [I] Servername or NULL (local Computer)
6458 * level [I] Structure-Level (1 or 2) for pBuffer
6459 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6460 * pMonitorName [I] Name of the Monitor that manage the Port
6467 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6473 pi2 = (PORT_INFO_2W *) pBuffer;
6475 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6476 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6477 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6478 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6481 if ((level < 1) || (level > 2)) {
6482 SetLastError(ERROR_INVALID_LEVEL);
6486 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6487 SetLastError(ERROR_INVALID_PARAMETER);
6491 /* load the Monitor */
6492 pm = monitor_load(pMonitorName, NULL);
6494 SetLastError(ERROR_INVALID_PARAMETER);
6498 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6499 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6500 TRACE("got %u with %u\n", res, GetLastError());
6504 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6510 /******************************************************************************
6511 * AddPrinterConnectionA (WINSPOOL.@)
6513 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6515 FIXME("%s\n", debugstr_a(pName));
6519 /******************************************************************************
6520 * AddPrinterConnectionW (WINSPOOL.@)
6522 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6524 FIXME("%s\n", debugstr_w(pName));
6528 /******************************************************************************
6529 * AddPrinterDriverExW (WINSPOOL.@)
6531 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6534 * pName [I] Servername or NULL (local Computer)
6535 * level [I] Level for the supplied DRIVER_INFO_*W struct
6536 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6537 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6544 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6546 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6548 if ((backend == NULL) && !load_backend()) return FALSE;
6550 if (level < 2 || level == 5 || level == 7 || level > 8) {
6551 SetLastError(ERROR_INVALID_LEVEL);
6556 SetLastError(ERROR_INVALID_PARAMETER);
6560 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6563 /******************************************************************************
6564 * AddPrinterDriverExA (WINSPOOL.@)
6566 * See AddPrinterDriverExW.
6569 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6571 DRIVER_INFO_8A *diA;
6573 LPWSTR nameW = NULL;
6578 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6580 diA = (DRIVER_INFO_8A *) pDriverInfo;
6581 ZeroMemory(&diW, sizeof(diW));
6583 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6584 SetLastError(ERROR_INVALID_LEVEL);
6589 SetLastError(ERROR_INVALID_PARAMETER);
6593 /* convert servername to unicode */
6595 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6596 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6597 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6601 diW.cVersion = diA->cVersion;
6604 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6605 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6606 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6609 if (diA->pEnvironment) {
6610 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6611 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6612 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6615 if (diA->pDriverPath) {
6616 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6617 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6618 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6621 if (diA->pDataFile) {
6622 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6623 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6624 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6627 if (diA->pConfigFile) {
6628 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6629 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6630 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6633 if ((Level > 2) && diA->pDependentFiles) {
6634 lenA = multi_sz_lenA(diA->pDependentFiles);
6635 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6636 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6637 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6640 if ((Level > 2) && diA->pMonitorName) {
6641 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6642 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6643 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6646 if ((Level > 3) && diA->pDefaultDataType) {
6647 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6648 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6649 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6652 if ((Level > 3) && diA->pszzPreviousNames) {
6653 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6654 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6655 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6656 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6659 if ((Level > 5) && diA->pszMfgName) {
6660 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6661 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6662 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6665 if ((Level > 5) && diA->pszOEMUrl) {
6666 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6667 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6668 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6671 if ((Level > 5) && diA->pszHardwareID) {
6672 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6673 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6674 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6677 if ((Level > 5) && diA->pszProvider) {
6678 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6679 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6680 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6684 FIXME("level %u is incomplete\n", Level);
6687 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6688 TRACE("got %u with %u\n", res, GetLastError());
6689 HeapFree(GetProcessHeap(), 0, nameW);
6690 HeapFree(GetProcessHeap(), 0, diW.pName);
6691 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6692 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6693 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6694 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6695 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6696 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6697 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6698 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6699 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6700 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6701 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6702 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6704 TRACE("=> %u with %u\n", res, GetLastError());
6708 /******************************************************************************
6709 * ConfigurePortA (WINSPOOL.@)
6711 * See ConfigurePortW.
6714 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6716 LPWSTR nameW = NULL;
6717 LPWSTR portW = NULL;
6721 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6723 /* convert servername to unicode */
6725 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6726 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6727 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6730 /* convert portname to unicode */
6732 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6733 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6734 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6737 res = ConfigurePortW(nameW, hWnd, portW);
6738 HeapFree(GetProcessHeap(), 0, nameW);
6739 HeapFree(GetProcessHeap(), 0, portW);
6743 /******************************************************************************
6744 * ConfigurePortW (WINSPOOL.@)
6746 * Display the Configuration-Dialog for a specific Port
6749 * pName [I] Servername or NULL (local Computer)
6750 * hWnd [I] Handle to parent Window for the Dialog-Box
6751 * pPortName [I] Name of the Port, that should be configured
6758 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6764 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6766 if (pName && pName[0]) {
6767 SetLastError(ERROR_INVALID_PARAMETER);
6772 SetLastError(RPC_X_NULL_REF_POINTER);
6776 /* an empty Portname is Invalid, but can popup a Dialog */
6777 if (!pPortName[0]) {
6778 SetLastError(ERROR_NOT_SUPPORTED);
6782 pm = monitor_load_by_port(pPortName);
6783 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6784 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6785 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6786 TRACE("got %d with %u\n", res, GetLastError());
6790 pui = monitor_loadui(pm);
6791 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6792 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6793 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6794 TRACE("got %d with %u\n", res, GetLastError());
6798 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6799 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6801 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6802 SetLastError(ERROR_NOT_SUPPORTED);
6805 monitor_unload(pui);
6809 TRACE("returning %d with %u\n", res, GetLastError());
6813 /******************************************************************************
6814 * ConnectToPrinterDlg (WINSPOOL.@)
6816 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6818 FIXME("%p %x\n", hWnd, Flags);
6822 /******************************************************************************
6823 * DeletePrinterConnectionA (WINSPOOL.@)
6825 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6827 FIXME("%s\n", debugstr_a(pName));
6831 /******************************************************************************
6832 * DeletePrinterConnectionW (WINSPOOL.@)
6834 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6836 FIXME("%s\n", debugstr_w(pName));
6840 /******************************************************************************
6841 * DeletePrinterDriverExW (WINSPOOL.@)
6843 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6844 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6849 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6850 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6852 if(pName && pName[0])
6854 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6855 SetLastError(ERROR_INVALID_PARAMETER);
6861 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6862 SetLastError(ERROR_INVALID_PARAMETER);
6866 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6870 ERR("Can't open drivers key\n");
6874 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6877 RegCloseKey(hkey_drivers);
6882 /******************************************************************************
6883 * DeletePrinterDriverExA (WINSPOOL.@)
6885 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6886 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6888 UNICODE_STRING NameW, EnvW, DriverW;
6891 asciitounicode(&NameW, pName);
6892 asciitounicode(&EnvW, pEnvironment);
6893 asciitounicode(&DriverW, pDriverName);
6895 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6897 RtlFreeUnicodeString(&DriverW);
6898 RtlFreeUnicodeString(&EnvW);
6899 RtlFreeUnicodeString(&NameW);
6904 /******************************************************************************
6905 * DeletePrinterDataExW (WINSPOOL.@)
6907 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6910 FIXME("%p %s %s\n", hPrinter,
6911 debugstr_w(pKeyName), debugstr_w(pValueName));
6912 return ERROR_INVALID_PARAMETER;
6915 /******************************************************************************
6916 * DeletePrinterDataExA (WINSPOOL.@)
6918 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6921 FIXME("%p %s %s\n", hPrinter,
6922 debugstr_a(pKeyName), debugstr_a(pValueName));
6923 return ERROR_INVALID_PARAMETER;
6926 /******************************************************************************
6927 * DeletePrintProcessorA (WINSPOOL.@)
6929 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6931 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6932 debugstr_a(pPrintProcessorName));
6936 /******************************************************************************
6937 * DeletePrintProcessorW (WINSPOOL.@)
6939 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6941 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6942 debugstr_w(pPrintProcessorName));
6946 /******************************************************************************
6947 * DeletePrintProvidorA (WINSPOOL.@)
6949 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6951 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6952 debugstr_a(pPrintProviderName));
6956 /******************************************************************************
6957 * DeletePrintProvidorW (WINSPOOL.@)
6959 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6961 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6962 debugstr_w(pPrintProviderName));
6966 /******************************************************************************
6967 * EnumFormsA (WINSPOOL.@)
6969 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6970 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6972 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6973 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6977 /******************************************************************************
6978 * EnumFormsW (WINSPOOL.@)
6980 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6981 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6983 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6984 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6988 /*****************************************************************************
6989 * EnumMonitorsA [WINSPOOL.@]
6991 * See EnumMonitorsW.
6994 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6995 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6998 LPBYTE bufferW = NULL;
6999 LPWSTR nameW = NULL;
7001 DWORD numentries = 0;
7004 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7005 cbBuf, pcbNeeded, pcReturned);
7007 /* convert servername to unicode */
7009 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7010 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7011 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7013 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7014 needed = cbBuf * sizeof(WCHAR);
7015 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7016 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7018 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7019 if (pcbNeeded) needed = *pcbNeeded;
7020 /* HeapReAlloc return NULL, when bufferW was NULL */
7021 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7022 HeapAlloc(GetProcessHeap(), 0, needed);
7024 /* Try again with the large Buffer */
7025 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7027 numentries = pcReturned ? *pcReturned : 0;
7030 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7031 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7034 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7035 DWORD entrysize = 0;
7038 LPMONITOR_INFO_2W mi2w;
7039 LPMONITOR_INFO_2A mi2a;
7041 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7042 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7044 /* First pass: calculate the size for all Entries */
7045 mi2w = (LPMONITOR_INFO_2W) bufferW;
7046 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7048 while (index < numentries) {
7050 needed += entrysize; /* MONITOR_INFO_?A */
7051 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7053 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7054 NULL, 0, NULL, NULL);
7056 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7057 NULL, 0, NULL, NULL);
7058 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7059 NULL, 0, NULL, NULL);
7061 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7062 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7063 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7066 /* check for errors and quit on failure */
7067 if (cbBuf < needed) {
7068 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7072 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7073 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7074 cbBuf -= len ; /* free Bytes in the user-Buffer */
7075 mi2w = (LPMONITOR_INFO_2W) bufferW;
7076 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7078 /* Second Pass: Fill the User Buffer (if we have one) */
7079 while ((index < numentries) && pMonitors) {
7081 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7083 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7084 ptr, cbBuf , NULL, NULL);
7088 mi2a->pEnvironment = ptr;
7089 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7090 ptr, cbBuf, NULL, NULL);
7094 mi2a->pDLLName = ptr;
7095 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7096 ptr, cbBuf, NULL, NULL);
7100 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7101 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7102 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7106 if (pcbNeeded) *pcbNeeded = needed;
7107 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7109 HeapFree(GetProcessHeap(), 0, nameW);
7110 HeapFree(GetProcessHeap(), 0, bufferW);
7112 TRACE("returning %d with %d (%d byte for %d entries)\n",
7113 (res), GetLastError(), needed, numentries);
7119 /*****************************************************************************
7120 * EnumMonitorsW [WINSPOOL.@]
7122 * Enumerate available Port-Monitors
7125 * pName [I] Servername or NULL (local Computer)
7126 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7127 * pMonitors [O] PTR to Buffer that receives the Result
7128 * cbBuf [I] Size of Buffer at pMonitors
7129 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7130 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7134 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7137 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7138 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7141 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7142 cbBuf, pcbNeeded, pcReturned);
7144 if ((backend == NULL) && !load_backend()) return FALSE;
7146 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7147 SetLastError(RPC_X_NULL_REF_POINTER);
7151 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7154 /******************************************************************************
7155 * SpoolerInit (WINSPOOL.@)
7157 * Initialize the Spooler
7164 * The function fails on windows, when the spooler service is not running
7167 BOOL WINAPI SpoolerInit(void)
7170 if ((backend == NULL) && !load_backend()) return FALSE;
7174 /******************************************************************************
7175 * XcvDataW (WINSPOOL.@)
7177 * Execute commands in the Printmonitor DLL
7180 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7181 * pszDataName [i] Name of the command to execute
7182 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7183 * cbInputData [i] Size in Bytes of Buffer at pInputData
7184 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7185 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7186 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7187 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7194 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7195 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7197 * Minimal List of commands, that a Printmonitor DLL should support:
7199 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7200 *| "AddPort" : Add a Port
7201 *| "DeletePort": Delete a Port
7203 * Many Printmonitors support additional commands. Examples for localspl.dll:
7204 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7205 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7208 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7209 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7210 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7212 opened_printer_t *printer;
7214 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7215 pInputData, cbInputData, pOutputData,
7216 cbOutputData, pcbOutputNeeded, pdwStatus);
7218 printer = get_opened_printer(hXcv);
7219 if (!printer || (!printer->hXcv)) {
7220 SetLastError(ERROR_INVALID_HANDLE);
7224 if (!pcbOutputNeeded) {
7225 SetLastError(ERROR_INVALID_PARAMETER);
7229 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7230 SetLastError(RPC_X_NULL_REF_POINTER);
7234 *pcbOutputNeeded = 0;
7236 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7237 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7242 /*****************************************************************************
7243 * EnumPrinterDataA [WINSPOOL.@]
7246 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7247 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7248 DWORD cbData, LPDWORD pcbData )
7250 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7251 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7252 return ERROR_NO_MORE_ITEMS;
7255 /*****************************************************************************
7256 * EnumPrinterDataW [WINSPOOL.@]
7259 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7260 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7261 DWORD cbData, LPDWORD pcbData )
7263 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7264 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7265 return ERROR_NO_MORE_ITEMS;
7268 /*****************************************************************************
7269 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7272 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7273 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7274 LPDWORD pcbNeeded, LPDWORD pcReturned)
7276 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7277 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7278 pcbNeeded, pcReturned);
7282 /*****************************************************************************
7283 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7286 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7287 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7288 LPDWORD pcbNeeded, LPDWORD pcReturned)
7290 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7291 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7292 pcbNeeded, pcReturned);
7296 /*****************************************************************************
7297 * EnumPrintProcessorsA [WINSPOOL.@]
7300 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7301 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7303 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7304 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7308 /*****************************************************************************
7309 * EnumPrintProcessorsW [WINSPOOL.@]
7312 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7313 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7315 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7316 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7317 cbBuf, pcbNeeded, pcbReturned);
7321 /*****************************************************************************
7322 * ExtDeviceMode [WINSPOOL.@]
7325 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7326 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7329 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7330 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7331 debugstr_a(pProfile), fMode);
7335 /*****************************************************************************
7336 * FindClosePrinterChangeNotification [WINSPOOL.@]
7339 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7341 FIXME("Stub: %p\n", hChange);
7345 /*****************************************************************************
7346 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7349 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7350 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7352 FIXME("Stub: %p %x %x %p\n",
7353 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7354 return INVALID_HANDLE_VALUE;
7357 /*****************************************************************************
7358 * FindNextPrinterChangeNotification [WINSPOOL.@]
7361 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7362 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7364 FIXME("Stub: %p %p %p %p\n",
7365 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7369 /*****************************************************************************
7370 * FreePrinterNotifyInfo [WINSPOOL.@]
7373 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7375 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7379 /*****************************************************************************
7382 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7383 * ansi depending on the unicode parameter.
7385 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7395 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7398 memcpy(ptr, str, *size);
7405 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7408 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7415 /*****************************************************************************
7418 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7419 LPDWORD pcbNeeded, BOOL unicode)
7421 DWORD size, left = cbBuf;
7422 BOOL space = (cbBuf > 0);
7429 ji1->JobId = job->job_id;
7432 string_to_buf(job->document_title, ptr, left, &size, unicode);
7433 if(space && size <= left)
7435 ji1->pDocument = (LPWSTR)ptr;
7446 /*****************************************************************************
7449 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7450 LPDWORD pcbNeeded, BOOL unicode)
7452 DWORD size, left = cbBuf;
7453 BOOL space = (cbBuf > 0);
7460 ji2->JobId = job->job_id;
7463 string_to_buf(job->document_title, ptr, left, &size, unicode);
7464 if(space && size <= left)
7466 ji2->pDocument = (LPWSTR)ptr;
7477 /*****************************************************************************
7480 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7481 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7484 DWORD needed = 0, size;
7488 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7490 EnterCriticalSection(&printer_handles_cs);
7491 job = get_job(hPrinter, JobId);
7498 size = sizeof(JOB_INFO_1W);
7503 memset(pJob, 0, size);
7507 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7512 size = sizeof(JOB_INFO_2W);
7517 memset(pJob, 0, size);
7521 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7526 size = sizeof(JOB_INFO_3);
7530 memset(pJob, 0, size);
7539 SetLastError(ERROR_INVALID_LEVEL);
7543 *pcbNeeded = needed;
7545 LeaveCriticalSection(&printer_handles_cs);
7549 /*****************************************************************************
7550 * GetJobA [WINSPOOL.@]
7553 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7554 DWORD cbBuf, LPDWORD pcbNeeded)
7556 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7559 /*****************************************************************************
7560 * GetJobW [WINSPOOL.@]
7563 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7564 DWORD cbBuf, LPDWORD pcbNeeded)
7566 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7569 /*****************************************************************************
7572 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7574 char *unixname, *queue, *cmd;
7575 char fmt[] = "lpr -P%s %s";
7579 if(!(unixname = wine_get_unix_file_name(filename)))
7582 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7583 queue = HeapAlloc(GetProcessHeap(), 0, len);
7584 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7586 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7587 sprintf(cmd, fmt, queue, unixname);
7589 TRACE("printing with: %s\n", cmd);
7592 HeapFree(GetProcessHeap(), 0, cmd);
7593 HeapFree(GetProcessHeap(), 0, queue);
7594 HeapFree(GetProcessHeap(), 0, unixname);
7598 /*****************************************************************************
7601 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7603 #ifdef SONAME_LIBCUPS
7606 char *unixname, *queue, *doc_titleA;
7610 if(!(unixname = wine_get_unix_file_name(filename)))
7613 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7614 queue = HeapAlloc(GetProcessHeap(), 0, len);
7615 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7617 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7618 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7619 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7621 TRACE("printing via cups\n");
7622 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7623 HeapFree(GetProcessHeap(), 0, doc_titleA);
7624 HeapFree(GetProcessHeap(), 0, queue);
7625 HeapFree(GetProcessHeap(), 0, unixname);
7631 return schedule_lpr(printer_name, filename);
7635 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7642 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7646 if(HIWORD(wparam) == BN_CLICKED)
7648 if(LOWORD(wparam) == IDOK)
7651 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7654 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7655 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7657 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7659 WCHAR caption[200], message[200];
7662 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7663 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7664 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7665 if(mb_ret == IDCANCEL)
7667 HeapFree(GetProcessHeap(), 0, filename);
7671 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7672 if(hf == INVALID_HANDLE_VALUE)
7674 WCHAR caption[200], message[200];
7676 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7677 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7678 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7679 HeapFree(GetProcessHeap(), 0, filename);
7683 DeleteFileW(filename);
7684 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7686 EndDialog(hwnd, IDOK);
7689 if(LOWORD(wparam) == IDCANCEL)
7691 EndDialog(hwnd, IDCANCEL);
7700 /*****************************************************************************
7703 static BOOL get_filename(LPWSTR *filename)
7705 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7706 file_dlg_proc, (LPARAM)filename) == IDOK;
7709 /*****************************************************************************
7712 static BOOL schedule_file(LPCWSTR filename)
7714 LPWSTR output = NULL;
7716 if(get_filename(&output))
7719 TRACE("copy to %s\n", debugstr_w(output));
7720 r = CopyFileW(filename, output, FALSE);
7721 HeapFree(GetProcessHeap(), 0, output);
7727 /*****************************************************************************
7730 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7733 char *unixname, *cmdA;
7735 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7739 if(!(unixname = wine_get_unix_file_name(filename)))
7742 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7743 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7744 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7746 TRACE("printing with: %s\n", cmdA);
7748 if((file_fd = open(unixname, O_RDONLY)) == -1)
7753 ERR("pipe() failed!\n");
7763 /* reset signals that we previously set to SIG_IGN */
7764 signal(SIGPIPE, SIG_DFL);
7765 signal(SIGCHLD, SIG_DFL);
7767 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7771 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7772 write(fds[1], buf, no_read);
7777 if(file_fd != -1) close(file_fd);
7778 if(fds[0] != -1) close(fds[0]);
7779 if(fds[1] != -1) close(fds[1]);
7781 HeapFree(GetProcessHeap(), 0, cmdA);
7782 HeapFree(GetProcessHeap(), 0, unixname);
7789 /*****************************************************************************
7792 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7794 int in_fd, out_fd, no_read;
7797 char *unixname, *outputA;
7800 if(!(unixname = wine_get_unix_file_name(filename)))
7803 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7804 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7805 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7807 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7808 in_fd = open(unixname, O_RDONLY);
7809 if(out_fd == -1 || in_fd == -1)
7812 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7813 write(out_fd, buf, no_read);
7817 if(in_fd != -1) close(in_fd);
7818 if(out_fd != -1) close(out_fd);
7819 HeapFree(GetProcessHeap(), 0, outputA);
7820 HeapFree(GetProcessHeap(), 0, unixname);
7824 /*****************************************************************************
7825 * ScheduleJob [WINSPOOL.@]
7828 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7830 opened_printer_t *printer;
7832 struct list *cursor, *cursor2;
7834 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7835 EnterCriticalSection(&printer_handles_cs);
7836 printer = get_opened_printer(hPrinter);
7840 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7842 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7845 if(job->job_id != dwJobID) continue;
7847 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7848 if(hf != INVALID_HANDLE_VALUE)
7850 PRINTER_INFO_5W *pi5;
7854 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7855 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7857 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7858 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7859 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7860 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7861 debugstr_w(pi5->pPortName));
7865 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7866 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7868 DWORD type, count = sizeof(output);
7869 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7872 if(output[0] == '|')
7874 ret = schedule_pipe(output + 1, job->filename);
7878 ret = schedule_unixfile(output, job->filename);
7880 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7882 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7884 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7886 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7888 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7890 ret = schedule_file(job->filename);
7894 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7896 HeapFree(GetProcessHeap(), 0, pi5);
7898 DeleteFileW(job->filename);
7900 list_remove(cursor);
7901 HeapFree(GetProcessHeap(), 0, job->document_title);
7902 HeapFree(GetProcessHeap(), 0, job->filename);
7903 HeapFree(GetProcessHeap(), 0, job);
7907 LeaveCriticalSection(&printer_handles_cs);
7911 /*****************************************************************************
7912 * StartDocDlgA [WINSPOOL.@]
7914 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7916 UNICODE_STRING usBuffer;
7919 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7922 docW.cbSize = sizeof(docW);
7923 if (doc->lpszDocName)
7925 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7926 if (!(docW.lpszDocName = docnameW)) return NULL;
7928 if (doc->lpszOutput)
7930 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7931 if (!(docW.lpszOutput = outputW)) return NULL;
7933 if (doc->lpszDatatype)
7935 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7936 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7938 docW.fwType = doc->fwType;
7940 retW = StartDocDlgW(hPrinter, &docW);
7944 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7945 ret = HeapAlloc(GetProcessHeap(), 0, len);
7946 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7947 HeapFree(GetProcessHeap(), 0, retW);
7950 HeapFree(GetProcessHeap(), 0, datatypeW);
7951 HeapFree(GetProcessHeap(), 0, outputW);
7952 HeapFree(GetProcessHeap(), 0, docnameW);
7957 /*****************************************************************************
7958 * StartDocDlgW [WINSPOOL.@]
7960 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7961 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7962 * port is "FILE:". Also returns the full path if passed a relative path.
7964 * The caller should free the returned string from the process heap.
7966 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7971 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7973 PRINTER_INFO_5W *pi5;
7974 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7975 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7977 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7978 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7979 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7981 HeapFree(GetProcessHeap(), 0, pi5);
7984 HeapFree(GetProcessHeap(), 0, pi5);
7987 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7991 if (get_filename(&name))
7993 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7995 HeapFree(GetProcessHeap(), 0, name);
7998 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7999 GetFullPathNameW(name, len, ret, NULL);
8000 HeapFree(GetProcessHeap(), 0, name);
8005 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8008 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8009 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8011 attr = GetFileAttributesW(ret);
8012 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8014 HeapFree(GetProcessHeap(), 0, ret);