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-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
39 #ifdef HAVE_SYS_WAIT_H
46 #ifdef HAVE_CUPS_CUPS_H
47 # include <cups/cups.h>
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
52 #include "wine/library.h"
61 #include "wine/windef16.h"
62 #include "wine/unicode.h"
63 #include "wine/debug.h"
64 #include "wine/list.h"
67 #include "ddk/winsplp.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
72 /* ############################### */
74 static CRITICAL_SECTION printer_handles_cs;
75 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
77 0, 0, &printer_handles_cs,
78 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
79 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
81 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
83 /* ############################### */
98 HANDLE backend_printer;
108 WCHAR *document_title;
118 LPCWSTR versionregpath;
119 LPCWSTR versionsubdir;
122 /* ############################### */
124 static opened_printer_t **printer_handles;
125 static UINT nb_printer_handles;
126 static LONG next_job_id = 1;
128 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
129 WORD fwCapability, LPSTR lpszOutput,
131 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
132 LPSTR lpszDevice, LPSTR lpszPort,
133 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
136 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
137 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
138 'c','o','n','t','r','o','l','\\',
139 'P','r','i','n','t','\\',
140 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
141 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
143 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
144 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
145 'C','o','n','t','r','o','l','\\',
146 'P','r','i','n','t','\\',
147 'P','r','i','n','t','e','r','s',0};
149 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
151 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
152 'M','i','c','r','o','s','o','f','t','\\',
153 'W','i','n','d','o','w','s',' ','N','T','\\',
154 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
155 'W','i','n','d','o','w','s',0};
157 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
158 'M','i','c','r','o','s','o','f','t','\\',
159 'W','i','n','d','o','w','s',' ','N','T','\\',
160 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
161 'D','e','v','i','c','e','s',0};
163 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
164 'M','i','c','r','o','s','o','f','t','\\',
165 'W','i','n','d','o','w','s',' ','N','T','\\',
166 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
167 'P','o','r','t','s',0};
169 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
170 'M','i','c','r','o','s','o','f','t','\\',
171 'W','i','n','d','o','w','s',' ','N','T','\\',
172 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
173 'P','r','i','n','t','e','r','P','o','r','t','s',0};
175 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
176 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
177 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
178 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
179 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
180 static const WCHAR subdir_x64W[] = {'x','6','4',0};
181 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
182 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
183 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
184 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
185 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
187 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
188 static const WCHAR backslashW[] = {'\\',0};
189 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
190 'i','o','n',' ','F','i','l','e',0};
191 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
192 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
193 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
194 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
195 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
196 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
197 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
198 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
199 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
200 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
201 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
202 static const WCHAR NameW[] = {'N','a','m','e',0};
203 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
204 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
205 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
206 static const WCHAR PortW[] = {'P','o','r','t',0};
207 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
208 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
209 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
210 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
211 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
212 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
213 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
214 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
215 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
216 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
217 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
218 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
219 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
220 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
221 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
222 static WCHAR rawW[] = {'R','A','W',0};
223 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
224 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
225 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
226 static const WCHAR commaW[] = {',',0};
227 static WCHAR emptyStringW[] = {0};
229 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
231 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
232 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
233 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
235 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
236 'D','o','c','u','m','e','n','t',0};
238 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
239 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
240 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
241 0, sizeof(DRIVER_INFO_8W)};
244 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
245 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
246 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
247 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
248 sizeof(PRINTER_INFO_9W)};
250 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
251 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
252 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
254 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
256 /******************************************************************
257 * validate the user-supplied printing-environment [internal]
260 * env [I] PTR to Environment-String or NULL
264 * Success: PTR to printenv_t
267 * An empty string is handled the same way as NULL.
268 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
272 static const printenv_t * validate_envW(LPCWSTR env)
274 const printenv_t *result = NULL;
277 TRACE("testing %s\n", debugstr_w(env));
280 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
282 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
284 result = all_printenv[i];
289 if (result == NULL) {
290 FIXME("unsupported Environment: %s\n", debugstr_w(env));
291 SetLastError(ERROR_INVALID_ENVIRONMENT);
293 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
297 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
299 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
305 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
306 if passed a NULL string. This returns NULLs to the result.
308 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
312 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
313 return usBufferPtr->Buffer;
315 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
319 static LPWSTR strdupW(LPCWSTR p)
325 len = (strlenW(p) + 1) * sizeof(WCHAR);
326 ret = HeapAlloc(GetProcessHeap(), 0, len);
331 static LPSTR strdupWtoA( LPCWSTR str )
336 if (!str) return NULL;
337 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
338 ret = HeapAlloc( GetProcessHeap(), 0, len );
339 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
343 /******************************************************************
344 * verify, that the filename is a local file
347 static inline BOOL is_local_file(LPWSTR name)
349 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
352 /* ################################ */
354 static int multi_sz_lenA(const char *str)
356 const char *ptr = str;
360 ptr += lstrlenA(ptr) + 1;
363 return ptr - str + 1;
367 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
370 /* If forcing, or no profile string entry for device yet, set the entry
372 * The always change entry if not WINEPS yet is discussable.
375 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
377 !strstr(qbuf,"WINEPS.DRV")
379 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
382 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
383 WriteProfileStringA("windows","device",buf);
384 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
385 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
388 HeapFree(GetProcessHeap(),0,buf);
392 static BOOL add_printer_driver(WCHAR *name)
396 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
399 di3.pEnvironment = envname_x86W;
400 di3.pDriverPath = driver_nt;
401 di3.pDataFile = generic_ppdW;
402 di3.pConfigFile = driver_nt;
403 di3.pDefaultDataType = rawW;
405 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
406 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
409 di3.pEnvironment = envname_win40W;
410 di3.pDriverPath = driver_9x;
411 di3.pConfigFile = driver_9x;
412 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
413 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
418 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
422 #ifdef SONAME_LIBCUPS
423 static typeof(cupsFreeDests) *pcupsFreeDests;
424 static typeof(cupsGetDests) *pcupsGetDests;
425 static typeof(cupsGetPPD) *pcupsGetPPD;
426 static typeof(cupsPrintFile) *pcupsPrintFile;
427 static void *cupshandle;
429 static BOOL CUPS_LoadPrinters(void)
432 BOOL hadprinter = FALSE, haddefault = FALSE;
436 HKEY hkeyPrinter, hkeyPrinters;
438 WCHAR nameW[MAX_PATH];
440 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
442 TRACE("%s\n", loaderror);
445 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
448 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
449 if (!p##x) return FALSE;
451 DYNCUPS(cupsFreeDests);
453 DYNCUPS(cupsGetDests);
454 DYNCUPS(cupsPrintFile);
457 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
459 ERR("Can't create Printers key\n");
463 nrofdests = pcupsGetDests(&dests);
464 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
465 for (i=0;i<nrofdests;i++) {
466 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
468 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
469 lstrcpyW(port, CUPS_Port);
470 lstrcatW(port, nameW);
472 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
473 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
474 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
476 TRACE("Printer already exists\n");
477 /* overwrite old LPR:* port */
478 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
479 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
480 RegCloseKey(hkeyPrinter);
482 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
483 ' ','u','s','i','n','g',' ','C','U','P','S',0};
485 add_printer_driver(nameW);
487 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
488 pi2.pPrinterName = nameW;
489 pi2.pDatatype = rawW;
490 pi2.pPrintProcessor = WinPrintW;
491 pi2.pDriverName = nameW;
492 pi2.pComment = comment_cups;
493 pi2.pLocation = emptyStringW;
494 pi2.pPortName = port;
495 pi2.pParameters = emptyStringW;
496 pi2.pShareName = emptyStringW;
497 pi2.pSepFile = emptyStringW;
499 if (!AddPrinterW(NULL, 2, (LPBYTE)&pi2)) {
500 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
501 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError());
504 HeapFree(GetProcessHeap(),0,port);
507 if (dests[i].is_default) {
508 SetDefaultPrinterW(nameW);
512 if (hadprinter && !haddefault) {
513 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
514 SetDefaultPrinterW(nameW);
516 pcupsFreeDests(nrofdests, dests);
517 RegCloseKey(hkeyPrinters);
523 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
524 PRINTER_INFO_2A pinfo2a;
527 char *e,*s,*name,*prettyname,*devname;
528 BOOL ret = FALSE, set_default = FALSE;
529 char *port = NULL, *env_default;
530 HKEY hkeyPrinter, hkeyPrinters;
531 WCHAR devnameW[MAX_PATH];
533 while (isspace(*pent)) pent++;
534 r = strchr(pent,':');
538 name_len = strlen(pent);
539 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
540 memcpy(name, pent, name_len);
541 name[name_len] = '\0';
547 TRACE("name=%s entry=%s\n",name, pent);
549 if(ispunct(*name)) { /* a tc entry, not a real printer */
550 TRACE("skipping tc entry\n");
554 if(strstr(pent,":server")) { /* server only version so skip */
555 TRACE("skipping server entry\n");
559 /* Determine whether this is a postscript printer. */
562 env_default = getenv("PRINTER");
564 /* Get longest name, usually the one at the right for later display. */
565 while((s=strchr(prettyname,'|'))) {
568 while(isspace(*--e)) *e = '\0';
569 TRACE("\t%s\n", debugstr_a(prettyname));
570 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
571 for(prettyname = s+1; isspace(*prettyname); prettyname++)
574 e = prettyname + strlen(prettyname);
575 while(isspace(*--e)) *e = '\0';
576 TRACE("\t%s\n", debugstr_a(prettyname));
577 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
579 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
580 * if it is too long, we use it as comment below. */
581 devname = prettyname;
582 if (strlen(devname)>=CCHDEVICENAME-1)
584 if (strlen(devname)>=CCHDEVICENAME-1) {
589 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
590 sprintf(port,"LPR:%s",name);
592 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
594 ERR("Can't create Printers key\n");
599 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
601 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
602 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
604 TRACE("Printer already exists\n");
605 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
606 RegCloseKey(hkeyPrinter);
608 static CHAR data_type[] = "RAW",
609 print_proc[] = "WinPrint",
610 comment[] = "WINEPS Printer using LPR",
611 params[] = "<parameters?>",
612 share_name[] = "<share name?>",
613 sep_file[] = "<sep file?>";
615 add_printer_driver(devnameW);
617 memset(&pinfo2a,0,sizeof(pinfo2a));
618 pinfo2a.pPrinterName = devname;
619 pinfo2a.pDatatype = data_type;
620 pinfo2a.pPrintProcessor = print_proc;
621 pinfo2a.pDriverName = devname;
622 pinfo2a.pComment = comment;
623 pinfo2a.pLocation = prettyname;
624 pinfo2a.pPortName = port;
625 pinfo2a.pParameters = params;
626 pinfo2a.pShareName = share_name;
627 pinfo2a.pSepFile = sep_file;
629 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
630 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
631 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
634 RegCloseKey(hkeyPrinters);
636 if (isfirst || set_default)
637 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
640 HeapFree(GetProcessHeap(), 0, port);
641 HeapFree(GetProcessHeap(), 0, name);
646 PRINTCAP_LoadPrinters(void) {
647 BOOL hadprinter = FALSE;
651 BOOL had_bash = FALSE;
653 f = fopen("/etc/printcap","r");
657 while(fgets(buf,sizeof(buf),f)) {
660 end=strchr(buf,'\n');
664 while(isspace(*start)) start++;
665 if(*start == '#' || *start == '\0')
668 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
669 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
670 HeapFree(GetProcessHeap(),0,pent);
674 if (end && *--end == '\\') {
681 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
684 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
690 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
691 HeapFree(GetProcessHeap(),0,pent);
697 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
700 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
701 (lstrlenW(value) + 1) * sizeof(WCHAR));
703 return ERROR_FILE_NOT_FOUND;
706 /******************************************************************
707 * get_servername_from_name (internal)
709 * for an external server, a copy of the serverpart from the full name is returned
712 static LPWSTR get_servername_from_name(LPCWSTR name)
716 WCHAR buffer[MAX_PATH];
719 if (name == NULL) return NULL;
720 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
722 server = strdupW(&name[2]); /* skip over both backslash */
723 if (server == NULL) return NULL;
725 /* strip '\' and the printername */
726 ptr = strchrW(server, '\\');
727 if (ptr) ptr[0] = '\0';
729 TRACE("found %s\n", debugstr_w(server));
731 len = sizeof(buffer)/sizeof(buffer[0]);
732 if (GetComputerNameW(buffer, &len)) {
733 if (lstrcmpW(buffer, server) == 0) {
734 /* The requested Servername is our computername */
735 HeapFree(GetProcessHeap(), 0, server);
742 /******************************************************************
743 * get_basename_from_name (internal)
745 * skip over the serverpart from the full name
748 static LPCWSTR get_basename_from_name(LPCWSTR name)
750 if (name == NULL) return NULL;
751 if ((name[0] == '\\') && (name[1] == '\\')) {
752 /* skip over the servername and search for the following '\' */
753 name = strchrW(&name[2], '\\');
754 if ((name) && (name[1])) {
755 /* found a separator ('\') followed by a name:
756 skip over the separator and return the rest */
761 /* no basename present (we found only a servername) */
768 /******************************************************************
769 * get_opened_printer_entry
770 * Get the first place empty in the opened printer table
773 * - pDefault is ignored
775 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
777 UINT_PTR handle = nb_printer_handles, i;
778 jobqueue_t *queue = NULL;
779 opened_printer_t *printer = NULL;
783 if ((backend == NULL) && !load_backend()) return NULL;
785 servername = get_servername_from_name(name);
787 FIXME("server %s not supported\n", debugstr_w(servername));
788 HeapFree(GetProcessHeap(), 0, servername);
789 SetLastError(ERROR_INVALID_PRINTER_NAME);
793 printername = get_basename_from_name(name);
794 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
796 /* an empty printername is invalid */
797 if (printername && (!printername[0])) {
798 SetLastError(ERROR_INVALID_PARAMETER);
802 EnterCriticalSection(&printer_handles_cs);
804 for (i = 0; i < nb_printer_handles; i++)
806 if (!printer_handles[i])
808 if(handle == nb_printer_handles)
813 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
814 queue = printer_handles[i]->queue;
818 if (handle >= nb_printer_handles)
820 opened_printer_t **new_array;
822 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
823 (nb_printer_handles + 16) * sizeof(*new_array) );
825 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
826 (nb_printer_handles + 16) * sizeof(*new_array) );
833 printer_handles = new_array;
834 nb_printer_handles += 16;
837 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
843 /* get a printer handle from the backend */
844 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
849 /* clone the base name. This is NULL for the printserver */
850 printer->printername = strdupW(printername);
852 /* clone the full name */
853 printer->name = strdupW(name);
854 if (name && (!printer->name)) {
860 printer->queue = queue;
863 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
864 if (!printer->queue) {
868 list_init(&printer->queue->jobs);
869 printer->queue->ref = 0;
871 InterlockedIncrement(&printer->queue->ref);
873 printer_handles[handle] = printer;
876 LeaveCriticalSection(&printer_handles_cs);
877 if (!handle && printer) {
878 /* Something failed: Free all resources */
879 HeapFree(GetProcessHeap(), 0, printer->printername);
880 HeapFree(GetProcessHeap(), 0, printer->name);
881 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
882 HeapFree(GetProcessHeap(), 0, printer);
885 return (HANDLE)handle;
888 /******************************************************************
890 * Get the pointer to the opened printer referred by the handle
892 static opened_printer_t *get_opened_printer(HANDLE hprn)
894 UINT_PTR idx = (UINT_PTR)hprn;
895 opened_printer_t *ret = NULL;
897 EnterCriticalSection(&printer_handles_cs);
899 if ((idx > 0) && (idx <= nb_printer_handles)) {
900 ret = printer_handles[idx - 1];
902 LeaveCriticalSection(&printer_handles_cs);
906 /******************************************************************
907 * get_opened_printer_name
908 * Get the pointer to the opened printer name referred by the handle
910 static LPCWSTR get_opened_printer_name(HANDLE hprn)
912 opened_printer_t *printer = get_opened_printer(hprn);
913 if(!printer) return NULL;
914 return printer->name;
917 /******************************************************************
918 * WINSPOOL_GetOpenedPrinterRegKey
921 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
923 LPCWSTR name = get_opened_printer_name(hPrinter);
927 if(!name) return ERROR_INVALID_HANDLE;
929 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
933 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
935 ERR("Can't find opened printer %s in registry\n",
937 RegCloseKey(hkeyPrinters);
938 return ERROR_INVALID_PRINTER_NAME; /* ? */
940 RegCloseKey(hkeyPrinters);
941 return ERROR_SUCCESS;
944 void WINSPOOL_LoadSystemPrinters(void)
946 HKEY hkey, hkeyPrinters;
948 DWORD needed, num, i;
949 WCHAR PrinterName[256];
952 /* This ensures that all printer entries have a valid Name value. If causes
953 problems later if they don't. If one is found to be missed we create one
954 and set it equal to the name of the key */
955 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
956 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
957 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
958 for(i = 0; i < num; i++) {
959 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
960 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
961 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
962 set_reg_szW(hkey, NameW, PrinterName);
969 RegCloseKey(hkeyPrinters);
972 /* We want to avoid calling AddPrinter on printers as much as
973 possible, because on cups printers this will (eventually) lead
974 to a call to cupsGetPPD which takes forever, even with non-cups
975 printers AddPrinter takes a while. So we'll tag all printers that
976 were automatically added last time around, if they still exist
977 we'll leave them be otherwise we'll delete them. */
978 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num) && needed) {
979 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
980 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
981 for(i = 0; i < num; i++) {
982 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
983 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
984 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
986 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
994 HeapFree(GetProcessHeap(), 0, pi);
998 #ifdef SONAME_LIBCUPS
999 done = CUPS_LoadPrinters();
1002 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1003 PRINTCAP_LoadPrinters();
1005 /* Now enumerate the list again and delete any printers that are still tagged */
1006 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1008 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1009 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1010 for(i = 0; i < num; i++) {
1011 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1012 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1013 BOOL delete_driver = FALSE;
1014 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1015 DWORD dw, type, size = sizeof(dw);
1016 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1017 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1018 DeletePrinter(hprn);
1019 delete_driver = TRUE;
1025 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1030 HeapFree(GetProcessHeap(), 0, pi);
1037 /******************************************************************
1040 * Get the pointer to the specified job.
1041 * Should hold the printer_handles_cs before calling.
1043 static job_t *get_job(HANDLE hprn, DWORD JobId)
1045 opened_printer_t *printer = get_opened_printer(hprn);
1048 if(!printer) return NULL;
1049 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1051 if(job->job_id == JobId)
1057 /***********************************************************
1060 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1063 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1066 Formname = (dmA->dmSize > off_formname);
1067 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1068 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1069 dmW->dmDeviceName, CCHDEVICENAME);
1071 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1072 dmA->dmSize - CCHDEVICENAME);
1074 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1075 off_formname - CCHDEVICENAME);
1076 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1077 dmW->dmFormName, CCHFORMNAME);
1078 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1079 (off_formname + CCHFORMNAME));
1082 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1083 dmA->dmDriverExtra);
1087 /***********************************************************
1089 * Creates an ansi copy of supplied devmode
1091 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1096 if (!dmW) return NULL;
1097 size = dmW->dmSize - CCHDEVICENAME -
1098 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1100 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1101 if (!dmA) return NULL;
1103 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1104 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1106 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1107 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1108 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1112 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1113 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1114 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1115 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1117 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1121 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1125 /******************************************************************
1126 * convert_printerinfo_W_to_A [internal]
1129 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1130 DWORD level, DWORD outlen, DWORD numentries)
1136 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1138 len = pi_sizeof[level] * numentries;
1139 ptr = (LPSTR) out + len;
1142 /* copy the numbers of all PRINTER_INFO_* first */
1143 memcpy(out, pPrintersW, len);
1145 while (id < numentries) {
1149 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1150 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1152 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1153 if (piW->pDescription) {
1154 piA->pDescription = ptr;
1155 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1156 ptr, outlen, NULL, NULL);
1162 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1163 ptr, outlen, NULL, NULL);
1167 if (piW->pComment) {
1168 piA->pComment = ptr;
1169 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1170 ptr, outlen, NULL, NULL);
1179 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1180 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1183 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1184 if (piW->pServerName) {
1185 piA->pServerName = ptr;
1186 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1187 ptr, outlen, NULL, NULL);
1191 if (piW->pPrinterName) {
1192 piA->pPrinterName = ptr;
1193 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1194 ptr, outlen, NULL, NULL);
1198 if (piW->pShareName) {
1199 piA->pShareName = ptr;
1200 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1201 ptr, outlen, NULL, NULL);
1205 if (piW->pPortName) {
1206 piA->pPortName = ptr;
1207 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1208 ptr, outlen, NULL, NULL);
1212 if (piW->pDriverName) {
1213 piA->pDriverName = ptr;
1214 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1215 ptr, outlen, NULL, NULL);
1219 if (piW->pComment) {
1220 piA->pComment = ptr;
1221 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1222 ptr, outlen, NULL, NULL);
1226 if (piW->pLocation) {
1227 piA->pLocation = ptr;
1228 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1229 ptr, outlen, NULL, NULL);
1234 dmA = DEVMODEdupWtoA(piW->pDevMode);
1236 /* align DEVMODEA to a DWORD boundary */
1237 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1241 piA->pDevMode = (LPDEVMODEA) ptr;
1242 len = dmA->dmSize + dmA->dmDriverExtra;
1243 memcpy(ptr, dmA, len);
1244 HeapFree(GetProcessHeap(), 0, dmA);
1250 if (piW->pSepFile) {
1251 piA->pSepFile = ptr;
1252 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1253 ptr, outlen, NULL, NULL);
1257 if (piW->pPrintProcessor) {
1258 piA->pPrintProcessor = ptr;
1259 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1260 ptr, outlen, NULL, NULL);
1264 if (piW->pDatatype) {
1265 piA->pDatatype = ptr;
1266 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1267 ptr, outlen, NULL, NULL);
1271 if (piW->pParameters) {
1272 piA->pParameters = ptr;
1273 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1274 ptr, outlen, NULL, NULL);
1278 if (piW->pSecurityDescriptor) {
1279 piA->pSecurityDescriptor = NULL;
1280 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1287 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1288 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1290 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1292 if (piW->pPrinterName) {
1293 piA->pPrinterName = ptr;
1294 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1295 ptr, outlen, NULL, NULL);
1299 if (piW->pServerName) {
1300 piA->pServerName = ptr;
1301 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1302 ptr, outlen, NULL, NULL);
1311 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1312 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1314 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1316 if (piW->pPrinterName) {
1317 piA->pPrinterName = ptr;
1318 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1319 ptr, outlen, NULL, NULL);
1323 if (piW->pPortName) {
1324 piA->pPortName = ptr;
1325 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1326 ptr, outlen, NULL, NULL);
1333 case 6: /* 6A and 6W are the same structure */
1338 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1339 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1341 TRACE("(%u) #%u\n", level, id);
1342 if (piW->pszObjectGUID) {
1343 piA->pszObjectGUID = ptr;
1344 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1345 ptr, outlen, NULL, NULL);
1354 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1355 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1358 TRACE("(%u) #%u\n", level, id);
1359 dmA = DEVMODEdupWtoA(piW->pDevMode);
1361 /* align DEVMODEA to a DWORD boundary */
1362 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1366 piA->pDevMode = (LPDEVMODEA) ptr;
1367 len = dmA->dmSize + dmA->dmDriverExtra;
1368 memcpy(ptr, dmA, len);
1369 HeapFree(GetProcessHeap(), 0, dmA);
1379 FIXME("for level %u\n", level);
1381 pPrintersW += pi_sizeof[level];
1382 out += pi_sizeof[level];
1387 /******************************************************************
1388 * convert_driverinfo_W_to_A [internal]
1391 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1392 DWORD level, DWORD outlen, DWORD numentries)
1398 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1400 len = di_sizeof[level] * numentries;
1401 ptr = (LPSTR) out + len;
1404 /* copy the numbers of all PRINTER_INFO_* first */
1405 memcpy(out, pDriversW, len);
1407 #define COPY_STRING(fld) \
1410 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1411 ptr += len; outlen -= len;\
1413 #define COPY_MULTIZ_STRING(fld) \
1414 { LPWSTR p = diW->fld; if (p){ \
1417 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1418 ptr += len; outlen -= len; p += len;\
1420 while(len > 1 && outlen > 0); \
1423 while (id < numentries)
1429 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1430 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1432 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1439 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1440 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1442 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1445 COPY_STRING(pEnvironment);
1446 COPY_STRING(pDriverPath);
1447 COPY_STRING(pDataFile);
1448 COPY_STRING(pConfigFile);
1453 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1454 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1456 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1459 COPY_STRING(pEnvironment);
1460 COPY_STRING(pDriverPath);
1461 COPY_STRING(pDataFile);
1462 COPY_STRING(pConfigFile);
1463 COPY_STRING(pHelpFile);
1464 COPY_MULTIZ_STRING(pDependentFiles);
1465 COPY_STRING(pMonitorName);
1466 COPY_STRING(pDefaultDataType);
1471 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1472 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1474 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1477 COPY_STRING(pEnvironment);
1478 COPY_STRING(pDriverPath);
1479 COPY_STRING(pDataFile);
1480 COPY_STRING(pConfigFile);
1481 COPY_STRING(pHelpFile);
1482 COPY_MULTIZ_STRING(pDependentFiles);
1483 COPY_STRING(pMonitorName);
1484 COPY_STRING(pDefaultDataType);
1485 COPY_MULTIZ_STRING(pszzPreviousNames);
1490 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1491 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1493 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1496 COPY_STRING(pEnvironment);
1497 COPY_STRING(pDriverPath);
1498 COPY_STRING(pDataFile);
1499 COPY_STRING(pConfigFile);
1504 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1505 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1507 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1510 COPY_STRING(pEnvironment);
1511 COPY_STRING(pDriverPath);
1512 COPY_STRING(pDataFile);
1513 COPY_STRING(pConfigFile);
1514 COPY_STRING(pHelpFile);
1515 COPY_MULTIZ_STRING(pDependentFiles);
1516 COPY_STRING(pMonitorName);
1517 COPY_STRING(pDefaultDataType);
1518 COPY_MULTIZ_STRING(pszzPreviousNames);
1519 COPY_STRING(pszMfgName);
1520 COPY_STRING(pszOEMUrl);
1521 COPY_STRING(pszHardwareID);
1522 COPY_STRING(pszProvider);
1527 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1528 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1530 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1533 COPY_STRING(pEnvironment);
1534 COPY_STRING(pDriverPath);
1535 COPY_STRING(pDataFile);
1536 COPY_STRING(pConfigFile);
1537 COPY_STRING(pHelpFile);
1538 COPY_MULTIZ_STRING(pDependentFiles);
1539 COPY_STRING(pMonitorName);
1540 COPY_STRING(pDefaultDataType);
1541 COPY_MULTIZ_STRING(pszzPreviousNames);
1542 COPY_STRING(pszMfgName);
1543 COPY_STRING(pszOEMUrl);
1544 COPY_STRING(pszHardwareID);
1545 COPY_STRING(pszProvider);
1546 COPY_STRING(pszPrintProcessor);
1547 COPY_STRING(pszVendorSetup);
1548 COPY_MULTIZ_STRING(pszzColorProfiles);
1549 COPY_STRING(pszInfPath);
1550 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1556 FIXME("for level %u\n", level);
1559 pDriversW += di_sizeof[level];
1560 out += di_sizeof[level];
1565 #undef COPY_MULTIZ_STRING
1569 /***********************************************************
1570 * PRINTER_INFO_2AtoW
1571 * Creates a unicode copy of PRINTER_INFO_2A on heap
1573 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1575 LPPRINTER_INFO_2W piW;
1576 UNICODE_STRING usBuffer;
1578 if(!piA) return NULL;
1579 piW = HeapAlloc(heap, 0, sizeof(*piW));
1580 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1582 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1583 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1584 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1585 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1586 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1587 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1588 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1589 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1590 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1591 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1592 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1593 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1597 /***********************************************************
1598 * FREE_PRINTER_INFO_2W
1599 * Free PRINTER_INFO_2W and all strings
1601 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1605 HeapFree(heap,0,piW->pServerName);
1606 HeapFree(heap,0,piW->pPrinterName);
1607 HeapFree(heap,0,piW->pShareName);
1608 HeapFree(heap,0,piW->pPortName);
1609 HeapFree(heap,0,piW->pDriverName);
1610 HeapFree(heap,0,piW->pComment);
1611 HeapFree(heap,0,piW->pLocation);
1612 HeapFree(heap,0,piW->pDevMode);
1613 HeapFree(heap,0,piW->pSepFile);
1614 HeapFree(heap,0,piW->pPrintProcessor);
1615 HeapFree(heap,0,piW->pDatatype);
1616 HeapFree(heap,0,piW->pParameters);
1617 HeapFree(heap,0,piW);
1621 /******************************************************************
1622 * DeviceCapabilities [WINSPOOL.@]
1623 * DeviceCapabilitiesA [WINSPOOL.@]
1626 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1627 LPSTR pOutput, LPDEVMODEA lpdm)
1631 if (!GDI_CallDeviceCapabilities16)
1633 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1635 if (!GDI_CallDeviceCapabilities16) return -1;
1637 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1639 /* If DC_PAPERSIZE map POINT16s to POINTs */
1640 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1641 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1642 POINT *pt = (POINT *)pOutput;
1644 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1645 for(i = 0; i < ret; i++, pt++)
1650 HeapFree( GetProcessHeap(), 0, tmp );
1656 /*****************************************************************************
1657 * DeviceCapabilitiesW [WINSPOOL.@]
1659 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1662 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1663 WORD fwCapability, LPWSTR pOutput,
1664 const DEVMODEW *pDevMode)
1666 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1667 LPSTR pDeviceA = strdupWtoA(pDevice);
1668 LPSTR pPortA = strdupWtoA(pPort);
1671 if(pOutput && (fwCapability == DC_BINNAMES ||
1672 fwCapability == DC_FILEDEPENDENCIES ||
1673 fwCapability == DC_PAPERNAMES)) {
1674 /* These need A -> W translation */
1677 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1681 switch(fwCapability) {
1686 case DC_FILEDEPENDENCIES:
1690 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1691 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1693 for(i = 0; i < ret; i++)
1694 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1695 pOutput + (i * size), size);
1696 HeapFree(GetProcessHeap(), 0, pOutputA);
1698 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1699 (LPSTR)pOutput, dmA);
1701 HeapFree(GetProcessHeap(),0,pPortA);
1702 HeapFree(GetProcessHeap(),0,pDeviceA);
1703 HeapFree(GetProcessHeap(),0,dmA);
1707 /******************************************************************
1708 * DocumentPropertiesA [WINSPOOL.@]
1710 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1712 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1713 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1714 LPDEVMODEA pDevModeInput,DWORD fMode )
1716 LPSTR lpName = pDeviceName;
1717 static CHAR port[] = "LPT1:";
1720 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1721 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1725 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1727 ERR("no name from hPrinter?\n");
1728 SetLastError(ERROR_INVALID_HANDLE);
1731 lpName = strdupWtoA(lpNameW);
1734 if (!GDI_CallExtDeviceMode16)
1736 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1738 if (!GDI_CallExtDeviceMode16) {
1739 ERR("No CallExtDeviceMode16?\n");
1743 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1744 pDevModeInput, NULL, fMode);
1747 HeapFree(GetProcessHeap(),0,lpName);
1752 /*****************************************************************************
1753 * DocumentPropertiesW (WINSPOOL.@)
1755 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1757 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1759 LPDEVMODEW pDevModeOutput,
1760 LPDEVMODEW pDevModeInput, DWORD fMode)
1763 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1764 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1765 LPDEVMODEA pDevModeOutputA = NULL;
1768 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1769 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1771 if(pDevModeOutput) {
1772 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1773 if(ret < 0) return ret;
1774 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1776 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1777 pDevModeInputA, fMode);
1778 if(pDevModeOutput) {
1779 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1780 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1782 if(fMode == 0 && ret > 0)
1783 ret += (CCHDEVICENAME + CCHFORMNAME);
1784 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1785 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1789 /*****************************************************************************
1790 * IsValidDevmodeA [WINSPOOL.@]
1792 * Validate a DEVMODE structure and fix errors if possible.
1795 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1797 FIXME("(%p,%ld): stub\n", pDevMode, size);
1805 /*****************************************************************************
1806 * IsValidDevmodeW [WINSPOOL.@]
1808 * Validate a DEVMODE structure and fix errors if possible.
1811 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1813 FIXME("(%p,%ld): stub\n", pDevMode, size);
1821 /******************************************************************
1822 * OpenPrinterA [WINSPOOL.@]
1827 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1828 LPPRINTER_DEFAULTSA pDefault)
1830 UNICODE_STRING lpPrinterNameW;
1831 UNICODE_STRING usBuffer;
1832 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1833 PWSTR pwstrPrinterNameW;
1836 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1839 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1840 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1841 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1842 pDefaultW = &DefaultW;
1844 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1846 RtlFreeUnicodeString(&usBuffer);
1847 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1849 RtlFreeUnicodeString(&lpPrinterNameW);
1853 /******************************************************************
1854 * OpenPrinterW [WINSPOOL.@]
1856 * Open a Printer / Printserver or a Printer-Object
1859 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1860 * phPrinter [O] The resulting Handle is stored here
1861 * pDefault [I] PTR to Default Printer Settings or NULL
1868 * lpPrinterName is one of:
1869 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1870 *| Printer: "PrinterName"
1871 *| Printer-Object: "PrinterName,Job xxx"
1872 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1873 *| XcvPort: "Servername,XcvPort PortName"
1876 *| Printer-Object not supported
1877 *| pDefaults is ignored
1880 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1883 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1885 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1886 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1890 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1891 SetLastError(ERROR_INVALID_PARAMETER);
1895 /* Get the unique handle of the printer or Printserver */
1896 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1897 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1898 return (*phPrinter != 0);
1901 /******************************************************************
1902 * AddMonitorA [WINSPOOL.@]
1907 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1909 LPWSTR nameW = NULL;
1912 LPMONITOR_INFO_2A mi2a;
1913 MONITOR_INFO_2W mi2w;
1915 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1916 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1917 debugstr_a(mi2a ? mi2a->pName : NULL),
1918 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1919 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1922 SetLastError(ERROR_INVALID_LEVEL);
1926 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1932 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1933 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1934 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1937 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1939 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1940 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1941 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1943 if (mi2a->pEnvironment) {
1944 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1945 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1946 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1948 if (mi2a->pDLLName) {
1949 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1950 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1951 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1954 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1956 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1957 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1958 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1960 HeapFree(GetProcessHeap(), 0, nameW);
1964 /******************************************************************************
1965 * AddMonitorW [WINSPOOL.@]
1967 * Install a Printmonitor
1970 * pName [I] Servername or NULL (local Computer)
1971 * Level [I] Structure-Level (Must be 2)
1972 * pMonitors [I] PTR to MONITOR_INFO_2
1979 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1982 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1984 LPMONITOR_INFO_2W mi2w;
1986 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1987 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1988 debugstr_w(mi2w ? mi2w->pName : NULL),
1989 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1990 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1992 if ((backend == NULL) && !load_backend()) return FALSE;
1995 SetLastError(ERROR_INVALID_LEVEL);
1999 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2004 return backend->fpAddMonitor(pName, Level, pMonitors);
2007 /******************************************************************
2008 * DeletePrinterDriverA [WINSPOOL.@]
2011 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2013 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2016 /******************************************************************
2017 * DeletePrinterDriverW [WINSPOOL.@]
2020 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2022 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2025 /******************************************************************
2026 * DeleteMonitorA [WINSPOOL.@]
2028 * See DeleteMonitorW.
2031 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2033 LPWSTR nameW = NULL;
2034 LPWSTR EnvironmentW = NULL;
2035 LPWSTR MonitorNameW = NULL;
2040 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2041 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2042 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2046 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2047 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2048 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2051 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2052 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2053 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2056 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2058 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2059 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2060 HeapFree(GetProcessHeap(), 0, nameW);
2064 /******************************************************************
2065 * DeleteMonitorW [WINSPOOL.@]
2067 * Delete a specific Printmonitor from a Printing-Environment
2070 * pName [I] Servername or NULL (local Computer)
2071 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2072 * pMonitorName [I] Name of the Monitor, that should be deleted
2079 * pEnvironment is ignored in Windows for the local Computer.
2082 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2085 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2086 debugstr_w(pMonitorName));
2088 if ((backend == NULL) && !load_backend()) return FALSE;
2090 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2094 /******************************************************************
2095 * DeletePortA [WINSPOOL.@]
2100 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2102 LPWSTR nameW = NULL;
2103 LPWSTR portW = NULL;
2107 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2109 /* convert servername to unicode */
2111 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2112 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2113 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2116 /* convert portname to unicode */
2118 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2119 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2120 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2123 res = DeletePortW(nameW, hWnd, portW);
2124 HeapFree(GetProcessHeap(), 0, nameW);
2125 HeapFree(GetProcessHeap(), 0, portW);
2129 /******************************************************************
2130 * DeletePortW [WINSPOOL.@]
2132 * Delete a specific Port
2135 * pName [I] Servername or NULL (local Computer)
2136 * hWnd [I] Handle to parent Window for the Dialog-Box
2137 * pPortName [I] Name of the Port, that should be deleted
2144 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2146 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2148 if ((backend == NULL) && !load_backend()) return FALSE;
2151 SetLastError(RPC_X_NULL_REF_POINTER);
2155 return backend->fpDeletePort(pName, hWnd, pPortName);
2158 /******************************************************************************
2159 * SetPrinterW [WINSPOOL.@]
2161 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2163 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2164 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2168 /******************************************************************************
2169 * WritePrinter [WINSPOOL.@]
2171 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2173 opened_printer_t *printer;
2176 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2178 EnterCriticalSection(&printer_handles_cs);
2179 printer = get_opened_printer(hPrinter);
2182 SetLastError(ERROR_INVALID_HANDLE);
2188 SetLastError(ERROR_SPL_NO_STARTDOC);
2192 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2194 LeaveCriticalSection(&printer_handles_cs);
2198 /*****************************************************************************
2199 * AddFormA [WINSPOOL.@]
2201 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2203 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2207 /*****************************************************************************
2208 * AddFormW [WINSPOOL.@]
2210 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2212 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2216 /*****************************************************************************
2217 * AddJobA [WINSPOOL.@]
2219 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2222 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2226 SetLastError(ERROR_INVALID_LEVEL);
2230 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2233 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2234 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2235 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2236 if(*pcbNeeded > cbBuf) {
2237 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2240 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2241 addjobA->JobId = addjobW->JobId;
2242 addjobA->Path = (char *)(addjobA + 1);
2243 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2249 /*****************************************************************************
2250 * AddJobW [WINSPOOL.@]
2252 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2254 opened_printer_t *printer;
2257 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2258 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2259 WCHAR path[MAX_PATH], filename[MAX_PATH];
2261 ADDJOB_INFO_1W *addjob;
2263 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2265 EnterCriticalSection(&printer_handles_cs);
2267 printer = get_opened_printer(hPrinter);
2270 SetLastError(ERROR_INVALID_HANDLE);
2275 SetLastError(ERROR_INVALID_LEVEL);
2279 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2283 job->job_id = InterlockedIncrement(&next_job_id);
2285 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2286 if(path[len - 1] != '\\')
2288 memcpy(path + len, spool_path, sizeof(spool_path));
2289 sprintfW(filename, fmtW, path, job->job_id);
2291 len = strlenW(filename);
2292 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2293 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2294 job->document_title = strdupW(default_doc_title);
2295 job->printer_name = strdupW(printer->name);
2296 job->devmode = NULL;
2297 list_add_tail(&printer->queue->jobs, &job->entry);
2299 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2300 if(*pcbNeeded <= cbBuf) {
2301 addjob = (ADDJOB_INFO_1W*)pData;
2302 addjob->JobId = job->job_id;
2303 addjob->Path = (WCHAR *)(addjob + 1);
2304 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2307 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2310 LeaveCriticalSection(&printer_handles_cs);
2314 /*****************************************************************************
2315 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2317 * Return the PATH for the Print-Processors
2319 * See GetPrintProcessorDirectoryW.
2323 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2324 DWORD level, LPBYTE Info,
2325 DWORD cbBuf, LPDWORD pcbNeeded)
2327 LPWSTR serverW = NULL;
2332 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2333 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2337 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2338 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2339 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2343 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2344 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2345 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2348 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2349 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2351 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2354 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2355 cbBuf, NULL, NULL) > 0;
2358 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2359 HeapFree(GetProcessHeap(), 0, envW);
2360 HeapFree(GetProcessHeap(), 0, serverW);
2364 /*****************************************************************************
2365 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2367 * Return the PATH for the Print-Processors
2370 * server [I] Servername (NT only) or NULL (local Computer)
2371 * env [I] Printing-Environment (see below) or NULL (Default)
2372 * level [I] Structure-Level (must be 1)
2373 * Info [O] PTR to Buffer that receives the Result
2374 * cbBuf [I] Size of Buffer at "Info"
2375 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2376 * required for the Buffer at "Info"
2379 * Success: TRUE and in pcbNeeded the Bytes used in Info
2380 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2381 * if cbBuf is too small
2383 * Native Values returned in Info on Success:
2384 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2385 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2386 *| win9x(Windows 4.0): "%winsysdir%"
2388 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2391 * Only NULL or "" is supported for server
2394 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2395 DWORD level, LPBYTE Info,
2396 DWORD cbBuf, LPDWORD pcbNeeded)
2399 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2400 Info, cbBuf, pcbNeeded);
2402 if ((backend == NULL) && !load_backend()) return FALSE;
2405 /* (Level != 1) is ignored in win9x */
2406 SetLastError(ERROR_INVALID_LEVEL);
2410 if (pcbNeeded == NULL) {
2411 /* (pcbNeeded == NULL) is ignored in win9x */
2412 SetLastError(RPC_X_NULL_REF_POINTER);
2416 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2419 /*****************************************************************************
2420 * WINSPOOL_OpenDriverReg [internal]
2422 * opens the registry for the printer drivers depending on the given input
2423 * variable pEnvironment
2426 * the opened hkey on success
2429 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2433 const printenv_t * env;
2435 TRACE("(%s)\n", debugstr_w(pEnvironment));
2437 env = validate_envW(pEnvironment);
2438 if (!env) return NULL;
2440 buffer = HeapAlloc( GetProcessHeap(), 0,
2441 (strlenW(DriversW) + strlenW(env->envname) +
2442 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2444 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2445 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2446 HeapFree(GetProcessHeap(), 0, buffer);
2451 /*****************************************************************************
2452 * set_devices_and_printerports [internal]
2454 * set the [Devices] and [PrinterPorts] entries for a printer.
2457 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2459 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2463 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2465 /* FIXME: the driver must change to "winspool" */
2466 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2468 lstrcpyW(devline, driver_nt);
2469 lstrcatW(devline, commaW);
2470 lstrcatW(devline, pi->pPortName);
2472 TRACE("using %s\n", debugstr_w(devline));
2473 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2474 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2475 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2476 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2480 lstrcatW(devline, timeout_15_45);
2481 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2482 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2483 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2484 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2487 HeapFree(GetProcessHeap(), 0, devline);
2491 /*****************************************************************************
2492 * AddPrinterW [WINSPOOL.@]
2494 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2496 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2500 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2502 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2503 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2504 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2505 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2506 statusW[] = {'S','t','a','t','u','s',0},
2507 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2509 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2512 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2513 SetLastError(ERROR_INVALID_PARAMETER);
2517 ERR("Level = %d, unsupported!\n", Level);
2518 SetLastError(ERROR_INVALID_LEVEL);
2522 SetLastError(ERROR_INVALID_PARAMETER);
2525 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2527 ERR("Can't create Printers key\n");
2530 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2531 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2532 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2533 RegCloseKey(hkeyPrinter);
2534 RegCloseKey(hkeyPrinters);
2537 RegCloseKey(hkeyPrinter);
2539 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2541 ERR("Can't create Drivers key\n");
2542 RegCloseKey(hkeyPrinters);
2545 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2547 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2548 RegCloseKey(hkeyPrinters);
2549 RegCloseKey(hkeyDrivers);
2550 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2553 RegCloseKey(hkeyDriver);
2554 RegCloseKey(hkeyDrivers);
2556 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2557 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2558 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2559 RegCloseKey(hkeyPrinters);
2563 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2565 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2566 SetLastError(ERROR_INVALID_PRINTER_NAME);
2567 RegCloseKey(hkeyPrinters);
2571 set_devices_and_printerports(pi);
2572 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2573 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2574 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2576 /* See if we can load the driver. We may need the devmode structure anyway
2579 * Note that DocumentPropertiesW will briefly try to open the printer we
2580 * just create to find a DEVMODEA struct (it will use the WINEPS default
2581 * one in case it is not there, so we are ok).
2583 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2586 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2587 size = sizeof(DEVMODEW);
2593 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2595 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2597 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2598 HeapFree(GetProcessHeap(),0,dmW);
2603 /* set devmode to printer name */
2604 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2608 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2609 and we support these drivers. NT writes DEVMODEW so somehow
2610 we'll need to distinguish between these when we support NT
2614 dmA = DEVMODEdupWtoA(dmW);
2615 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2616 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2617 HeapFree(GetProcessHeap(), 0, dmA);
2619 HeapFree(GetProcessHeap(), 0, dmW);
2621 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2622 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2623 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2624 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2626 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2627 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2628 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2629 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2630 (LPBYTE)&pi->Priority, sizeof(DWORD));
2631 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2632 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2633 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2634 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2635 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2636 (LPBYTE)&pi->Status, sizeof(DWORD));
2637 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2638 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2640 RegCloseKey(hkeyPrinter);
2641 RegCloseKey(hkeyPrinters);
2642 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2643 ERR("OpenPrinter failing\n");
2649 /*****************************************************************************
2650 * AddPrinterA [WINSPOOL.@]
2652 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2654 UNICODE_STRING pNameW;
2656 PRINTER_INFO_2W *piW;
2657 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2660 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2662 ERR("Level = %d, unsupported!\n", Level);
2663 SetLastError(ERROR_INVALID_LEVEL);
2666 pwstrNameW = asciitounicode(&pNameW,pName);
2667 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2669 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2671 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2672 RtlFreeUnicodeString(&pNameW);
2677 /*****************************************************************************
2678 * ClosePrinter [WINSPOOL.@]
2680 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2682 UINT_PTR i = (UINT_PTR)hPrinter;
2683 opened_printer_t *printer = NULL;
2686 TRACE("(%p)\n", hPrinter);
2688 EnterCriticalSection(&printer_handles_cs);
2690 if ((i > 0) && (i <= nb_printer_handles))
2691 printer = printer_handles[i - 1];
2696 struct list *cursor, *cursor2;
2698 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2700 if (printer->backend_printer) {
2701 backend->fpClosePrinter(printer->backend_printer);
2705 EndDocPrinter(hPrinter);
2707 if(InterlockedDecrement(&printer->queue->ref) == 0)
2709 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2711 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2712 ScheduleJob(hPrinter, job->job_id);
2714 HeapFree(GetProcessHeap(), 0, printer->queue);
2717 HeapFree(GetProcessHeap(), 0, printer->printername);
2718 HeapFree(GetProcessHeap(), 0, printer->name);
2719 HeapFree(GetProcessHeap(), 0, printer);
2720 printer_handles[i - 1] = NULL;
2723 LeaveCriticalSection(&printer_handles_cs);
2727 /*****************************************************************************
2728 * DeleteFormA [WINSPOOL.@]
2730 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2732 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2736 /*****************************************************************************
2737 * DeleteFormW [WINSPOOL.@]
2739 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2741 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2745 /*****************************************************************************
2746 * DeletePrinter [WINSPOOL.@]
2748 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2750 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2751 HKEY hkeyPrinters, hkey;
2754 SetLastError(ERROR_INVALID_HANDLE);
2757 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2758 RegDeleteTreeW(hkeyPrinters, lpNameW);
2759 RegCloseKey(hkeyPrinters);
2761 WriteProfileStringW(devicesW, lpNameW, NULL);
2762 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2764 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2765 RegDeleteValueW(hkey, lpNameW);
2769 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2770 RegDeleteValueW(hkey, lpNameW);
2776 /*****************************************************************************
2777 * SetPrinterA [WINSPOOL.@]
2779 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2782 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2786 /*****************************************************************************
2787 * SetJobA [WINSPOOL.@]
2789 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2790 LPBYTE pJob, DWORD Command)
2794 UNICODE_STRING usBuffer;
2796 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2798 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2799 are all ignored by SetJob, so we don't bother copying them */
2807 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2808 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2810 JobW = (LPBYTE)info1W;
2811 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2812 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2813 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2814 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2815 info1W->Status = info1A->Status;
2816 info1W->Priority = info1A->Priority;
2817 info1W->Position = info1A->Position;
2818 info1W->PagesPrinted = info1A->PagesPrinted;
2823 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2824 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2826 JobW = (LPBYTE)info2W;
2827 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2828 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2829 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2830 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2831 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2832 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2833 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2834 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2835 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2836 info2W->Status = info2A->Status;
2837 info2W->Priority = info2A->Priority;
2838 info2W->Position = info2A->Position;
2839 info2W->StartTime = info2A->StartTime;
2840 info2W->UntilTime = info2A->UntilTime;
2841 info2W->PagesPrinted = info2A->PagesPrinted;
2845 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2846 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2849 SetLastError(ERROR_INVALID_LEVEL);
2853 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2859 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2860 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2861 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2862 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2863 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2868 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2869 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2870 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2871 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2872 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2873 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2874 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2875 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2876 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2880 HeapFree(GetProcessHeap(), 0, JobW);
2885 /*****************************************************************************
2886 * SetJobW [WINSPOOL.@]
2888 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2889 LPBYTE pJob, DWORD Command)
2895 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2896 FIXME("Ignoring everything other than document title\n");
2898 EnterCriticalSection(&printer_handles_cs);
2899 job = get_job(hPrinter, JobId);
2909 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2910 HeapFree(GetProcessHeap(), 0, job->document_title);
2911 job->document_title = strdupW(info1->pDocument);
2916 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2917 HeapFree(GetProcessHeap(), 0, job->document_title);
2918 job->document_title = strdupW(info2->pDocument);
2919 HeapFree(GetProcessHeap(), 0, job->devmode);
2920 if (info2->pDevMode)
2922 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2923 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2924 memcpy(job->devmode, info2->pDevMode, size);
2927 job->devmode = NULL;
2933 SetLastError(ERROR_INVALID_LEVEL);
2938 LeaveCriticalSection(&printer_handles_cs);
2942 /*****************************************************************************
2943 * EndDocPrinter [WINSPOOL.@]
2945 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2947 opened_printer_t *printer;
2949 TRACE("(%p)\n", hPrinter);
2951 EnterCriticalSection(&printer_handles_cs);
2953 printer = get_opened_printer(hPrinter);
2956 SetLastError(ERROR_INVALID_HANDLE);
2962 SetLastError(ERROR_SPL_NO_STARTDOC);
2966 CloseHandle(printer->doc->hf);
2967 ScheduleJob(hPrinter, printer->doc->job_id);
2968 HeapFree(GetProcessHeap(), 0, printer->doc);
2969 printer->doc = NULL;
2972 LeaveCriticalSection(&printer_handles_cs);
2976 /*****************************************************************************
2977 * EndPagePrinter [WINSPOOL.@]
2979 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2981 FIXME("(%p): stub\n", hPrinter);
2985 /*****************************************************************************
2986 * StartDocPrinterA [WINSPOOL.@]
2988 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2990 UNICODE_STRING usBuffer;
2992 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2995 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2996 or one (DOC_INFO_3) extra DWORDs */
3000 doc2W.JobId = doc2->JobId;
3003 doc2W.dwMode = doc2->dwMode;
3006 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3007 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3008 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3012 SetLastError(ERROR_INVALID_LEVEL);
3016 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3018 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3019 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3020 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3025 /*****************************************************************************
3026 * StartDocPrinterW [WINSPOOL.@]
3028 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3030 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3031 opened_printer_t *printer;
3032 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3033 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3034 JOB_INFO_1W job_info;
3035 DWORD needed, ret = 0;
3040 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3041 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3042 debugstr_w(doc->pDatatype));
3044 if(Level < 1 || Level > 3)
3046 SetLastError(ERROR_INVALID_LEVEL);
3050 EnterCriticalSection(&printer_handles_cs);
3051 printer = get_opened_printer(hPrinter);
3054 SetLastError(ERROR_INVALID_HANDLE);
3060 SetLastError(ERROR_INVALID_PRINTER_STATE);
3064 /* Even if we're printing to a file we still add a print job, we'll
3065 just ignore the spool file name */
3067 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3069 ERR("AddJob failed gle %u\n", GetLastError());
3073 /* use pOutputFile only, when it is a real filename */
3074 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3075 filename = doc->pOutputFile;
3077 filename = addjob->Path;
3079 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3080 if(hf == INVALID_HANDLE_VALUE)
3083 memset(&job_info, 0, sizeof(job_info));
3084 job_info.pDocument = doc->pDocName;
3085 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3087 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3088 printer->doc->hf = hf;
3089 ret = printer->doc->job_id = addjob->JobId;
3090 job = get_job(hPrinter, ret);
3091 job->portname = strdupW(doc->pOutputFile);
3094 LeaveCriticalSection(&printer_handles_cs);
3099 /*****************************************************************************
3100 * StartPagePrinter [WINSPOOL.@]
3102 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3104 FIXME("(%p): stub\n", hPrinter);
3108 /*****************************************************************************
3109 * GetFormA [WINSPOOL.@]
3111 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3112 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3114 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3115 Level,pForm,cbBuf,pcbNeeded);
3119 /*****************************************************************************
3120 * GetFormW [WINSPOOL.@]
3122 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3123 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3125 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3126 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3130 /*****************************************************************************
3131 * SetFormA [WINSPOOL.@]
3133 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3136 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3140 /*****************************************************************************
3141 * SetFormW [WINSPOOL.@]
3143 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3146 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3150 /*****************************************************************************
3151 * ReadPrinter [WINSPOOL.@]
3153 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3154 LPDWORD pNoBytesRead)
3156 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3160 /*****************************************************************************
3161 * ResetPrinterA [WINSPOOL.@]
3163 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3165 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3169 /*****************************************************************************
3170 * ResetPrinterW [WINSPOOL.@]
3172 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3174 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3178 /*****************************************************************************
3179 * WINSPOOL_GetDWORDFromReg
3181 * Return DWORD associated with ValueName from hkey.
3183 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3185 DWORD sz = sizeof(DWORD), type, value = 0;
3188 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3190 if(ret != ERROR_SUCCESS) {
3191 WARN("Got ret = %d on name %s\n", ret, ValueName);
3194 if(type != REG_DWORD) {
3195 ERR("Got type %d\n", type);
3202 /*****************************************************************************
3203 * get_filename_from_reg [internal]
3205 * Get ValueName from hkey storing result in out
3206 * when the Value in the registry has only a filename, use driverdir as prefix
3207 * outlen is space left in out
3208 * String is stored either as unicode or ascii
3212 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3213 LPBYTE out, DWORD outlen, LPDWORD needed)
3215 WCHAR filename[MAX_PATH];
3219 LPWSTR buffer = filename;
3223 size = sizeof(filename);
3225 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3226 if (ret == ERROR_MORE_DATA) {
3227 TRACE("need dynamic buffer: %u\n", size);
3228 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3230 /* No Memory is bad */
3234 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3237 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3238 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3244 /* do we have a full path ? */
3245 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3246 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3249 /* we must build the full Path */
3251 if ((out) && (outlen > dirlen)) {
3252 lstrcpyW((LPWSTR)out, driverdir);
3260 /* write the filename */
3261 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3262 if ((out) && (outlen >= size)) {
3263 lstrcpyW((LPWSTR)out, ptr);
3270 ptr += lstrlenW(ptr)+1;
3271 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3274 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3276 /* write the multisz-termination */
3277 if (type == REG_MULTI_SZ) {
3278 size = sizeof(WCHAR);
3281 if (out && (outlen >= size)) {
3282 memset (out, 0, size);
3288 /*****************************************************************************
3289 * WINSPOOL_GetStringFromReg
3291 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3292 * String is stored as unicode.
3294 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3295 DWORD buflen, DWORD *needed)
3297 DWORD sz = buflen, type;
3300 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3301 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3302 WARN("Got ret = %d\n", ret);
3306 /* add space for terminating '\0' */
3307 sz += sizeof(WCHAR);
3311 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3316 /*****************************************************************************
3317 * WINSPOOL_GetDefaultDevMode
3319 * Get a default DevMode values for wineps.
3323 static void WINSPOOL_GetDefaultDevMode(
3325 DWORD buflen, DWORD *needed)
3328 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3330 /* fill default DEVMODE - should be read from ppd... */
3331 ZeroMemory( &dm, sizeof(dm) );
3332 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3333 dm.dmSpecVersion = DM_SPECVERSION;
3334 dm.dmDriverVersion = 1;
3335 dm.dmSize = sizeof(DEVMODEW);
3336 dm.dmDriverExtra = 0;
3338 DM_ORIENTATION | DM_PAPERSIZE |
3339 DM_PAPERLENGTH | DM_PAPERWIDTH |
3342 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3343 DM_YRESOLUTION | DM_TTOPTION;
3345 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3346 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3347 dm.u1.s1.dmPaperLength = 2970;
3348 dm.u1.s1.dmPaperWidth = 2100;
3350 dm.u1.s1.dmScale = 100;
3351 dm.u1.s1.dmCopies = 1;
3352 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3353 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3356 dm.dmYResolution = 300; /* 300dpi */
3357 dm.dmTTOption = DMTT_BITMAP;
3360 /* dm.dmLogPixels */
3361 /* dm.dmBitsPerPel */
3362 /* dm.dmPelsWidth */
3363 /* dm.dmPelsHeight */
3364 /* dm.u2.dmDisplayFlags */
3365 /* dm.dmDisplayFrequency */
3366 /* dm.dmICMMethod */
3367 /* dm.dmICMIntent */
3368 /* dm.dmMediaType */
3369 /* dm.dmDitherType */
3370 /* dm.dmReserved1 */
3371 /* dm.dmReserved2 */
3372 /* dm.dmPanningWidth */
3373 /* dm.dmPanningHeight */
3375 if(buflen >= sizeof(DEVMODEW))
3376 memcpy(ptr, &dm, sizeof(DEVMODEW));
3377 *needed = sizeof(DEVMODEW);
3380 /*****************************************************************************
3381 * WINSPOOL_GetDevModeFromReg
3383 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3384 * DevMode is stored either as unicode or ascii.
3386 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3388 DWORD buflen, DWORD *needed)
3390 DWORD sz = buflen, type;
3393 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3394 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3395 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3396 if (sz < sizeof(DEVMODEA))
3398 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3401 /* ensures that dmSize is not erratically bogus if registry is invalid */
3402 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3403 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3404 sz += (CCHDEVICENAME + CCHFORMNAME);
3405 if (ptr && (buflen >= sz)) {
3406 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3407 memcpy(ptr, dmW, sz);
3408 HeapFree(GetProcessHeap(),0,dmW);
3414 /*********************************************************************
3415 * WINSPOOL_GetPrinter_1
3417 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3419 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3420 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3422 DWORD size, left = cbBuf;
3423 BOOL space = (cbBuf > 0);
3428 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3429 if(space && size <= left) {
3430 pi1->pName = (LPWSTR)ptr;
3438 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3439 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3440 if(space && size <= left) {
3441 pi1->pDescription = (LPWSTR)ptr;
3449 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3450 if(space && size <= left) {
3451 pi1->pComment = (LPWSTR)ptr;
3459 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3461 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3462 memset(pi1, 0, sizeof(*pi1));
3466 /*********************************************************************
3467 * WINSPOOL_GetPrinter_2
3469 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3471 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3472 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3474 DWORD size, left = cbBuf;
3475 BOOL space = (cbBuf > 0);
3480 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3481 if(space && size <= left) {
3482 pi2->pPrinterName = (LPWSTR)ptr;
3489 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3490 if(space && size <= left) {
3491 pi2->pShareName = (LPWSTR)ptr;
3498 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3499 if(space && size <= left) {
3500 pi2->pPortName = (LPWSTR)ptr;
3507 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3508 if(space && size <= left) {
3509 pi2->pDriverName = (LPWSTR)ptr;
3516 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3517 if(space && size <= left) {
3518 pi2->pComment = (LPWSTR)ptr;
3525 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3526 if(space && size <= left) {
3527 pi2->pLocation = (LPWSTR)ptr;
3534 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3535 if(space && size <= left) {
3536 pi2->pDevMode = (LPDEVMODEW)ptr;
3545 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3546 if(space && size <= left) {
3547 pi2->pDevMode = (LPDEVMODEW)ptr;
3554 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3555 if(space && size <= left) {
3556 pi2->pSepFile = (LPWSTR)ptr;
3563 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3564 if(space && size <= left) {
3565 pi2->pPrintProcessor = (LPWSTR)ptr;
3572 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3573 if(space && size <= left) {
3574 pi2->pDatatype = (LPWSTR)ptr;
3581 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3582 if(space && size <= left) {
3583 pi2->pParameters = (LPWSTR)ptr;
3591 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3592 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3593 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3594 "Default Priority");
3595 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3596 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3599 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3600 memset(pi2, 0, sizeof(*pi2));
3605 /*********************************************************************
3606 * WINSPOOL_GetPrinter_4
3608 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3610 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3611 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3613 DWORD size, left = cbBuf;
3614 BOOL space = (cbBuf > 0);
3619 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3620 if(space && size <= left) {
3621 pi4->pPrinterName = (LPWSTR)ptr;
3629 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3632 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3633 memset(pi4, 0, sizeof(*pi4));
3638 /*********************************************************************
3639 * WINSPOOL_GetPrinter_5
3641 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3643 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3644 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3646 DWORD size, left = cbBuf;
3647 BOOL space = (cbBuf > 0);
3652 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3653 if(space && size <= left) {
3654 pi5->pPrinterName = (LPWSTR)ptr;
3661 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3662 if(space && size <= left) {
3663 pi5->pPortName = (LPWSTR)ptr;
3671 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3672 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3674 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3678 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3679 memset(pi5, 0, sizeof(*pi5));
3684 /*********************************************************************
3685 * WINSPOOL_GetPrinter_7
3687 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3689 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3690 DWORD cbBuf, LPDWORD pcbNeeded)
3692 DWORD size, left = cbBuf;
3693 BOOL space = (cbBuf > 0);
3698 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3701 size = sizeof(pi7->pszObjectGUID);
3703 if (space && size <= left) {
3704 pi7->pszObjectGUID = (LPWSTR)ptr;
3711 /* We do not have a Directory Service */
3712 pi7->dwAction = DSPRINT_UNPUBLISH;
3715 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3716 memset(pi7, 0, sizeof(*pi7));
3721 /*********************************************************************
3722 * WINSPOOL_GetPrinter_9
3724 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3726 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3727 DWORD cbBuf, LPDWORD pcbNeeded)
3730 BOOL space = (cbBuf > 0);
3734 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3735 if(space && size <= cbBuf) {
3736 pi9->pDevMode = (LPDEVMODEW)buf;
3743 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3744 if(space && size <= cbBuf) {
3745 pi9->pDevMode = (LPDEVMODEW)buf;
3751 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3752 memset(pi9, 0, sizeof(*pi9));
3757 /*****************************************************************************
3758 * GetPrinterW [WINSPOOL.@]
3760 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3761 DWORD cbBuf, LPDWORD pcbNeeded)
3764 DWORD size, needed = 0;
3766 HKEY hkeyPrinter, hkeyPrinters;
3769 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3771 if (!(name = get_opened_printer_name(hPrinter))) {
3772 SetLastError(ERROR_INVALID_HANDLE);
3776 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3778 ERR("Can't create Printers key\n");
3781 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3783 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3784 RegCloseKey(hkeyPrinters);
3785 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3792 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3794 size = sizeof(PRINTER_INFO_2W);
3796 ptr = pPrinter + size;
3798 memset(pPrinter, 0, size);
3803 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3810 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3812 size = sizeof(PRINTER_INFO_4W);
3814 ptr = pPrinter + size;
3816 memset(pPrinter, 0, size);
3821 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3829 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3831 size = sizeof(PRINTER_INFO_5W);
3833 ptr = pPrinter + size;
3835 memset(pPrinter, 0, size);
3841 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3849 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3851 size = sizeof(PRINTER_INFO_6);
3852 if (size <= cbBuf) {
3853 /* FIXME: We do not update the status yet */
3854 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3866 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3868 size = sizeof(PRINTER_INFO_7W);
3869 if (size <= cbBuf) {
3870 ptr = pPrinter + size;
3872 memset(pPrinter, 0, size);
3878 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3886 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3888 size = sizeof(PRINTER_INFO_9W);
3890 ptr = pPrinter + size;
3892 memset(pPrinter, 0, size);
3898 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3905 FIXME("Unimplemented level %d\n", Level);
3906 SetLastError(ERROR_INVALID_LEVEL);
3907 RegCloseKey(hkeyPrinters);
3908 RegCloseKey(hkeyPrinter);
3912 RegCloseKey(hkeyPrinter);
3913 RegCloseKey(hkeyPrinters);
3915 TRACE("returning %d needed = %d\n", ret, needed);
3916 if(pcbNeeded) *pcbNeeded = needed;
3918 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3922 /*****************************************************************************
3923 * GetPrinterA [WINSPOOL.@]
3925 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3926 DWORD cbBuf, LPDWORD pcbNeeded)
3932 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3934 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3936 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3937 HeapFree(GetProcessHeap(), 0, buf);
3942 /*****************************************************************************
3943 * WINSPOOL_EnumPrintersW
3945 * Implementation of EnumPrintersW
3947 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3948 DWORD dwLevel, LPBYTE lpbPrinters,
3949 DWORD cbBuf, LPDWORD lpdwNeeded,
3950 LPDWORD lpdwReturned)
3953 HKEY hkeyPrinters, hkeyPrinter;
3954 WCHAR PrinterName[255];
3955 DWORD needed = 0, number = 0;
3956 DWORD used, i, left;
3960 memset(lpbPrinters, 0, cbBuf);
3966 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3967 if(dwType == PRINTER_ENUM_DEFAULT)
3970 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3971 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3972 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3974 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3980 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3981 FIXME("dwType = %08x\n", dwType);
3982 SetLastError(ERROR_INVALID_FLAGS);
3986 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3988 ERR("Can't create Printers key\n");
3992 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3993 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3994 RegCloseKey(hkeyPrinters);
3995 ERR("Can't query Printers key\n");
3998 TRACE("Found %d printers\n", number);
4002 used = number * sizeof(PRINTER_INFO_1W);
4005 used = number * sizeof(PRINTER_INFO_2W);
4008 used = number * sizeof(PRINTER_INFO_4W);
4011 used = number * sizeof(PRINTER_INFO_5W);
4015 SetLastError(ERROR_INVALID_LEVEL);
4016 RegCloseKey(hkeyPrinters);
4019 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4021 for(i = 0; i < number; i++) {
4022 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4024 ERR("Can't enum key number %d\n", i);
4025 RegCloseKey(hkeyPrinters);
4028 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4029 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4031 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4032 RegCloseKey(hkeyPrinters);
4037 buf = lpbPrinters + used;
4038 left = cbBuf - used;
4046 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4049 if(pi) pi += sizeof(PRINTER_INFO_1W);
4052 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4055 if(pi) pi += sizeof(PRINTER_INFO_2W);
4058 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4061 if(pi) pi += sizeof(PRINTER_INFO_4W);
4064 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4067 if(pi) pi += sizeof(PRINTER_INFO_5W);
4070 ERR("Shouldn't be here!\n");
4071 RegCloseKey(hkeyPrinter);
4072 RegCloseKey(hkeyPrinters);
4075 RegCloseKey(hkeyPrinter);
4077 RegCloseKey(hkeyPrinters);
4084 memset(lpbPrinters, 0, cbBuf);
4085 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4089 *lpdwReturned = number;
4090 SetLastError(ERROR_SUCCESS);
4095 /******************************************************************
4096 * EnumPrintersW [WINSPOOL.@]
4098 * Enumerates the available printers, print servers and print
4099 * providers, depending on the specified flags, name and level.
4103 * If level is set to 1:
4104 * Returns an array of PRINTER_INFO_1 data structures in the
4105 * lpbPrinters buffer.
4107 * If level is set to 2:
4108 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4109 * Returns an array of PRINTER_INFO_2 data structures in the
4110 * lpbPrinters buffer. Note that according to MSDN also an
4111 * OpenPrinter should be performed on every remote printer.
4113 * If level is set to 4 (officially WinNT only):
4114 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4115 * Fast: Only the registry is queried to retrieve printer names,
4116 * no connection to the driver is made.
4117 * Returns an array of PRINTER_INFO_4 data structures in the
4118 * lpbPrinters buffer.
4120 * If level is set to 5 (officially WinNT4/Win9x only):
4121 * Fast: Only the registry is queried to retrieve printer names,
4122 * no connection to the driver is made.
4123 * Returns an array of PRINTER_INFO_5 data structures in the
4124 * lpbPrinters buffer.
4126 * If level set to 3 or 6+:
4127 * returns zero (failure!)
4129 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4133 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4134 * - Only levels 2, 4 and 5 are implemented at the moment.
4135 * - 16-bit printer drivers are not enumerated.
4136 * - Returned amount of bytes used/needed does not match the real Windoze
4137 * implementation (as in this implementation, all strings are part
4138 * of the buffer, whereas Win32 keeps them somewhere else)
4139 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4142 * - In a regular Wine installation, no registry settings for printers
4143 * exist, which makes this function return an empty list.
4145 BOOL WINAPI EnumPrintersW(
4146 DWORD dwType, /* [in] Types of print objects to enumerate */
4147 LPWSTR lpszName, /* [in] name of objects to enumerate */
4148 DWORD dwLevel, /* [in] type of printer info structure */
4149 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4150 DWORD cbBuf, /* [in] max size of buffer in bytes */
4151 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4152 LPDWORD lpdwReturned /* [out] number of entries returned */
4155 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4156 lpdwNeeded, lpdwReturned);
4159 /******************************************************************
4160 * EnumPrintersA [WINSPOOL.@]
4165 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4166 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4169 UNICODE_STRING pNameU;
4173 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4174 pPrinters, cbBuf, pcbNeeded, pcReturned);
4176 pNameW = asciitounicode(&pNameU, pName);
4178 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4179 MS Office need this */
4180 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4182 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4184 RtlFreeUnicodeString(&pNameU);
4186 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4188 HeapFree(GetProcessHeap(), 0, pPrintersW);
4192 /*****************************************************************************
4193 * WINSPOOL_GetDriverInfoFromReg [internal]
4195 * Enters the information from the registry into the DRIVER_INFO struct
4198 * zero if the printer driver does not exist in the registry
4199 * (only if Level > 1) otherwise nonzero
4201 static BOOL WINSPOOL_GetDriverInfoFromReg(
4204 const printenv_t * env,
4206 LPBYTE ptr, /* DRIVER_INFO */
4207 LPBYTE pDriverStrings, /* strings buffer */
4208 DWORD cbBuf, /* size of string buffer */
4209 LPDWORD pcbNeeded) /* space needed for str. */
4213 WCHAR driverdir[MAX_PATH];
4215 LPBYTE strPtr = pDriverStrings;
4216 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4218 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4219 debugstr_w(DriverName), env,
4220 Level, di, pDriverStrings, cbBuf);
4222 if (di) ZeroMemory(di, di_sizeof[Level]);
4224 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4225 if (*pcbNeeded <= cbBuf)
4226 strcpyW((LPWSTR)strPtr, DriverName);
4228 /* pName for level 1 has a different offset! */
4230 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4234 /* .cVersion and .pName for level > 1 */
4236 di->cVersion = env->driverversion;
4237 di->pName = (LPWSTR) strPtr;
4238 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4241 /* Reserve Space for the largest subdir and a Backslash*/
4242 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4243 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4244 /* Should never Fail */
4247 lstrcatW(driverdir, env->versionsubdir);
4248 lstrcatW(driverdir, backslashW);
4250 /* dirlen must not include the terminating zero */
4251 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4253 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4254 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4255 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4260 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4263 if (*pcbNeeded <= cbBuf) {
4264 lstrcpyW((LPWSTR)strPtr, env->envname);
4265 if (di) di->pEnvironment = (LPWSTR)strPtr;
4266 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4269 /* .pDriverPath is the Graphics rendering engine.
4270 The full Path is required to avoid a crash in some apps */
4271 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4273 if (*pcbNeeded <= cbBuf)
4274 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4276 if (di) di->pDriverPath = (LPWSTR)strPtr;
4277 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4280 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4281 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4283 if (*pcbNeeded <= cbBuf)
4284 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4286 if (di) di->pDataFile = (LPWSTR)strPtr;
4287 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4290 /* .pConfigFile is the Driver user Interface */
4291 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4293 if (*pcbNeeded <= cbBuf)
4294 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4296 if (di) di->pConfigFile = (LPWSTR)strPtr;
4297 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4301 RegCloseKey(hkeyDriver);
4302 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4307 RegCloseKey(hkeyDriver);
4308 FIXME("level 5: incomplete\n");
4313 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4315 if (*pcbNeeded <= cbBuf)
4316 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4318 if (di) di->pHelpFile = (LPWSTR)strPtr;
4319 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4322 /* .pDependentFiles */
4323 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4325 if (*pcbNeeded <= cbBuf)
4326 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4328 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4329 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4331 else if (GetVersion() & 0x80000000) {
4332 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4333 size = 2 * sizeof(WCHAR);
4335 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4337 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4338 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4341 /* .pMonitorName is the optional Language Monitor */
4342 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4344 if (*pcbNeeded <= cbBuf)
4345 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4347 if (di) di->pMonitorName = (LPWSTR)strPtr;
4348 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4351 /* .pDefaultDataType */
4352 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4354 if(*pcbNeeded <= cbBuf)
4355 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4357 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4358 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4362 RegCloseKey(hkeyDriver);
4363 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4367 /* .pszzPreviousNames */
4368 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4370 if(*pcbNeeded <= cbBuf)
4371 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4373 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4374 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4378 RegCloseKey(hkeyDriver);
4379 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4383 /* support is missing, but not important enough for a FIXME */
4384 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4387 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4389 if(*pcbNeeded <= cbBuf)
4390 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4392 if (di) di->pszMfgName = (LPWSTR)strPtr;
4393 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4397 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4399 if(*pcbNeeded <= cbBuf)
4400 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4402 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4403 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4406 /* .pszHardwareID */
4407 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4409 if(*pcbNeeded <= cbBuf)
4410 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4412 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4413 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4417 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4419 if(*pcbNeeded <= cbBuf)
4420 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4422 if (di) di->pszProvider = (LPWSTR)strPtr;
4423 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4427 RegCloseKey(hkeyDriver);
4431 /* support is missing, but not important enough for a FIXME */
4432 TRACE("level 8: incomplete\n");
4434 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4435 RegCloseKey(hkeyDriver);
4439 /*****************************************************************************
4440 * GetPrinterDriverW [WINSPOOL.@]
4442 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4443 DWORD Level, LPBYTE pDriverInfo,
4444 DWORD cbBuf, LPDWORD pcbNeeded)
4447 WCHAR DriverName[100];
4448 DWORD ret, type, size, needed = 0;
4450 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4451 const printenv_t * env;
4453 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4454 Level,pDriverInfo,cbBuf, pcbNeeded);
4457 ZeroMemory(pDriverInfo, cbBuf);
4459 if (!(name = get_opened_printer_name(hPrinter))) {
4460 SetLastError(ERROR_INVALID_HANDLE);
4464 if (Level < 1 || Level == 7 || Level > 8) {
4465 SetLastError(ERROR_INVALID_LEVEL);
4469 env = validate_envW(pEnvironment);
4470 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4472 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4474 ERR("Can't create Printers key\n");
4477 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4479 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4480 RegCloseKey(hkeyPrinters);
4481 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4484 size = sizeof(DriverName);
4486 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4487 (LPBYTE)DriverName, &size);
4488 RegCloseKey(hkeyPrinter);
4489 RegCloseKey(hkeyPrinters);
4490 if(ret != ERROR_SUCCESS) {
4491 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4495 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4497 ERR("Can't create Drivers key\n");
4501 size = di_sizeof[Level];
4502 if ((size <= cbBuf) && pDriverInfo)
4503 ptr = pDriverInfo + size;
4505 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4506 env, Level, pDriverInfo, ptr,
4507 (cbBuf < size) ? 0 : cbBuf - size,
4509 RegCloseKey(hkeyDrivers);
4513 RegCloseKey(hkeyDrivers);
4515 if(pcbNeeded) *pcbNeeded = size + needed;
4516 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4517 if(cbBuf >= size + needed) return TRUE;
4518 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4522 /*****************************************************************************
4523 * GetPrinterDriverA [WINSPOOL.@]
4525 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4526 DWORD Level, LPBYTE pDriverInfo,
4527 DWORD cbBuf, LPDWORD pcbNeeded)
4530 UNICODE_STRING pEnvW;
4536 ZeroMemory(pDriverInfo, cbBuf);
4537 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4540 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4541 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4544 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4546 HeapFree(GetProcessHeap(), 0, buf);
4548 RtlFreeUnicodeString(&pEnvW);
4552 /*****************************************************************************
4553 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4555 * Return the PATH for the Printer-Drivers (UNICODE)
4558 * pName [I] Servername (NT only) or NULL (local Computer)
4559 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4560 * Level [I] Structure-Level (must be 1)
4561 * pDriverDirectory [O] PTR to Buffer that receives the Result
4562 * cbBuf [I] Size of Buffer at pDriverDirectory
4563 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4564 * required for pDriverDirectory
4567 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4568 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4569 * if cbBuf is too small
4571 * Native Values returned in pDriverDirectory on Success:
4572 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4573 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4574 *| win9x(Windows 4.0): "%winsysdir%"
4576 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4579 *- Only NULL or "" is supported for pName
4582 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4583 DWORD Level, LPBYTE pDriverDirectory,
4584 DWORD cbBuf, LPDWORD pcbNeeded)
4586 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4587 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4589 if ((backend == NULL) && !load_backend()) return FALSE;
4592 /* (Level != 1) is ignored in win9x */
4593 SetLastError(ERROR_INVALID_LEVEL);
4596 if (pcbNeeded == NULL) {
4597 /* (pcbNeeded == NULL) is ignored in win9x */
4598 SetLastError(RPC_X_NULL_REF_POINTER);
4602 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4603 pDriverDirectory, cbBuf, pcbNeeded);
4608 /*****************************************************************************
4609 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4611 * Return the PATH for the Printer-Drivers (ANSI)
4613 * See GetPrinterDriverDirectoryW.
4616 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4619 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4620 DWORD Level, LPBYTE pDriverDirectory,
4621 DWORD cbBuf, LPDWORD pcbNeeded)
4623 UNICODE_STRING nameW, environmentW;
4626 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4627 WCHAR *driverDirectoryW = NULL;
4629 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4630 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4632 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4634 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4635 else nameW.Buffer = NULL;
4636 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4637 else environmentW.Buffer = NULL;
4639 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4640 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4643 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4644 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4646 *pcbNeeded = needed;
4647 ret = (needed <= cbBuf) ? TRUE : FALSE;
4649 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4651 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4653 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4654 RtlFreeUnicodeString(&environmentW);
4655 RtlFreeUnicodeString(&nameW);
4660 /*****************************************************************************
4661 * AddPrinterDriverA [WINSPOOL.@]
4663 * See AddPrinterDriverW.
4666 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4668 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4669 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4672 /******************************************************************************
4673 * AddPrinterDriverW (WINSPOOL.@)
4675 * Install a Printer Driver
4678 * pName [I] Servername or NULL (local Computer)
4679 * level [I] Level for the supplied DRIVER_INFO_*W struct
4680 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4687 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4689 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4690 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4693 /*****************************************************************************
4694 * AddPrintProcessorA [WINSPOOL.@]
4696 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4697 LPSTR pPrintProcessorName)
4699 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4700 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4704 /*****************************************************************************
4705 * AddPrintProcessorW [WINSPOOL.@]
4707 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4708 LPWSTR pPrintProcessorName)
4710 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4711 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4715 /*****************************************************************************
4716 * AddPrintProvidorA [WINSPOOL.@]
4718 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4720 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4724 /*****************************************************************************
4725 * AddPrintProvidorW [WINSPOOL.@]
4727 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4729 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4733 /*****************************************************************************
4734 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4736 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4737 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4739 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4740 pDevModeOutput, pDevModeInput);
4744 /*****************************************************************************
4745 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4747 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4748 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4750 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4751 pDevModeOutput, pDevModeInput);
4755 /*****************************************************************************
4756 * PrinterProperties [WINSPOOL.@]
4758 * Displays a dialog to set the properties of the printer.
4761 * nonzero on success or zero on failure
4764 * implemented as stub only
4766 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4767 HANDLE hPrinter /* [in] handle to printer object */
4769 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4770 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4774 /*****************************************************************************
4775 * EnumJobsA [WINSPOOL.@]
4778 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4779 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4782 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4783 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4785 if(pcbNeeded) *pcbNeeded = 0;
4786 if(pcReturned) *pcReturned = 0;
4791 /*****************************************************************************
4792 * EnumJobsW [WINSPOOL.@]
4795 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4796 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4799 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4800 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4802 if(pcbNeeded) *pcbNeeded = 0;
4803 if(pcReturned) *pcReturned = 0;
4807 /*****************************************************************************
4808 * WINSPOOL_EnumPrinterDrivers [internal]
4810 * Delivers information about all printer drivers installed on the
4811 * localhost or a given server
4814 * nonzero on success or zero on failure. If the buffer for the returned
4815 * information is too small the function will return an error
4818 * - only implemented for localhost, foreign hosts will return an error
4820 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4821 DWORD Level, LPBYTE pDriverInfo,
4823 DWORD cbBuf, LPDWORD pcbNeeded,
4824 LPDWORD pcFound, DWORD data_offset)
4828 const printenv_t * env;
4830 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4831 debugstr_w(pName), debugstr_w(pEnvironment),
4832 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4834 env = validate_envW(pEnvironment);
4835 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4839 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4841 ERR("Can't open Drivers key\n");
4845 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4846 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4847 RegCloseKey(hkeyDrivers);
4848 ERR("Can't query Drivers key\n");
4851 TRACE("Found %d Drivers\n", *pcFound);
4853 /* get size of single struct
4854 * unicode and ascii structure have the same size
4856 size = di_sizeof[Level];
4858 if (data_offset == 0)
4859 data_offset = size * (*pcFound);
4860 *pcbNeeded = data_offset;
4862 for( i = 0; i < *pcFound; i++) {
4863 WCHAR DriverNameW[255];
4864 PBYTE table_ptr = NULL;
4865 PBYTE data_ptr = NULL;
4868 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4870 ERR("Can't enum key number %d\n", i);
4871 RegCloseKey(hkeyDrivers);
4875 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4876 table_ptr = pDriverInfo + (driver_index + i) * size;
4877 if (pDriverInfo && *pcbNeeded <= cbBuf)
4878 data_ptr = pDriverInfo + *pcbNeeded;
4880 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4881 env, Level, table_ptr, data_ptr,
4882 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4884 RegCloseKey(hkeyDrivers);
4888 *pcbNeeded += needed;
4891 RegCloseKey(hkeyDrivers);
4893 if(cbBuf < *pcbNeeded){
4894 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4901 /*****************************************************************************
4902 * EnumPrinterDriversW [WINSPOOL.@]
4904 * see function EnumPrinterDrivers for RETURNS, BUGS
4906 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4907 LPBYTE pDriverInfo, DWORD cbBuf,
4908 LPDWORD pcbNeeded, LPDWORD pcReturned)
4910 static const WCHAR allW[] = {'a','l','l',0};
4914 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4916 SetLastError(RPC_X_NULL_REF_POINTER);
4920 /* check for local drivers */
4921 if((pName) && (pName[0])) {
4922 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4923 SetLastError(ERROR_ACCESS_DENIED);
4927 /* check input parameter */
4928 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4929 SetLastError(ERROR_INVALID_LEVEL);
4933 if(pDriverInfo && cbBuf > 0)
4934 memset( pDriverInfo, 0, cbBuf);
4936 /* Exception: pull all printers */
4937 if (pEnvironment && !strcmpW(pEnvironment, allW))
4939 DWORD i, needed, bufsize = cbBuf;
4940 DWORD total_needed = 0;
4941 DWORD total_found = 0;
4944 /* Precompute the overall total; we need this to know
4945 where pointers end and data begins (i.e. data_offset) */
4946 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4949 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4950 NULL, 0, 0, &needed, &found, 0);
4951 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4952 total_needed += needed;
4953 total_found += found;
4956 data_offset = di_sizeof[Level] * total_found;
4961 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4964 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4965 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4966 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4968 *pcReturned += found;
4969 *pcbNeeded = needed;
4970 data_offset = needed;
4971 total_found += found;
4976 /* Normal behavior */
4977 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4978 0, cbBuf, pcbNeeded, &found, 0);
4980 *pcReturned = found;
4985 /*****************************************************************************
4986 * EnumPrinterDriversA [WINSPOOL.@]
4988 * see function EnumPrinterDrivers for RETURNS, BUGS
4990 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4991 LPBYTE pDriverInfo, DWORD cbBuf,
4992 LPDWORD pcbNeeded, LPDWORD pcReturned)
4995 UNICODE_STRING pNameW, pEnvironmentW;
4996 PWSTR pwstrNameW, pwstrEnvironmentW;
5000 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5002 pwstrNameW = asciitounicode(&pNameW, pName);
5003 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5005 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5006 buf, cbBuf, pcbNeeded, pcReturned);
5008 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5010 HeapFree(GetProcessHeap(), 0, buf);
5012 RtlFreeUnicodeString(&pNameW);
5013 RtlFreeUnicodeString(&pEnvironmentW);
5018 /******************************************************************************
5019 * EnumPortsA (WINSPOOL.@)
5024 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5025 LPDWORD pcbNeeded, LPDWORD pcReturned)
5028 LPBYTE bufferW = NULL;
5029 LPWSTR nameW = NULL;
5031 DWORD numentries = 0;
5034 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5035 cbBuf, pcbNeeded, pcReturned);
5037 /* convert servername to unicode */
5039 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5040 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5041 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5043 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5044 needed = cbBuf * sizeof(WCHAR);
5045 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5046 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5048 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5049 if (pcbNeeded) needed = *pcbNeeded;
5050 /* HeapReAlloc return NULL, when bufferW was NULL */
5051 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5052 HeapAlloc(GetProcessHeap(), 0, needed);
5054 /* Try again with the large Buffer */
5055 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5057 needed = pcbNeeded ? *pcbNeeded : 0;
5058 numentries = pcReturned ? *pcReturned : 0;
5061 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5062 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5065 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5066 DWORD entrysize = 0;
5069 LPPORT_INFO_2W pi2w;
5070 LPPORT_INFO_2A pi2a;
5073 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5075 /* First pass: calculate the size for all Entries */
5076 pi2w = (LPPORT_INFO_2W) bufferW;
5077 pi2a = (LPPORT_INFO_2A) pPorts;
5079 while (index < numentries) {
5081 needed += entrysize; /* PORT_INFO_?A */
5082 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5084 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5085 NULL, 0, NULL, NULL);
5087 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5088 NULL, 0, NULL, NULL);
5089 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5090 NULL, 0, NULL, NULL);
5092 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5093 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5094 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5097 /* check for errors and quit on failure */
5098 if (cbBuf < needed) {
5099 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5103 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5104 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5105 cbBuf -= len ; /* free Bytes in the user-Buffer */
5106 pi2w = (LPPORT_INFO_2W) bufferW;
5107 pi2a = (LPPORT_INFO_2A) pPorts;
5109 /* Second Pass: Fill the User Buffer (if we have one) */
5110 while ((index < numentries) && pPorts) {
5112 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5113 pi2a->pPortName = ptr;
5114 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5115 ptr, cbBuf , NULL, NULL);
5119 pi2a->pMonitorName = ptr;
5120 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5121 ptr, cbBuf, NULL, NULL);
5125 pi2a->pDescription = ptr;
5126 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5127 ptr, cbBuf, NULL, NULL);
5131 pi2a->fPortType = pi2w->fPortType;
5132 pi2a->Reserved = 0; /* documented: "must be zero" */
5135 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5136 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5137 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5142 if (pcbNeeded) *pcbNeeded = needed;
5143 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5145 HeapFree(GetProcessHeap(), 0, nameW);
5146 HeapFree(GetProcessHeap(), 0, bufferW);
5148 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5149 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5155 /******************************************************************************
5156 * EnumPortsW (WINSPOOL.@)
5158 * Enumerate available Ports
5161 * pName [I] Servername or NULL (local Computer)
5162 * Level [I] Structure-Level (1 or 2)
5163 * pPorts [O] PTR to Buffer that receives the Result
5164 * cbBuf [I] Size of Buffer at pPorts
5165 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5166 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5170 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5173 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5176 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5177 cbBuf, pcbNeeded, pcReturned);
5179 if ((backend == NULL) && !load_backend()) return FALSE;
5181 /* Level is not checked in win9x */
5182 if (!Level || (Level > 2)) {
5183 WARN("level (%d) is ignored in win9x\n", Level);
5184 SetLastError(ERROR_INVALID_LEVEL);
5187 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5188 SetLastError(RPC_X_NULL_REF_POINTER);
5192 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5195 /******************************************************************************
5196 * GetDefaultPrinterW (WINSPOOL.@)
5199 * This function must read the value from data 'device' of key
5200 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5202 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5206 WCHAR *buffer, *ptr;
5210 SetLastError(ERROR_INVALID_PARAMETER);
5214 /* make the buffer big enough for the stuff from the profile/registry,
5215 * the content must fit into the local buffer to compute the correct
5216 * size even if the extern buffer is too small or not given.
5217 * (20 for ,driver,port) */
5219 len = max(100, (insize + 20));
5220 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5222 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5224 SetLastError (ERROR_FILE_NOT_FOUND);
5228 TRACE("%s\n", debugstr_w(buffer));
5230 if ((ptr = strchrW(buffer, ',')) == NULL)
5232 SetLastError(ERROR_INVALID_NAME);
5238 *namesize = strlenW(buffer) + 1;
5239 if(!name || (*namesize > insize))
5241 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5245 strcpyW(name, buffer);
5248 HeapFree( GetProcessHeap(), 0, buffer);
5253 /******************************************************************************
5254 * GetDefaultPrinterA (WINSPOOL.@)
5256 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5260 WCHAR *bufferW = NULL;
5264 SetLastError(ERROR_INVALID_PARAMETER);
5268 if(name && *namesize) {
5270 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5273 if(!GetDefaultPrinterW( bufferW, namesize)) {
5278 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5282 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5285 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5288 HeapFree( GetProcessHeap(), 0, bufferW);
5293 /******************************************************************************
5294 * SetDefaultPrinterW (WINSPOOL.204)
5296 * Set the Name of the Default Printer
5299 * pszPrinter [I] Name of the Printer or NULL
5306 * When the Parameter is NULL or points to an Empty String and
5307 * a Default Printer was already present, then this Function changes nothing.
5308 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5309 * the First enumerated local Printer is used.
5312 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5314 WCHAR default_printer[MAX_PATH];
5315 LPWSTR buffer = NULL;
5321 TRACE("(%s)\n", debugstr_w(pszPrinter));
5322 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5324 default_printer[0] = '\0';
5325 size = sizeof(default_printer)/sizeof(WCHAR);
5327 /* if we have a default Printer, do nothing. */
5328 if (GetDefaultPrinterW(default_printer, &size))
5332 /* we have no default Printer: search local Printers and use the first */
5333 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5335 default_printer[0] = '\0';
5336 size = sizeof(default_printer)/sizeof(WCHAR);
5337 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5339 pszPrinter = default_printer;
5340 TRACE("using %s\n", debugstr_w(pszPrinter));
5345 if (pszPrinter == NULL) {
5346 TRACE("no local printer found\n");
5347 SetLastError(ERROR_FILE_NOT_FOUND);
5352 /* "pszPrinter" is never empty or NULL here. */
5353 namelen = lstrlenW(pszPrinter);
5354 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5355 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5357 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5358 HeapFree(GetProcessHeap(), 0, buffer);
5359 SetLastError(ERROR_FILE_NOT_FOUND);
5363 /* read the devices entry for the printer (driver,port) to build the string for the
5364 default device entry (printer,driver,port) */
5365 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5366 buffer[namelen] = ',';
5367 namelen++; /* move index to the start of the driver */
5369 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5370 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5372 TRACE("set device to %s\n", debugstr_w(buffer));
5374 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5375 TRACE("failed to set the device entry: %d\n", GetLastError());
5376 lres = ERROR_INVALID_PRINTER_NAME;
5379 /* remove the next section, when INIFileMapping is implemented */
5382 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5383 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5390 if (lres != ERROR_FILE_NOT_FOUND)
5391 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5393 SetLastError(ERROR_INVALID_PRINTER_NAME);
5397 HeapFree(GetProcessHeap(), 0, buffer);
5398 return (lres == ERROR_SUCCESS);
5401 /******************************************************************************
5402 * SetDefaultPrinterA (WINSPOOL.202)
5404 * See SetDefaultPrinterW.
5407 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5409 LPWSTR bufferW = NULL;
5412 TRACE("(%s)\n", debugstr_a(pszPrinter));
5414 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5415 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5416 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5418 res = SetDefaultPrinterW(bufferW);
5419 HeapFree(GetProcessHeap(), 0, bufferW);
5423 /******************************************************************************
5424 * SetPrinterDataExA (WINSPOOL.@)
5426 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5427 LPCSTR pValueName, DWORD Type,
5428 LPBYTE pData, DWORD cbData)
5430 HKEY hkeyPrinter, hkeySubkey;
5433 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5434 debugstr_a(pValueName), Type, pData, cbData);
5436 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5440 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5442 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5443 RegCloseKey(hkeyPrinter);
5446 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5447 RegCloseKey(hkeySubkey);
5448 RegCloseKey(hkeyPrinter);
5452 /******************************************************************************
5453 * SetPrinterDataExW (WINSPOOL.@)
5455 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5456 LPCWSTR pValueName, DWORD Type,
5457 LPBYTE pData, DWORD cbData)
5459 HKEY hkeyPrinter, hkeySubkey;
5462 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5463 debugstr_w(pValueName), Type, pData, cbData);
5465 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5469 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5471 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5472 RegCloseKey(hkeyPrinter);
5475 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5476 RegCloseKey(hkeySubkey);
5477 RegCloseKey(hkeyPrinter);
5481 /******************************************************************************
5482 * SetPrinterDataA (WINSPOOL.@)
5484 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5485 LPBYTE pData, DWORD cbData)
5487 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5491 /******************************************************************************
5492 * SetPrinterDataW (WINSPOOL.@)
5494 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5495 LPBYTE pData, DWORD cbData)
5497 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5501 /******************************************************************************
5502 * GetPrinterDataExA (WINSPOOL.@)
5504 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5505 LPCSTR pValueName, LPDWORD pType,
5506 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5508 opened_printer_t *printer;
5509 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5512 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5513 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5515 printer = get_opened_printer(hPrinter);
5516 if(!printer) return ERROR_INVALID_HANDLE;
5518 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5519 if (ret) return ret;
5521 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5523 if (printer->name) {
5525 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5527 RegCloseKey(hkeyPrinters);
5530 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5531 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5532 RegCloseKey(hkeyPrinter);
5533 RegCloseKey(hkeyPrinters);
5538 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5539 0, pType, pData, pcbNeeded);
5541 if (!ret && !pData) ret = ERROR_MORE_DATA;
5543 RegCloseKey(hkeySubkey);
5544 RegCloseKey(hkeyPrinter);
5545 RegCloseKey(hkeyPrinters);
5547 TRACE("--> %d\n", ret);
5551 /******************************************************************************
5552 * GetPrinterDataExW (WINSPOOL.@)
5554 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5555 LPCWSTR pValueName, LPDWORD pType,
5556 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5558 opened_printer_t *printer;
5559 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5562 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5563 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5565 printer = get_opened_printer(hPrinter);
5566 if(!printer) return ERROR_INVALID_HANDLE;
5568 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5569 if (ret) return ret;
5571 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5573 if (printer->name) {
5575 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5577 RegCloseKey(hkeyPrinters);
5580 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5581 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5582 RegCloseKey(hkeyPrinter);
5583 RegCloseKey(hkeyPrinters);
5588 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5589 0, pType, pData, pcbNeeded);
5591 if (!ret && !pData) ret = ERROR_MORE_DATA;
5593 RegCloseKey(hkeySubkey);
5594 RegCloseKey(hkeyPrinter);
5595 RegCloseKey(hkeyPrinters);
5597 TRACE("--> %d\n", ret);
5601 /******************************************************************************
5602 * GetPrinterDataA (WINSPOOL.@)
5604 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5605 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5607 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5608 pData, nSize, pcbNeeded);
5611 /******************************************************************************
5612 * GetPrinterDataW (WINSPOOL.@)
5614 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5615 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5617 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5618 pData, nSize, pcbNeeded);
5621 /*******************************************************************************
5622 * EnumPrinterDataExW [WINSPOOL.@]
5624 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5625 LPBYTE pEnumValues, DWORD cbEnumValues,
5626 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5628 HKEY hkPrinter, hkSubKey;
5629 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5630 cbValueNameLen, cbMaxValueLen, cbValueLen,
5635 PPRINTER_ENUM_VALUESW ppev;
5637 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5639 if (pKeyName == NULL || *pKeyName == 0)
5640 return ERROR_INVALID_PARAMETER;
5642 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5643 if (ret != ERROR_SUCCESS)
5645 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5650 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5651 if (ret != ERROR_SUCCESS)
5653 r = RegCloseKey (hkPrinter);
5654 if (r != ERROR_SUCCESS)
5655 WARN ("RegCloseKey returned %i\n", r);
5656 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5657 debugstr_w (pKeyName), ret);
5661 ret = RegCloseKey (hkPrinter);
5662 if (ret != ERROR_SUCCESS)
5664 ERR ("RegCloseKey returned %i\n", ret);
5665 r = RegCloseKey (hkSubKey);
5666 if (r != ERROR_SUCCESS)
5667 WARN ("RegCloseKey returned %i\n", r);
5671 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5672 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5673 if (ret != ERROR_SUCCESS)
5675 r = RegCloseKey (hkSubKey);
5676 if (r != ERROR_SUCCESS)
5677 WARN ("RegCloseKey returned %i\n", r);
5678 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5682 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5683 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5685 if (cValues == 0) /* empty key */
5687 r = RegCloseKey (hkSubKey);
5688 if (r != ERROR_SUCCESS)
5689 WARN ("RegCloseKey returned %i\n", r);
5690 *pcbEnumValues = *pnEnumValues = 0;
5691 return ERROR_SUCCESS;
5694 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5696 hHeap = GetProcessHeap ();
5699 ERR ("GetProcessHeap failed\n");
5700 r = RegCloseKey (hkSubKey);
5701 if (r != ERROR_SUCCESS)
5702 WARN ("RegCloseKey returned %i\n", r);
5703 return ERROR_OUTOFMEMORY;
5706 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5707 if (lpValueName == NULL)
5709 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5710 r = RegCloseKey (hkSubKey);
5711 if (r != ERROR_SUCCESS)
5712 WARN ("RegCloseKey returned %i\n", r);
5713 return ERROR_OUTOFMEMORY;
5716 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5717 if (lpValue == NULL)
5719 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5720 if (HeapFree (hHeap, 0, lpValueName) == 0)
5721 WARN ("HeapFree failed with code %i\n", GetLastError ());
5722 r = RegCloseKey (hkSubKey);
5723 if (r != ERROR_SUCCESS)
5724 WARN ("RegCloseKey returned %i\n", r);
5725 return ERROR_OUTOFMEMORY;
5728 TRACE ("pass 1: calculating buffer required for all names and values\n");
5730 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5732 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5734 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5736 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5737 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5738 NULL, NULL, lpValue, &cbValueLen);
5739 if (ret != ERROR_SUCCESS)
5741 if (HeapFree (hHeap, 0, lpValue) == 0)
5742 WARN ("HeapFree failed with code %i\n", GetLastError ());
5743 if (HeapFree (hHeap, 0, lpValueName) == 0)
5744 WARN ("HeapFree failed with code %i\n", GetLastError ());
5745 r = RegCloseKey (hkSubKey);
5746 if (r != ERROR_SUCCESS)
5747 WARN ("RegCloseKey returned %i\n", r);
5748 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5752 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5753 debugstr_w (lpValueName), dwIndex,
5754 cbValueNameLen + 1, cbValueLen);
5756 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5757 cbBufSize += cbValueLen;
5760 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5762 *pcbEnumValues = cbBufSize;
5763 *pnEnumValues = cValues;
5765 if (cbEnumValues < cbBufSize) /* buffer too small */
5767 if (HeapFree (hHeap, 0, lpValue) == 0)
5768 WARN ("HeapFree failed with code %i\n", GetLastError ());
5769 if (HeapFree (hHeap, 0, lpValueName) == 0)
5770 WARN ("HeapFree failed with code %i\n", GetLastError ());
5771 r = RegCloseKey (hkSubKey);
5772 if (r != ERROR_SUCCESS)
5773 WARN ("RegCloseKey returned %i\n", r);
5774 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5775 return ERROR_MORE_DATA;
5778 TRACE ("pass 2: copying all names and values to buffer\n");
5780 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5781 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5783 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5785 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5786 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5787 NULL, &dwType, lpValue, &cbValueLen);
5788 if (ret != ERROR_SUCCESS)
5790 if (HeapFree (hHeap, 0, lpValue) == 0)
5791 WARN ("HeapFree failed with code %i\n", GetLastError ());
5792 if (HeapFree (hHeap, 0, lpValueName) == 0)
5793 WARN ("HeapFree failed with code %i\n", GetLastError ());
5794 r = RegCloseKey (hkSubKey);
5795 if (r != ERROR_SUCCESS)
5796 WARN ("RegCloseKey returned %i\n", r);
5797 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5801 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5802 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5803 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5804 pEnumValues += cbValueNameLen;
5806 /* return # of *bytes* (including trailing \0), not # of chars */
5807 ppev[dwIndex].cbValueName = cbValueNameLen;
5809 ppev[dwIndex].dwType = dwType;
5811 memcpy (pEnumValues, lpValue, cbValueLen);
5812 ppev[dwIndex].pData = pEnumValues;
5813 pEnumValues += cbValueLen;
5815 ppev[dwIndex].cbData = cbValueLen;
5817 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5818 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5821 if (HeapFree (hHeap, 0, lpValue) == 0)
5823 ret = GetLastError ();
5824 ERR ("HeapFree failed with code %i\n", ret);
5825 if (HeapFree (hHeap, 0, lpValueName) == 0)
5826 WARN ("HeapFree failed with code %i\n", GetLastError ());
5827 r = RegCloseKey (hkSubKey);
5828 if (r != ERROR_SUCCESS)
5829 WARN ("RegCloseKey returned %i\n", r);
5833 if (HeapFree (hHeap, 0, lpValueName) == 0)
5835 ret = GetLastError ();
5836 ERR ("HeapFree failed with code %i\n", ret);
5837 r = RegCloseKey (hkSubKey);
5838 if (r != ERROR_SUCCESS)
5839 WARN ("RegCloseKey returned %i\n", r);
5843 ret = RegCloseKey (hkSubKey);
5844 if (ret != ERROR_SUCCESS)
5846 ERR ("RegCloseKey returned %i\n", ret);
5850 return ERROR_SUCCESS;
5853 /*******************************************************************************
5854 * EnumPrinterDataExA [WINSPOOL.@]
5856 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5857 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5858 * what Windows 2000 SP1 does.
5861 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5862 LPBYTE pEnumValues, DWORD cbEnumValues,
5863 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5867 DWORD ret, dwIndex, dwBufSize;
5871 TRACE ("%p %s\n", hPrinter, pKeyName);
5873 if (pKeyName == NULL || *pKeyName == 0)
5874 return ERROR_INVALID_PARAMETER;
5876 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5879 ret = GetLastError ();
5880 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5884 hHeap = GetProcessHeap ();
5887 ERR ("GetProcessHeap failed\n");
5888 return ERROR_OUTOFMEMORY;
5891 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5892 if (pKeyNameW == NULL)
5894 ERR ("Failed to allocate %i bytes from process heap\n",
5895 (LONG)(len * sizeof (WCHAR)));
5896 return ERROR_OUTOFMEMORY;
5899 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5901 ret = GetLastError ();
5902 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5903 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5904 WARN ("HeapFree failed with code %i\n", GetLastError ());
5908 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5909 pcbEnumValues, pnEnumValues);
5910 if (ret != ERROR_SUCCESS)
5912 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5913 WARN ("HeapFree failed with code %i\n", GetLastError ());
5914 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5918 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5920 ret = GetLastError ();
5921 ERR ("HeapFree failed with code %i\n", ret);
5925 if (*pnEnumValues == 0) /* empty key */
5926 return ERROR_SUCCESS;
5929 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5931 PPRINTER_ENUM_VALUESW ppev =
5932 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5934 if (dwBufSize < ppev->cbValueName)
5935 dwBufSize = ppev->cbValueName;
5937 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5938 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5939 dwBufSize = ppev->cbData;
5942 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5944 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5945 if (pBuffer == NULL)
5947 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5948 return ERROR_OUTOFMEMORY;
5951 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5953 PPRINTER_ENUM_VALUESW ppev =
5954 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5956 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5957 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5961 ret = GetLastError ();
5962 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5963 if (HeapFree (hHeap, 0, pBuffer) == 0)
5964 WARN ("HeapFree failed with code %i\n", GetLastError ());
5968 memcpy (ppev->pValueName, pBuffer, len);
5970 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5972 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5973 ppev->dwType != REG_MULTI_SZ)
5976 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5977 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5980 ret = GetLastError ();
5981 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5982 if (HeapFree (hHeap, 0, pBuffer) == 0)
5983 WARN ("HeapFree failed with code %i\n", GetLastError ());
5987 memcpy (ppev->pData, pBuffer, len);
5989 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5990 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5993 if (HeapFree (hHeap, 0, pBuffer) == 0)
5995 ret = GetLastError ();
5996 ERR ("HeapFree failed with code %i\n", ret);
6000 return ERROR_SUCCESS;
6003 /******************************************************************************
6004 * AbortPrinter (WINSPOOL.@)
6006 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6008 FIXME("(%p), stub!\n", hPrinter);
6012 /******************************************************************************
6013 * AddPortA (WINSPOOL.@)
6018 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6020 LPWSTR nameW = NULL;
6021 LPWSTR monitorW = NULL;
6025 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6028 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6029 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6030 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6034 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6035 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6036 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6038 res = AddPortW(nameW, hWnd, monitorW);
6039 HeapFree(GetProcessHeap(), 0, nameW);
6040 HeapFree(GetProcessHeap(), 0, monitorW);
6044 /******************************************************************************
6045 * AddPortW (WINSPOOL.@)
6047 * Add a Port for a specific Monitor
6050 * pName [I] Servername or NULL (local Computer)
6051 * hWnd [I] Handle to parent Window for the Dialog-Box
6052 * pMonitorName [I] Name of the Monitor that manage the Port
6059 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6061 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6063 if ((backend == NULL) && !load_backend()) return FALSE;
6065 if (!pMonitorName) {
6066 SetLastError(RPC_X_NULL_REF_POINTER);
6070 return backend->fpAddPort(pName, hWnd, pMonitorName);
6073 /******************************************************************************
6074 * AddPortExA (WINSPOOL.@)
6079 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6082 PORT_INFO_2A * pi2A;
6083 LPWSTR nameW = NULL;
6084 LPWSTR monitorW = NULL;
6088 pi2A = (PORT_INFO_2A *) pBuffer;
6090 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6091 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6093 if ((level < 1) || (level > 2)) {
6094 SetLastError(ERROR_INVALID_LEVEL);
6099 SetLastError(ERROR_INVALID_PARAMETER);
6104 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6105 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6106 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6110 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6111 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6112 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6115 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6117 if (pi2A->pPortName) {
6118 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6119 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6120 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6124 if (pi2A->pMonitorName) {
6125 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6126 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6127 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6130 if (pi2A->pDescription) {
6131 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6132 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6133 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6135 pi2W.fPortType = pi2A->fPortType;
6136 pi2W.Reserved = pi2A->Reserved;
6139 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6141 HeapFree(GetProcessHeap(), 0, nameW);
6142 HeapFree(GetProcessHeap(), 0, monitorW);
6143 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6144 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6145 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6150 /******************************************************************************
6151 * AddPortExW (WINSPOOL.@)
6153 * Add a Port for a specific Monitor, without presenting a user interface
6156 * pName [I] Servername or NULL (local Computer)
6157 * level [I] Structure-Level (1 or 2) for pBuffer
6158 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6159 * pMonitorName [I] Name of the Monitor that manage the Port
6166 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6170 pi2 = (PORT_INFO_2W *) pBuffer;
6172 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6173 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6174 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6175 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6177 if ((backend == NULL) && !load_backend()) return FALSE;
6179 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6180 SetLastError(ERROR_INVALID_PARAMETER);
6184 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6187 /******************************************************************************
6188 * AddPrinterConnectionA (WINSPOOL.@)
6190 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6192 FIXME("%s\n", debugstr_a(pName));
6196 /******************************************************************************
6197 * AddPrinterConnectionW (WINSPOOL.@)
6199 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6201 FIXME("%s\n", debugstr_w(pName));
6205 /******************************************************************************
6206 * AddPrinterDriverExW (WINSPOOL.@)
6208 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6211 * pName [I] Servername or NULL (local Computer)
6212 * level [I] Level for the supplied DRIVER_INFO_*W struct
6213 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6214 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6221 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6223 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6225 if ((backend == NULL) && !load_backend()) return FALSE;
6227 if (level < 2 || level == 5 || level == 7 || level > 8) {
6228 SetLastError(ERROR_INVALID_LEVEL);
6233 SetLastError(ERROR_INVALID_PARAMETER);
6237 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6240 /******************************************************************************
6241 * AddPrinterDriverExA (WINSPOOL.@)
6243 * See AddPrinterDriverExW.
6246 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6248 DRIVER_INFO_8A *diA;
6250 LPWSTR nameW = NULL;
6255 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6257 diA = (DRIVER_INFO_8A *) pDriverInfo;
6258 ZeroMemory(&diW, sizeof(diW));
6260 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6261 SetLastError(ERROR_INVALID_LEVEL);
6266 SetLastError(ERROR_INVALID_PARAMETER);
6270 /* convert servername to unicode */
6272 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6273 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6274 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6278 diW.cVersion = diA->cVersion;
6281 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6282 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6283 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6286 if (diA->pEnvironment) {
6287 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6288 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6289 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6292 if (diA->pDriverPath) {
6293 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6294 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6295 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6298 if (diA->pDataFile) {
6299 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6300 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6301 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6304 if (diA->pConfigFile) {
6305 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6306 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6307 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6310 if ((Level > 2) && diA->pDependentFiles) {
6311 lenA = multi_sz_lenA(diA->pDependentFiles);
6312 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6313 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6314 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6317 if ((Level > 2) && diA->pMonitorName) {
6318 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6319 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6320 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6323 if ((Level > 3) && diA->pDefaultDataType) {
6324 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6325 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6326 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6329 if ((Level > 3) && diA->pszzPreviousNames) {
6330 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6331 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6332 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6333 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6336 if ((Level > 5) && diA->pszMfgName) {
6337 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6338 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6339 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6342 if ((Level > 5) && diA->pszOEMUrl) {
6343 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6344 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6345 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6348 if ((Level > 5) && diA->pszHardwareID) {
6349 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6350 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6351 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6354 if ((Level > 5) && diA->pszProvider) {
6355 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6356 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6357 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6361 FIXME("level %u is incomplete\n", Level);
6364 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6365 TRACE("got %u with %u\n", res, GetLastError());
6366 HeapFree(GetProcessHeap(), 0, nameW);
6367 HeapFree(GetProcessHeap(), 0, diW.pName);
6368 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6369 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6370 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6371 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6372 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6373 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6374 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6375 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6376 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6377 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6378 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6379 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6381 TRACE("=> %u with %u\n", res, GetLastError());
6385 /******************************************************************************
6386 * ConfigurePortA (WINSPOOL.@)
6388 * See ConfigurePortW.
6391 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6393 LPWSTR nameW = NULL;
6394 LPWSTR portW = NULL;
6398 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6400 /* convert servername to unicode */
6402 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6403 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6404 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6407 /* convert portname to unicode */
6409 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6410 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6411 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6414 res = ConfigurePortW(nameW, hWnd, portW);
6415 HeapFree(GetProcessHeap(), 0, nameW);
6416 HeapFree(GetProcessHeap(), 0, portW);
6420 /******************************************************************************
6421 * ConfigurePortW (WINSPOOL.@)
6423 * Display the Configuration-Dialog for a specific Port
6426 * pName [I] Servername or NULL (local Computer)
6427 * hWnd [I] Handle to parent Window for the Dialog-Box
6428 * pPortName [I] Name of the Port, that should be configured
6435 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6438 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6440 if ((backend == NULL) && !load_backend()) return FALSE;
6443 SetLastError(RPC_X_NULL_REF_POINTER);
6447 return backend->fpConfigurePort(pName, hWnd, pPortName);
6450 /******************************************************************************
6451 * ConnectToPrinterDlg (WINSPOOL.@)
6453 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6455 FIXME("%p %x\n", hWnd, Flags);
6459 /******************************************************************************
6460 * DeletePrinterConnectionA (WINSPOOL.@)
6462 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6464 FIXME("%s\n", debugstr_a(pName));
6468 /******************************************************************************
6469 * DeletePrinterConnectionW (WINSPOOL.@)
6471 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6473 FIXME("%s\n", debugstr_w(pName));
6477 /******************************************************************************
6478 * DeletePrinterDriverExW (WINSPOOL.@)
6480 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6481 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6486 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6487 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6489 if(pName && pName[0])
6491 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6492 SetLastError(ERROR_INVALID_PARAMETER);
6498 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6499 SetLastError(ERROR_INVALID_PARAMETER);
6503 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6507 ERR("Can't open drivers key\n");
6511 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6514 RegCloseKey(hkey_drivers);
6519 /******************************************************************************
6520 * DeletePrinterDriverExA (WINSPOOL.@)
6522 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6523 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6525 UNICODE_STRING NameW, EnvW, DriverW;
6528 asciitounicode(&NameW, pName);
6529 asciitounicode(&EnvW, pEnvironment);
6530 asciitounicode(&DriverW, pDriverName);
6532 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6534 RtlFreeUnicodeString(&DriverW);
6535 RtlFreeUnicodeString(&EnvW);
6536 RtlFreeUnicodeString(&NameW);
6541 /******************************************************************************
6542 * DeletePrinterDataExW (WINSPOOL.@)
6544 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6547 FIXME("%p %s %s\n", hPrinter,
6548 debugstr_w(pKeyName), debugstr_w(pValueName));
6549 return ERROR_INVALID_PARAMETER;
6552 /******************************************************************************
6553 * DeletePrinterDataExA (WINSPOOL.@)
6555 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6558 FIXME("%p %s %s\n", hPrinter,
6559 debugstr_a(pKeyName), debugstr_a(pValueName));
6560 return ERROR_INVALID_PARAMETER;
6563 /******************************************************************************
6564 * DeletePrintProcessorA (WINSPOOL.@)
6566 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6568 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6569 debugstr_a(pPrintProcessorName));
6573 /******************************************************************************
6574 * DeletePrintProcessorW (WINSPOOL.@)
6576 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6578 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6579 debugstr_w(pPrintProcessorName));
6583 /******************************************************************************
6584 * DeletePrintProvidorA (WINSPOOL.@)
6586 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6588 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6589 debugstr_a(pPrintProviderName));
6593 /******************************************************************************
6594 * DeletePrintProvidorW (WINSPOOL.@)
6596 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6598 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6599 debugstr_w(pPrintProviderName));
6603 /******************************************************************************
6604 * EnumFormsA (WINSPOOL.@)
6606 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6607 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6609 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6610 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6614 /******************************************************************************
6615 * EnumFormsW (WINSPOOL.@)
6617 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6618 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6620 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6621 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6625 /*****************************************************************************
6626 * EnumMonitorsA [WINSPOOL.@]
6628 * See EnumMonitorsW.
6631 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6632 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6635 LPBYTE bufferW = NULL;
6636 LPWSTR nameW = NULL;
6638 DWORD numentries = 0;
6641 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6642 cbBuf, pcbNeeded, pcReturned);
6644 /* convert servername to unicode */
6646 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6647 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6648 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6650 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6651 needed = cbBuf * sizeof(WCHAR);
6652 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6653 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6655 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6656 if (pcbNeeded) needed = *pcbNeeded;
6657 /* HeapReAlloc return NULL, when bufferW was NULL */
6658 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6659 HeapAlloc(GetProcessHeap(), 0, needed);
6661 /* Try again with the large Buffer */
6662 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6664 numentries = pcReturned ? *pcReturned : 0;
6667 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6668 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6671 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6672 DWORD entrysize = 0;
6675 LPMONITOR_INFO_2W mi2w;
6676 LPMONITOR_INFO_2A mi2a;
6678 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6679 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6681 /* First pass: calculate the size for all Entries */
6682 mi2w = (LPMONITOR_INFO_2W) bufferW;
6683 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6685 while (index < numentries) {
6687 needed += entrysize; /* MONITOR_INFO_?A */
6688 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6690 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6691 NULL, 0, NULL, NULL);
6693 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6694 NULL, 0, NULL, NULL);
6695 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6696 NULL, 0, NULL, NULL);
6698 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6699 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6700 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6703 /* check for errors and quit on failure */
6704 if (cbBuf < needed) {
6705 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6709 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6710 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6711 cbBuf -= len ; /* free Bytes in the user-Buffer */
6712 mi2w = (LPMONITOR_INFO_2W) bufferW;
6713 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6715 /* Second Pass: Fill the User Buffer (if we have one) */
6716 while ((index < numentries) && pMonitors) {
6718 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6720 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6721 ptr, cbBuf , NULL, NULL);
6725 mi2a->pEnvironment = ptr;
6726 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6727 ptr, cbBuf, NULL, NULL);
6731 mi2a->pDLLName = ptr;
6732 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6733 ptr, cbBuf, NULL, NULL);
6737 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6738 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6739 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6743 if (pcbNeeded) *pcbNeeded = needed;
6744 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6746 HeapFree(GetProcessHeap(), 0, nameW);
6747 HeapFree(GetProcessHeap(), 0, bufferW);
6749 TRACE("returning %d with %d (%d byte for %d entries)\n",
6750 (res), GetLastError(), needed, numentries);
6756 /*****************************************************************************
6757 * EnumMonitorsW [WINSPOOL.@]
6759 * Enumerate available Port-Monitors
6762 * pName [I] Servername or NULL (local Computer)
6763 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6764 * pMonitors [O] PTR to Buffer that receives the Result
6765 * cbBuf [I] Size of Buffer at pMonitors
6766 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6767 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6771 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6774 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6775 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6778 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6779 cbBuf, pcbNeeded, pcReturned);
6781 if ((backend == NULL) && !load_backend()) return FALSE;
6783 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6784 SetLastError(RPC_X_NULL_REF_POINTER);
6788 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6791 /******************************************************************************
6792 * SpoolerInit (WINSPOOL.@)
6794 * Initialize the Spooler
6801 * The function fails on windows, when the spooler service is not running
6804 BOOL WINAPI SpoolerInit(void)
6807 if ((backend == NULL) && !load_backend()) return FALSE;
6811 /******************************************************************************
6812 * XcvDataW (WINSPOOL.@)
6814 * Execute commands in the Printmonitor DLL
6817 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6818 * pszDataName [i] Name of the command to execute
6819 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6820 * cbInputData [i] Size in Bytes of Buffer at pInputData
6821 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6822 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6823 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6824 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6831 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6832 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6834 * Minimal List of commands, that a Printmonitor DLL should support:
6836 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6837 *| "AddPort" : Add a Port
6838 *| "DeletePort": Delete a Port
6840 * Many Printmonitors support additional commands. Examples for localspl.dll:
6841 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6842 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6845 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6846 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6847 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6849 opened_printer_t *printer;
6851 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6852 pInputData, cbInputData, pOutputData,
6853 cbOutputData, pcbOutputNeeded, pdwStatus);
6855 if ((backend == NULL) && !load_backend()) return FALSE;
6857 printer = get_opened_printer(hXcv);
6858 if (!printer || (!printer->backend_printer)) {
6859 SetLastError(ERROR_INVALID_HANDLE);
6863 if (!pcbOutputNeeded) {
6864 SetLastError(ERROR_INVALID_PARAMETER);
6868 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6869 SetLastError(RPC_X_NULL_REF_POINTER);
6873 *pcbOutputNeeded = 0;
6875 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6876 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6880 /*****************************************************************************
6881 * EnumPrinterDataA [WINSPOOL.@]
6884 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6885 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6886 DWORD cbData, LPDWORD pcbData )
6888 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6889 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6890 return ERROR_NO_MORE_ITEMS;
6893 /*****************************************************************************
6894 * EnumPrinterDataW [WINSPOOL.@]
6897 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6898 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6899 DWORD cbData, LPDWORD pcbData )
6901 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6902 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6903 return ERROR_NO_MORE_ITEMS;
6906 /*****************************************************************************
6907 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6910 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6911 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6912 LPDWORD pcbNeeded, LPDWORD pcReturned)
6914 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6915 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6916 pcbNeeded, pcReturned);
6920 /*****************************************************************************
6921 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6924 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6925 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6926 LPDWORD pcbNeeded, LPDWORD pcReturned)
6928 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6929 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6930 pcbNeeded, pcReturned);
6934 /*****************************************************************************
6935 * EnumPrintProcessorsA [WINSPOOL.@]
6937 * See EnumPrintProcessorsW.
6940 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6941 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6944 LPBYTE bufferW = NULL;
6945 LPWSTR nameW = NULL;
6948 DWORD numentries = 0;
6951 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6952 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6954 /* convert names to unicode */
6956 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6957 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6958 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6961 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6962 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6966 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6967 needed = cbBuf * sizeof(WCHAR);
6968 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6969 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6971 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6972 if (pcbNeeded) needed = *pcbNeeded;
6973 /* HeapReAlloc return NULL, when bufferW was NULL */
6974 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6975 HeapAlloc(GetProcessHeap(), 0, needed);
6977 /* Try again with the large Buffer */
6978 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6980 numentries = pcReturned ? *pcReturned : 0;
6984 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6987 PPRINTPROCESSOR_INFO_1W ppiw;
6988 PPRINTPROCESSOR_INFO_1A ppia;
6990 /* First pass: calculate the size for all Entries */
6991 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6992 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6994 while (index < numentries) {
6996 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6997 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6999 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7000 NULL, 0, NULL, NULL);
7002 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7003 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7006 /* check for errors and quit on failure */
7007 if (cbBuf < needed) {
7008 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7013 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7014 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7015 cbBuf -= len ; /* free Bytes in the user-Buffer */
7016 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7017 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7019 /* Second Pass: Fill the User Buffer (if we have one) */
7020 while ((index < numentries) && pPPInfo) {
7022 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7024 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7025 ptr, cbBuf , NULL, NULL);
7029 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7030 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7035 if (pcbNeeded) *pcbNeeded = needed;
7036 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7038 HeapFree(GetProcessHeap(), 0, nameW);
7039 HeapFree(GetProcessHeap(), 0, envW);
7040 HeapFree(GetProcessHeap(), 0, bufferW);
7042 TRACE("returning %d with %d (%d byte for %d entries)\n",
7043 (res), GetLastError(), needed, numentries);
7048 /*****************************************************************************
7049 * EnumPrintProcessorsW [WINSPOOL.@]
7051 * Enumerate available Print Processors
7054 * pName [I] Servername or NULL (local Computer)
7055 * pEnvironment [I] Printing-Environment or NULL (Default)
7056 * Level [I] Structure-Level (Only 1 is allowed)
7057 * pPPInfo [O] PTR to Buffer that receives the Result
7058 * cbBuf [I] Size of Buffer at pPPInfo
7059 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7060 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7064 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7067 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7068 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7071 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7072 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7074 if ((backend == NULL) && !load_backend()) return FALSE;
7076 if (!pcbNeeded || !pcReturned) {
7077 SetLastError(RPC_X_NULL_REF_POINTER);
7081 if (!pPPInfo && (cbBuf > 0)) {
7082 SetLastError(ERROR_INVALID_USER_BUFFER);
7086 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7087 cbBuf, pcbNeeded, pcReturned);
7090 /*****************************************************************************
7091 * ExtDeviceMode [WINSPOOL.@]
7094 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7095 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7098 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7099 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7100 debugstr_a(pProfile), fMode);
7104 /*****************************************************************************
7105 * FindClosePrinterChangeNotification [WINSPOOL.@]
7108 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7110 FIXME("Stub: %p\n", hChange);
7114 /*****************************************************************************
7115 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7118 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7119 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7121 FIXME("Stub: %p %x %x %p\n",
7122 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7123 return INVALID_HANDLE_VALUE;
7126 /*****************************************************************************
7127 * FindNextPrinterChangeNotification [WINSPOOL.@]
7130 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7131 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7133 FIXME("Stub: %p %p %p %p\n",
7134 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7138 /*****************************************************************************
7139 * FreePrinterNotifyInfo [WINSPOOL.@]
7142 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7144 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7148 /*****************************************************************************
7151 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7152 * ansi depending on the unicode parameter.
7154 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7164 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7167 memcpy(ptr, str, *size);
7174 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7177 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7184 /*****************************************************************************
7187 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7188 LPDWORD pcbNeeded, BOOL unicode)
7190 DWORD size, left = cbBuf;
7191 BOOL space = (cbBuf > 0);
7198 ji1->JobId = job->job_id;
7201 string_to_buf(job->document_title, ptr, left, &size, unicode);
7202 if(space && size <= left)
7204 ji1->pDocument = (LPWSTR)ptr;
7212 if (job->printer_name)
7214 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7215 if(space && size <= left)
7217 ji1->pPrinterName = (LPWSTR)ptr;
7229 /*****************************************************************************
7232 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7233 LPDWORD pcbNeeded, BOOL unicode)
7235 DWORD size, left = cbBuf;
7237 BOOL space = (cbBuf > 0);
7239 LPDEVMODEA dmA = NULL;
7246 ji2->JobId = job->job_id;
7249 string_to_buf(job->document_title, ptr, left, &size, unicode);
7250 if(space && size <= left)
7252 ji2->pDocument = (LPWSTR)ptr;
7260 if (job->printer_name)
7262 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7263 if(space && size <= left)
7265 ji2->pPrinterName = (LPWSTR)ptr;
7278 dmA = DEVMODEdupWtoA(job->devmode);
7279 devmode = (LPDEVMODEW) dmA;
7280 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7284 devmode = job->devmode;
7285 size = devmode->dmSize + devmode->dmDriverExtra;
7289 FIXME("Can't convert DEVMODE W to A\n");
7292 /* align DEVMODE to a DWORD boundary */
7293 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7299 memcpy(ptr, devmode, size-shift);
7300 ji2->pDevMode = (LPDEVMODEW)ptr;
7301 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7314 /*****************************************************************************
7317 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7318 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7321 DWORD needed = 0, size;
7325 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7327 EnterCriticalSection(&printer_handles_cs);
7328 job = get_job(hPrinter, JobId);
7335 size = sizeof(JOB_INFO_1W);
7340 memset(pJob, 0, size);
7344 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7349 size = sizeof(JOB_INFO_2W);
7354 memset(pJob, 0, size);
7358 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7363 size = sizeof(JOB_INFO_3);
7367 memset(pJob, 0, size);
7376 SetLastError(ERROR_INVALID_LEVEL);
7380 *pcbNeeded = needed;
7382 LeaveCriticalSection(&printer_handles_cs);
7386 /*****************************************************************************
7387 * GetJobA [WINSPOOL.@]
7390 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7391 DWORD cbBuf, LPDWORD pcbNeeded)
7393 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7396 /*****************************************************************************
7397 * GetJobW [WINSPOOL.@]
7400 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7401 DWORD cbBuf, LPDWORD pcbNeeded)
7403 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7406 /*****************************************************************************
7409 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7412 char *unixname, *cmdA;
7414 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7420 if(!(unixname = wine_get_unix_file_name(filename)))
7423 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7424 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7425 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7427 TRACE("printing with: %s\n", cmdA);
7429 if((file_fd = open(unixname, O_RDONLY)) == -1)
7434 ERR("pipe() failed!\n");
7438 if ((pid = fork()) == 0)
7444 /* reset signals that we previously set to SIG_IGN */
7445 signal(SIGPIPE, SIG_DFL);
7447 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7452 ERR("fork() failed!\n");
7456 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7457 write(fds[1], buf, no_read);
7464 wret = waitpid(pid, &status, 0);
7465 } while (wret < 0 && errno == EINTR);
7468 ERR("waitpid() failed!\n");
7471 if (!WIFEXITED(status) || WEXITSTATUS(status))
7473 ERR("child process failed! %d\n", status);
7480 if(file_fd != -1) close(file_fd);
7481 if(fds[0] != -1) close(fds[0]);
7482 if(fds[1] != -1) close(fds[1]);
7484 HeapFree(GetProcessHeap(), 0, cmdA);
7485 HeapFree(GetProcessHeap(), 0, unixname);
7492 /*****************************************************************************
7495 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7498 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7501 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7502 sprintfW(cmd, fmtW, printer_name);
7504 r = schedule_pipe(cmd, filename);
7506 HeapFree(GetProcessHeap(), 0, cmd);
7510 /*****************************************************************************
7513 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7515 #ifdef SONAME_LIBCUPS
7518 char *unixname, *queue, *unix_doc_title;
7522 if(!(unixname = wine_get_unix_file_name(filename)))
7525 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7526 queue = HeapAlloc(GetProcessHeap(), 0, len);
7527 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7529 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7530 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7531 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7533 TRACE("printing via cups\n");
7534 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7535 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7536 HeapFree(GetProcessHeap(), 0, queue);
7537 HeapFree(GetProcessHeap(), 0, unixname);
7543 return schedule_lpr(printer_name, filename);
7547 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7554 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7558 if(HIWORD(wparam) == BN_CLICKED)
7560 if(LOWORD(wparam) == IDOK)
7563 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7566 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7567 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7569 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7571 WCHAR caption[200], message[200];
7574 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7575 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7576 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7577 if(mb_ret == IDCANCEL)
7579 HeapFree(GetProcessHeap(), 0, filename);
7583 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7584 if(hf == INVALID_HANDLE_VALUE)
7586 WCHAR caption[200], message[200];
7588 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7589 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7590 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7591 HeapFree(GetProcessHeap(), 0, filename);
7595 DeleteFileW(filename);
7596 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7598 EndDialog(hwnd, IDOK);
7601 if(LOWORD(wparam) == IDCANCEL)
7603 EndDialog(hwnd, IDCANCEL);
7612 /*****************************************************************************
7615 static BOOL get_filename(LPWSTR *filename)
7617 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7618 file_dlg_proc, (LPARAM)filename) == IDOK;
7621 /*****************************************************************************
7624 static BOOL schedule_file(LPCWSTR filename)
7626 LPWSTR output = NULL;
7628 if(get_filename(&output))
7631 TRACE("copy to %s\n", debugstr_w(output));
7632 r = CopyFileW(filename, output, FALSE);
7633 HeapFree(GetProcessHeap(), 0, output);
7639 /*****************************************************************************
7642 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7644 int in_fd, out_fd, no_read;
7647 char *unixname, *outputA;
7650 if(!(unixname = wine_get_unix_file_name(filename)))
7653 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7654 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7655 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7657 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7658 in_fd = open(unixname, O_RDONLY);
7659 if(out_fd == -1 || in_fd == -1)
7662 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7663 write(out_fd, buf, no_read);
7667 if(in_fd != -1) close(in_fd);
7668 if(out_fd != -1) close(out_fd);
7669 HeapFree(GetProcessHeap(), 0, outputA);
7670 HeapFree(GetProcessHeap(), 0, unixname);
7674 /*****************************************************************************
7675 * ScheduleJob [WINSPOOL.@]
7678 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7680 opened_printer_t *printer;
7682 struct list *cursor, *cursor2;
7684 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7685 EnterCriticalSection(&printer_handles_cs);
7686 printer = get_opened_printer(hPrinter);
7690 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7692 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7695 if(job->job_id != dwJobID) continue;
7697 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7698 if(hf != INVALID_HANDLE_VALUE)
7700 PRINTER_INFO_5W *pi5 = NULL;
7701 LPWSTR portname = job->portname;
7705 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7706 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7710 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7711 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7712 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7713 portname = pi5->pPortName;
7715 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7716 debugstr_w(portname));
7720 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7721 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7723 DWORD type, count = sizeof(output);
7724 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7727 if(output[0] == '|')
7729 ret = schedule_pipe(output + 1, job->filename);
7733 ret = schedule_unixfile(output, job->filename);
7735 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7737 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7739 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7741 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7743 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7745 ret = schedule_file(job->filename);
7749 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7751 HeapFree(GetProcessHeap(), 0, pi5);
7753 DeleteFileW(job->filename);
7755 list_remove(cursor);
7756 HeapFree(GetProcessHeap(), 0, job->document_title);
7757 HeapFree(GetProcessHeap(), 0, job->printer_name);
7758 HeapFree(GetProcessHeap(), 0, job->portname);
7759 HeapFree(GetProcessHeap(), 0, job->filename);
7760 HeapFree(GetProcessHeap(), 0, job->devmode);
7761 HeapFree(GetProcessHeap(), 0, job);
7765 LeaveCriticalSection(&printer_handles_cs);
7769 /*****************************************************************************
7770 * StartDocDlgA [WINSPOOL.@]
7772 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7774 UNICODE_STRING usBuffer;
7777 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7780 docW.cbSize = sizeof(docW);
7781 if (doc->lpszDocName)
7783 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7784 if (!(docW.lpszDocName = docnameW)) return NULL;
7786 if (doc->lpszOutput)
7788 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7789 if (!(docW.lpszOutput = outputW)) return NULL;
7791 if (doc->lpszDatatype)
7793 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7794 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7796 docW.fwType = doc->fwType;
7798 retW = StartDocDlgW(hPrinter, &docW);
7802 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7803 ret = HeapAlloc(GetProcessHeap(), 0, len);
7804 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7805 HeapFree(GetProcessHeap(), 0, retW);
7808 HeapFree(GetProcessHeap(), 0, datatypeW);
7809 HeapFree(GetProcessHeap(), 0, outputW);
7810 HeapFree(GetProcessHeap(), 0, docnameW);
7815 /*****************************************************************************
7816 * StartDocDlgW [WINSPOOL.@]
7818 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7819 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7820 * port is "FILE:". Also returns the full path if passed a relative path.
7822 * The caller should free the returned string from the process heap.
7824 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7829 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7831 PRINTER_INFO_5W *pi5;
7832 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7833 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7835 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7836 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7837 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7839 HeapFree(GetProcessHeap(), 0, pi5);
7842 HeapFree(GetProcessHeap(), 0, pi5);
7845 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7849 if (get_filename(&name))
7851 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7853 HeapFree(GetProcessHeap(), 0, name);
7856 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7857 GetFullPathNameW(name, len, ret, NULL);
7858 HeapFree(GetProcessHeap(), 0, name);
7863 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7866 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7867 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7869 attr = GetFileAttributesW(ret);
7870 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7872 HeapFree(GetProcessHeap(), 0, ret);