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 monitor_t * pm = NULL;
2275 LPMONITOR_INFO_2W mi2w;
2281 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2282 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2283 debugstr_w(mi2w ? mi2w->pName : NULL),
2284 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2285 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2288 SetLastError(ERROR_INVALID_LEVEL);
2292 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2297 if (pName && (pName[0])) {
2298 FIXME("for server %s not implemented\n", debugstr_w(pName));
2299 SetLastError(ERROR_ACCESS_DENIED);
2304 if (!mi2w->pName || (! mi2w->pName[0])) {
2305 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2306 SetLastError(ERROR_INVALID_PARAMETER);
2309 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2310 WARN("Environment %s requested (we support only %s)\n",
2311 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2312 SetLastError(ERROR_INVALID_ENVIRONMENT);
2316 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2317 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2318 SetLastError(ERROR_INVALID_PARAMETER);
2322 /* Load and initialize the monitor. SetLastError() is called on failure */
2323 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2328 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2329 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2333 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2334 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2335 &disposition) == ERROR_SUCCESS) {
2337 /* Some installers set options for the port before calling AddMonitor.
2338 We query the "Driver" entry to verify that the monitor is installed,
2339 before we return an error.
2340 When a user installs two print monitors at the same time with the
2341 same name but with a different driver DLL and a task switch comes
2342 between RegQueryValueExW and RegSetValueExW, a race condition
2343 is possible but silently ignored. */
2347 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2348 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2349 &namesize) == ERROR_SUCCESS)) {
2350 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2351 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2352 9x: ERROR_ALREADY_EXISTS (183) */
2353 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2358 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2359 res = (RegSetValueExW(hentry, DriverW, 0,
2360 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2362 RegCloseKey(hentry);
2369 /******************************************************************
2370 * DeletePrinterDriverA [WINSPOOL.@]
2373 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2375 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2378 /******************************************************************
2379 * DeletePrinterDriverW [WINSPOOL.@]
2382 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2384 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2387 /******************************************************************
2388 * DeleteMonitorA [WINSPOOL.@]
2390 * See DeleteMonitorW.
2393 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2395 LPWSTR nameW = NULL;
2396 LPWSTR EnvironmentW = NULL;
2397 LPWSTR MonitorNameW = NULL;
2402 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2403 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2404 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2408 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2409 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2410 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2413 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2414 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2415 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2418 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2420 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2421 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2422 HeapFree(GetProcessHeap(), 0, nameW);
2426 /******************************************************************
2427 * DeleteMonitorW [WINSPOOL.@]
2429 * Delete a specific Printmonitor from a Printing-Environment
2432 * pName [I] Servername or NULL (local Computer)
2433 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2434 * pMonitorName [I] Name of the Monitor, that should be deleted
2441 * pEnvironment is ignored in Windows for the local Computer.
2445 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2449 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2450 debugstr_w(pMonitorName));
2452 if (pName && (pName[0])) {
2453 FIXME("for server %s not implemented\n", debugstr_w(pName));
2454 SetLastError(ERROR_ACCESS_DENIED);
2458 /* pEnvironment is ignored in Windows for the local Computer */
2460 if (!pMonitorName || !pMonitorName[0]) {
2461 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2462 SetLastError(ERROR_INVALID_PARAMETER);
2466 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2467 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2471 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2472 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2477 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2480 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2481 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2485 /******************************************************************
2486 * DeletePortA [WINSPOOL.@]
2491 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2493 LPWSTR nameW = NULL;
2494 LPWSTR portW = NULL;
2498 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2500 /* convert servername to unicode */
2502 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2503 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2504 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2507 /* convert portname to unicode */
2509 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2510 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2511 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2514 res = DeletePortW(nameW, hWnd, portW);
2515 HeapFree(GetProcessHeap(), 0, nameW);
2516 HeapFree(GetProcessHeap(), 0, portW);
2520 /******************************************************************
2521 * DeletePortW [WINSPOOL.@]
2523 * Delete a specific Port
2526 * pName [I] Servername or NULL (local Computer)
2527 * hWnd [I] Handle to parent Window for the Dialog-Box
2528 * pPortName [I] Name of the Port, that should be deleted
2535 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2541 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2543 if (pName && pName[0]) {
2544 SetLastError(ERROR_INVALID_PARAMETER);
2549 SetLastError(RPC_X_NULL_REF_POINTER);
2553 /* an empty Portname is Invalid */
2554 if (!pPortName[0]) {
2555 SetLastError(ERROR_NOT_SUPPORTED);
2559 pm = monitor_load_by_port(pPortName);
2560 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2561 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2562 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2563 TRACE("got %d with %u\n", res, GetLastError());
2567 pui = monitor_loadui(pm);
2568 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2569 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2570 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2571 TRACE("got %d with %u\n", res, GetLastError());
2575 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2576 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2578 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2579 SetLastError(ERROR_NOT_SUPPORTED);
2582 monitor_unload(pui);
2586 TRACE("returning %d with %u\n", res, GetLastError());
2590 /******************************************************************************
2591 * SetPrinterW [WINSPOOL.@]
2593 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2595 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2596 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2600 /******************************************************************************
2601 * WritePrinter [WINSPOOL.@]
2603 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2605 opened_printer_t *printer;
2608 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2610 EnterCriticalSection(&printer_handles_cs);
2611 printer = get_opened_printer(hPrinter);
2614 SetLastError(ERROR_INVALID_HANDLE);
2620 SetLastError(ERROR_SPL_NO_STARTDOC);
2624 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2626 LeaveCriticalSection(&printer_handles_cs);
2630 /*****************************************************************************
2631 * AddFormA [WINSPOOL.@]
2633 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2635 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2639 /*****************************************************************************
2640 * AddFormW [WINSPOOL.@]
2642 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2644 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2648 /*****************************************************************************
2649 * AddJobA [WINSPOOL.@]
2651 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2654 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2658 SetLastError(ERROR_INVALID_LEVEL);
2662 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2665 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2666 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2667 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2668 if(*pcbNeeded > cbBuf) {
2669 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2672 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2673 addjobA->JobId = addjobW->JobId;
2674 addjobA->Path = (char *)(addjobA + 1);
2675 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2681 /*****************************************************************************
2682 * AddJobW [WINSPOOL.@]
2684 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2686 opened_printer_t *printer;
2689 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2690 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2691 WCHAR path[MAX_PATH], filename[MAX_PATH];
2693 ADDJOB_INFO_1W *addjob;
2695 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2697 EnterCriticalSection(&printer_handles_cs);
2699 printer = get_opened_printer(hPrinter);
2702 SetLastError(ERROR_INVALID_HANDLE);
2707 SetLastError(ERROR_INVALID_LEVEL);
2711 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2715 job->job_id = InterlockedIncrement(&next_job_id);
2717 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2718 if(path[len - 1] != '\\')
2720 memcpy(path + len, spool_path, sizeof(spool_path));
2721 sprintfW(filename, fmtW, path, job->job_id);
2723 len = strlenW(filename);
2724 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2725 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2726 job->document_title = strdupW(default_doc_title);
2727 list_add_tail(&printer->queue->jobs, &job->entry);
2729 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2730 if(*pcbNeeded <= cbBuf) {
2731 addjob = (ADDJOB_INFO_1W*)pData;
2732 addjob->JobId = job->job_id;
2733 addjob->Path = (WCHAR *)(addjob + 1);
2734 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2737 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2740 LeaveCriticalSection(&printer_handles_cs);
2744 /*****************************************************************************
2745 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2747 * Return the PATH for the Print-Processors
2749 * See GetPrintProcessorDirectoryW.
2753 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2754 DWORD level, LPBYTE Info,
2755 DWORD cbBuf, LPDWORD pcbNeeded)
2757 LPWSTR serverW = NULL;
2762 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2763 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2767 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2768 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2769 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2773 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2774 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2775 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2778 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2779 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2781 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2784 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2785 cbBuf, NULL, NULL) > 0;
2788 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2789 HeapFree(GetProcessHeap(), 0, envW);
2790 HeapFree(GetProcessHeap(), 0, serverW);
2794 /*****************************************************************************
2795 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2797 * Return the PATH for the Print-Processors
2800 * server [I] Servername (NT only) or NULL (local Computer)
2801 * env [I] Printing-Environment (see below) or NULL (Default)
2802 * level [I] Structure-Level (must be 1)
2803 * Info [O] PTR to Buffer that receives the Result
2804 * cbBuf [I] Size of Buffer at "Info"
2805 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2806 * required for the Buffer at "Info"
2809 * Success: TRUE and in pcbNeeded the Bytes used in Info
2810 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2811 * if cbBuf is too small
2813 * Native Values returned in Info on Success:
2814 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2815 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2816 *| win9x(Windows 4.0): "%winsysdir%"
2818 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2821 * Only NULL or "" is supported for server
2824 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2825 DWORD level, LPBYTE Info,
2826 DWORD cbBuf, LPDWORD pcbNeeded)
2829 const printenv_t * env_t;
2831 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2832 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2834 if(server != NULL && server[0]) {
2835 FIXME("server not supported: %s\n", debugstr_w(server));
2836 SetLastError(ERROR_INVALID_PARAMETER);
2840 env_t = validate_envW(env);
2841 if(!env_t) return FALSE; /* environment invalid or unsupported */
2844 WARN("(Level: %d) is ignored in win9x\n", level);
2845 SetLastError(ERROR_INVALID_LEVEL);
2849 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2850 needed = GetSystemDirectoryW(NULL, 0);
2851 /* add the Size for the Subdirectories */
2852 needed += lstrlenW(spoolprtprocsW);
2853 needed += lstrlenW(env_t->subdir);
2854 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2856 if(pcbNeeded) *pcbNeeded = needed;
2857 TRACE ("required: 0x%x/%d\n", needed, needed);
2858 if (needed > cbBuf) {
2859 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2862 if(pcbNeeded == NULL) {
2863 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2864 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2865 SetLastError(RPC_X_NULL_REF_POINTER);
2869 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2870 SetLastError(RPC_X_NULL_REF_POINTER);
2874 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2875 /* add the Subdirectories */
2876 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2877 lstrcatW((LPWSTR) Info, env_t->subdir);
2878 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2882 /*****************************************************************************
2883 * WINSPOOL_OpenDriverReg [internal]
2885 * opens the registry for the printer drivers depending on the given input
2886 * variable pEnvironment
2889 * the opened hkey on success
2892 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2896 const printenv_t * env;
2899 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2901 if (!pEnvironment || unicode) {
2902 /* pEnvironment was NULL or an Unicode-String: use it direct */
2903 env = validate_envW(pEnvironment);
2907 /* pEnvironment was an ANSI-String: convert to unicode first */
2909 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2910 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2911 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2912 env = validate_envW(buffer);
2913 HeapFree(GetProcessHeap(), 0, buffer);
2915 if (!env) return NULL;
2917 buffer = HeapAlloc( GetProcessHeap(), 0,
2918 (strlenW(DriversW) + strlenW(env->envname) +
2919 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2921 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2922 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2923 HeapFree(GetProcessHeap(), 0, buffer);
2928 /*****************************************************************************
2929 * AddPrinterW [WINSPOOL.@]
2931 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2933 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2937 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2939 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2940 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2941 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2942 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2943 statusW[] = {'S','t','a','t','u','s',0},
2944 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2946 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2949 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2950 SetLastError(ERROR_INVALID_PARAMETER);
2954 ERR("Level = %d, unsupported!\n", Level);
2955 SetLastError(ERROR_INVALID_LEVEL);
2959 SetLastError(ERROR_INVALID_PARAMETER);
2962 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2964 ERR("Can't create Printers key\n");
2967 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2968 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2969 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2970 RegCloseKey(hkeyPrinter);
2971 RegCloseKey(hkeyPrinters);
2974 RegCloseKey(hkeyPrinter);
2976 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2978 ERR("Can't create Drivers key\n");
2979 RegCloseKey(hkeyPrinters);
2982 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2984 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2985 RegCloseKey(hkeyPrinters);
2986 RegCloseKey(hkeyDrivers);
2987 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2990 RegCloseKey(hkeyDriver);
2991 RegCloseKey(hkeyDrivers);
2993 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2994 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2995 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2996 RegCloseKey(hkeyPrinters);
3000 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3002 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3003 SetLastError(ERROR_INVALID_PRINTER_NAME);
3004 RegCloseKey(hkeyPrinters);
3007 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
3008 (LPBYTE)&pi->Attributes, sizeof(DWORD));
3009 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3011 /* See if we can load the driver. We may need the devmode structure anyway
3014 * Note that DocumentPropertiesW will briefly try to open the printer we
3015 * just create to find a DEVMODEA struct (it will use the WINEPS default
3016 * one in case it is not there, so we are ok).
3018 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3021 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3022 size = sizeof(DEVMODEW);
3028 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3030 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
3032 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3033 HeapFree(GetProcessHeap(),0,dmW);
3038 /* set devmode to printer name */
3039 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
3043 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3044 and we support these drivers. NT writes DEVMODEW so somehow
3045 we'll need to distinguish between these when we support NT
3049 dmA = DEVMODEdupWtoA(dmW);
3050 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
3051 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
3052 HeapFree(GetProcessHeap(), 0, dmA);
3054 HeapFree(GetProcessHeap(), 0, dmW);
3056 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3057 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3058 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3059 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3061 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3062 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3063 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3064 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
3065 (LPBYTE)&pi->Priority, sizeof(DWORD));
3066 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3067 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3068 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
3069 (LPBYTE)&pi->StartTime, sizeof(DWORD));
3070 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
3071 (LPBYTE)&pi->Status, sizeof(DWORD));
3072 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
3073 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
3075 RegCloseKey(hkeyPrinter);
3076 RegCloseKey(hkeyPrinters);
3077 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3078 ERR("OpenPrinter failing\n");
3084 /*****************************************************************************
3085 * AddPrinterA [WINSPOOL.@]
3087 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3089 UNICODE_STRING pNameW;
3091 PRINTER_INFO_2W *piW;
3092 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3095 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
3097 ERR("Level = %d, unsupported!\n", Level);
3098 SetLastError(ERROR_INVALID_LEVEL);
3101 pwstrNameW = asciitounicode(&pNameW,pName);
3102 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3104 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3106 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3107 RtlFreeUnicodeString(&pNameW);
3112 /*****************************************************************************
3113 * ClosePrinter [WINSPOOL.@]
3115 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3117 UINT_PTR i = (UINT_PTR)hPrinter;
3118 opened_printer_t *printer = NULL;
3121 TRACE("(%p)\n", hPrinter);
3123 EnterCriticalSection(&printer_handles_cs);
3125 if ((i > 0) && (i <= nb_printer_handles))
3126 printer = printer_handles[i - 1];
3131 struct list *cursor, *cursor2;
3133 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3134 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3135 printer->hXcv, debugstr_w(printer->name), printer->doc );
3138 EndDocPrinter(hPrinter);
3140 if(InterlockedDecrement(&printer->queue->ref) == 0)
3142 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3144 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3145 ScheduleJob(hPrinter, job->job_id);
3147 HeapFree(GetProcessHeap(), 0, printer->queue);
3149 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3150 monitor_unload(printer->pm);
3151 HeapFree(GetProcessHeap(), 0, printer->printername);
3152 HeapFree(GetProcessHeap(), 0, printer->name);
3153 HeapFree(GetProcessHeap(), 0, printer);
3154 printer_handles[i - 1] = NULL;
3157 LeaveCriticalSection(&printer_handles_cs);
3161 /*****************************************************************************
3162 * DeleteFormA [WINSPOOL.@]
3164 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3166 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3170 /*****************************************************************************
3171 * DeleteFormW [WINSPOOL.@]
3173 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3175 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3179 /*****************************************************************************
3180 * DeletePrinter [WINSPOOL.@]
3182 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3184 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3185 HKEY hkeyPrinters, hkey;
3188 SetLastError(ERROR_INVALID_HANDLE);
3191 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3192 RegDeleteTreeW(hkeyPrinters, lpNameW);
3193 RegCloseKey(hkeyPrinters);
3195 WriteProfileStringW(devicesW, lpNameW, NULL);
3196 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3198 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3199 RegDeleteValueW(hkey, lpNameW);
3203 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3204 RegDeleteValueW(hkey, lpNameW);
3210 /*****************************************************************************
3211 * SetPrinterA [WINSPOOL.@]
3213 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3216 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3220 /*****************************************************************************
3221 * SetJobA [WINSPOOL.@]
3223 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3224 LPBYTE pJob, DWORD Command)
3228 UNICODE_STRING usBuffer;
3230 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3232 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3233 are all ignored by SetJob, so we don't bother copying them */
3241 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3242 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3244 JobW = (LPBYTE)info1W;
3245 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3246 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3247 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3248 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3249 info1W->Status = info1A->Status;
3250 info1W->Priority = info1A->Priority;
3251 info1W->Position = info1A->Position;
3252 info1W->PagesPrinted = info1A->PagesPrinted;
3257 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3258 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3260 JobW = (LPBYTE)info2W;
3261 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3262 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3263 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3264 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3265 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3266 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3267 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3268 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3269 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3270 info2W->Status = info2A->Status;
3271 info2W->Priority = info2A->Priority;
3272 info2W->Position = info2A->Position;
3273 info2W->StartTime = info2A->StartTime;
3274 info2W->UntilTime = info2A->UntilTime;
3275 info2W->PagesPrinted = info2A->PagesPrinted;
3279 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3280 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3283 SetLastError(ERROR_INVALID_LEVEL);
3287 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3293 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3294 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3295 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3296 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3297 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3302 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3303 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3304 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3305 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3306 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3307 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3308 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3309 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3310 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3314 HeapFree(GetProcessHeap(), 0, JobW);
3319 /*****************************************************************************
3320 * SetJobW [WINSPOOL.@]
3322 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3323 LPBYTE pJob, DWORD Command)
3328 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3329 FIXME("Ignoring everything other than document title\n");
3331 EnterCriticalSection(&printer_handles_cs);
3332 job = get_job(hPrinter, JobId);
3342 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3343 HeapFree(GetProcessHeap(), 0, job->document_title);
3344 job->document_title = strdupW(info1->pDocument);
3349 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3350 HeapFree(GetProcessHeap(), 0, job->document_title);
3351 job->document_title = strdupW(info2->pDocument);
3357 SetLastError(ERROR_INVALID_LEVEL);
3362 LeaveCriticalSection(&printer_handles_cs);
3366 /*****************************************************************************
3367 * EndDocPrinter [WINSPOOL.@]
3369 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3371 opened_printer_t *printer;
3373 TRACE("(%p)\n", hPrinter);
3375 EnterCriticalSection(&printer_handles_cs);
3377 printer = get_opened_printer(hPrinter);
3380 SetLastError(ERROR_INVALID_HANDLE);
3386 SetLastError(ERROR_SPL_NO_STARTDOC);
3390 CloseHandle(printer->doc->hf);
3391 ScheduleJob(hPrinter, printer->doc->job_id);
3392 HeapFree(GetProcessHeap(), 0, printer->doc);
3393 printer->doc = NULL;
3396 LeaveCriticalSection(&printer_handles_cs);
3400 /*****************************************************************************
3401 * EndPagePrinter [WINSPOOL.@]
3403 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3405 FIXME("(%p): stub\n", hPrinter);
3409 /*****************************************************************************
3410 * StartDocPrinterA [WINSPOOL.@]
3412 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3414 UNICODE_STRING usBuffer;
3416 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3419 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3420 or one (DOC_INFO_3) extra DWORDs */
3424 doc2W.JobId = doc2->JobId;
3427 doc2W.dwMode = doc2->dwMode;
3430 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3431 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3432 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3436 SetLastError(ERROR_INVALID_LEVEL);
3440 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3442 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3443 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3444 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3449 /*****************************************************************************
3450 * StartDocPrinterW [WINSPOOL.@]
3452 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3454 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3455 opened_printer_t *printer;
3456 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3457 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3458 JOB_INFO_1W job_info;
3459 DWORD needed, ret = 0;
3463 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3464 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3465 debugstr_w(doc->pDatatype));
3467 if(Level < 1 || Level > 3)
3469 SetLastError(ERROR_INVALID_LEVEL);
3473 EnterCriticalSection(&printer_handles_cs);
3474 printer = get_opened_printer(hPrinter);
3477 SetLastError(ERROR_INVALID_HANDLE);
3483 SetLastError(ERROR_INVALID_PRINTER_STATE);
3487 /* Even if we're printing to a file we still add a print job, we'll
3488 just ignore the spool file name */
3490 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3492 ERR("AddJob failed gle %u\n", GetLastError());
3496 if(doc->pOutputFile)
3497 filename = doc->pOutputFile;
3499 filename = addjob->Path;
3501 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3502 if(hf == INVALID_HANDLE_VALUE)
3505 memset(&job_info, 0, sizeof(job_info));
3506 job_info.pDocument = doc->pDocName;
3507 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3509 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3510 printer->doc->hf = hf;
3511 ret = printer->doc->job_id = addjob->JobId;
3513 LeaveCriticalSection(&printer_handles_cs);
3518 /*****************************************************************************
3519 * StartPagePrinter [WINSPOOL.@]
3521 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3523 FIXME("(%p): stub\n", hPrinter);
3527 /*****************************************************************************
3528 * GetFormA [WINSPOOL.@]
3530 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3531 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3533 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3534 Level,pForm,cbBuf,pcbNeeded);
3538 /*****************************************************************************
3539 * GetFormW [WINSPOOL.@]
3541 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3542 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3544 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3545 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3549 /*****************************************************************************
3550 * SetFormA [WINSPOOL.@]
3552 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3555 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3559 /*****************************************************************************
3560 * SetFormW [WINSPOOL.@]
3562 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3565 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3569 /*****************************************************************************
3570 * ReadPrinter [WINSPOOL.@]
3572 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3573 LPDWORD pNoBytesRead)
3575 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3579 /*****************************************************************************
3580 * ResetPrinterA [WINSPOOL.@]
3582 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3584 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3588 /*****************************************************************************
3589 * ResetPrinterW [WINSPOOL.@]
3591 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3593 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3597 /*****************************************************************************
3598 * WINSPOOL_GetDWORDFromReg
3600 * Return DWORD associated with ValueName from hkey.
3602 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3604 DWORD sz = sizeof(DWORD), type, value = 0;
3607 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3609 if(ret != ERROR_SUCCESS) {
3610 WARN("Got ret = %d on name %s\n", ret, ValueName);
3613 if(type != REG_DWORD) {
3614 ERR("Got type %d\n", type);
3621 /*****************************************************************************
3622 * get_filename_from_reg [internal]
3624 * Get ValueName from hkey storing result in out
3625 * when the Value in the registry has only a filename, use driverdir as prefix
3626 * outlen is space left in out
3627 * String is stored either as unicode or ascii
3631 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3632 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3634 WCHAR filename[MAX_PATH];
3638 LPWSTR buffer = filename;
3642 size = sizeof(filename);
3644 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3645 if (ret == ERROR_MORE_DATA) {
3646 TRACE("need dynamic buffer: %u\n", size);
3647 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3649 /* No Memory is bad */
3653 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3656 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3657 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3663 /* do we have a full path ? */
3664 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3665 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3668 /* we must build the full Path */
3670 if ((out) && (outlen > dirlen)) {
3672 lstrcpyW((LPWSTR)out, driverdir);
3676 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3685 /* write the filename */
3687 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3688 if ((out) && (outlen >= size)) {
3689 lstrcpyW((LPWSTR)out, ptr);
3698 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3699 if ((out) && (outlen >= size)) {
3700 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3708 ptr += lstrlenW(ptr)+1;
3709 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3712 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3714 /* write the multisz-termination */
3715 if (type == REG_MULTI_SZ) {
3716 size = (unicode) ? sizeof(WCHAR) : 1;
3719 if (out && (outlen >= size)) {
3720 memset (out, 0, size);
3726 /*****************************************************************************
3727 * WINSPOOL_GetStringFromReg
3729 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3730 * String is stored either as unicode or ascii.
3731 * Bit of a hack here to get the ValueName if we want ascii.
3733 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3734 DWORD buflen, DWORD *needed,
3737 DWORD sz = buflen, type;
3741 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3743 LPSTR ValueNameA = strdupWtoA(ValueName);
3744 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3745 HeapFree(GetProcessHeap(),0,ValueNameA);
3747 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3748 WARN("Got ret = %d\n", ret);
3752 /* add space for terminating '\0' */
3753 sz += unicode ? sizeof(WCHAR) : 1;
3757 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3762 /*****************************************************************************
3763 * WINSPOOL_GetDefaultDevMode
3765 * Get a default DevMode values for wineps.
3769 static void WINSPOOL_GetDefaultDevMode(
3771 DWORD buflen, DWORD *needed,
3775 static const char szwps[] = "wineps.drv";
3777 /* fill default DEVMODE - should be read from ppd... */
3778 ZeroMemory( &dm, sizeof(dm) );
3779 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3780 dm.dmSpecVersion = DM_SPECVERSION;
3781 dm.dmDriverVersion = 1;
3782 dm.dmSize = sizeof(DEVMODEA);
3783 dm.dmDriverExtra = 0;
3785 DM_ORIENTATION | DM_PAPERSIZE |
3786 DM_PAPERLENGTH | DM_PAPERWIDTH |
3789 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3790 DM_YRESOLUTION | DM_TTOPTION;
3792 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3793 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3794 dm.u1.s1.dmPaperLength = 2970;
3795 dm.u1.s1.dmPaperWidth = 2100;
3797 dm.u1.s1.dmScale = 100;
3798 dm.u1.s1.dmCopies = 1;
3799 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3800 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3803 dm.dmYResolution = 300; /* 300dpi */
3804 dm.dmTTOption = DMTT_BITMAP;
3807 /* dm.dmLogPixels */
3808 /* dm.dmBitsPerPel */
3809 /* dm.dmPelsWidth */
3810 /* dm.dmPelsHeight */
3811 /* dm.u2.dmDisplayFlags */
3812 /* dm.dmDisplayFrequency */
3813 /* dm.dmICMMethod */
3814 /* dm.dmICMIntent */
3815 /* dm.dmMediaType */
3816 /* dm.dmDitherType */
3817 /* dm.dmReserved1 */
3818 /* dm.dmReserved2 */
3819 /* dm.dmPanningWidth */
3820 /* dm.dmPanningHeight */
3823 if(buflen >= sizeof(DEVMODEW)) {
3824 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3825 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3826 HeapFree(GetProcessHeap(),0,pdmW);
3828 *needed = sizeof(DEVMODEW);
3832 if(buflen >= sizeof(DEVMODEA)) {
3833 memcpy(ptr, &dm, sizeof(DEVMODEA));
3835 *needed = sizeof(DEVMODEA);
3839 /*****************************************************************************
3840 * WINSPOOL_GetDevModeFromReg
3842 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3843 * DevMode is stored either as unicode or ascii.
3845 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3847 DWORD buflen, DWORD *needed,
3850 DWORD sz = buflen, type;
3853 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3854 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3855 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3856 if (sz < sizeof(DEVMODEA))
3858 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3861 /* ensures that dmSize is not erratically bogus if registry is invalid */
3862 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3863 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3865 sz += (CCHDEVICENAME + CCHFORMNAME);
3867 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3868 memcpy(ptr, dmW, sz);
3869 HeapFree(GetProcessHeap(),0,dmW);
3876 /*********************************************************************
3877 * WINSPOOL_GetPrinter_1
3879 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3880 * The strings are either stored as unicode or ascii.
3882 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3883 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3886 DWORD size, left = cbBuf;
3887 BOOL space = (cbBuf > 0);
3892 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3894 if(space && size <= left) {
3895 pi1->pName = (LPWSTR)ptr;
3903 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3904 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3906 if(space && size <= left) {
3907 pi1->pDescription = (LPWSTR)ptr;
3915 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3917 if(space && size <= left) {
3918 pi1->pComment = (LPWSTR)ptr;
3926 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3928 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3929 memset(pi1, 0, sizeof(*pi1));
3933 /*********************************************************************
3934 * WINSPOOL_GetPrinter_2
3936 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3937 * The strings are either stored as unicode or ascii.
3939 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3940 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3943 DWORD size, left = cbBuf;
3944 BOOL space = (cbBuf > 0);
3949 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3951 if(space && size <= left) {
3952 pi2->pPrinterName = (LPWSTR)ptr;
3959 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3961 if(space && size <= left) {
3962 pi2->pShareName = (LPWSTR)ptr;
3969 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3971 if(space && size <= left) {
3972 pi2->pPortName = (LPWSTR)ptr;
3979 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3981 if(space && size <= left) {
3982 pi2->pDriverName = (LPWSTR)ptr;
3989 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3991 if(space && size <= left) {
3992 pi2->pComment = (LPWSTR)ptr;
3999 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
4001 if(space && size <= left) {
4002 pi2->pLocation = (LPWSTR)ptr;
4009 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
4011 if(space && size <= left) {
4012 pi2->pDevMode = (LPDEVMODEW)ptr;
4021 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
4022 if(space && size <= left) {
4023 pi2->pDevMode = (LPDEVMODEW)ptr;
4030 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
4032 if(space && size <= left) {
4033 pi2->pSepFile = (LPWSTR)ptr;
4040 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
4042 if(space && size <= left) {
4043 pi2->pPrintProcessor = (LPWSTR)ptr;
4050 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
4052 if(space && size <= left) {
4053 pi2->pDatatype = (LPWSTR)ptr;
4060 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
4062 if(space && size <= left) {
4063 pi2->pParameters = (LPWSTR)ptr;
4071 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4072 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
4073 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4074 "Default Priority");
4075 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
4076 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
4079 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4080 memset(pi2, 0, sizeof(*pi2));
4085 /*********************************************************************
4086 * WINSPOOL_GetPrinter_4
4088 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4090 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4091 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4094 DWORD size, left = cbBuf;
4095 BOOL space = (cbBuf > 0);
4100 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4102 if(space && size <= left) {
4103 pi4->pPrinterName = (LPWSTR)ptr;
4111 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4114 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4115 memset(pi4, 0, sizeof(*pi4));
4120 /*********************************************************************
4121 * WINSPOOL_GetPrinter_5
4123 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4125 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4126 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4129 DWORD size, left = cbBuf;
4130 BOOL space = (cbBuf > 0);
4135 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4137 if(space && size <= left) {
4138 pi5->pPrinterName = (LPWSTR)ptr;
4145 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4147 if(space && size <= left) {
4148 pi5->pPortName = (LPWSTR)ptr;
4156 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4157 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4159 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4163 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4164 memset(pi5, 0, sizeof(*pi5));
4169 /*********************************************************************
4170 * WINSPOOL_GetPrinter_7
4172 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4174 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4175 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4177 DWORD size, left = cbBuf;
4178 BOOL space = (cbBuf > 0);
4183 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4185 if (space && size <= left) {
4186 pi7->pszObjectGUID = (LPWSTR)ptr;
4194 /* We do not have a Directory Service */
4195 pi7->dwAction = DSPRINT_UNPUBLISH;
4198 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4199 memset(pi7, 0, sizeof(*pi7));
4204 /*********************************************************************
4205 * WINSPOOL_GetPrinter_9
4207 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4208 * The strings are either stored as unicode or ascii.
4210 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4211 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4214 BOOL space = (cbBuf > 0);
4218 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4219 if(space && size <= cbBuf) {
4220 pi9->pDevMode = (LPDEVMODEW)buf;
4227 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4228 if(space && size <= cbBuf) {
4229 pi9->pDevMode = (LPDEVMODEW)buf;
4235 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4236 memset(pi9, 0, sizeof(*pi9));
4241 /*****************************************************************************
4242 * WINSPOOL_GetPrinter
4244 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4245 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4246 * just a collection of pointers to strings.
4248 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4249 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4252 DWORD size, needed = 0;
4254 HKEY hkeyPrinter, hkeyPrinters;
4257 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4259 if (!(name = get_opened_printer_name(hPrinter))) {
4260 SetLastError(ERROR_INVALID_HANDLE);
4264 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4266 ERR("Can't create Printers key\n");
4269 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4271 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4272 RegCloseKey(hkeyPrinters);
4273 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4280 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4282 size = sizeof(PRINTER_INFO_2W);
4284 ptr = pPrinter + size;
4286 memset(pPrinter, 0, size);
4291 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4299 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4301 size = sizeof(PRINTER_INFO_4W);
4303 ptr = pPrinter + size;
4305 memset(pPrinter, 0, size);
4310 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4319 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4321 size = sizeof(PRINTER_INFO_5W);
4323 ptr = pPrinter + size;
4325 memset(pPrinter, 0, size);
4331 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4340 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4342 size = sizeof(PRINTER_INFO_6);
4343 if (size <= cbBuf) {
4344 /* FIXME: We do not update the status yet */
4345 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4357 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4359 size = sizeof(PRINTER_INFO_7W);
4360 if (size <= cbBuf) {
4361 ptr = pPrinter + size;
4363 memset(pPrinter, 0, size);
4369 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4377 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4379 size = sizeof(PRINTER_INFO_9W);
4381 ptr = pPrinter + size;
4383 memset(pPrinter, 0, size);
4389 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4396 FIXME("Unimplemented level %d\n", Level);
4397 SetLastError(ERROR_INVALID_LEVEL);
4398 RegCloseKey(hkeyPrinters);
4399 RegCloseKey(hkeyPrinter);
4403 RegCloseKey(hkeyPrinter);
4404 RegCloseKey(hkeyPrinters);
4406 TRACE("returning %d needed = %d\n", ret, needed);
4407 if(pcbNeeded) *pcbNeeded = needed;
4409 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4413 /*****************************************************************************
4414 * GetPrinterW [WINSPOOL.@]
4416 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4417 DWORD cbBuf, LPDWORD pcbNeeded)
4419 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4423 /*****************************************************************************
4424 * GetPrinterA [WINSPOOL.@]
4426 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4427 DWORD cbBuf, LPDWORD pcbNeeded)
4429 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4433 /*****************************************************************************
4434 * WINSPOOL_EnumPrinters
4436 * Implementation of EnumPrintersA|W
4438 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4439 DWORD dwLevel, LPBYTE lpbPrinters,
4440 DWORD cbBuf, LPDWORD lpdwNeeded,
4441 LPDWORD lpdwReturned, BOOL unicode)
4444 HKEY hkeyPrinters, hkeyPrinter;
4445 WCHAR PrinterName[255];
4446 DWORD needed = 0, number = 0;
4447 DWORD used, i, left;
4451 memset(lpbPrinters, 0, cbBuf);
4457 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4458 if(dwType == PRINTER_ENUM_DEFAULT)
4461 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4462 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4463 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4465 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4473 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4474 FIXME("dwType = %08x\n", dwType);
4475 SetLastError(ERROR_INVALID_FLAGS);
4479 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4481 ERR("Can't create Printers key\n");
4485 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4486 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4487 RegCloseKey(hkeyPrinters);
4488 ERR("Can't query Printers key\n");
4491 TRACE("Found %d printers\n", number);
4495 used = number * sizeof(PRINTER_INFO_1W);
4498 used = number * sizeof(PRINTER_INFO_2W);
4501 used = number * sizeof(PRINTER_INFO_4W);
4504 used = number * sizeof(PRINTER_INFO_5W);
4508 SetLastError(ERROR_INVALID_LEVEL);
4509 RegCloseKey(hkeyPrinters);
4512 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4514 for(i = 0; i < number; i++) {
4515 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4517 ERR("Can't enum key number %d\n", i);
4518 RegCloseKey(hkeyPrinters);
4521 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4522 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4524 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4525 RegCloseKey(hkeyPrinters);
4530 buf = lpbPrinters + used;
4531 left = cbBuf - used;
4539 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4540 left, &needed, unicode);
4542 if(pi) pi += sizeof(PRINTER_INFO_1W);
4545 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4546 left, &needed, unicode);
4548 if(pi) pi += sizeof(PRINTER_INFO_2W);
4551 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4552 left, &needed, unicode);
4554 if(pi) pi += sizeof(PRINTER_INFO_4W);
4557 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4558 left, &needed, unicode);
4560 if(pi) pi += sizeof(PRINTER_INFO_5W);
4563 ERR("Shouldn't be here!\n");
4564 RegCloseKey(hkeyPrinter);
4565 RegCloseKey(hkeyPrinters);
4568 RegCloseKey(hkeyPrinter);
4570 RegCloseKey(hkeyPrinters);
4577 memset(lpbPrinters, 0, cbBuf);
4578 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4582 *lpdwReturned = number;
4583 SetLastError(ERROR_SUCCESS);
4588 /******************************************************************
4589 * EnumPrintersW [WINSPOOL.@]
4591 * Enumerates the available printers, print servers and print
4592 * providers, depending on the specified flags, name and level.
4596 * If level is set to 1:
4597 * Returns an array of PRINTER_INFO_1 data structures in the
4598 * lpbPrinters buffer.
4600 * If level is set to 2:
4601 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4602 * Returns an array of PRINTER_INFO_2 data structures in the
4603 * lpbPrinters buffer. Note that according to MSDN also an
4604 * OpenPrinter should be performed on every remote printer.
4606 * If level is set to 4 (officially WinNT only):
4607 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4608 * Fast: Only the registry is queried to retrieve printer names,
4609 * no connection to the driver is made.
4610 * Returns an array of PRINTER_INFO_4 data structures in the
4611 * lpbPrinters buffer.
4613 * If level is set to 5 (officially WinNT4/Win9x only):
4614 * Fast: Only the registry is queried to retrieve printer names,
4615 * no connection to the driver is made.
4616 * Returns an array of PRINTER_INFO_5 data structures in the
4617 * lpbPrinters buffer.
4619 * If level set to 3 or 6+:
4620 * returns zero (failure!)
4622 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4626 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4627 * - Only levels 2, 4 and 5 are implemented at the moment.
4628 * - 16-bit printer drivers are not enumerated.
4629 * - Returned amount of bytes used/needed does not match the real Windoze
4630 * implementation (as in this implementation, all strings are part
4631 * of the buffer, whereas Win32 keeps them somewhere else)
4632 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4635 * - In a regular Wine installation, no registry settings for printers
4636 * exist, which makes this function return an empty list.
4638 BOOL WINAPI EnumPrintersW(
4639 DWORD dwType, /* [in] Types of print objects to enumerate */
4640 LPWSTR lpszName, /* [in] name of objects to enumerate */
4641 DWORD dwLevel, /* [in] type of printer info structure */
4642 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4643 DWORD cbBuf, /* [in] max size of buffer in bytes */
4644 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4645 LPDWORD lpdwReturned /* [out] number of entries returned */
4648 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4649 lpdwNeeded, lpdwReturned, TRUE);
4652 /******************************************************************
4653 * EnumPrintersA [WINSPOOL.@]
4658 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4659 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4662 UNICODE_STRING pNameU;
4666 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4667 pPrinters, cbBuf, pcbNeeded, pcReturned);
4669 pNameW = asciitounicode(&pNameU, pName);
4671 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4672 MS Office need this */
4673 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4675 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4677 RtlFreeUnicodeString(&pNameU);
4679 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4681 HeapFree(GetProcessHeap(), 0, pPrintersW);
4685 /*****************************************************************************
4686 * WINSPOOL_GetDriverInfoFromReg [internal]
4688 * Enters the information from the registry into the DRIVER_INFO struct
4691 * zero if the printer driver does not exist in the registry
4692 * (only if Level > 1) otherwise nonzero
4694 static BOOL WINSPOOL_GetDriverInfoFromReg(
4697 const printenv_t * env,
4699 LPBYTE ptr, /* DRIVER_INFO */
4700 LPBYTE pDriverStrings, /* strings buffer */
4701 DWORD cbBuf, /* size of string buffer */
4702 LPDWORD pcbNeeded, /* space needed for str. */
4703 BOOL unicode) /* type of strings */
4707 WCHAR driverdir[MAX_PATH];
4709 LPBYTE strPtr = pDriverStrings;
4710 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4712 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4713 debugstr_w(DriverName), env,
4714 Level, di, pDriverStrings, cbBuf, unicode);
4716 if (di) ZeroMemory(di, di_sizeof[Level]);
4719 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4720 if (*pcbNeeded <= cbBuf)
4721 strcpyW((LPWSTR)strPtr, DriverName);
4725 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4726 if (*pcbNeeded <= cbBuf)
4727 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4730 /* pName for level 1 has a different offset! */
4732 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4736 /* .cVersion and .pName for level > 1 */
4738 di->cVersion = env->driverversion;
4739 di->pName = (LPWSTR) strPtr;
4740 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4743 /* Reserve Space for the largest subdir and a Backslash*/
4744 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4745 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4746 /* Should never Fail */
4749 lstrcatW(driverdir, env->versionsubdir);
4750 lstrcatW(driverdir, backslashW);
4752 /* dirlen must not include the terminating zero */
4753 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4754 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4756 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4757 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4758 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4764 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4766 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4769 if (*pcbNeeded <= cbBuf) {
4771 lstrcpyW((LPWSTR)strPtr, env->envname);
4775 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4777 if (di) di->pEnvironment = (LPWSTR)strPtr;
4778 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4781 /* .pDriverPath is the Graphics rendering engine.
4782 The full Path is required to avoid a crash in some apps */
4783 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4785 if (*pcbNeeded <= cbBuf)
4786 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4788 if (di) di->pDriverPath = (LPWSTR)strPtr;
4789 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4792 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4793 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4795 if (*pcbNeeded <= cbBuf)
4796 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4798 if (di) di->pDataFile = (LPWSTR)strPtr;
4799 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4802 /* .pConfigFile is the Driver user Interface */
4803 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4805 if (*pcbNeeded <= cbBuf)
4806 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4808 if (di) di->pConfigFile = (LPWSTR)strPtr;
4809 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4813 RegCloseKey(hkeyDriver);
4814 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4819 RegCloseKey(hkeyDriver);
4820 FIXME("level 5: incomplete\n");
4825 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4827 if (*pcbNeeded <= cbBuf)
4828 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4830 if (di) di->pHelpFile = (LPWSTR)strPtr;
4831 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4834 /* .pDependentFiles */
4835 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4837 if (*pcbNeeded <= cbBuf)
4838 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4840 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4841 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4843 else if (GetVersion() & 0x80000000) {
4844 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4845 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4847 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4849 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4850 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4853 /* .pMonitorName is the optional Language Monitor */
4854 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4856 if (*pcbNeeded <= cbBuf)
4857 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4859 if (di) di->pMonitorName = (LPWSTR)strPtr;
4860 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4863 /* .pDefaultDataType */
4864 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4866 if(*pcbNeeded <= cbBuf)
4867 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4869 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4870 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4874 RegCloseKey(hkeyDriver);
4875 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4879 /* .pszzPreviousNames */
4880 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4882 if(*pcbNeeded <= cbBuf)
4883 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4885 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4886 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4890 RegCloseKey(hkeyDriver);
4891 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4895 /* support is missing, but not important enough for a FIXME */
4896 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4899 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4901 if(*pcbNeeded <= cbBuf)
4902 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4904 if (di) di->pszMfgName = (LPWSTR)strPtr;
4905 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4909 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4911 if(*pcbNeeded <= cbBuf)
4912 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4914 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4915 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4918 /* .pszHardwareID */
4919 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4921 if(*pcbNeeded <= cbBuf)
4922 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4924 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4925 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4929 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4931 if(*pcbNeeded <= cbBuf)
4932 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4934 if (di) di->pszProvider = (LPWSTR)strPtr;
4935 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4939 RegCloseKey(hkeyDriver);
4943 /* support is missing, but not important enough for a FIXME */
4944 TRACE("level 8: incomplete\n");
4946 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4947 RegCloseKey(hkeyDriver);
4951 /*****************************************************************************
4952 * WINSPOOL_GetPrinterDriver
4954 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4955 DWORD Level, LPBYTE pDriverInfo,
4956 DWORD cbBuf, LPDWORD pcbNeeded,
4960 WCHAR DriverName[100];
4961 DWORD ret, type, size, needed = 0;
4963 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4964 const printenv_t * env;
4966 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4967 Level,pDriverInfo,cbBuf, pcbNeeded);
4970 if (!(name = get_opened_printer_name(hPrinter))) {
4971 SetLastError(ERROR_INVALID_HANDLE);
4975 if (Level < 1 || Level == 7 || Level > 8) {
4976 SetLastError(ERROR_INVALID_LEVEL);
4980 env = validate_envW(pEnvironment);
4981 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4983 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4985 ERR("Can't create Printers key\n");
4988 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4990 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4991 RegCloseKey(hkeyPrinters);
4992 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4995 size = sizeof(DriverName);
4997 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4998 (LPBYTE)DriverName, &size);
4999 RegCloseKey(hkeyPrinter);
5000 RegCloseKey(hkeyPrinters);
5001 if(ret != ERROR_SUCCESS) {
5002 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5006 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
5008 ERR("Can't create Drivers key\n");
5012 size = di_sizeof[Level];
5013 if ((size <= cbBuf) && pDriverInfo)
5014 ptr = pDriverInfo + size;
5016 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5017 env, Level, pDriverInfo, ptr,
5018 (cbBuf < size) ? 0 : cbBuf - size,
5019 &needed, unicode)) {
5020 RegCloseKey(hkeyDrivers);
5024 RegCloseKey(hkeyDrivers);
5026 if(pcbNeeded) *pcbNeeded = size + needed;
5027 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5028 if(cbBuf >= needed) return TRUE;
5029 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5033 /*****************************************************************************
5034 * GetPrinterDriverA [WINSPOOL.@]
5036 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5037 DWORD Level, LPBYTE pDriverInfo,
5038 DWORD cbBuf, LPDWORD pcbNeeded)
5041 UNICODE_STRING pEnvW;
5044 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5045 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
5046 cbBuf, pcbNeeded, FALSE);
5047 RtlFreeUnicodeString(&pEnvW);
5050 /*****************************************************************************
5051 * GetPrinterDriverW [WINSPOOL.@]
5053 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5054 DWORD Level, LPBYTE pDriverInfo,
5055 DWORD cbBuf, LPDWORD pcbNeeded)
5057 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
5058 pDriverInfo, cbBuf, pcbNeeded, TRUE);
5061 /*****************************************************************************
5062 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5064 * Return the PATH for the Printer-Drivers (UNICODE)
5067 * pName [I] Servername (NT only) or NULL (local Computer)
5068 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5069 * Level [I] Structure-Level (must be 1)
5070 * pDriverDirectory [O] PTR to Buffer that receives the Result
5071 * cbBuf [I] Size of Buffer at pDriverDirectory
5072 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5073 * required for pDriverDirectory
5076 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5077 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5078 * if cbBuf is too small
5080 * Native Values returned in pDriverDirectory on Success:
5081 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5082 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5083 *| win9x(Windows 4.0): "%winsysdir%"
5085 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5088 *- Only NULL or "" is supported for pName
5091 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5092 DWORD Level, LPBYTE pDriverDirectory,
5093 DWORD cbBuf, LPDWORD pcbNeeded)
5095 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5096 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5098 if ((backend == NULL) && !load_backend()) return FALSE;
5101 /* (Level != 1) is ignored in win9x */
5102 SetLastError(ERROR_INVALID_LEVEL);
5105 if (pcbNeeded == NULL) {
5106 /* (pcbNeeded == NULL) is ignored in win9x */
5107 SetLastError(RPC_X_NULL_REF_POINTER);
5111 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5112 pDriverDirectory, cbBuf, pcbNeeded);
5117 /*****************************************************************************
5118 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5120 * Return the PATH for the Printer-Drivers (ANSI)
5122 * See GetPrinterDriverDirectoryW.
5125 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5128 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5129 DWORD Level, LPBYTE pDriverDirectory,
5130 DWORD cbBuf, LPDWORD pcbNeeded)
5132 UNICODE_STRING nameW, environmentW;
5135 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5136 WCHAR *driverDirectoryW = NULL;
5138 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5139 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5141 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5143 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5144 else nameW.Buffer = NULL;
5145 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5146 else environmentW.Buffer = NULL;
5148 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5149 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5152 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5153 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5155 *pcbNeeded = needed;
5156 ret = (needed <= cbBuf) ? TRUE : FALSE;
5158 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5160 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5162 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5163 RtlFreeUnicodeString(&environmentW);
5164 RtlFreeUnicodeString(&nameW);
5169 /*****************************************************************************
5170 * AddPrinterDriverA [WINSPOOL.@]
5172 * See AddPrinterDriverW.
5175 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5177 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5178 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5181 /******************************************************************************
5182 * AddPrinterDriverW (WINSPOOL.@)
5184 * Install a Printer Driver
5187 * pName [I] Servername or NULL (local Computer)
5188 * level [I] Level for the supplied DRIVER_INFO_*W struct
5189 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5196 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5198 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5199 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5202 /*****************************************************************************
5203 * AddPrintProcessorA [WINSPOOL.@]
5205 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5206 LPSTR pPrintProcessorName)
5208 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5209 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5213 /*****************************************************************************
5214 * AddPrintProcessorW [WINSPOOL.@]
5216 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5217 LPWSTR pPrintProcessorName)
5219 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5220 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5224 /*****************************************************************************
5225 * AddPrintProvidorA [WINSPOOL.@]
5227 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5229 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5233 /*****************************************************************************
5234 * AddPrintProvidorW [WINSPOOL.@]
5236 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5238 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5242 /*****************************************************************************
5243 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5245 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5246 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5248 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5249 pDevModeOutput, pDevModeInput);
5253 /*****************************************************************************
5254 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5256 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5257 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5259 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5260 pDevModeOutput, pDevModeInput);
5264 /*****************************************************************************
5265 * PrinterProperties [WINSPOOL.@]
5267 * Displays a dialog to set the properties of the printer.
5270 * nonzero on success or zero on failure
5273 * implemented as stub only
5275 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5276 HANDLE hPrinter /* [in] handle to printer object */
5278 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5279 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5283 /*****************************************************************************
5284 * EnumJobsA [WINSPOOL.@]
5287 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5288 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5291 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5292 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5294 if(pcbNeeded) *pcbNeeded = 0;
5295 if(pcReturned) *pcReturned = 0;
5300 /*****************************************************************************
5301 * EnumJobsW [WINSPOOL.@]
5304 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5305 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5308 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5309 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5311 if(pcbNeeded) *pcbNeeded = 0;
5312 if(pcReturned) *pcReturned = 0;
5316 /*****************************************************************************
5317 * WINSPOOL_EnumPrinterDrivers [internal]
5319 * Delivers information about all printer drivers installed on the
5320 * localhost or a given server
5323 * nonzero on success or zero on failure. If the buffer for the returned
5324 * information is too small the function will return an error
5327 * - only implemented for localhost, foreign hosts will return an error
5329 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5330 DWORD Level, LPBYTE pDriverInfo,
5331 DWORD cbBuf, LPDWORD pcbNeeded,
5332 LPDWORD pcReturned, BOOL unicode)
5335 DWORD i, needed, number = 0, size = 0;
5336 WCHAR DriverNameW[255];
5338 const printenv_t * env;
5340 TRACE("%s,%s,%d,%p,%d,%d\n",
5341 debugstr_w(pName), debugstr_w(pEnvironment),
5342 Level, pDriverInfo, cbBuf, unicode);
5344 /* check for local drivers */
5345 if((pName) && (pName[0])) {
5346 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5347 SetLastError(ERROR_ACCESS_DENIED);
5351 env = validate_envW(pEnvironment);
5352 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5354 /* check input parameter */
5355 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5356 SetLastError(ERROR_INVALID_LEVEL);
5360 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5361 SetLastError(RPC_X_NULL_REF_POINTER);
5365 /* initialize return values */
5367 memset( pDriverInfo, 0, cbBuf);
5371 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5373 ERR("Can't open Drivers key\n");
5377 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5378 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5379 RegCloseKey(hkeyDrivers);
5380 ERR("Can't query Drivers key\n");
5383 TRACE("Found %d Drivers\n", number);
5385 /* get size of single struct
5386 * unicode and ascii structure have the same size
5388 size = di_sizeof[Level];
5390 /* calculate required buffer size */
5391 *pcbNeeded = size * number;
5393 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5395 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5396 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5398 ERR("Can't enum key number %d\n", i);
5399 RegCloseKey(hkeyDrivers);
5402 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5404 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5405 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5406 &needed, unicode)) {
5407 RegCloseKey(hkeyDrivers);
5410 (*pcbNeeded) += needed;
5413 RegCloseKey(hkeyDrivers);
5415 if(cbBuf < *pcbNeeded){
5416 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5420 *pcReturned = number;
5424 /*****************************************************************************
5425 * EnumPrinterDriversW [WINSPOOL.@]
5427 * see function EnumPrinterDrivers for RETURNS, BUGS
5429 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5430 LPBYTE pDriverInfo, DWORD cbBuf,
5431 LPDWORD pcbNeeded, LPDWORD pcReturned)
5433 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5434 cbBuf, pcbNeeded, pcReturned, TRUE);
5437 /*****************************************************************************
5438 * EnumPrinterDriversA [WINSPOOL.@]
5440 * see function EnumPrinterDrivers for RETURNS, BUGS
5442 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5443 LPBYTE pDriverInfo, DWORD cbBuf,
5444 LPDWORD pcbNeeded, LPDWORD pcReturned)
5446 UNICODE_STRING pNameW, pEnvironmentW;
5447 PWSTR pwstrNameW, pwstrEnvironmentW;
5449 pwstrNameW = asciitounicode(&pNameW, pName);
5450 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5452 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5453 Level, pDriverInfo, cbBuf, pcbNeeded,
5455 RtlFreeUnicodeString(&pNameW);
5456 RtlFreeUnicodeString(&pEnvironmentW);
5461 /******************************************************************************
5462 * EnumPortsA (WINSPOOL.@)
5467 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5468 LPDWORD pcbNeeded, LPDWORD pcReturned)
5471 LPBYTE bufferW = NULL;
5472 LPWSTR nameW = NULL;
5474 DWORD numentries = 0;
5477 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5478 cbBuf, pcbNeeded, pcReturned);
5480 /* convert servername to unicode */
5482 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5483 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5484 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5486 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5487 needed = cbBuf * sizeof(WCHAR);
5488 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5489 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5491 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5492 if (pcbNeeded) needed = *pcbNeeded;
5493 /* HeapReAlloc return NULL, when bufferW was NULL */
5494 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5495 HeapAlloc(GetProcessHeap(), 0, needed);
5497 /* Try again with the large Buffer */
5498 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5500 needed = pcbNeeded ? *pcbNeeded : 0;
5501 numentries = pcReturned ? *pcReturned : 0;
5504 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5505 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5508 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5509 DWORD entrysize = 0;
5512 LPPORT_INFO_2W pi2w;
5513 LPPORT_INFO_2A pi2a;
5516 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5518 /* First pass: calculate the size for all Entries */
5519 pi2w = (LPPORT_INFO_2W) bufferW;
5520 pi2a = (LPPORT_INFO_2A) pPorts;
5522 while (index < numentries) {
5524 needed += entrysize; /* PORT_INFO_?A */
5525 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5527 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5528 NULL, 0, NULL, NULL);
5530 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5531 NULL, 0, NULL, NULL);
5532 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5533 NULL, 0, NULL, NULL);
5535 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5536 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5537 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5540 /* check for errors and quit on failure */
5541 if (cbBuf < needed) {
5542 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5546 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5547 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5548 cbBuf -= len ; /* free Bytes in the user-Buffer */
5549 pi2w = (LPPORT_INFO_2W) bufferW;
5550 pi2a = (LPPORT_INFO_2A) pPorts;
5552 /* Second Pass: Fill the User Buffer (if we have one) */
5553 while ((index < numentries) && pPorts) {
5555 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5556 pi2a->pPortName = ptr;
5557 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5558 ptr, cbBuf , NULL, NULL);
5562 pi2a->pMonitorName = ptr;
5563 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5564 ptr, cbBuf, NULL, NULL);
5568 pi2a->pDescription = ptr;
5569 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5570 ptr, cbBuf, NULL, NULL);
5574 pi2a->fPortType = pi2w->fPortType;
5575 pi2a->Reserved = 0; /* documented: "must be zero" */
5578 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5579 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5580 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5585 if (pcbNeeded) *pcbNeeded = needed;
5586 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5588 HeapFree(GetProcessHeap(), 0, nameW);
5589 HeapFree(GetProcessHeap(), 0, bufferW);
5591 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5592 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5598 /******************************************************************************
5599 * EnumPortsW (WINSPOOL.@)
5601 * Enumerate available Ports
5604 * name [I] Servername or NULL (local Computer)
5605 * level [I] Structure-Level (1 or 2)
5606 * buffer [O] PTR to Buffer that receives the Result
5607 * bufsize [I] Size of Buffer at buffer
5608 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5609 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5613 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5617 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5620 DWORD numentries = 0;
5623 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5624 cbBuf, pcbNeeded, pcReturned);
5626 if (pName && (pName[0])) {
5627 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5628 SetLastError(ERROR_ACCESS_DENIED);
5632 /* Level is not checked in win9x */
5633 if (!Level || (Level > 2)) {
5634 WARN("level (%d) is ignored in win9x\n", Level);
5635 SetLastError(ERROR_INVALID_LEVEL);
5639 SetLastError(RPC_X_NULL_REF_POINTER);
5643 EnterCriticalSection(&monitor_handles_cs);
5646 /* Scan all local Ports */
5648 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5650 /* we calculated the needed buffersize. now do the error-checks */
5651 if (cbBuf < needed) {
5652 monitor_unloadall();
5653 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5654 goto emP_cleanup_cs;
5656 else if (!pPorts || !pcReturned) {
5657 monitor_unloadall();
5658 SetLastError(RPC_X_NULL_REF_POINTER);
5659 goto emP_cleanup_cs;
5662 /* Fill the Buffer */
5663 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5665 monitor_unloadall();
5668 LeaveCriticalSection(&monitor_handles_cs);
5671 if (pcbNeeded) *pcbNeeded = needed;
5672 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5674 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5675 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5680 /******************************************************************************
5681 * GetDefaultPrinterW (WINSPOOL.@)
5684 * This function must read the value from data 'device' of key
5685 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5687 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5691 WCHAR *buffer, *ptr;
5695 SetLastError(ERROR_INVALID_PARAMETER);
5699 /* make the buffer big enough for the stuff from the profile/registry,
5700 * the content must fit into the local buffer to compute the correct
5701 * size even if the extern buffer is too small or not given.
5702 * (20 for ,driver,port) */
5704 len = max(100, (insize + 20));
5705 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5707 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5709 SetLastError (ERROR_FILE_NOT_FOUND);
5713 TRACE("%s\n", debugstr_w(buffer));
5715 if ((ptr = strchrW(buffer, ',')) == NULL)
5717 SetLastError(ERROR_INVALID_NAME);
5723 *namesize = strlenW(buffer) + 1;
5724 if(!name || (*namesize > insize))
5726 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5730 strcpyW(name, buffer);
5733 HeapFree( GetProcessHeap(), 0, buffer);
5738 /******************************************************************************
5739 * GetDefaultPrinterA (WINSPOOL.@)
5741 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5745 WCHAR *bufferW = NULL;
5749 SetLastError(ERROR_INVALID_PARAMETER);
5753 if(name && *namesize) {
5755 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5758 if(!GetDefaultPrinterW( bufferW, namesize)) {
5763 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5767 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5770 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5773 HeapFree( GetProcessHeap(), 0, bufferW);
5778 /******************************************************************************
5779 * SetDefaultPrinterW (WINSPOOL.204)
5781 * Set the Name of the Default Printer
5784 * pszPrinter [I] Name of the Printer or NULL
5791 * When the Parameter is NULL or points to an Empty String and
5792 * a Default Printer was already present, then this Function changes nothing.
5793 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5794 * the First enumerated local Printer is used.
5797 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5800 TRACE("(%s)\n", debugstr_w(pszPrinter));
5802 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5806 /******************************************************************************
5807 * SetDefaultPrinterA (WINSPOOL.202)
5809 * See SetDefaultPrinterW.
5812 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5815 TRACE("(%s)\n", debugstr_a(pszPrinter));
5817 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5822 /******************************************************************************
5823 * SetPrinterDataExA (WINSPOOL.@)
5825 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5826 LPCSTR pValueName, DWORD Type,
5827 LPBYTE pData, DWORD cbData)
5829 HKEY hkeyPrinter, hkeySubkey;
5832 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5833 debugstr_a(pValueName), Type, pData, cbData);
5835 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5839 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5841 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5842 RegCloseKey(hkeyPrinter);
5845 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5846 RegCloseKey(hkeySubkey);
5847 RegCloseKey(hkeyPrinter);
5851 /******************************************************************************
5852 * SetPrinterDataExW (WINSPOOL.@)
5854 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5855 LPCWSTR pValueName, DWORD Type,
5856 LPBYTE pData, DWORD cbData)
5858 HKEY hkeyPrinter, hkeySubkey;
5861 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5862 debugstr_w(pValueName), Type, pData, cbData);
5864 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5868 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5870 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5871 RegCloseKey(hkeyPrinter);
5874 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5875 RegCloseKey(hkeySubkey);
5876 RegCloseKey(hkeyPrinter);
5880 /******************************************************************************
5881 * SetPrinterDataA (WINSPOOL.@)
5883 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5884 LPBYTE pData, DWORD cbData)
5886 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5890 /******************************************************************************
5891 * SetPrinterDataW (WINSPOOL.@)
5893 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5894 LPBYTE pData, DWORD cbData)
5896 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5900 /******************************************************************************
5901 * GetPrinterDataExA (WINSPOOL.@)
5903 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5904 LPCSTR pValueName, LPDWORD pType,
5905 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5907 HKEY hkeyPrinter, hkeySubkey;
5910 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5911 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5914 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5918 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5920 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5921 RegCloseKey(hkeyPrinter);
5925 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5926 RegCloseKey(hkeySubkey);
5927 RegCloseKey(hkeyPrinter);
5931 /******************************************************************************
5932 * GetPrinterDataExW (WINSPOOL.@)
5934 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5935 LPCWSTR pValueName, LPDWORD pType,
5936 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5938 HKEY hkeyPrinter, hkeySubkey;
5941 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5942 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5945 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5949 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5951 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5952 RegCloseKey(hkeyPrinter);
5956 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5957 RegCloseKey(hkeySubkey);
5958 RegCloseKey(hkeyPrinter);
5962 /******************************************************************************
5963 * GetPrinterDataA (WINSPOOL.@)
5965 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5966 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5968 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5969 pData, nSize, pcbNeeded);
5972 /******************************************************************************
5973 * GetPrinterDataW (WINSPOOL.@)
5975 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5976 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5978 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5979 pData, nSize, pcbNeeded);
5982 /*******************************************************************************
5983 * EnumPrinterDataExW [WINSPOOL.@]
5985 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5986 LPBYTE pEnumValues, DWORD cbEnumValues,
5987 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5989 HKEY hkPrinter, hkSubKey;
5990 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5991 cbValueNameLen, cbMaxValueLen, cbValueLen,
5996 PPRINTER_ENUM_VALUESW ppev;
5998 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6000 if (pKeyName == NULL || *pKeyName == 0)
6001 return ERROR_INVALID_PARAMETER;
6003 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6004 if (ret != ERROR_SUCCESS)
6006 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6011 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6012 if (ret != ERROR_SUCCESS)
6014 r = RegCloseKey (hkPrinter);
6015 if (r != ERROR_SUCCESS)
6016 WARN ("RegCloseKey returned %i\n", r);
6017 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6018 debugstr_w (pKeyName), ret);
6022 ret = RegCloseKey (hkPrinter);
6023 if (ret != ERROR_SUCCESS)
6025 ERR ("RegCloseKey returned %i\n", ret);
6026 r = RegCloseKey (hkSubKey);
6027 if (r != ERROR_SUCCESS)
6028 WARN ("RegCloseKey returned %i\n", r);
6032 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6033 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6034 if (ret != ERROR_SUCCESS)
6036 r = RegCloseKey (hkSubKey);
6037 if (r != ERROR_SUCCESS)
6038 WARN ("RegCloseKey returned %i\n", r);
6039 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6043 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6044 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6046 if (cValues == 0) /* empty key */
6048 r = RegCloseKey (hkSubKey);
6049 if (r != ERROR_SUCCESS)
6050 WARN ("RegCloseKey returned %i\n", r);
6051 *pcbEnumValues = *pnEnumValues = 0;
6052 return ERROR_SUCCESS;
6055 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6057 hHeap = GetProcessHeap ();
6060 ERR ("GetProcessHeap failed\n");
6061 r = RegCloseKey (hkSubKey);
6062 if (r != ERROR_SUCCESS)
6063 WARN ("RegCloseKey returned %i\n", r);
6064 return ERROR_OUTOFMEMORY;
6067 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6068 if (lpValueName == NULL)
6070 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6071 r = RegCloseKey (hkSubKey);
6072 if (r != ERROR_SUCCESS)
6073 WARN ("RegCloseKey returned %i\n", r);
6074 return ERROR_OUTOFMEMORY;
6077 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6078 if (lpValue == NULL)
6080 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6081 if (HeapFree (hHeap, 0, lpValueName) == 0)
6082 WARN ("HeapFree failed with code %i\n", GetLastError ());
6083 r = RegCloseKey (hkSubKey);
6084 if (r != ERROR_SUCCESS)
6085 WARN ("RegCloseKey returned %i\n", r);
6086 return ERROR_OUTOFMEMORY;
6089 TRACE ("pass 1: calculating buffer required for all names and values\n");
6091 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6093 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6095 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6097 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6098 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6099 NULL, NULL, lpValue, &cbValueLen);
6100 if (ret != ERROR_SUCCESS)
6102 if (HeapFree (hHeap, 0, lpValue) == 0)
6103 WARN ("HeapFree failed with code %i\n", GetLastError ());
6104 if (HeapFree (hHeap, 0, lpValueName) == 0)
6105 WARN ("HeapFree failed with code %i\n", GetLastError ());
6106 r = RegCloseKey (hkSubKey);
6107 if (r != ERROR_SUCCESS)
6108 WARN ("RegCloseKey returned %i\n", r);
6109 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6113 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6114 debugstr_w (lpValueName), dwIndex,
6115 cbValueNameLen + 1, cbValueLen);
6117 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6118 cbBufSize += cbValueLen;
6121 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6123 *pcbEnumValues = cbBufSize;
6124 *pnEnumValues = cValues;
6126 if (cbEnumValues < cbBufSize) /* buffer too small */
6128 if (HeapFree (hHeap, 0, lpValue) == 0)
6129 WARN ("HeapFree failed with code %i\n", GetLastError ());
6130 if (HeapFree (hHeap, 0, lpValueName) == 0)
6131 WARN ("HeapFree failed with code %i\n", GetLastError ());
6132 r = RegCloseKey (hkSubKey);
6133 if (r != ERROR_SUCCESS)
6134 WARN ("RegCloseKey returned %i\n", r);
6135 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6136 return ERROR_MORE_DATA;
6139 TRACE ("pass 2: copying all names and values to buffer\n");
6141 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6142 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6144 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6146 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6147 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6148 NULL, &dwType, lpValue, &cbValueLen);
6149 if (ret != ERROR_SUCCESS)
6151 if (HeapFree (hHeap, 0, lpValue) == 0)
6152 WARN ("HeapFree failed with code %i\n", GetLastError ());
6153 if (HeapFree (hHeap, 0, lpValueName) == 0)
6154 WARN ("HeapFree failed with code %i\n", GetLastError ());
6155 r = RegCloseKey (hkSubKey);
6156 if (r != ERROR_SUCCESS)
6157 WARN ("RegCloseKey returned %i\n", r);
6158 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6162 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6163 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6164 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6165 pEnumValues += cbValueNameLen;
6167 /* return # of *bytes* (including trailing \0), not # of chars */
6168 ppev[dwIndex].cbValueName = cbValueNameLen;
6170 ppev[dwIndex].dwType = dwType;
6172 memcpy (pEnumValues, lpValue, cbValueLen);
6173 ppev[dwIndex].pData = pEnumValues;
6174 pEnumValues += cbValueLen;
6176 ppev[dwIndex].cbData = cbValueLen;
6178 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6179 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6182 if (HeapFree (hHeap, 0, lpValue) == 0)
6184 ret = GetLastError ();
6185 ERR ("HeapFree failed with code %i\n", ret);
6186 if (HeapFree (hHeap, 0, lpValueName) == 0)
6187 WARN ("HeapFree failed with code %i\n", GetLastError ());
6188 r = RegCloseKey (hkSubKey);
6189 if (r != ERROR_SUCCESS)
6190 WARN ("RegCloseKey returned %i\n", r);
6194 if (HeapFree (hHeap, 0, lpValueName) == 0)
6196 ret = GetLastError ();
6197 ERR ("HeapFree failed with code %i\n", ret);
6198 r = RegCloseKey (hkSubKey);
6199 if (r != ERROR_SUCCESS)
6200 WARN ("RegCloseKey returned %i\n", r);
6204 ret = RegCloseKey (hkSubKey);
6205 if (ret != ERROR_SUCCESS)
6207 ERR ("RegCloseKey returned %i\n", ret);
6211 return ERROR_SUCCESS;
6214 /*******************************************************************************
6215 * EnumPrinterDataExA [WINSPOOL.@]
6217 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6218 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6219 * what Windows 2000 SP1 does.
6222 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6223 LPBYTE pEnumValues, DWORD cbEnumValues,
6224 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6228 DWORD ret, dwIndex, dwBufSize;
6232 TRACE ("%p %s\n", hPrinter, pKeyName);
6234 if (pKeyName == NULL || *pKeyName == 0)
6235 return ERROR_INVALID_PARAMETER;
6237 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6240 ret = GetLastError ();
6241 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6245 hHeap = GetProcessHeap ();
6248 ERR ("GetProcessHeap failed\n");
6249 return ERROR_OUTOFMEMORY;
6252 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6253 if (pKeyNameW == NULL)
6255 ERR ("Failed to allocate %i bytes from process heap\n",
6256 (LONG)(len * sizeof (WCHAR)));
6257 return ERROR_OUTOFMEMORY;
6260 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6262 ret = GetLastError ();
6263 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6264 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6265 WARN ("HeapFree failed with code %i\n", GetLastError ());
6269 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6270 pcbEnumValues, pnEnumValues);
6271 if (ret != ERROR_SUCCESS)
6273 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6274 WARN ("HeapFree failed with code %i\n", GetLastError ());
6275 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6279 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6281 ret = GetLastError ();
6282 ERR ("HeapFree failed with code %i\n", ret);
6286 if (*pnEnumValues == 0) /* empty key */
6287 return ERROR_SUCCESS;
6290 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6292 PPRINTER_ENUM_VALUESW ppev =
6293 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6295 if (dwBufSize < ppev->cbValueName)
6296 dwBufSize = ppev->cbValueName;
6298 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6299 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6300 dwBufSize = ppev->cbData;
6303 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6305 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6306 if (pBuffer == NULL)
6308 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6309 return ERROR_OUTOFMEMORY;
6312 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6314 PPRINTER_ENUM_VALUESW ppev =
6315 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6317 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6318 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6322 ret = GetLastError ();
6323 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6324 if (HeapFree (hHeap, 0, pBuffer) == 0)
6325 WARN ("HeapFree failed with code %i\n", GetLastError ());
6329 memcpy (ppev->pValueName, pBuffer, len);
6331 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6333 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6334 ppev->dwType != REG_MULTI_SZ)
6337 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6338 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6341 ret = GetLastError ();
6342 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6343 if (HeapFree (hHeap, 0, pBuffer) == 0)
6344 WARN ("HeapFree failed with code %i\n", GetLastError ());
6348 memcpy (ppev->pData, pBuffer, len);
6350 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6351 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6354 if (HeapFree (hHeap, 0, pBuffer) == 0)
6356 ret = GetLastError ();
6357 ERR ("HeapFree failed with code %i\n", ret);
6361 return ERROR_SUCCESS;
6364 /******************************************************************************
6365 * AbortPrinter (WINSPOOL.@)
6367 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6369 FIXME("(%p), stub!\n", hPrinter);
6373 /******************************************************************************
6374 * AddPortA (WINSPOOL.@)
6379 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6381 LPWSTR nameW = NULL;
6382 LPWSTR monitorW = NULL;
6386 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6389 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6390 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6391 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6395 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6396 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6397 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6399 res = AddPortW(nameW, hWnd, monitorW);
6400 HeapFree(GetProcessHeap(), 0, nameW);
6401 HeapFree(GetProcessHeap(), 0, monitorW);
6405 /******************************************************************************
6406 * AddPortW (WINSPOOL.@)
6408 * Add a Port for a specific Monitor
6411 * pName [I] Servername or NULL (local Computer)
6412 * hWnd [I] Handle to parent Window for the Dialog-Box
6413 * pMonitorName [I] Name of the Monitor that manage the Port
6420 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6426 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6428 if (pName && pName[0]) {
6429 SetLastError(ERROR_INVALID_PARAMETER);
6433 if (!pMonitorName) {
6434 SetLastError(RPC_X_NULL_REF_POINTER);
6438 /* an empty Monitorname is Invalid */
6439 if (!pMonitorName[0]) {
6440 SetLastError(ERROR_NOT_SUPPORTED);
6444 pm = monitor_load(pMonitorName, NULL);
6445 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6446 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6447 TRACE("got %d with %u\n", res, GetLastError());
6452 pui = monitor_loadui(pm);
6453 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6454 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6455 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6456 TRACE("got %d with %u\n", res, GetLastError());
6461 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6462 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6464 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6465 SetLastError(ERROR_NOT_SUPPORTED);
6468 monitor_unload(pui);
6471 TRACE("returning %d with %u\n", res, GetLastError());
6475 /******************************************************************************
6476 * AddPortExA (WINSPOOL.@)
6481 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6484 PORT_INFO_2A * pi2A;
6485 LPWSTR nameW = NULL;
6486 LPWSTR monitorW = NULL;
6490 pi2A = (PORT_INFO_2A *) pBuffer;
6492 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6493 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6495 if ((level < 1) || (level > 2)) {
6496 SetLastError(ERROR_INVALID_LEVEL);
6501 SetLastError(ERROR_INVALID_PARAMETER);
6506 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6507 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6508 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6512 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6513 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6514 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6517 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6519 if (pi2A->pPortName) {
6520 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6521 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6522 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6526 if (pi2A->pMonitorName) {
6527 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6528 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6529 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6532 if (pi2A->pDescription) {
6533 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6534 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6535 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6537 pi2W.fPortType = pi2A->fPortType;
6538 pi2W.Reserved = pi2A->Reserved;
6541 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6543 HeapFree(GetProcessHeap(), 0, nameW);
6544 HeapFree(GetProcessHeap(), 0, monitorW);
6545 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6546 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6547 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6552 /******************************************************************************
6553 * AddPortExW (WINSPOOL.@)
6555 * Add a Port for a specific Monitor, without presenting a user interface
6558 * pName [I] Servername or NULL (local Computer)
6559 * level [I] Structure-Level (1 or 2) for pBuffer
6560 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6561 * pMonitorName [I] Name of the Monitor that manage the Port
6568 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6574 pi2 = (PORT_INFO_2W *) pBuffer;
6576 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6577 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6578 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6579 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6582 if ((level < 1) || (level > 2)) {
6583 SetLastError(ERROR_INVALID_LEVEL);
6587 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6588 SetLastError(ERROR_INVALID_PARAMETER);
6592 /* load the Monitor */
6593 pm = monitor_load(pMonitorName, NULL);
6595 SetLastError(ERROR_INVALID_PARAMETER);
6599 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6600 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6601 TRACE("got %u with %u\n", res, GetLastError());
6605 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6611 /******************************************************************************
6612 * AddPrinterConnectionA (WINSPOOL.@)
6614 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6616 FIXME("%s\n", debugstr_a(pName));
6620 /******************************************************************************
6621 * AddPrinterConnectionW (WINSPOOL.@)
6623 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6625 FIXME("%s\n", debugstr_w(pName));
6629 /******************************************************************************
6630 * AddPrinterDriverExW (WINSPOOL.@)
6632 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6635 * pName [I] Servername or NULL (local Computer)
6636 * level [I] Level for the supplied DRIVER_INFO_*W struct
6637 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6638 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6645 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6647 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6649 if ((backend == NULL) && !load_backend()) return FALSE;
6651 if (level < 2 || level == 5 || level == 7 || level > 8) {
6652 SetLastError(ERROR_INVALID_LEVEL);
6657 SetLastError(ERROR_INVALID_PARAMETER);
6661 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6664 /******************************************************************************
6665 * AddPrinterDriverExA (WINSPOOL.@)
6667 * See AddPrinterDriverExW.
6670 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6672 DRIVER_INFO_8A *diA;
6674 LPWSTR nameW = NULL;
6679 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6681 diA = (DRIVER_INFO_8A *) pDriverInfo;
6682 ZeroMemory(&diW, sizeof(diW));
6684 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6685 SetLastError(ERROR_INVALID_LEVEL);
6690 SetLastError(ERROR_INVALID_PARAMETER);
6694 /* convert servername to unicode */
6696 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6697 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6698 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6702 diW.cVersion = diA->cVersion;
6705 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6706 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6707 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6710 if (diA->pEnvironment) {
6711 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6712 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6713 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6716 if (diA->pDriverPath) {
6717 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6718 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6719 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6722 if (diA->pDataFile) {
6723 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6724 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6725 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6728 if (diA->pConfigFile) {
6729 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6730 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6731 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6734 if ((Level > 2) && diA->pDependentFiles) {
6735 lenA = multi_sz_lenA(diA->pDependentFiles);
6736 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6737 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6738 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6741 if ((Level > 2) && diA->pMonitorName) {
6742 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6743 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6744 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6747 if ((Level > 3) && diA->pDefaultDataType) {
6748 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6749 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6750 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6753 if ((Level > 3) && diA->pszzPreviousNames) {
6754 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6755 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6756 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6757 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6760 if ((Level > 5) && diA->pszMfgName) {
6761 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6762 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6763 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6766 if ((Level > 5) && diA->pszOEMUrl) {
6767 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6768 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6769 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6772 if ((Level > 5) && diA->pszHardwareID) {
6773 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6774 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6775 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6778 if ((Level > 5) && diA->pszProvider) {
6779 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6780 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6781 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6785 FIXME("level %u is incomplete\n", Level);
6788 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6789 TRACE("got %u with %u\n", res, GetLastError());
6790 HeapFree(GetProcessHeap(), 0, nameW);
6791 HeapFree(GetProcessHeap(), 0, diW.pName);
6792 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6793 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6794 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6795 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6796 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6797 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6798 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6799 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6800 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6801 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6802 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6803 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6805 TRACE("=> %u with %u\n", res, GetLastError());
6809 /******************************************************************************
6810 * ConfigurePortA (WINSPOOL.@)
6812 * See ConfigurePortW.
6815 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6817 LPWSTR nameW = NULL;
6818 LPWSTR portW = NULL;
6822 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6824 /* convert servername to unicode */
6826 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6827 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6828 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6831 /* convert portname to unicode */
6833 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6834 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6835 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6838 res = ConfigurePortW(nameW, hWnd, portW);
6839 HeapFree(GetProcessHeap(), 0, nameW);
6840 HeapFree(GetProcessHeap(), 0, portW);
6844 /******************************************************************************
6845 * ConfigurePortW (WINSPOOL.@)
6847 * Display the Configuration-Dialog for a specific Port
6850 * pName [I] Servername or NULL (local Computer)
6851 * hWnd [I] Handle to parent Window for the Dialog-Box
6852 * pPortName [I] Name of the Port, that should be configured
6859 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6865 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6867 if (pName && pName[0]) {
6868 SetLastError(ERROR_INVALID_PARAMETER);
6873 SetLastError(RPC_X_NULL_REF_POINTER);
6877 /* an empty Portname is Invalid, but can popup a Dialog */
6878 if (!pPortName[0]) {
6879 SetLastError(ERROR_NOT_SUPPORTED);
6883 pm = monitor_load_by_port(pPortName);
6884 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6885 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6886 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6887 TRACE("got %d with %u\n", res, GetLastError());
6891 pui = monitor_loadui(pm);
6892 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6893 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6894 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6895 TRACE("got %d with %u\n", res, GetLastError());
6899 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6900 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6902 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6903 SetLastError(ERROR_NOT_SUPPORTED);
6906 monitor_unload(pui);
6910 TRACE("returning %d with %u\n", res, GetLastError());
6914 /******************************************************************************
6915 * ConnectToPrinterDlg (WINSPOOL.@)
6917 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6919 FIXME("%p %x\n", hWnd, Flags);
6923 /******************************************************************************
6924 * DeletePrinterConnectionA (WINSPOOL.@)
6926 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6928 FIXME("%s\n", debugstr_a(pName));
6932 /******************************************************************************
6933 * DeletePrinterConnectionW (WINSPOOL.@)
6935 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6937 FIXME("%s\n", debugstr_w(pName));
6941 /******************************************************************************
6942 * DeletePrinterDriverExW (WINSPOOL.@)
6944 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6945 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6950 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6951 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6953 if(pName && pName[0])
6955 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6956 SetLastError(ERROR_INVALID_PARAMETER);
6962 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6963 SetLastError(ERROR_INVALID_PARAMETER);
6967 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6971 ERR("Can't open drivers key\n");
6975 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6978 RegCloseKey(hkey_drivers);
6983 /******************************************************************************
6984 * DeletePrinterDriverExA (WINSPOOL.@)
6986 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6987 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6989 UNICODE_STRING NameW, EnvW, DriverW;
6992 asciitounicode(&NameW, pName);
6993 asciitounicode(&EnvW, pEnvironment);
6994 asciitounicode(&DriverW, pDriverName);
6996 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6998 RtlFreeUnicodeString(&DriverW);
6999 RtlFreeUnicodeString(&EnvW);
7000 RtlFreeUnicodeString(&NameW);
7005 /******************************************************************************
7006 * DeletePrinterDataExW (WINSPOOL.@)
7008 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7011 FIXME("%p %s %s\n", hPrinter,
7012 debugstr_w(pKeyName), debugstr_w(pValueName));
7013 return ERROR_INVALID_PARAMETER;
7016 /******************************************************************************
7017 * DeletePrinterDataExA (WINSPOOL.@)
7019 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7022 FIXME("%p %s %s\n", hPrinter,
7023 debugstr_a(pKeyName), debugstr_a(pValueName));
7024 return ERROR_INVALID_PARAMETER;
7027 /******************************************************************************
7028 * DeletePrintProcessorA (WINSPOOL.@)
7030 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7032 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7033 debugstr_a(pPrintProcessorName));
7037 /******************************************************************************
7038 * DeletePrintProcessorW (WINSPOOL.@)
7040 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7042 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7043 debugstr_w(pPrintProcessorName));
7047 /******************************************************************************
7048 * DeletePrintProvidorA (WINSPOOL.@)
7050 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7052 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7053 debugstr_a(pPrintProviderName));
7057 /******************************************************************************
7058 * DeletePrintProvidorW (WINSPOOL.@)
7060 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7062 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7063 debugstr_w(pPrintProviderName));
7067 /******************************************************************************
7068 * EnumFormsA (WINSPOOL.@)
7070 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7071 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7073 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7074 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7078 /******************************************************************************
7079 * EnumFormsW (WINSPOOL.@)
7081 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7082 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7084 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7085 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7089 /*****************************************************************************
7090 * EnumMonitorsA [WINSPOOL.@]
7092 * See EnumMonitorsW.
7095 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7096 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7099 LPBYTE bufferW = NULL;
7100 LPWSTR nameW = NULL;
7102 DWORD numentries = 0;
7105 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7106 cbBuf, pcbNeeded, pcReturned);
7108 /* convert servername to unicode */
7110 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7111 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7112 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7114 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7115 needed = cbBuf * sizeof(WCHAR);
7116 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7117 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7119 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7120 if (pcbNeeded) needed = *pcbNeeded;
7121 /* HeapReAlloc return NULL, when bufferW was NULL */
7122 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7123 HeapAlloc(GetProcessHeap(), 0, needed);
7125 /* Try again with the large Buffer */
7126 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7128 numentries = pcReturned ? *pcReturned : 0;
7131 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7132 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7135 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7136 DWORD entrysize = 0;
7139 LPMONITOR_INFO_2W mi2w;
7140 LPMONITOR_INFO_2A mi2a;
7142 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7143 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7145 /* First pass: calculate the size for all Entries */
7146 mi2w = (LPMONITOR_INFO_2W) bufferW;
7147 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7149 while (index < numentries) {
7151 needed += entrysize; /* MONITOR_INFO_?A */
7152 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7154 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7155 NULL, 0, NULL, NULL);
7157 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7158 NULL, 0, NULL, NULL);
7159 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7160 NULL, 0, NULL, NULL);
7162 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7163 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7164 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7167 /* check for errors and quit on failure */
7168 if (cbBuf < needed) {
7169 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7173 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7174 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7175 cbBuf -= len ; /* free Bytes in the user-Buffer */
7176 mi2w = (LPMONITOR_INFO_2W) bufferW;
7177 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7179 /* Second Pass: Fill the User Buffer (if we have one) */
7180 while ((index < numentries) && pMonitors) {
7182 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7184 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7185 ptr, cbBuf , NULL, NULL);
7189 mi2a->pEnvironment = ptr;
7190 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7191 ptr, cbBuf, NULL, NULL);
7195 mi2a->pDLLName = ptr;
7196 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7197 ptr, cbBuf, NULL, NULL);
7201 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7202 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7203 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7207 if (pcbNeeded) *pcbNeeded = needed;
7208 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7210 HeapFree(GetProcessHeap(), 0, nameW);
7211 HeapFree(GetProcessHeap(), 0, bufferW);
7213 TRACE("returning %d with %d (%d byte for %d entries)\n",
7214 (res), GetLastError(), needed, numentries);
7220 /*****************************************************************************
7221 * EnumMonitorsW [WINSPOOL.@]
7223 * Enumerate available Port-Monitors
7226 * pName [I] Servername or NULL (local Computer)
7227 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7228 * pMonitors [O] PTR to Buffer that receives the Result
7229 * cbBuf [I] Size of Buffer at pMonitors
7230 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7231 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7235 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7238 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7239 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7242 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7243 cbBuf, pcbNeeded, pcReturned);
7245 if ((backend == NULL) && !load_backend()) return FALSE;
7247 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7248 SetLastError(RPC_X_NULL_REF_POINTER);
7252 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7255 /******************************************************************************
7256 * SpoolerInit (WINSPOOL.@)
7258 * Initialize the Spooler
7265 * The function fails on windows, when the spooler service is not running
7268 BOOL WINAPI SpoolerInit(void)
7271 if ((backend == NULL) && !load_backend()) return FALSE;
7275 /******************************************************************************
7276 * XcvDataW (WINSPOOL.@)
7278 * Execute commands in the Printmonitor DLL
7281 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7282 * pszDataName [i] Name of the command to execute
7283 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7284 * cbInputData [i] Size in Bytes of Buffer at pInputData
7285 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7286 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7287 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7288 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7295 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7296 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7298 * Minimal List of commands, that a Printmonitor DLL should support:
7300 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7301 *| "AddPort" : Add a Port
7302 *| "DeletePort": Delete a Port
7304 * Many Printmonitors support additional commands. Examples for localspl.dll:
7305 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7306 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7309 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7310 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7311 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7313 opened_printer_t *printer;
7315 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7316 pInputData, cbInputData, pOutputData,
7317 cbOutputData, pcbOutputNeeded, pdwStatus);
7319 printer = get_opened_printer(hXcv);
7320 if (!printer || (!printer->hXcv)) {
7321 SetLastError(ERROR_INVALID_HANDLE);
7325 if (!pcbOutputNeeded) {
7326 SetLastError(ERROR_INVALID_PARAMETER);
7330 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7331 SetLastError(RPC_X_NULL_REF_POINTER);
7335 *pcbOutputNeeded = 0;
7337 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7338 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7343 /*****************************************************************************
7344 * EnumPrinterDataA [WINSPOOL.@]
7347 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7348 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7349 DWORD cbData, LPDWORD pcbData )
7351 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7352 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7353 return ERROR_NO_MORE_ITEMS;
7356 /*****************************************************************************
7357 * EnumPrinterDataW [WINSPOOL.@]
7360 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7361 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7362 DWORD cbData, LPDWORD pcbData )
7364 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7365 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7366 return ERROR_NO_MORE_ITEMS;
7369 /*****************************************************************************
7370 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7373 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7374 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7375 LPDWORD pcbNeeded, LPDWORD pcReturned)
7377 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7378 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7379 pcbNeeded, pcReturned);
7383 /*****************************************************************************
7384 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7387 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7388 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7389 LPDWORD pcbNeeded, LPDWORD pcReturned)
7391 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7392 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7393 pcbNeeded, pcReturned);
7397 /*****************************************************************************
7398 * EnumPrintProcessorsA [WINSPOOL.@]
7401 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7402 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7404 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7405 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7409 /*****************************************************************************
7410 * EnumPrintProcessorsW [WINSPOOL.@]
7413 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7414 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7416 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7417 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7418 cbBuf, pcbNeeded, pcbReturned);
7422 /*****************************************************************************
7423 * ExtDeviceMode [WINSPOOL.@]
7426 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7427 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7430 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7431 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7432 debugstr_a(pProfile), fMode);
7436 /*****************************************************************************
7437 * FindClosePrinterChangeNotification [WINSPOOL.@]
7440 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7442 FIXME("Stub: %p\n", hChange);
7446 /*****************************************************************************
7447 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7450 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7451 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7453 FIXME("Stub: %p %x %x %p\n",
7454 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7455 return INVALID_HANDLE_VALUE;
7458 /*****************************************************************************
7459 * FindNextPrinterChangeNotification [WINSPOOL.@]
7462 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7463 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7465 FIXME("Stub: %p %p %p %p\n",
7466 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7470 /*****************************************************************************
7471 * FreePrinterNotifyInfo [WINSPOOL.@]
7474 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7476 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7480 /*****************************************************************************
7483 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7484 * ansi depending on the unicode parameter.
7486 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7496 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7499 memcpy(ptr, str, *size);
7506 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7509 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7516 /*****************************************************************************
7519 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7520 LPDWORD pcbNeeded, BOOL unicode)
7522 DWORD size, left = cbBuf;
7523 BOOL space = (cbBuf > 0);
7530 ji1->JobId = job->job_id;
7533 string_to_buf(job->document_title, ptr, left, &size, unicode);
7534 if(space && size <= left)
7536 ji1->pDocument = (LPWSTR)ptr;
7547 /*****************************************************************************
7550 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7551 LPDWORD pcbNeeded, BOOL unicode)
7553 DWORD size, left = cbBuf;
7554 BOOL space = (cbBuf > 0);
7561 ji2->JobId = job->job_id;
7564 string_to_buf(job->document_title, ptr, left, &size, unicode);
7565 if(space && size <= left)
7567 ji2->pDocument = (LPWSTR)ptr;
7578 /*****************************************************************************
7581 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7582 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7585 DWORD needed = 0, size;
7589 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7591 EnterCriticalSection(&printer_handles_cs);
7592 job = get_job(hPrinter, JobId);
7599 size = sizeof(JOB_INFO_1W);
7604 memset(pJob, 0, size);
7608 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7613 size = sizeof(JOB_INFO_2W);
7618 memset(pJob, 0, size);
7622 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7627 size = sizeof(JOB_INFO_3);
7631 memset(pJob, 0, size);
7640 SetLastError(ERROR_INVALID_LEVEL);
7644 *pcbNeeded = needed;
7646 LeaveCriticalSection(&printer_handles_cs);
7650 /*****************************************************************************
7651 * GetJobA [WINSPOOL.@]
7654 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7655 DWORD cbBuf, LPDWORD pcbNeeded)
7657 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7660 /*****************************************************************************
7661 * GetJobW [WINSPOOL.@]
7664 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7665 DWORD cbBuf, LPDWORD pcbNeeded)
7667 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7670 /*****************************************************************************
7673 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7675 char *unixname, *queue, *cmd;
7676 char fmt[] = "lpr -P%s %s";
7679 if(!(unixname = wine_get_unix_file_name(filename)))
7682 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7683 queue = HeapAlloc(GetProcessHeap(), 0, len);
7684 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7686 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7687 sprintf(cmd, fmt, queue, unixname);
7689 TRACE("printing with: %s\n", cmd);
7692 HeapFree(GetProcessHeap(), 0, cmd);
7693 HeapFree(GetProcessHeap(), 0, queue);
7694 HeapFree(GetProcessHeap(), 0, unixname);
7698 /*****************************************************************************
7701 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7703 #ifdef SONAME_LIBCUPS
7706 char *unixname, *queue, *doc_titleA;
7710 if(!(unixname = wine_get_unix_file_name(filename)))
7713 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7714 queue = HeapAlloc(GetProcessHeap(), 0, len);
7715 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7717 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7718 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7719 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7721 TRACE("printing via cups\n");
7722 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7723 HeapFree(GetProcessHeap(), 0, doc_titleA);
7724 HeapFree(GetProcessHeap(), 0, queue);
7725 HeapFree(GetProcessHeap(), 0, unixname);
7731 return schedule_lpr(printer_name, filename);
7735 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7742 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7746 if(HIWORD(wparam) == BN_CLICKED)
7748 if(LOWORD(wparam) == IDOK)
7751 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7754 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7755 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7757 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7759 WCHAR caption[200], message[200];
7762 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7763 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7764 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7765 if(mb_ret == IDCANCEL)
7767 HeapFree(GetProcessHeap(), 0, filename);
7771 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7772 if(hf == INVALID_HANDLE_VALUE)
7774 WCHAR caption[200], message[200];
7776 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7777 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7778 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7779 HeapFree(GetProcessHeap(), 0, filename);
7783 DeleteFileW(filename);
7784 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7786 EndDialog(hwnd, IDOK);
7789 if(LOWORD(wparam) == IDCANCEL)
7791 EndDialog(hwnd, IDCANCEL);
7800 /*****************************************************************************
7803 static BOOL get_filename(LPWSTR *filename)
7805 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7806 file_dlg_proc, (LPARAM)filename) == IDOK;
7809 /*****************************************************************************
7812 static BOOL schedule_file(LPCWSTR filename)
7814 LPWSTR output = NULL;
7816 if(get_filename(&output))
7818 TRACE("copy to %s\n", debugstr_w(output));
7819 CopyFileW(filename, output, FALSE);
7820 HeapFree(GetProcessHeap(), 0, output);
7826 /*****************************************************************************
7829 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7832 char *unixname, *cmdA;
7834 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7838 if(!(unixname = wine_get_unix_file_name(filename)))
7841 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7842 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7843 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7845 TRACE("printing with: %s\n", cmdA);
7847 if((file_fd = open(unixname, O_RDONLY)) == -1)
7852 ERR("pipe() failed!\n");
7862 /* reset signals that we previously set to SIG_IGN */
7863 signal(SIGPIPE, SIG_DFL);
7864 signal(SIGCHLD, SIG_DFL);
7866 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7870 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7871 write(fds[1], buf, no_read);
7876 if(file_fd != -1) close(file_fd);
7877 if(fds[0] != -1) close(fds[0]);
7878 if(fds[1] != -1) close(fds[1]);
7880 HeapFree(GetProcessHeap(), 0, cmdA);
7881 HeapFree(GetProcessHeap(), 0, unixname);
7888 /*****************************************************************************
7891 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7893 int in_fd, out_fd, no_read;
7896 char *unixname, *outputA;
7899 if(!(unixname = wine_get_unix_file_name(filename)))
7902 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7903 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7904 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7906 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7907 in_fd = open(unixname, O_RDONLY);
7908 if(out_fd == -1 || in_fd == -1)
7911 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7912 write(out_fd, buf, no_read);
7916 if(in_fd != -1) close(in_fd);
7917 if(out_fd != -1) close(out_fd);
7918 HeapFree(GetProcessHeap(), 0, outputA);
7919 HeapFree(GetProcessHeap(), 0, unixname);
7923 /*****************************************************************************
7924 * ScheduleJob [WINSPOOL.@]
7927 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7929 opened_printer_t *printer;
7931 struct list *cursor, *cursor2;
7933 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7934 EnterCriticalSection(&printer_handles_cs);
7935 printer = get_opened_printer(hPrinter);
7939 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7941 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7944 if(job->job_id != dwJobID) continue;
7946 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7947 if(hf != INVALID_HANDLE_VALUE)
7949 PRINTER_INFO_5W *pi5;
7953 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7954 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7956 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7957 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7958 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7959 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7960 debugstr_w(pi5->pPortName));
7964 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7965 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7967 DWORD type, count = sizeof(output);
7968 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7971 if(output[0] == '|')
7973 schedule_pipe(output + 1, job->filename);
7977 schedule_unixfile(output, job->filename);
7979 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7981 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7983 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7985 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7987 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7989 schedule_file(job->filename);
7993 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7995 HeapFree(GetProcessHeap(), 0, pi5);
7997 DeleteFileW(job->filename);
7999 list_remove(cursor);
8000 HeapFree(GetProcessHeap(), 0, job->document_title);
8001 HeapFree(GetProcessHeap(), 0, job->filename);
8002 HeapFree(GetProcessHeap(), 0, job);
8007 LeaveCriticalSection(&printer_handles_cs);
8011 /*****************************************************************************
8012 * StartDocDlgA [WINSPOOL.@]
8014 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8016 UNICODE_STRING usBuffer;
8019 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8022 docW.cbSize = sizeof(docW);
8023 if (doc->lpszDocName)
8025 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8026 if (!(docW.lpszDocName = docnameW)) return NULL;
8028 if (doc->lpszOutput)
8030 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8031 if (!(docW.lpszOutput = outputW)) return NULL;
8033 if (doc->lpszDatatype)
8035 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8036 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8038 docW.fwType = doc->fwType;
8040 retW = StartDocDlgW(hPrinter, &docW);
8044 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8045 ret = HeapAlloc(GetProcessHeap(), 0, len);
8046 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8047 HeapFree(GetProcessHeap(), 0, retW);
8050 HeapFree(GetProcessHeap(), 0, datatypeW);
8051 HeapFree(GetProcessHeap(), 0, outputW);
8052 HeapFree(GetProcessHeap(), 0, docnameW);
8057 /*****************************************************************************
8058 * StartDocDlgW [WINSPOOL.@]
8060 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8061 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8062 * port is "FILE:". Also returns the full path if passed a relative path.
8064 * The caller should free the returned string from the process heap.
8066 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8071 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8073 PRINTER_INFO_5W *pi5;
8074 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8075 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8077 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8078 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8079 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8081 HeapFree(GetProcessHeap(), 0, pi5);
8084 HeapFree(GetProcessHeap(), 0, pi5);
8087 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8091 if (get_filename(&name))
8093 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8095 HeapFree(GetProcessHeap(), 0, name);
8098 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8099 GetFullPathNameW(name, len, ret, NULL);
8100 HeapFree(GetProcessHeap(), 0, name);
8105 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8108 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8109 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8111 attr = GetFileAttributesW(ret);
8112 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8114 HeapFree(GetProcessHeap(), 0, ret);