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"
40 #ifdef HAVE_CUPS_CUPS_H
41 # include <cups/cups.h>
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
46 #include "wine/library.h"
55 #include "wine/windef16.h"
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
58 #include "wine/list.h"
61 #include "ddk/winsplp.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
66 /* ############################### */
68 static CRITICAL_SECTION printer_handles_cs;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
71 0, 0, &printer_handles_cs,
72 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
77 /* ############################### */
92 HANDLE backend_printer;
102 WCHAR *document_title;
112 LPCWSTR versionregpath;
113 LPCWSTR versionsubdir;
116 /* ############################### */
118 static opened_printer_t **printer_handles;
119 static UINT nb_printer_handles;
120 static LONG next_job_id = 1;
122 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
123 WORD fwCapability, LPSTR lpszOutput,
125 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
126 LPSTR lpszDevice, LPSTR lpszPort,
127 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
130 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'c','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
135 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
137 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
138 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
139 'C','o','n','t','r','o','l','\\',
140 'P','r','i','n','t','\\',
141 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
145 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
146 'M','i','c','r','o','s','o','f','t','\\',
147 'W','i','n','d','o','w','s',' ','N','T','\\',
148 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
149 'W','i','n','d','o','w','s',0};
151 static const WCHAR user_printers_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 'D','e','v','i','c','e','s',0};
157 static const WCHAR WinNT_CV_PortsW[] = {'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 'P','o','r','t','s',0};
163 static const WCHAR WinNT_CV_PrinterPortsW[] = { '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','r','i','n','t','e','r','P','o','r','t','s',0};
169 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
170 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
171 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
172 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
173 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
174 static const WCHAR subdir_x64W[] = {'x','6','4',0};
175 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
176 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
177 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
178 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
179 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
181 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
182 static const WCHAR backslashW[] = {'\\',0};
183 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
184 'i','o','n',' ','F','i','l','e',0};
185 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
186 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
187 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
188 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
189 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
190 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
191 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
192 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
193 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
194 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
195 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
196 static const WCHAR NameW[] = {'N','a','m','e',0};
197 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
198 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
199 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
200 static const WCHAR PortW[] = {'P','o','r','t',0};
201 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
202 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
203 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
204 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
205 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
206 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
207 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
208 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
209 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
210 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
211 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
212 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
213 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
214 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
215 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
216 static WCHAR rawW[] = {'R','A','W',0};
217 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
218 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
219 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
220 static const WCHAR commaW[] = {',',0};
221 static WCHAR emptyStringW[] = {0};
223 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
225 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
226 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
227 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
229 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
230 'D','o','c','u','m','e','n','t',0};
232 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
233 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
234 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
235 0, sizeof(DRIVER_INFO_8W)};
238 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
239 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
240 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
241 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
242 sizeof(PRINTER_INFO_9W)};
244 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
245 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
246 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
248 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
250 /******************************************************************
251 * validate the user-supplied printing-environment [internal]
254 * env [I] PTR to Environment-String or NULL
258 * Success: PTR to printenv_t
261 * An empty string is handled the same way as NULL.
262 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
266 static const printenv_t * validate_envW(LPCWSTR env)
268 const printenv_t *result = NULL;
271 TRACE("testing %s\n", debugstr_w(env));
274 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
276 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
278 result = all_printenv[i];
283 if (result == NULL) {
284 FIXME("unsupported Environment: %s\n", debugstr_w(env));
285 SetLastError(ERROR_INVALID_ENVIRONMENT);
287 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
291 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
293 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
299 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
300 if passed a NULL string. This returns NULLs to the result.
302 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
306 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
307 return usBufferPtr->Buffer;
309 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
313 static LPWSTR strdupW(LPCWSTR p)
319 len = (strlenW(p) + 1) * sizeof(WCHAR);
320 ret = HeapAlloc(GetProcessHeap(), 0, len);
325 static LPSTR strdupWtoA( LPCWSTR str )
330 if (!str) return NULL;
331 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
332 ret = HeapAlloc( GetProcessHeap(), 0, len );
333 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
337 /******************************************************************
338 * verify, that the filename is a local file
341 static inline BOOL is_local_file(LPWSTR name)
343 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
346 /* ################################ */
348 static int multi_sz_lenA(const char *str)
350 const char *ptr = str;
354 ptr += lstrlenA(ptr) + 1;
357 return ptr - str + 1;
361 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
364 /* If forcing, or no profile string entry for device yet, set the entry
366 * The always change entry if not WINEPS yet is discussable.
369 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
371 !strstr(qbuf,"WINEPS.DRV")
373 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
376 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
377 WriteProfileStringA("windows","device",buf);
378 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
379 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
382 HeapFree(GetProcessHeap(),0,buf);
386 static BOOL add_printer_driver(WCHAR *name)
390 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
393 di3.pEnvironment = envname_x86W;
394 di3.pDriverPath = driver_nt;
395 di3.pDataFile = generic_ppdW;
396 di3.pConfigFile = driver_nt;
397 di3.pDefaultDataType = rawW;
399 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
400 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
403 di3.pEnvironment = envname_win40W;
404 di3.pDriverPath = driver_9x;
405 di3.pConfigFile = driver_9x;
406 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
407 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
412 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
416 #ifdef SONAME_LIBCUPS
417 static typeof(cupsFreeDests) *pcupsFreeDests;
418 static typeof(cupsGetDests) *pcupsGetDests;
419 static typeof(cupsGetPPD) *pcupsGetPPD;
420 static typeof(cupsPrintFile) *pcupsPrintFile;
421 static void *cupshandle;
423 static BOOL CUPS_LoadPrinters(void)
426 BOOL hadprinter = FALSE, haddefault = FALSE;
430 HKEY hkeyPrinter, hkeyPrinters;
432 WCHAR nameW[MAX_PATH];
434 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
436 TRACE("%s\n", loaderror);
439 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
442 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
443 if (!p##x) return FALSE;
445 DYNCUPS(cupsFreeDests);
447 DYNCUPS(cupsGetDests);
448 DYNCUPS(cupsPrintFile);
451 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
453 ERR("Can't create Printers key\n");
457 nrofdests = pcupsGetDests(&dests);
458 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
459 for (i=0;i<nrofdests;i++) {
460 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
462 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
463 lstrcpyW(port, CUPS_Port);
464 lstrcatW(port, nameW);
466 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
467 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
468 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
470 TRACE("Printer already exists\n");
471 /* overwrite old LPR:* port */
472 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
473 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
474 RegCloseKey(hkeyPrinter);
476 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
477 ' ','u','s','i','n','g',' ','C','U','P','S',0};
479 add_printer_driver(nameW);
481 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
482 pi2.pPrinterName = nameW;
483 pi2.pDatatype = rawW;
484 pi2.pPrintProcessor = WinPrintW;
485 pi2.pDriverName = nameW;
486 pi2.pComment = comment_cups;
487 pi2.pLocation = emptyStringW;
488 pi2.pPortName = port;
489 pi2.pParameters = emptyStringW;
490 pi2.pShareName = emptyStringW;
491 pi2.pSepFile = emptyStringW;
493 if (!AddPrinterW(NULL, 2, (LPBYTE)&pi2)) {
494 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
495 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError());
498 HeapFree(GetProcessHeap(),0,port);
501 if (dests[i].is_default) {
502 SetDefaultPrinterW(nameW);
506 if (hadprinter && !haddefault) {
507 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
508 SetDefaultPrinterW(nameW);
510 pcupsFreeDests(nrofdests, dests);
511 RegCloseKey(hkeyPrinters);
517 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
518 PRINTER_INFO_2A pinfo2a;
521 char *e,*s,*name,*prettyname,*devname;
522 BOOL ret = FALSE, set_default = FALSE;
523 char *port = NULL, *env_default;
524 HKEY hkeyPrinter, hkeyPrinters;
525 WCHAR devnameW[MAX_PATH];
527 while (isspace(*pent)) pent++;
528 r = strchr(pent,':');
532 name_len = strlen(pent);
533 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
534 memcpy(name, pent, name_len);
535 name[name_len] = '\0';
541 TRACE("name=%s entry=%s\n",name, pent);
543 if(ispunct(*name)) { /* a tc entry, not a real printer */
544 TRACE("skipping tc entry\n");
548 if(strstr(pent,":server")) { /* server only version so skip */
549 TRACE("skipping server entry\n");
553 /* Determine whether this is a postscript printer. */
556 env_default = getenv("PRINTER");
558 /* Get longest name, usually the one at the right for later display. */
559 while((s=strchr(prettyname,'|'))) {
562 while(isspace(*--e)) *e = '\0';
563 TRACE("\t%s\n", debugstr_a(prettyname));
564 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
565 for(prettyname = s+1; isspace(*prettyname); prettyname++)
568 e = prettyname + strlen(prettyname);
569 while(isspace(*--e)) *e = '\0';
570 TRACE("\t%s\n", debugstr_a(prettyname));
571 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
573 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
574 * if it is too long, we use it as comment below. */
575 devname = prettyname;
576 if (strlen(devname)>=CCHDEVICENAME-1)
578 if (strlen(devname)>=CCHDEVICENAME-1) {
583 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
584 sprintf(port,"LPR:%s",name);
586 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
588 ERR("Can't create Printers key\n");
593 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
595 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
596 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
598 TRACE("Printer already exists\n");
599 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
600 RegCloseKey(hkeyPrinter);
602 static CHAR data_type[] = "RAW",
603 print_proc[] = "WinPrint",
604 comment[] = "WINEPS Printer using LPR",
605 params[] = "<parameters?>",
606 share_name[] = "<share name?>",
607 sep_file[] = "<sep file?>";
609 add_printer_driver(devnameW);
611 memset(&pinfo2a,0,sizeof(pinfo2a));
612 pinfo2a.pPrinterName = devname;
613 pinfo2a.pDatatype = data_type;
614 pinfo2a.pPrintProcessor = print_proc;
615 pinfo2a.pDriverName = devname;
616 pinfo2a.pComment = comment;
617 pinfo2a.pLocation = prettyname;
618 pinfo2a.pPortName = port;
619 pinfo2a.pParameters = params;
620 pinfo2a.pShareName = share_name;
621 pinfo2a.pSepFile = sep_file;
623 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
624 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
625 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
628 RegCloseKey(hkeyPrinters);
630 if (isfirst || set_default)
631 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
634 HeapFree(GetProcessHeap(), 0, port);
635 HeapFree(GetProcessHeap(), 0, name);
640 PRINTCAP_LoadPrinters(void) {
641 BOOL hadprinter = FALSE;
645 BOOL had_bash = FALSE;
647 f = fopen("/etc/printcap","r");
651 while(fgets(buf,sizeof(buf),f)) {
654 end=strchr(buf,'\n');
658 while(isspace(*start)) start++;
659 if(*start == '#' || *start == '\0')
662 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
663 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
664 HeapFree(GetProcessHeap(),0,pent);
668 if (end && *--end == '\\') {
675 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
678 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
684 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
685 HeapFree(GetProcessHeap(),0,pent);
691 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
694 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
695 (lstrlenW(value) + 1) * sizeof(WCHAR));
697 return ERROR_FILE_NOT_FOUND;
700 /******************************************************************
701 * get_servername_from_name (internal)
703 * for an external server, a copy of the serverpart from the full name is returned
706 static LPWSTR get_servername_from_name(LPCWSTR name)
710 WCHAR buffer[MAX_PATH];
713 if (name == NULL) return NULL;
714 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
716 server = strdupW(&name[2]); /* skip over both backslash */
717 if (server == NULL) return NULL;
719 /* strip '\' and the printername */
720 ptr = strchrW(server, '\\');
721 if (ptr) ptr[0] = '\0';
723 TRACE("found %s\n", debugstr_w(server));
725 len = sizeof(buffer)/sizeof(buffer[0]);
726 if (GetComputerNameW(buffer, &len)) {
727 if (lstrcmpW(buffer, server) == 0) {
728 /* The requested Servername is our computername */
729 HeapFree(GetProcessHeap(), 0, server);
736 /******************************************************************
737 * get_basename_from_name (internal)
739 * skip over the serverpart from the full name
742 static LPCWSTR get_basename_from_name(LPCWSTR name)
744 if (name == NULL) return NULL;
745 if ((name[0] == '\\') && (name[1] == '\\')) {
746 /* skip over the servername and search for the following '\' */
747 name = strchrW(&name[2], '\\');
748 if ((name) && (name[1])) {
749 /* found a separator ('\') followed by a name:
750 skip over the separator and return the rest */
755 /* no basename present (we found only a servername) */
762 /******************************************************************
763 * get_opened_printer_entry
764 * Get the first place empty in the opened printer table
767 * - pDefault is ignored
769 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
771 UINT_PTR handle = nb_printer_handles, i;
772 jobqueue_t *queue = NULL;
773 opened_printer_t *printer = NULL;
777 if ((backend == NULL) && !load_backend()) return NULL;
779 servername = get_servername_from_name(name);
781 FIXME("server %s not supported\n", debugstr_w(servername));
782 HeapFree(GetProcessHeap(), 0, servername);
783 SetLastError(ERROR_INVALID_PRINTER_NAME);
787 printername = get_basename_from_name(name);
788 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
790 /* an empty printername is invalid */
791 if (printername && (!printername[0])) {
792 SetLastError(ERROR_INVALID_PARAMETER);
796 EnterCriticalSection(&printer_handles_cs);
798 for (i = 0; i < nb_printer_handles; i++)
800 if (!printer_handles[i])
802 if(handle == nb_printer_handles)
807 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
808 queue = printer_handles[i]->queue;
812 if (handle >= nb_printer_handles)
814 opened_printer_t **new_array;
816 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
817 (nb_printer_handles + 16) * sizeof(*new_array) );
819 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
820 (nb_printer_handles + 16) * sizeof(*new_array) );
827 printer_handles = new_array;
828 nb_printer_handles += 16;
831 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
837 /* get a printer handle from the backend */
838 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
843 /* clone the base name. This is NULL for the printserver */
844 printer->printername = strdupW(printername);
846 /* clone the full name */
847 printer->name = strdupW(name);
848 if (name && (!printer->name)) {
854 printer->queue = queue;
857 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
858 if (!printer->queue) {
862 list_init(&printer->queue->jobs);
863 printer->queue->ref = 0;
865 InterlockedIncrement(&printer->queue->ref);
867 printer_handles[handle] = printer;
870 LeaveCriticalSection(&printer_handles_cs);
871 if (!handle && printer) {
872 /* Something failed: Free all resources */
873 HeapFree(GetProcessHeap(), 0, printer->printername);
874 HeapFree(GetProcessHeap(), 0, printer->name);
875 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
876 HeapFree(GetProcessHeap(), 0, printer);
879 return (HANDLE)handle;
882 /******************************************************************
884 * Get the pointer to the opened printer referred by the handle
886 static opened_printer_t *get_opened_printer(HANDLE hprn)
888 UINT_PTR idx = (UINT_PTR)hprn;
889 opened_printer_t *ret = NULL;
891 EnterCriticalSection(&printer_handles_cs);
893 if ((idx > 0) && (idx <= nb_printer_handles)) {
894 ret = printer_handles[idx - 1];
896 LeaveCriticalSection(&printer_handles_cs);
900 /******************************************************************
901 * get_opened_printer_name
902 * Get the pointer to the opened printer name referred by the handle
904 static LPCWSTR get_opened_printer_name(HANDLE hprn)
906 opened_printer_t *printer = get_opened_printer(hprn);
907 if(!printer) return NULL;
908 return printer->name;
911 /******************************************************************
912 * WINSPOOL_GetOpenedPrinterRegKey
915 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
917 LPCWSTR name = get_opened_printer_name(hPrinter);
921 if(!name) return ERROR_INVALID_HANDLE;
923 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
927 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
929 ERR("Can't find opened printer %s in registry\n",
931 RegCloseKey(hkeyPrinters);
932 return ERROR_INVALID_PRINTER_NAME; /* ? */
934 RegCloseKey(hkeyPrinters);
935 return ERROR_SUCCESS;
938 void WINSPOOL_LoadSystemPrinters(void)
940 HKEY hkey, hkeyPrinters;
942 DWORD needed, num, i;
943 WCHAR PrinterName[256];
946 /* This ensures that all printer entries have a valid Name value. If causes
947 problems later if they don't. If one is found to be missed we create one
948 and set it equal to the name of the key */
949 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
950 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
951 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
952 for(i = 0; i < num; i++) {
953 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
954 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
955 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
956 set_reg_szW(hkey, NameW, PrinterName);
963 RegCloseKey(hkeyPrinters);
966 /* We want to avoid calling AddPrinter on printers as much as
967 possible, because on cups printers this will (eventually) lead
968 to a call to cupsGetPPD which takes forever, even with non-cups
969 printers AddPrinter takes a while. So we'll tag all printers that
970 were automatically added last time around, if they still exist
971 we'll leave them be otherwise we'll delete them. */
972 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num) && needed) {
973 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
974 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
975 for(i = 0; i < num; i++) {
976 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
977 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
978 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
980 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
988 HeapFree(GetProcessHeap(), 0, pi);
992 #ifdef SONAME_LIBCUPS
993 done = CUPS_LoadPrinters();
996 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
997 PRINTCAP_LoadPrinters();
999 /* Now enumerate the list again and delete any printers that are still tagged */
1000 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1002 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1003 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1004 for(i = 0; i < num; i++) {
1005 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1006 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1007 BOOL delete_driver = FALSE;
1008 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1009 DWORD dw, type, size = sizeof(dw);
1010 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1011 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1012 DeletePrinter(hprn);
1013 delete_driver = TRUE;
1019 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1024 HeapFree(GetProcessHeap(), 0, pi);
1031 /******************************************************************
1034 * Get the pointer to the specified job.
1035 * Should hold the printer_handles_cs before calling.
1037 static job_t *get_job(HANDLE hprn, DWORD JobId)
1039 opened_printer_t *printer = get_opened_printer(hprn);
1042 if(!printer) return NULL;
1043 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1045 if(job->job_id == JobId)
1051 /***********************************************************
1054 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1057 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1060 Formname = (dmA->dmSize > off_formname);
1061 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1062 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1063 dmW->dmDeviceName, CCHDEVICENAME);
1065 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1066 dmA->dmSize - CCHDEVICENAME);
1068 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1069 off_formname - CCHDEVICENAME);
1070 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1071 dmW->dmFormName, CCHFORMNAME);
1072 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1073 (off_formname + CCHFORMNAME));
1076 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1077 dmA->dmDriverExtra);
1081 /***********************************************************
1083 * Creates an ansi copy of supplied devmode
1085 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1090 if (!dmW) return NULL;
1091 size = dmW->dmSize - CCHDEVICENAME -
1092 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1094 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1095 if (!dmA) return NULL;
1097 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1098 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1100 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1101 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1102 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1106 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1107 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1108 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1109 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1111 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1115 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1119 /******************************************************************
1120 * convert_printerinfo_W_to_A [internal]
1123 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1124 DWORD level, DWORD outlen, DWORD numentries)
1130 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1132 len = pi_sizeof[level] * numentries;
1133 ptr = (LPSTR) out + len;
1136 /* copy the numbers of all PRINTER_INFO_* first */
1137 memcpy(out, pPrintersW, len);
1139 while (id < numentries) {
1143 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1144 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1146 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1147 if (piW->pDescription) {
1148 piA->pDescription = ptr;
1149 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1150 ptr, outlen, NULL, NULL);
1156 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1157 ptr, outlen, NULL, NULL);
1161 if (piW->pComment) {
1162 piA->pComment = ptr;
1163 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1164 ptr, outlen, NULL, NULL);
1173 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1174 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1177 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1178 if (piW->pServerName) {
1179 piA->pServerName = ptr;
1180 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1181 ptr, outlen, NULL, NULL);
1185 if (piW->pPrinterName) {
1186 piA->pPrinterName = ptr;
1187 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1188 ptr, outlen, NULL, NULL);
1192 if (piW->pShareName) {
1193 piA->pShareName = ptr;
1194 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1195 ptr, outlen, NULL, NULL);
1199 if (piW->pPortName) {
1200 piA->pPortName = ptr;
1201 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1202 ptr, outlen, NULL, NULL);
1206 if (piW->pDriverName) {
1207 piA->pDriverName = ptr;
1208 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1209 ptr, outlen, NULL, NULL);
1213 if (piW->pComment) {
1214 piA->pComment = ptr;
1215 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1216 ptr, outlen, NULL, NULL);
1220 if (piW->pLocation) {
1221 piA->pLocation = ptr;
1222 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1223 ptr, outlen, NULL, NULL);
1228 dmA = DEVMODEdupWtoA(piW->pDevMode);
1230 /* align DEVMODEA to a DWORD boundary */
1231 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1235 piA->pDevMode = (LPDEVMODEA) ptr;
1236 len = dmA->dmSize + dmA->dmDriverExtra;
1237 memcpy(ptr, dmA, len);
1238 HeapFree(GetProcessHeap(), 0, dmA);
1244 if (piW->pSepFile) {
1245 piA->pSepFile = ptr;
1246 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1247 ptr, outlen, NULL, NULL);
1251 if (piW->pPrintProcessor) {
1252 piA->pPrintProcessor = ptr;
1253 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1254 ptr, outlen, NULL, NULL);
1258 if (piW->pDatatype) {
1259 piA->pDatatype = ptr;
1260 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1261 ptr, outlen, NULL, NULL);
1265 if (piW->pParameters) {
1266 piA->pParameters = ptr;
1267 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1268 ptr, outlen, NULL, NULL);
1272 if (piW->pSecurityDescriptor) {
1273 piA->pSecurityDescriptor = NULL;
1274 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1281 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1282 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1284 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1286 if (piW->pPrinterName) {
1287 piA->pPrinterName = ptr;
1288 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1289 ptr, outlen, NULL, NULL);
1293 if (piW->pServerName) {
1294 piA->pServerName = ptr;
1295 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1296 ptr, outlen, NULL, NULL);
1305 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1306 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1308 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1310 if (piW->pPrinterName) {
1311 piA->pPrinterName = ptr;
1312 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1313 ptr, outlen, NULL, NULL);
1317 if (piW->pPortName) {
1318 piA->pPortName = ptr;
1319 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1320 ptr, outlen, NULL, NULL);
1327 case 6: /* 6A and 6W are the same structure */
1332 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1333 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1335 TRACE("(%u) #%u\n", level, id);
1336 if (piW->pszObjectGUID) {
1337 piA->pszObjectGUID = ptr;
1338 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1339 ptr, outlen, NULL, NULL);
1348 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1349 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1352 TRACE("(%u) #%u\n", level, id);
1353 dmA = DEVMODEdupWtoA(piW->pDevMode);
1355 /* align DEVMODEA to a DWORD boundary */
1356 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1360 piA->pDevMode = (LPDEVMODEA) ptr;
1361 len = dmA->dmSize + dmA->dmDriverExtra;
1362 memcpy(ptr, dmA, len);
1363 HeapFree(GetProcessHeap(), 0, dmA);
1373 FIXME("for level %u\n", level);
1375 pPrintersW += pi_sizeof[level];
1376 out += pi_sizeof[level];
1381 /******************************************************************
1382 * convert_driverinfo_W_to_A [internal]
1385 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1386 DWORD level, DWORD outlen, DWORD numentries)
1392 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1394 len = di_sizeof[level] * numentries;
1395 ptr = (LPSTR) out + len;
1398 /* copy the numbers of all PRINTER_INFO_* first */
1399 memcpy(out, pDriversW, len);
1401 #define COPY_STRING(fld) \
1404 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1405 ptr += len; outlen -= len;\
1407 #define COPY_MULTIZ_STRING(fld) \
1408 { LPWSTR p = diW->fld; if (p){ \
1411 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1412 ptr += len; outlen -= len; p += len;\
1414 while(len > 1 && outlen > 0); \
1417 while (id < numentries)
1423 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1424 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1426 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1433 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1434 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1436 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1439 COPY_STRING(pEnvironment);
1440 COPY_STRING(pDriverPath);
1441 COPY_STRING(pDataFile);
1442 COPY_STRING(pConfigFile);
1447 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1448 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1450 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1453 COPY_STRING(pEnvironment);
1454 COPY_STRING(pDriverPath);
1455 COPY_STRING(pDataFile);
1456 COPY_STRING(pConfigFile);
1457 COPY_STRING(pHelpFile);
1458 COPY_MULTIZ_STRING(pDependentFiles);
1459 COPY_STRING(pMonitorName);
1460 COPY_STRING(pDefaultDataType);
1465 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1466 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1468 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1471 COPY_STRING(pEnvironment);
1472 COPY_STRING(pDriverPath);
1473 COPY_STRING(pDataFile);
1474 COPY_STRING(pConfigFile);
1475 COPY_STRING(pHelpFile);
1476 COPY_MULTIZ_STRING(pDependentFiles);
1477 COPY_STRING(pMonitorName);
1478 COPY_STRING(pDefaultDataType);
1479 COPY_MULTIZ_STRING(pszzPreviousNames);
1484 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1485 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1487 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1490 COPY_STRING(pEnvironment);
1491 COPY_STRING(pDriverPath);
1492 COPY_STRING(pDataFile);
1493 COPY_STRING(pConfigFile);
1498 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1499 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1501 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1504 COPY_STRING(pEnvironment);
1505 COPY_STRING(pDriverPath);
1506 COPY_STRING(pDataFile);
1507 COPY_STRING(pConfigFile);
1508 COPY_STRING(pHelpFile);
1509 COPY_MULTIZ_STRING(pDependentFiles);
1510 COPY_STRING(pMonitorName);
1511 COPY_STRING(pDefaultDataType);
1512 COPY_MULTIZ_STRING(pszzPreviousNames);
1513 COPY_STRING(pszMfgName);
1514 COPY_STRING(pszOEMUrl);
1515 COPY_STRING(pszHardwareID);
1516 COPY_STRING(pszProvider);
1521 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1522 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1524 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1527 COPY_STRING(pEnvironment);
1528 COPY_STRING(pDriverPath);
1529 COPY_STRING(pDataFile);
1530 COPY_STRING(pConfigFile);
1531 COPY_STRING(pHelpFile);
1532 COPY_MULTIZ_STRING(pDependentFiles);
1533 COPY_STRING(pMonitorName);
1534 COPY_STRING(pDefaultDataType);
1535 COPY_MULTIZ_STRING(pszzPreviousNames);
1536 COPY_STRING(pszMfgName);
1537 COPY_STRING(pszOEMUrl);
1538 COPY_STRING(pszHardwareID);
1539 COPY_STRING(pszProvider);
1540 COPY_STRING(pszPrintProcessor);
1541 COPY_STRING(pszVendorSetup);
1542 COPY_MULTIZ_STRING(pszzColorProfiles);
1543 COPY_STRING(pszInfPath);
1544 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1550 FIXME("for level %u\n", level);
1553 pDriversW += di_sizeof[level];
1554 out += di_sizeof[level];
1559 #undef COPY_MULTIZ_STRING
1563 /***********************************************************
1564 * PRINTER_INFO_2AtoW
1565 * Creates a unicode copy of PRINTER_INFO_2A on heap
1567 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1569 LPPRINTER_INFO_2W piW;
1570 UNICODE_STRING usBuffer;
1572 if(!piA) return NULL;
1573 piW = HeapAlloc(heap, 0, sizeof(*piW));
1574 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1576 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1577 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1578 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1579 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1580 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1581 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1582 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1583 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1584 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1585 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1586 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1587 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1591 /***********************************************************
1592 * FREE_PRINTER_INFO_2W
1593 * Free PRINTER_INFO_2W and all strings
1595 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1599 HeapFree(heap,0,piW->pServerName);
1600 HeapFree(heap,0,piW->pPrinterName);
1601 HeapFree(heap,0,piW->pShareName);
1602 HeapFree(heap,0,piW->pPortName);
1603 HeapFree(heap,0,piW->pDriverName);
1604 HeapFree(heap,0,piW->pComment);
1605 HeapFree(heap,0,piW->pLocation);
1606 HeapFree(heap,0,piW->pDevMode);
1607 HeapFree(heap,0,piW->pSepFile);
1608 HeapFree(heap,0,piW->pPrintProcessor);
1609 HeapFree(heap,0,piW->pDatatype);
1610 HeapFree(heap,0,piW->pParameters);
1611 HeapFree(heap,0,piW);
1615 /******************************************************************
1616 * DeviceCapabilities [WINSPOOL.@]
1617 * DeviceCapabilitiesA [WINSPOOL.@]
1620 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1621 LPSTR pOutput, LPDEVMODEA lpdm)
1625 if (!GDI_CallDeviceCapabilities16)
1627 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1629 if (!GDI_CallDeviceCapabilities16) return -1;
1631 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1633 /* If DC_PAPERSIZE map POINT16s to POINTs */
1634 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1635 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1636 POINT *pt = (POINT *)pOutput;
1638 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1639 for(i = 0; i < ret; i++, pt++)
1644 HeapFree( GetProcessHeap(), 0, tmp );
1650 /*****************************************************************************
1651 * DeviceCapabilitiesW [WINSPOOL.@]
1653 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1656 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1657 WORD fwCapability, LPWSTR pOutput,
1658 const DEVMODEW *pDevMode)
1660 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1661 LPSTR pDeviceA = strdupWtoA(pDevice);
1662 LPSTR pPortA = strdupWtoA(pPort);
1665 if(pOutput && (fwCapability == DC_BINNAMES ||
1666 fwCapability == DC_FILEDEPENDENCIES ||
1667 fwCapability == DC_PAPERNAMES)) {
1668 /* These need A -> W translation */
1671 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1675 switch(fwCapability) {
1680 case DC_FILEDEPENDENCIES:
1684 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1685 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1687 for(i = 0; i < ret; i++)
1688 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1689 pOutput + (i * size), size);
1690 HeapFree(GetProcessHeap(), 0, pOutputA);
1692 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1693 (LPSTR)pOutput, dmA);
1695 HeapFree(GetProcessHeap(),0,pPortA);
1696 HeapFree(GetProcessHeap(),0,pDeviceA);
1697 HeapFree(GetProcessHeap(),0,dmA);
1701 /******************************************************************
1702 * DocumentPropertiesA [WINSPOOL.@]
1704 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1706 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1707 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1708 LPDEVMODEA pDevModeInput,DWORD fMode )
1710 LPSTR lpName = pDeviceName;
1711 static CHAR port[] = "LPT1:";
1714 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1715 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1719 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1721 ERR("no name from hPrinter?\n");
1722 SetLastError(ERROR_INVALID_HANDLE);
1725 lpName = strdupWtoA(lpNameW);
1728 if (!GDI_CallExtDeviceMode16)
1730 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1732 if (!GDI_CallExtDeviceMode16) {
1733 ERR("No CallExtDeviceMode16?\n");
1737 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1738 pDevModeInput, NULL, fMode);
1741 HeapFree(GetProcessHeap(),0,lpName);
1746 /*****************************************************************************
1747 * DocumentPropertiesW (WINSPOOL.@)
1749 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1751 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1753 LPDEVMODEW pDevModeOutput,
1754 LPDEVMODEW pDevModeInput, DWORD fMode)
1757 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1758 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1759 LPDEVMODEA pDevModeOutputA = NULL;
1762 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1763 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1765 if(pDevModeOutput) {
1766 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1767 if(ret < 0) return ret;
1768 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1770 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1771 pDevModeInputA, fMode);
1772 if(pDevModeOutput) {
1773 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1774 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1776 if(fMode == 0 && ret > 0)
1777 ret += (CCHDEVICENAME + CCHFORMNAME);
1778 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1779 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1783 /*****************************************************************************
1784 * IsValidDevmodeA [WINSPOOL.@]
1786 * Validate a DEVMODE structure and fix errors if possible.
1789 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1791 FIXME("(%p,%ld): stub\n", pDevMode, size);
1799 /*****************************************************************************
1800 * IsValidDevmodeW [WINSPOOL.@]
1802 * Validate a DEVMODE structure and fix errors if possible.
1805 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1807 FIXME("(%p,%ld): stub\n", pDevMode, size);
1815 /******************************************************************
1816 * OpenPrinterA [WINSPOOL.@]
1821 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1822 LPPRINTER_DEFAULTSA pDefault)
1824 UNICODE_STRING lpPrinterNameW;
1825 UNICODE_STRING usBuffer;
1826 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1827 PWSTR pwstrPrinterNameW;
1830 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1833 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1834 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1835 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1836 pDefaultW = &DefaultW;
1838 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1840 RtlFreeUnicodeString(&usBuffer);
1841 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1843 RtlFreeUnicodeString(&lpPrinterNameW);
1847 /******************************************************************
1848 * OpenPrinterW [WINSPOOL.@]
1850 * Open a Printer / Printserver or a Printer-Object
1853 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1854 * phPrinter [O] The resulting Handle is stored here
1855 * pDefault [I] PTR to Default Printer Settings or NULL
1862 * lpPrinterName is one of:
1863 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1864 *| Printer: "PrinterName"
1865 *| Printer-Object: "PrinterName,Job xxx"
1866 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1867 *| XcvPort: "Servername,XcvPort PortName"
1870 *| Printer-Object not supported
1871 *| pDefaults is ignored
1874 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1877 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1879 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1880 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1884 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1885 SetLastError(ERROR_INVALID_PARAMETER);
1889 /* Get the unique handle of the printer or Printserver */
1890 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1891 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1892 return (*phPrinter != 0);
1895 /******************************************************************
1896 * AddMonitorA [WINSPOOL.@]
1901 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1903 LPWSTR nameW = NULL;
1906 LPMONITOR_INFO_2A mi2a;
1907 MONITOR_INFO_2W mi2w;
1909 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1910 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1911 debugstr_a(mi2a ? mi2a->pName : NULL),
1912 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1913 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1916 SetLastError(ERROR_INVALID_LEVEL);
1920 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1926 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1927 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1928 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1931 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1933 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1934 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1935 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1937 if (mi2a->pEnvironment) {
1938 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1939 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1940 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1942 if (mi2a->pDLLName) {
1943 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1944 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1945 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1948 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1950 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1951 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1952 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1954 HeapFree(GetProcessHeap(), 0, nameW);
1958 /******************************************************************************
1959 * AddMonitorW [WINSPOOL.@]
1961 * Install a Printmonitor
1964 * pName [I] Servername or NULL (local Computer)
1965 * Level [I] Structure-Level (Must be 2)
1966 * pMonitors [I] PTR to MONITOR_INFO_2
1973 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1976 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1978 LPMONITOR_INFO_2W mi2w;
1980 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1981 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1982 debugstr_w(mi2w ? mi2w->pName : NULL),
1983 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1984 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1986 if ((backend == NULL) && !load_backend()) return FALSE;
1989 SetLastError(ERROR_INVALID_LEVEL);
1993 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1998 return backend->fpAddMonitor(pName, Level, pMonitors);
2001 /******************************************************************
2002 * DeletePrinterDriverA [WINSPOOL.@]
2005 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2007 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2010 /******************************************************************
2011 * DeletePrinterDriverW [WINSPOOL.@]
2014 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2016 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2019 /******************************************************************
2020 * DeleteMonitorA [WINSPOOL.@]
2022 * See DeleteMonitorW.
2025 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2027 LPWSTR nameW = NULL;
2028 LPWSTR EnvironmentW = NULL;
2029 LPWSTR MonitorNameW = NULL;
2034 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2035 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2036 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2040 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2041 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2042 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2045 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2046 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2047 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2050 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2052 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2053 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2054 HeapFree(GetProcessHeap(), 0, nameW);
2058 /******************************************************************
2059 * DeleteMonitorW [WINSPOOL.@]
2061 * Delete a specific Printmonitor from a Printing-Environment
2064 * pName [I] Servername or NULL (local Computer)
2065 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2066 * pMonitorName [I] Name of the Monitor, that should be deleted
2073 * pEnvironment is ignored in Windows for the local Computer.
2076 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2079 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2080 debugstr_w(pMonitorName));
2082 if ((backend == NULL) && !load_backend()) return FALSE;
2084 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2088 /******************************************************************
2089 * DeletePortA [WINSPOOL.@]
2094 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2096 LPWSTR nameW = NULL;
2097 LPWSTR portW = NULL;
2101 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2103 /* convert servername to unicode */
2105 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2106 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2107 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2110 /* convert portname to unicode */
2112 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2113 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2114 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2117 res = DeletePortW(nameW, hWnd, portW);
2118 HeapFree(GetProcessHeap(), 0, nameW);
2119 HeapFree(GetProcessHeap(), 0, portW);
2123 /******************************************************************
2124 * DeletePortW [WINSPOOL.@]
2126 * Delete a specific Port
2129 * pName [I] Servername or NULL (local Computer)
2130 * hWnd [I] Handle to parent Window for the Dialog-Box
2131 * pPortName [I] Name of the Port, that should be deleted
2138 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2140 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2142 if ((backend == NULL) && !load_backend()) return FALSE;
2145 SetLastError(RPC_X_NULL_REF_POINTER);
2149 return backend->fpDeletePort(pName, hWnd, pPortName);
2152 /******************************************************************************
2153 * SetPrinterW [WINSPOOL.@]
2155 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2157 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2158 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2162 /******************************************************************************
2163 * WritePrinter [WINSPOOL.@]
2165 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2167 opened_printer_t *printer;
2170 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2172 EnterCriticalSection(&printer_handles_cs);
2173 printer = get_opened_printer(hPrinter);
2176 SetLastError(ERROR_INVALID_HANDLE);
2182 SetLastError(ERROR_SPL_NO_STARTDOC);
2186 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2188 LeaveCriticalSection(&printer_handles_cs);
2192 /*****************************************************************************
2193 * AddFormA [WINSPOOL.@]
2195 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2197 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2201 /*****************************************************************************
2202 * AddFormW [WINSPOOL.@]
2204 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2206 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2210 /*****************************************************************************
2211 * AddJobA [WINSPOOL.@]
2213 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2216 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2220 SetLastError(ERROR_INVALID_LEVEL);
2224 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2227 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2228 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2229 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2230 if(*pcbNeeded > cbBuf) {
2231 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2234 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2235 addjobA->JobId = addjobW->JobId;
2236 addjobA->Path = (char *)(addjobA + 1);
2237 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2243 /*****************************************************************************
2244 * AddJobW [WINSPOOL.@]
2246 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2248 opened_printer_t *printer;
2251 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2252 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2253 WCHAR path[MAX_PATH], filename[MAX_PATH];
2255 ADDJOB_INFO_1W *addjob;
2257 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2259 EnterCriticalSection(&printer_handles_cs);
2261 printer = get_opened_printer(hPrinter);
2264 SetLastError(ERROR_INVALID_HANDLE);
2269 SetLastError(ERROR_INVALID_LEVEL);
2273 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2277 job->job_id = InterlockedIncrement(&next_job_id);
2279 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2280 if(path[len - 1] != '\\')
2282 memcpy(path + len, spool_path, sizeof(spool_path));
2283 sprintfW(filename, fmtW, path, job->job_id);
2285 len = strlenW(filename);
2286 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2287 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2288 job->document_title = strdupW(default_doc_title);
2289 job->printer_name = strdupW(printer->name);
2290 job->devmode = NULL;
2291 list_add_tail(&printer->queue->jobs, &job->entry);
2293 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2294 if(*pcbNeeded <= cbBuf) {
2295 addjob = (ADDJOB_INFO_1W*)pData;
2296 addjob->JobId = job->job_id;
2297 addjob->Path = (WCHAR *)(addjob + 1);
2298 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2301 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2304 LeaveCriticalSection(&printer_handles_cs);
2308 /*****************************************************************************
2309 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2311 * Return the PATH for the Print-Processors
2313 * See GetPrintProcessorDirectoryW.
2317 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2318 DWORD level, LPBYTE Info,
2319 DWORD cbBuf, LPDWORD pcbNeeded)
2321 LPWSTR serverW = NULL;
2326 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2327 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2331 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2332 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2333 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2337 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2338 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2339 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2342 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2343 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2345 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2348 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2349 cbBuf, NULL, NULL) > 0;
2352 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2353 HeapFree(GetProcessHeap(), 0, envW);
2354 HeapFree(GetProcessHeap(), 0, serverW);
2358 /*****************************************************************************
2359 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2361 * Return the PATH for the Print-Processors
2364 * server [I] Servername (NT only) or NULL (local Computer)
2365 * env [I] Printing-Environment (see below) or NULL (Default)
2366 * level [I] Structure-Level (must be 1)
2367 * Info [O] PTR to Buffer that receives the Result
2368 * cbBuf [I] Size of Buffer at "Info"
2369 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2370 * required for the Buffer at "Info"
2373 * Success: TRUE and in pcbNeeded the Bytes used in Info
2374 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2375 * if cbBuf is too small
2377 * Native Values returned in Info on Success:
2378 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2379 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2380 *| win9x(Windows 4.0): "%winsysdir%"
2382 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2385 * Only NULL or "" is supported for server
2388 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2389 DWORD level, LPBYTE Info,
2390 DWORD cbBuf, LPDWORD pcbNeeded)
2393 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2394 Info, cbBuf, pcbNeeded);
2396 if ((backend == NULL) && !load_backend()) return FALSE;
2399 /* (Level != 1) is ignored in win9x */
2400 SetLastError(ERROR_INVALID_LEVEL);
2404 if (pcbNeeded == NULL) {
2405 /* (pcbNeeded == NULL) is ignored in win9x */
2406 SetLastError(RPC_X_NULL_REF_POINTER);
2410 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2413 /*****************************************************************************
2414 * WINSPOOL_OpenDriverReg [internal]
2416 * opens the registry for the printer drivers depending on the given input
2417 * variable pEnvironment
2420 * the opened hkey on success
2423 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2427 const printenv_t * env;
2429 TRACE("(%s)\n", debugstr_w(pEnvironment));
2431 env = validate_envW(pEnvironment);
2432 if (!env) return NULL;
2434 buffer = HeapAlloc( GetProcessHeap(), 0,
2435 (strlenW(DriversW) + strlenW(env->envname) +
2436 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2438 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2439 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2440 HeapFree(GetProcessHeap(), 0, buffer);
2445 /*****************************************************************************
2446 * set_devices_and_printerports [internal]
2448 * set the [Devices] and [PrinterPorts] entries for a printer.
2451 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2453 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2457 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2459 /* FIXME: the driver must change to "winspool" */
2460 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2462 lstrcpyW(devline, driver_nt);
2463 lstrcatW(devline, commaW);
2464 lstrcatW(devline, pi->pPortName);
2466 TRACE("using %s\n", debugstr_w(devline));
2467 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2468 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2469 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2470 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2474 lstrcatW(devline, timeout_15_45);
2475 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2476 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2477 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2478 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2481 HeapFree(GetProcessHeap(), 0, devline);
2485 /*****************************************************************************
2486 * AddPrinterW [WINSPOOL.@]
2488 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2490 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2494 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2496 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2497 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2498 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2499 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2500 statusW[] = {'S','t','a','t','u','s',0},
2501 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2503 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2506 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2507 SetLastError(ERROR_INVALID_PARAMETER);
2511 ERR("Level = %d, unsupported!\n", Level);
2512 SetLastError(ERROR_INVALID_LEVEL);
2516 SetLastError(ERROR_INVALID_PARAMETER);
2519 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2521 ERR("Can't create Printers key\n");
2524 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2525 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2526 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2527 RegCloseKey(hkeyPrinter);
2528 RegCloseKey(hkeyPrinters);
2531 RegCloseKey(hkeyPrinter);
2533 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2535 ERR("Can't create Drivers key\n");
2536 RegCloseKey(hkeyPrinters);
2539 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2541 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2542 RegCloseKey(hkeyPrinters);
2543 RegCloseKey(hkeyDrivers);
2544 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2547 RegCloseKey(hkeyDriver);
2548 RegCloseKey(hkeyDrivers);
2550 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2551 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2552 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2553 RegCloseKey(hkeyPrinters);
2557 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2559 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2560 SetLastError(ERROR_INVALID_PRINTER_NAME);
2561 RegCloseKey(hkeyPrinters);
2565 set_devices_and_printerports(pi);
2566 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2567 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2568 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2570 /* See if we can load the driver. We may need the devmode structure anyway
2573 * Note that DocumentPropertiesW will briefly try to open the printer we
2574 * just create to find a DEVMODEA struct (it will use the WINEPS default
2575 * one in case it is not there, so we are ok).
2577 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2580 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2581 size = sizeof(DEVMODEW);
2587 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2589 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2591 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2592 HeapFree(GetProcessHeap(),0,dmW);
2597 /* set devmode to printer name */
2598 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2602 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2603 and we support these drivers. NT writes DEVMODEW so somehow
2604 we'll need to distinguish between these when we support NT
2608 dmA = DEVMODEdupWtoA(dmW);
2609 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2610 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2611 HeapFree(GetProcessHeap(), 0, dmA);
2613 HeapFree(GetProcessHeap(), 0, dmW);
2615 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2616 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2617 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2618 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2620 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2621 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2622 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2623 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2624 (LPBYTE)&pi->Priority, sizeof(DWORD));
2625 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2626 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2627 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2628 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2629 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2630 (LPBYTE)&pi->Status, sizeof(DWORD));
2631 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2632 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2634 RegCloseKey(hkeyPrinter);
2635 RegCloseKey(hkeyPrinters);
2636 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2637 ERR("OpenPrinter failing\n");
2643 /*****************************************************************************
2644 * AddPrinterA [WINSPOOL.@]
2646 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2648 UNICODE_STRING pNameW;
2650 PRINTER_INFO_2W *piW;
2651 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2654 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2656 ERR("Level = %d, unsupported!\n", Level);
2657 SetLastError(ERROR_INVALID_LEVEL);
2660 pwstrNameW = asciitounicode(&pNameW,pName);
2661 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2663 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2665 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2666 RtlFreeUnicodeString(&pNameW);
2671 /*****************************************************************************
2672 * ClosePrinter [WINSPOOL.@]
2674 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2676 UINT_PTR i = (UINT_PTR)hPrinter;
2677 opened_printer_t *printer = NULL;
2680 TRACE("(%p)\n", hPrinter);
2682 EnterCriticalSection(&printer_handles_cs);
2684 if ((i > 0) && (i <= nb_printer_handles))
2685 printer = printer_handles[i - 1];
2690 struct list *cursor, *cursor2;
2692 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2694 if (printer->backend_printer) {
2695 backend->fpClosePrinter(printer->backend_printer);
2699 EndDocPrinter(hPrinter);
2701 if(InterlockedDecrement(&printer->queue->ref) == 0)
2703 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2705 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2706 ScheduleJob(hPrinter, job->job_id);
2708 HeapFree(GetProcessHeap(), 0, printer->queue);
2711 HeapFree(GetProcessHeap(), 0, printer->printername);
2712 HeapFree(GetProcessHeap(), 0, printer->name);
2713 HeapFree(GetProcessHeap(), 0, printer);
2714 printer_handles[i - 1] = NULL;
2717 LeaveCriticalSection(&printer_handles_cs);
2721 /*****************************************************************************
2722 * DeleteFormA [WINSPOOL.@]
2724 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2726 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2730 /*****************************************************************************
2731 * DeleteFormW [WINSPOOL.@]
2733 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2735 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2739 /*****************************************************************************
2740 * DeletePrinter [WINSPOOL.@]
2742 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2744 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2745 HKEY hkeyPrinters, hkey;
2748 SetLastError(ERROR_INVALID_HANDLE);
2751 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2752 RegDeleteTreeW(hkeyPrinters, lpNameW);
2753 RegCloseKey(hkeyPrinters);
2755 WriteProfileStringW(devicesW, lpNameW, NULL);
2756 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2758 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2759 RegDeleteValueW(hkey, lpNameW);
2763 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2764 RegDeleteValueW(hkey, lpNameW);
2770 /*****************************************************************************
2771 * SetPrinterA [WINSPOOL.@]
2773 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2776 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2780 /*****************************************************************************
2781 * SetJobA [WINSPOOL.@]
2783 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2784 LPBYTE pJob, DWORD Command)
2788 UNICODE_STRING usBuffer;
2790 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2792 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2793 are all ignored by SetJob, so we don't bother copying them */
2801 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2802 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2804 JobW = (LPBYTE)info1W;
2805 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2806 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2807 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2808 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2809 info1W->Status = info1A->Status;
2810 info1W->Priority = info1A->Priority;
2811 info1W->Position = info1A->Position;
2812 info1W->PagesPrinted = info1A->PagesPrinted;
2817 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2818 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2820 JobW = (LPBYTE)info2W;
2821 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2822 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2823 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2824 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2825 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2826 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2827 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2828 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2829 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2830 info2W->Status = info2A->Status;
2831 info2W->Priority = info2A->Priority;
2832 info2W->Position = info2A->Position;
2833 info2W->StartTime = info2A->StartTime;
2834 info2W->UntilTime = info2A->UntilTime;
2835 info2W->PagesPrinted = info2A->PagesPrinted;
2839 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2840 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2843 SetLastError(ERROR_INVALID_LEVEL);
2847 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2853 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2854 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2855 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2856 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2857 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2862 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2863 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2864 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2865 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2866 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2867 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2868 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2869 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2870 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2874 HeapFree(GetProcessHeap(), 0, JobW);
2879 /*****************************************************************************
2880 * SetJobW [WINSPOOL.@]
2882 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2883 LPBYTE pJob, DWORD Command)
2889 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2890 FIXME("Ignoring everything other than document title\n");
2892 EnterCriticalSection(&printer_handles_cs);
2893 job = get_job(hPrinter, JobId);
2903 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2904 HeapFree(GetProcessHeap(), 0, job->document_title);
2905 job->document_title = strdupW(info1->pDocument);
2910 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2911 HeapFree(GetProcessHeap(), 0, job->document_title);
2912 job->document_title = strdupW(info2->pDocument);
2913 HeapFree(GetProcessHeap(), 0, job->devmode);
2914 if (info2->pDevMode)
2916 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2917 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2918 memcpy(job->devmode, info2->pDevMode, size);
2921 job->devmode = NULL;
2927 SetLastError(ERROR_INVALID_LEVEL);
2932 LeaveCriticalSection(&printer_handles_cs);
2936 /*****************************************************************************
2937 * EndDocPrinter [WINSPOOL.@]
2939 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2941 opened_printer_t *printer;
2943 TRACE("(%p)\n", hPrinter);
2945 EnterCriticalSection(&printer_handles_cs);
2947 printer = get_opened_printer(hPrinter);
2950 SetLastError(ERROR_INVALID_HANDLE);
2956 SetLastError(ERROR_SPL_NO_STARTDOC);
2960 CloseHandle(printer->doc->hf);
2961 ScheduleJob(hPrinter, printer->doc->job_id);
2962 HeapFree(GetProcessHeap(), 0, printer->doc);
2963 printer->doc = NULL;
2966 LeaveCriticalSection(&printer_handles_cs);
2970 /*****************************************************************************
2971 * EndPagePrinter [WINSPOOL.@]
2973 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2975 FIXME("(%p): stub\n", hPrinter);
2979 /*****************************************************************************
2980 * StartDocPrinterA [WINSPOOL.@]
2982 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2984 UNICODE_STRING usBuffer;
2986 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2989 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2990 or one (DOC_INFO_3) extra DWORDs */
2994 doc2W.JobId = doc2->JobId;
2997 doc2W.dwMode = doc2->dwMode;
3000 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3001 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3002 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3006 SetLastError(ERROR_INVALID_LEVEL);
3010 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3012 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3013 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3014 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3019 /*****************************************************************************
3020 * StartDocPrinterW [WINSPOOL.@]
3022 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3024 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3025 opened_printer_t *printer;
3026 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3027 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3028 JOB_INFO_1W job_info;
3029 DWORD needed, ret = 0;
3034 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3035 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3036 debugstr_w(doc->pDatatype));
3038 if(Level < 1 || Level > 3)
3040 SetLastError(ERROR_INVALID_LEVEL);
3044 EnterCriticalSection(&printer_handles_cs);
3045 printer = get_opened_printer(hPrinter);
3048 SetLastError(ERROR_INVALID_HANDLE);
3054 SetLastError(ERROR_INVALID_PRINTER_STATE);
3058 /* Even if we're printing to a file we still add a print job, we'll
3059 just ignore the spool file name */
3061 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3063 ERR("AddJob failed gle %u\n", GetLastError());
3067 /* use pOutputFile only, when it is a real filename */
3068 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3069 filename = doc->pOutputFile;
3071 filename = addjob->Path;
3073 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3074 if(hf == INVALID_HANDLE_VALUE)
3077 memset(&job_info, 0, sizeof(job_info));
3078 job_info.pDocument = doc->pDocName;
3079 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3081 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3082 printer->doc->hf = hf;
3083 ret = printer->doc->job_id = addjob->JobId;
3084 job = get_job(hPrinter, ret);
3085 job->portname = strdupW(doc->pOutputFile);
3088 LeaveCriticalSection(&printer_handles_cs);
3093 /*****************************************************************************
3094 * StartPagePrinter [WINSPOOL.@]
3096 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3098 FIXME("(%p): stub\n", hPrinter);
3102 /*****************************************************************************
3103 * GetFormA [WINSPOOL.@]
3105 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3106 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3108 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3109 Level,pForm,cbBuf,pcbNeeded);
3113 /*****************************************************************************
3114 * GetFormW [WINSPOOL.@]
3116 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3117 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3119 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3120 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3124 /*****************************************************************************
3125 * SetFormA [WINSPOOL.@]
3127 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3130 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3134 /*****************************************************************************
3135 * SetFormW [WINSPOOL.@]
3137 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3140 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3144 /*****************************************************************************
3145 * ReadPrinter [WINSPOOL.@]
3147 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3148 LPDWORD pNoBytesRead)
3150 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3154 /*****************************************************************************
3155 * ResetPrinterA [WINSPOOL.@]
3157 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3159 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3163 /*****************************************************************************
3164 * ResetPrinterW [WINSPOOL.@]
3166 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3168 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3172 /*****************************************************************************
3173 * WINSPOOL_GetDWORDFromReg
3175 * Return DWORD associated with ValueName from hkey.
3177 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3179 DWORD sz = sizeof(DWORD), type, value = 0;
3182 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3184 if(ret != ERROR_SUCCESS) {
3185 WARN("Got ret = %d on name %s\n", ret, ValueName);
3188 if(type != REG_DWORD) {
3189 ERR("Got type %d\n", type);
3196 /*****************************************************************************
3197 * get_filename_from_reg [internal]
3199 * Get ValueName from hkey storing result in out
3200 * when the Value in the registry has only a filename, use driverdir as prefix
3201 * outlen is space left in out
3202 * String is stored either as unicode or ascii
3206 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3207 LPBYTE out, DWORD outlen, LPDWORD needed)
3209 WCHAR filename[MAX_PATH];
3213 LPWSTR buffer = filename;
3217 size = sizeof(filename);
3219 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3220 if (ret == ERROR_MORE_DATA) {
3221 TRACE("need dynamic buffer: %u\n", size);
3222 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3224 /* No Memory is bad */
3228 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3231 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3232 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3238 /* do we have a full path ? */
3239 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3240 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3243 /* we must build the full Path */
3245 if ((out) && (outlen > dirlen)) {
3246 lstrcpyW((LPWSTR)out, driverdir);
3254 /* write the filename */
3255 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3256 if ((out) && (outlen >= size)) {
3257 lstrcpyW((LPWSTR)out, ptr);
3264 ptr += lstrlenW(ptr)+1;
3265 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3268 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3270 /* write the multisz-termination */
3271 if (type == REG_MULTI_SZ) {
3272 size = sizeof(WCHAR);
3275 if (out && (outlen >= size)) {
3276 memset (out, 0, size);
3282 /*****************************************************************************
3283 * WINSPOOL_GetStringFromReg
3285 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3286 * String is stored as unicode.
3288 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3289 DWORD buflen, DWORD *needed)
3291 DWORD sz = buflen, type;
3294 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3295 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3296 WARN("Got ret = %d\n", ret);
3300 /* add space for terminating '\0' */
3301 sz += sizeof(WCHAR);
3305 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3310 /*****************************************************************************
3311 * WINSPOOL_GetDefaultDevMode
3313 * Get a default DevMode values for wineps.
3317 static void WINSPOOL_GetDefaultDevMode(
3319 DWORD buflen, DWORD *needed)
3322 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3324 /* fill default DEVMODE - should be read from ppd... */
3325 ZeroMemory( &dm, sizeof(dm) );
3326 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3327 dm.dmSpecVersion = DM_SPECVERSION;
3328 dm.dmDriverVersion = 1;
3329 dm.dmSize = sizeof(DEVMODEW);
3330 dm.dmDriverExtra = 0;
3332 DM_ORIENTATION | DM_PAPERSIZE |
3333 DM_PAPERLENGTH | DM_PAPERWIDTH |
3336 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3337 DM_YRESOLUTION | DM_TTOPTION;
3339 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3340 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3341 dm.u1.s1.dmPaperLength = 2970;
3342 dm.u1.s1.dmPaperWidth = 2100;
3344 dm.u1.s1.dmScale = 100;
3345 dm.u1.s1.dmCopies = 1;
3346 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3347 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3350 dm.dmYResolution = 300; /* 300dpi */
3351 dm.dmTTOption = DMTT_BITMAP;
3354 /* dm.dmLogPixels */
3355 /* dm.dmBitsPerPel */
3356 /* dm.dmPelsWidth */
3357 /* dm.dmPelsHeight */
3358 /* dm.u2.dmDisplayFlags */
3359 /* dm.dmDisplayFrequency */
3360 /* dm.dmICMMethod */
3361 /* dm.dmICMIntent */
3362 /* dm.dmMediaType */
3363 /* dm.dmDitherType */
3364 /* dm.dmReserved1 */
3365 /* dm.dmReserved2 */
3366 /* dm.dmPanningWidth */
3367 /* dm.dmPanningHeight */
3369 if(buflen >= sizeof(DEVMODEW))
3370 memcpy(ptr, &dm, sizeof(DEVMODEW));
3371 *needed = sizeof(DEVMODEW);
3374 /*****************************************************************************
3375 * WINSPOOL_GetDevModeFromReg
3377 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3378 * DevMode is stored either as unicode or ascii.
3380 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3382 DWORD buflen, DWORD *needed)
3384 DWORD sz = buflen, type;
3387 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3388 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3389 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3390 if (sz < sizeof(DEVMODEA))
3392 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3395 /* ensures that dmSize is not erratically bogus if registry is invalid */
3396 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3397 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3398 sz += (CCHDEVICENAME + CCHFORMNAME);
3399 if (ptr && (buflen >= sz)) {
3400 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3401 memcpy(ptr, dmW, sz);
3402 HeapFree(GetProcessHeap(),0,dmW);
3408 /*********************************************************************
3409 * WINSPOOL_GetPrinter_1
3411 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3413 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3414 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3416 DWORD size, left = cbBuf;
3417 BOOL space = (cbBuf > 0);
3422 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3423 if(space && size <= left) {
3424 pi1->pName = (LPWSTR)ptr;
3432 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3433 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3434 if(space && size <= left) {
3435 pi1->pDescription = (LPWSTR)ptr;
3443 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3444 if(space && size <= left) {
3445 pi1->pComment = (LPWSTR)ptr;
3453 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3455 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3456 memset(pi1, 0, sizeof(*pi1));
3460 /*********************************************************************
3461 * WINSPOOL_GetPrinter_2
3463 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3465 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3466 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3468 DWORD size, left = cbBuf;
3469 BOOL space = (cbBuf > 0);
3474 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3475 if(space && size <= left) {
3476 pi2->pPrinterName = (LPWSTR)ptr;
3483 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3484 if(space && size <= left) {
3485 pi2->pShareName = (LPWSTR)ptr;
3492 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3493 if(space && size <= left) {
3494 pi2->pPortName = (LPWSTR)ptr;
3501 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3502 if(space && size <= left) {
3503 pi2->pDriverName = (LPWSTR)ptr;
3510 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3511 if(space && size <= left) {
3512 pi2->pComment = (LPWSTR)ptr;
3519 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3520 if(space && size <= left) {
3521 pi2->pLocation = (LPWSTR)ptr;
3528 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3529 if(space && size <= left) {
3530 pi2->pDevMode = (LPDEVMODEW)ptr;
3539 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3540 if(space && size <= left) {
3541 pi2->pDevMode = (LPDEVMODEW)ptr;
3548 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3549 if(space && size <= left) {
3550 pi2->pSepFile = (LPWSTR)ptr;
3557 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3558 if(space && size <= left) {
3559 pi2->pPrintProcessor = (LPWSTR)ptr;
3566 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3567 if(space && size <= left) {
3568 pi2->pDatatype = (LPWSTR)ptr;
3575 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3576 if(space && size <= left) {
3577 pi2->pParameters = (LPWSTR)ptr;
3585 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3586 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3587 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3588 "Default Priority");
3589 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3590 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3593 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3594 memset(pi2, 0, sizeof(*pi2));
3599 /*********************************************************************
3600 * WINSPOOL_GetPrinter_4
3602 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3604 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3605 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3607 DWORD size, left = cbBuf;
3608 BOOL space = (cbBuf > 0);
3613 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3614 if(space && size <= left) {
3615 pi4->pPrinterName = (LPWSTR)ptr;
3623 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3626 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3627 memset(pi4, 0, sizeof(*pi4));
3632 /*********************************************************************
3633 * WINSPOOL_GetPrinter_5
3635 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3637 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3638 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3640 DWORD size, left = cbBuf;
3641 BOOL space = (cbBuf > 0);
3646 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3647 if(space && size <= left) {
3648 pi5->pPrinterName = (LPWSTR)ptr;
3655 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3656 if(space && size <= left) {
3657 pi5->pPortName = (LPWSTR)ptr;
3665 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3666 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3668 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3672 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3673 memset(pi5, 0, sizeof(*pi5));
3678 /*********************************************************************
3679 * WINSPOOL_GetPrinter_7
3681 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3683 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3684 DWORD cbBuf, LPDWORD pcbNeeded)
3686 DWORD size, left = cbBuf;
3687 BOOL space = (cbBuf > 0);
3692 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3695 size = sizeof(pi7->pszObjectGUID);
3697 if (space && size <= left) {
3698 pi7->pszObjectGUID = (LPWSTR)ptr;
3705 /* We do not have a Directory Service */
3706 pi7->dwAction = DSPRINT_UNPUBLISH;
3709 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3710 memset(pi7, 0, sizeof(*pi7));
3715 /*********************************************************************
3716 * WINSPOOL_GetPrinter_9
3718 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3720 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3721 DWORD cbBuf, LPDWORD pcbNeeded)
3724 BOOL space = (cbBuf > 0);
3728 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3729 if(space && size <= cbBuf) {
3730 pi9->pDevMode = (LPDEVMODEW)buf;
3737 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3738 if(space && size <= cbBuf) {
3739 pi9->pDevMode = (LPDEVMODEW)buf;
3745 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3746 memset(pi9, 0, sizeof(*pi9));
3751 /*****************************************************************************
3752 * GetPrinterW [WINSPOOL.@]
3754 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3755 DWORD cbBuf, LPDWORD pcbNeeded)
3758 DWORD size, needed = 0;
3760 HKEY hkeyPrinter, hkeyPrinters;
3763 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3765 if (!(name = get_opened_printer_name(hPrinter))) {
3766 SetLastError(ERROR_INVALID_HANDLE);
3770 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3772 ERR("Can't create Printers key\n");
3775 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3777 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3778 RegCloseKey(hkeyPrinters);
3779 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3786 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3788 size = sizeof(PRINTER_INFO_2W);
3790 ptr = pPrinter + size;
3792 memset(pPrinter, 0, size);
3797 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3804 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3806 size = sizeof(PRINTER_INFO_4W);
3808 ptr = pPrinter + size;
3810 memset(pPrinter, 0, size);
3815 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3823 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3825 size = sizeof(PRINTER_INFO_5W);
3827 ptr = pPrinter + size;
3829 memset(pPrinter, 0, size);
3835 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3843 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3845 size = sizeof(PRINTER_INFO_6);
3846 if (size <= cbBuf) {
3847 /* FIXME: We do not update the status yet */
3848 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3860 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3862 size = sizeof(PRINTER_INFO_7W);
3863 if (size <= cbBuf) {
3864 ptr = pPrinter + size;
3866 memset(pPrinter, 0, size);
3872 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3880 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3882 size = sizeof(PRINTER_INFO_9W);
3884 ptr = pPrinter + size;
3886 memset(pPrinter, 0, size);
3892 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3899 FIXME("Unimplemented level %d\n", Level);
3900 SetLastError(ERROR_INVALID_LEVEL);
3901 RegCloseKey(hkeyPrinters);
3902 RegCloseKey(hkeyPrinter);
3906 RegCloseKey(hkeyPrinter);
3907 RegCloseKey(hkeyPrinters);
3909 TRACE("returning %d needed = %d\n", ret, needed);
3910 if(pcbNeeded) *pcbNeeded = needed;
3912 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3916 /*****************************************************************************
3917 * GetPrinterA [WINSPOOL.@]
3919 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3920 DWORD cbBuf, LPDWORD pcbNeeded)
3926 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3928 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3930 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3931 HeapFree(GetProcessHeap(), 0, buf);
3936 /*****************************************************************************
3937 * WINSPOOL_EnumPrintersW
3939 * Implementation of EnumPrintersW
3941 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3942 DWORD dwLevel, LPBYTE lpbPrinters,
3943 DWORD cbBuf, LPDWORD lpdwNeeded,
3944 LPDWORD lpdwReturned)
3947 HKEY hkeyPrinters, hkeyPrinter;
3948 WCHAR PrinterName[255];
3949 DWORD needed = 0, number = 0;
3950 DWORD used, i, left;
3954 memset(lpbPrinters, 0, cbBuf);
3960 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3961 if(dwType == PRINTER_ENUM_DEFAULT)
3964 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3965 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3966 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3968 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3974 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3975 FIXME("dwType = %08x\n", dwType);
3976 SetLastError(ERROR_INVALID_FLAGS);
3980 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3982 ERR("Can't create Printers key\n");
3986 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3987 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3988 RegCloseKey(hkeyPrinters);
3989 ERR("Can't query Printers key\n");
3992 TRACE("Found %d printers\n", number);
3996 used = number * sizeof(PRINTER_INFO_1W);
3999 used = number * sizeof(PRINTER_INFO_2W);
4002 used = number * sizeof(PRINTER_INFO_4W);
4005 used = number * sizeof(PRINTER_INFO_5W);
4009 SetLastError(ERROR_INVALID_LEVEL);
4010 RegCloseKey(hkeyPrinters);
4013 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4015 for(i = 0; i < number; i++) {
4016 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4018 ERR("Can't enum key number %d\n", i);
4019 RegCloseKey(hkeyPrinters);
4022 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4023 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4025 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4026 RegCloseKey(hkeyPrinters);
4031 buf = lpbPrinters + used;
4032 left = cbBuf - used;
4040 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4043 if(pi) pi += sizeof(PRINTER_INFO_1W);
4046 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4049 if(pi) pi += sizeof(PRINTER_INFO_2W);
4052 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4055 if(pi) pi += sizeof(PRINTER_INFO_4W);
4058 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4061 if(pi) pi += sizeof(PRINTER_INFO_5W);
4064 ERR("Shouldn't be here!\n");
4065 RegCloseKey(hkeyPrinter);
4066 RegCloseKey(hkeyPrinters);
4069 RegCloseKey(hkeyPrinter);
4071 RegCloseKey(hkeyPrinters);
4078 memset(lpbPrinters, 0, cbBuf);
4079 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4083 *lpdwReturned = number;
4084 SetLastError(ERROR_SUCCESS);
4089 /******************************************************************
4090 * EnumPrintersW [WINSPOOL.@]
4092 * Enumerates the available printers, print servers and print
4093 * providers, depending on the specified flags, name and level.
4097 * If level is set to 1:
4098 * Returns an array of PRINTER_INFO_1 data structures in the
4099 * lpbPrinters buffer.
4101 * If level is set to 2:
4102 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4103 * Returns an array of PRINTER_INFO_2 data structures in the
4104 * lpbPrinters buffer. Note that according to MSDN also an
4105 * OpenPrinter should be performed on every remote printer.
4107 * If level is set to 4 (officially WinNT only):
4108 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4109 * Fast: Only the registry is queried to retrieve printer names,
4110 * no connection to the driver is made.
4111 * Returns an array of PRINTER_INFO_4 data structures in the
4112 * lpbPrinters buffer.
4114 * If level is set to 5 (officially WinNT4/Win9x only):
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_5 data structures in the
4118 * lpbPrinters buffer.
4120 * If level set to 3 or 6+:
4121 * returns zero (failure!)
4123 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4127 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4128 * - Only levels 2, 4 and 5 are implemented at the moment.
4129 * - 16-bit printer drivers are not enumerated.
4130 * - Returned amount of bytes used/needed does not match the real Windoze
4131 * implementation (as in this implementation, all strings are part
4132 * of the buffer, whereas Win32 keeps them somewhere else)
4133 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4136 * - In a regular Wine installation, no registry settings for printers
4137 * exist, which makes this function return an empty list.
4139 BOOL WINAPI EnumPrintersW(
4140 DWORD dwType, /* [in] Types of print objects to enumerate */
4141 LPWSTR lpszName, /* [in] name of objects to enumerate */
4142 DWORD dwLevel, /* [in] type of printer info structure */
4143 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4144 DWORD cbBuf, /* [in] max size of buffer in bytes */
4145 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4146 LPDWORD lpdwReturned /* [out] number of entries returned */
4149 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4150 lpdwNeeded, lpdwReturned);
4153 /******************************************************************
4154 * EnumPrintersA [WINSPOOL.@]
4159 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4160 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4163 UNICODE_STRING pNameU;
4167 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4168 pPrinters, cbBuf, pcbNeeded, pcReturned);
4170 pNameW = asciitounicode(&pNameU, pName);
4172 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4173 MS Office need this */
4174 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4176 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4178 RtlFreeUnicodeString(&pNameU);
4180 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4182 HeapFree(GetProcessHeap(), 0, pPrintersW);
4186 /*****************************************************************************
4187 * WINSPOOL_GetDriverInfoFromReg [internal]
4189 * Enters the information from the registry into the DRIVER_INFO struct
4192 * zero if the printer driver does not exist in the registry
4193 * (only if Level > 1) otherwise nonzero
4195 static BOOL WINSPOOL_GetDriverInfoFromReg(
4198 const printenv_t * env,
4200 LPBYTE ptr, /* DRIVER_INFO */
4201 LPBYTE pDriverStrings, /* strings buffer */
4202 DWORD cbBuf, /* size of string buffer */
4203 LPDWORD pcbNeeded) /* space needed for str. */
4207 WCHAR driverdir[MAX_PATH];
4209 LPBYTE strPtr = pDriverStrings;
4210 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4212 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4213 debugstr_w(DriverName), env,
4214 Level, di, pDriverStrings, cbBuf);
4216 if (di) ZeroMemory(di, di_sizeof[Level]);
4218 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4219 if (*pcbNeeded <= cbBuf)
4220 strcpyW((LPWSTR)strPtr, DriverName);
4222 /* pName for level 1 has a different offset! */
4224 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4228 /* .cVersion and .pName for level > 1 */
4230 di->cVersion = env->driverversion;
4231 di->pName = (LPWSTR) strPtr;
4232 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4235 /* Reserve Space for the largest subdir and a Backslash*/
4236 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4237 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4238 /* Should never Fail */
4241 lstrcatW(driverdir, env->versionsubdir);
4242 lstrcatW(driverdir, backslashW);
4244 /* dirlen must not include the terminating zero */
4245 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4247 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4248 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4249 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4254 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4257 if (*pcbNeeded <= cbBuf) {
4258 lstrcpyW((LPWSTR)strPtr, env->envname);
4259 if (di) di->pEnvironment = (LPWSTR)strPtr;
4260 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4263 /* .pDriverPath is the Graphics rendering engine.
4264 The full Path is required to avoid a crash in some apps */
4265 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4267 if (*pcbNeeded <= cbBuf)
4268 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4270 if (di) di->pDriverPath = (LPWSTR)strPtr;
4271 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4274 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4275 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4277 if (*pcbNeeded <= cbBuf)
4278 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4280 if (di) di->pDataFile = (LPWSTR)strPtr;
4281 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4284 /* .pConfigFile is the Driver user Interface */
4285 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4287 if (*pcbNeeded <= cbBuf)
4288 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4290 if (di) di->pConfigFile = (LPWSTR)strPtr;
4291 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4295 RegCloseKey(hkeyDriver);
4296 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4301 RegCloseKey(hkeyDriver);
4302 FIXME("level 5: incomplete\n");
4307 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4309 if (*pcbNeeded <= cbBuf)
4310 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4312 if (di) di->pHelpFile = (LPWSTR)strPtr;
4313 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4316 /* .pDependentFiles */
4317 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4319 if (*pcbNeeded <= cbBuf)
4320 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4322 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4323 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4325 else if (GetVersion() & 0x80000000) {
4326 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4327 size = 2 * sizeof(WCHAR);
4329 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4331 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4332 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4335 /* .pMonitorName is the optional Language Monitor */
4336 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4338 if (*pcbNeeded <= cbBuf)
4339 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4341 if (di) di->pMonitorName = (LPWSTR)strPtr;
4342 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4345 /* .pDefaultDataType */
4346 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4348 if(*pcbNeeded <= cbBuf)
4349 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4351 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4352 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4356 RegCloseKey(hkeyDriver);
4357 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4361 /* .pszzPreviousNames */
4362 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4364 if(*pcbNeeded <= cbBuf)
4365 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4367 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4368 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4372 RegCloseKey(hkeyDriver);
4373 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4377 /* support is missing, but not important enough for a FIXME */
4378 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4381 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4383 if(*pcbNeeded <= cbBuf)
4384 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4386 if (di) di->pszMfgName = (LPWSTR)strPtr;
4387 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4391 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4393 if(*pcbNeeded <= cbBuf)
4394 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4396 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4397 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4400 /* .pszHardwareID */
4401 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4403 if(*pcbNeeded <= cbBuf)
4404 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4406 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4407 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4411 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4413 if(*pcbNeeded <= cbBuf)
4414 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4416 if (di) di->pszProvider = (LPWSTR)strPtr;
4417 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4421 RegCloseKey(hkeyDriver);
4425 /* support is missing, but not important enough for a FIXME */
4426 TRACE("level 8: incomplete\n");
4428 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4429 RegCloseKey(hkeyDriver);
4433 /*****************************************************************************
4434 * GetPrinterDriverW [WINSPOOL.@]
4436 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4437 DWORD Level, LPBYTE pDriverInfo,
4438 DWORD cbBuf, LPDWORD pcbNeeded)
4441 WCHAR DriverName[100];
4442 DWORD ret, type, size, needed = 0;
4444 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4445 const printenv_t * env;
4447 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4448 Level,pDriverInfo,cbBuf, pcbNeeded);
4451 ZeroMemory(pDriverInfo, cbBuf);
4453 if (!(name = get_opened_printer_name(hPrinter))) {
4454 SetLastError(ERROR_INVALID_HANDLE);
4458 if (Level < 1 || Level == 7 || Level > 8) {
4459 SetLastError(ERROR_INVALID_LEVEL);
4463 env = validate_envW(pEnvironment);
4464 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4466 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4468 ERR("Can't create Printers key\n");
4471 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4473 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4474 RegCloseKey(hkeyPrinters);
4475 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4478 size = sizeof(DriverName);
4480 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4481 (LPBYTE)DriverName, &size);
4482 RegCloseKey(hkeyPrinter);
4483 RegCloseKey(hkeyPrinters);
4484 if(ret != ERROR_SUCCESS) {
4485 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4489 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4491 ERR("Can't create Drivers key\n");
4495 size = di_sizeof[Level];
4496 if ((size <= cbBuf) && pDriverInfo)
4497 ptr = pDriverInfo + size;
4499 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4500 env, Level, pDriverInfo, ptr,
4501 (cbBuf < size) ? 0 : cbBuf - size,
4503 RegCloseKey(hkeyDrivers);
4507 RegCloseKey(hkeyDrivers);
4509 if(pcbNeeded) *pcbNeeded = size + needed;
4510 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4511 if(cbBuf >= size + needed) return TRUE;
4512 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4516 /*****************************************************************************
4517 * GetPrinterDriverA [WINSPOOL.@]
4519 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4520 DWORD Level, LPBYTE pDriverInfo,
4521 DWORD cbBuf, LPDWORD pcbNeeded)
4524 UNICODE_STRING pEnvW;
4530 ZeroMemory(pDriverInfo, cbBuf);
4531 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4534 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4535 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4538 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4540 HeapFree(GetProcessHeap(), 0, buf);
4542 RtlFreeUnicodeString(&pEnvW);
4546 /*****************************************************************************
4547 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4549 * Return the PATH for the Printer-Drivers (UNICODE)
4552 * pName [I] Servername (NT only) or NULL (local Computer)
4553 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4554 * Level [I] Structure-Level (must be 1)
4555 * pDriverDirectory [O] PTR to Buffer that receives the Result
4556 * cbBuf [I] Size of Buffer at pDriverDirectory
4557 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4558 * required for pDriverDirectory
4561 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4562 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4563 * if cbBuf is too small
4565 * Native Values returned in pDriverDirectory on Success:
4566 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4567 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4568 *| win9x(Windows 4.0): "%winsysdir%"
4570 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4573 *- Only NULL or "" is supported for pName
4576 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4577 DWORD Level, LPBYTE pDriverDirectory,
4578 DWORD cbBuf, LPDWORD pcbNeeded)
4580 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4581 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4583 if ((backend == NULL) && !load_backend()) return FALSE;
4586 /* (Level != 1) is ignored in win9x */
4587 SetLastError(ERROR_INVALID_LEVEL);
4590 if (pcbNeeded == NULL) {
4591 /* (pcbNeeded == NULL) is ignored in win9x */
4592 SetLastError(RPC_X_NULL_REF_POINTER);
4596 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4597 pDriverDirectory, cbBuf, pcbNeeded);
4602 /*****************************************************************************
4603 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4605 * Return the PATH for the Printer-Drivers (ANSI)
4607 * See GetPrinterDriverDirectoryW.
4610 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4613 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4614 DWORD Level, LPBYTE pDriverDirectory,
4615 DWORD cbBuf, LPDWORD pcbNeeded)
4617 UNICODE_STRING nameW, environmentW;
4620 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4621 WCHAR *driverDirectoryW = NULL;
4623 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4624 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4626 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4628 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4629 else nameW.Buffer = NULL;
4630 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4631 else environmentW.Buffer = NULL;
4633 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4634 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4637 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4638 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4640 *pcbNeeded = needed;
4641 ret = (needed <= cbBuf) ? TRUE : FALSE;
4643 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4645 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4647 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4648 RtlFreeUnicodeString(&environmentW);
4649 RtlFreeUnicodeString(&nameW);
4654 /*****************************************************************************
4655 * AddPrinterDriverA [WINSPOOL.@]
4657 * See AddPrinterDriverW.
4660 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4662 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4663 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4666 /******************************************************************************
4667 * AddPrinterDriverW (WINSPOOL.@)
4669 * Install a Printer Driver
4672 * pName [I] Servername or NULL (local Computer)
4673 * level [I] Level for the supplied DRIVER_INFO_*W struct
4674 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4681 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4683 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4684 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4687 /*****************************************************************************
4688 * AddPrintProcessorA [WINSPOOL.@]
4690 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4691 LPSTR pPrintProcessorName)
4693 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4694 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4698 /*****************************************************************************
4699 * AddPrintProcessorW [WINSPOOL.@]
4701 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4702 LPWSTR pPrintProcessorName)
4704 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4705 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4709 /*****************************************************************************
4710 * AddPrintProvidorA [WINSPOOL.@]
4712 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4714 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4718 /*****************************************************************************
4719 * AddPrintProvidorW [WINSPOOL.@]
4721 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4723 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4727 /*****************************************************************************
4728 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4730 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4731 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4733 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4734 pDevModeOutput, pDevModeInput);
4738 /*****************************************************************************
4739 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4741 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4742 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4744 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4745 pDevModeOutput, pDevModeInput);
4749 /*****************************************************************************
4750 * PrinterProperties [WINSPOOL.@]
4752 * Displays a dialog to set the properties of the printer.
4755 * nonzero on success or zero on failure
4758 * implemented as stub only
4760 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4761 HANDLE hPrinter /* [in] handle to printer object */
4763 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4764 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4768 /*****************************************************************************
4769 * EnumJobsA [WINSPOOL.@]
4772 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4773 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4776 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4777 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4779 if(pcbNeeded) *pcbNeeded = 0;
4780 if(pcReturned) *pcReturned = 0;
4785 /*****************************************************************************
4786 * EnumJobsW [WINSPOOL.@]
4789 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4790 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4793 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4794 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4796 if(pcbNeeded) *pcbNeeded = 0;
4797 if(pcReturned) *pcReturned = 0;
4801 /*****************************************************************************
4802 * WINSPOOL_EnumPrinterDrivers [internal]
4804 * Delivers information about all printer drivers installed on the
4805 * localhost or a given server
4808 * nonzero on success or zero on failure. If the buffer for the returned
4809 * information is too small the function will return an error
4812 * - only implemented for localhost, foreign hosts will return an error
4814 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4815 DWORD Level, LPBYTE pDriverInfo,
4817 DWORD cbBuf, LPDWORD pcbNeeded,
4818 LPDWORD pcFound, DWORD data_offset)
4822 const printenv_t * env;
4824 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4825 debugstr_w(pName), debugstr_w(pEnvironment),
4826 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4828 env = validate_envW(pEnvironment);
4829 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4833 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4835 ERR("Can't open Drivers key\n");
4839 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4840 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4841 RegCloseKey(hkeyDrivers);
4842 ERR("Can't query Drivers key\n");
4845 TRACE("Found %d Drivers\n", *pcFound);
4847 /* get size of single struct
4848 * unicode and ascii structure have the same size
4850 size = di_sizeof[Level];
4852 if (data_offset == 0)
4853 data_offset = size * (*pcFound);
4854 *pcbNeeded = data_offset;
4856 for( i = 0; i < *pcFound; i++) {
4857 WCHAR DriverNameW[255];
4858 PBYTE table_ptr = NULL;
4859 PBYTE data_ptr = NULL;
4862 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4864 ERR("Can't enum key number %d\n", i);
4865 RegCloseKey(hkeyDrivers);
4869 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4870 table_ptr = pDriverInfo + (driver_index + i) * size;
4871 if (pDriverInfo && *pcbNeeded <= cbBuf)
4872 data_ptr = pDriverInfo + *pcbNeeded;
4874 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4875 env, Level, table_ptr, data_ptr,
4876 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4878 RegCloseKey(hkeyDrivers);
4882 *pcbNeeded += needed;
4885 RegCloseKey(hkeyDrivers);
4887 if(cbBuf < *pcbNeeded){
4888 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4895 /*****************************************************************************
4896 * EnumPrinterDriversW [WINSPOOL.@]
4898 * see function EnumPrinterDrivers for RETURNS, BUGS
4900 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4901 LPBYTE pDriverInfo, DWORD cbBuf,
4902 LPDWORD pcbNeeded, LPDWORD pcReturned)
4904 static const WCHAR allW[] = {'a','l','l',0};
4908 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4910 SetLastError(RPC_X_NULL_REF_POINTER);
4914 /* check for local drivers */
4915 if((pName) && (pName[0])) {
4916 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4917 SetLastError(ERROR_ACCESS_DENIED);
4921 /* check input parameter */
4922 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4923 SetLastError(ERROR_INVALID_LEVEL);
4927 if(pDriverInfo && cbBuf > 0)
4928 memset( pDriverInfo, 0, cbBuf);
4930 /* Exception: pull all printers */
4931 if (pEnvironment && !strcmpW(pEnvironment, allW))
4933 DWORD i, needed, bufsize = cbBuf;
4934 DWORD total_needed = 0;
4935 DWORD total_found = 0;
4938 /* Precompute the overall total; we need this to know
4939 where pointers end and data begins (i.e. data_offset) */
4940 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4943 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4944 NULL, 0, 0, &needed, &found, 0);
4945 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4946 total_needed += needed;
4947 total_found += found;
4950 data_offset = di_sizeof[Level] * total_found;
4955 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4958 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4959 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4960 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4962 *pcReturned += found;
4963 *pcbNeeded = needed;
4964 data_offset = needed;
4965 total_found += found;
4970 /* Normal behavior */
4971 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4972 0, cbBuf, pcbNeeded, &found, 0);
4974 *pcReturned = found;
4979 /*****************************************************************************
4980 * EnumPrinterDriversA [WINSPOOL.@]
4982 * see function EnumPrinterDrivers for RETURNS, BUGS
4984 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4985 LPBYTE pDriverInfo, DWORD cbBuf,
4986 LPDWORD pcbNeeded, LPDWORD pcReturned)
4989 UNICODE_STRING pNameW, pEnvironmentW;
4990 PWSTR pwstrNameW, pwstrEnvironmentW;
4994 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4996 pwstrNameW = asciitounicode(&pNameW, pName);
4997 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4999 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5000 buf, cbBuf, pcbNeeded, pcReturned);
5002 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5004 HeapFree(GetProcessHeap(), 0, buf);
5006 RtlFreeUnicodeString(&pNameW);
5007 RtlFreeUnicodeString(&pEnvironmentW);
5012 /******************************************************************************
5013 * EnumPortsA (WINSPOOL.@)
5018 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5019 LPDWORD pcbNeeded, LPDWORD pcReturned)
5022 LPBYTE bufferW = NULL;
5023 LPWSTR nameW = NULL;
5025 DWORD numentries = 0;
5028 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5029 cbBuf, pcbNeeded, pcReturned);
5031 /* convert servername to unicode */
5033 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5034 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5035 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5037 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5038 needed = cbBuf * sizeof(WCHAR);
5039 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5040 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5042 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5043 if (pcbNeeded) needed = *pcbNeeded;
5044 /* HeapReAlloc return NULL, when bufferW was NULL */
5045 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5046 HeapAlloc(GetProcessHeap(), 0, needed);
5048 /* Try again with the large Buffer */
5049 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5051 needed = pcbNeeded ? *pcbNeeded : 0;
5052 numentries = pcReturned ? *pcReturned : 0;
5055 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5056 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5059 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5060 DWORD entrysize = 0;
5063 LPPORT_INFO_2W pi2w;
5064 LPPORT_INFO_2A pi2a;
5067 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5069 /* First pass: calculate the size for all Entries */
5070 pi2w = (LPPORT_INFO_2W) bufferW;
5071 pi2a = (LPPORT_INFO_2A) pPorts;
5073 while (index < numentries) {
5075 needed += entrysize; /* PORT_INFO_?A */
5076 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5078 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5079 NULL, 0, NULL, NULL);
5081 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5082 NULL, 0, NULL, NULL);
5083 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5084 NULL, 0, NULL, NULL);
5086 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5087 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5088 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5091 /* check for errors and quit on failure */
5092 if (cbBuf < needed) {
5093 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5097 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5098 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5099 cbBuf -= len ; /* free Bytes in the user-Buffer */
5100 pi2w = (LPPORT_INFO_2W) bufferW;
5101 pi2a = (LPPORT_INFO_2A) pPorts;
5103 /* Second Pass: Fill the User Buffer (if we have one) */
5104 while ((index < numentries) && pPorts) {
5106 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5107 pi2a->pPortName = ptr;
5108 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5109 ptr, cbBuf , NULL, NULL);
5113 pi2a->pMonitorName = ptr;
5114 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5115 ptr, cbBuf, NULL, NULL);
5119 pi2a->pDescription = ptr;
5120 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5121 ptr, cbBuf, NULL, NULL);
5125 pi2a->fPortType = pi2w->fPortType;
5126 pi2a->Reserved = 0; /* documented: "must be zero" */
5129 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5130 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5131 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5136 if (pcbNeeded) *pcbNeeded = needed;
5137 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5139 HeapFree(GetProcessHeap(), 0, nameW);
5140 HeapFree(GetProcessHeap(), 0, bufferW);
5142 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5143 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5149 /******************************************************************************
5150 * EnumPortsW (WINSPOOL.@)
5152 * Enumerate available Ports
5155 * pName [I] Servername or NULL (local Computer)
5156 * Level [I] Structure-Level (1 or 2)
5157 * pPorts [O] PTR to Buffer that receives the Result
5158 * cbBuf [I] Size of Buffer at pPorts
5159 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5160 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5164 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5167 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5170 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5171 cbBuf, pcbNeeded, pcReturned);
5173 if ((backend == NULL) && !load_backend()) return FALSE;
5175 /* Level is not checked in win9x */
5176 if (!Level || (Level > 2)) {
5177 WARN("level (%d) is ignored in win9x\n", Level);
5178 SetLastError(ERROR_INVALID_LEVEL);
5181 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5182 SetLastError(RPC_X_NULL_REF_POINTER);
5186 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5189 /******************************************************************************
5190 * GetDefaultPrinterW (WINSPOOL.@)
5193 * This function must read the value from data 'device' of key
5194 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5196 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5200 WCHAR *buffer, *ptr;
5204 SetLastError(ERROR_INVALID_PARAMETER);
5208 /* make the buffer big enough for the stuff from the profile/registry,
5209 * the content must fit into the local buffer to compute the correct
5210 * size even if the extern buffer is too small or not given.
5211 * (20 for ,driver,port) */
5213 len = max(100, (insize + 20));
5214 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5216 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5218 SetLastError (ERROR_FILE_NOT_FOUND);
5222 TRACE("%s\n", debugstr_w(buffer));
5224 if ((ptr = strchrW(buffer, ',')) == NULL)
5226 SetLastError(ERROR_INVALID_NAME);
5232 *namesize = strlenW(buffer) + 1;
5233 if(!name || (*namesize > insize))
5235 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5239 strcpyW(name, buffer);
5242 HeapFree( GetProcessHeap(), 0, buffer);
5247 /******************************************************************************
5248 * GetDefaultPrinterA (WINSPOOL.@)
5250 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5254 WCHAR *bufferW = NULL;
5258 SetLastError(ERROR_INVALID_PARAMETER);
5262 if(name && *namesize) {
5264 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5267 if(!GetDefaultPrinterW( bufferW, namesize)) {
5272 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5276 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5279 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5282 HeapFree( GetProcessHeap(), 0, bufferW);
5287 /******************************************************************************
5288 * SetDefaultPrinterW (WINSPOOL.204)
5290 * Set the Name of the Default Printer
5293 * pszPrinter [I] Name of the Printer or NULL
5300 * When the Parameter is NULL or points to an Empty String and
5301 * a Default Printer was already present, then this Function changes nothing.
5302 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5303 * the First enumerated local Printer is used.
5306 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5308 WCHAR default_printer[MAX_PATH];
5309 LPWSTR buffer = NULL;
5315 TRACE("(%s)\n", debugstr_w(pszPrinter));
5316 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5318 default_printer[0] = '\0';
5319 size = sizeof(default_printer)/sizeof(WCHAR);
5321 /* if we have a default Printer, do nothing. */
5322 if (GetDefaultPrinterW(default_printer, &size))
5326 /* we have no default Printer: search local Printers and use the first */
5327 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5329 default_printer[0] = '\0';
5330 size = sizeof(default_printer)/sizeof(WCHAR);
5331 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5333 pszPrinter = default_printer;
5334 TRACE("using %s\n", debugstr_w(pszPrinter));
5339 if (pszPrinter == NULL) {
5340 TRACE("no local printer found\n");
5341 SetLastError(ERROR_FILE_NOT_FOUND);
5346 /* "pszPrinter" is never empty or NULL here. */
5347 namelen = lstrlenW(pszPrinter);
5348 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5349 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5351 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5352 HeapFree(GetProcessHeap(), 0, buffer);
5353 SetLastError(ERROR_FILE_NOT_FOUND);
5357 /* read the devices entry for the printer (driver,port) to build the string for the
5358 default device entry (printer,driver,port) */
5359 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5360 buffer[namelen] = ',';
5361 namelen++; /* move index to the start of the driver */
5363 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5364 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5366 TRACE("set device to %s\n", debugstr_w(buffer));
5368 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5369 TRACE("failed to set the device entry: %d\n", GetLastError());
5370 lres = ERROR_INVALID_PRINTER_NAME;
5373 /* remove the next section, when INIFileMapping is implemented */
5376 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5377 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5384 if (lres != ERROR_FILE_NOT_FOUND)
5385 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5387 SetLastError(ERROR_INVALID_PRINTER_NAME);
5391 HeapFree(GetProcessHeap(), 0, buffer);
5392 return (lres == ERROR_SUCCESS);
5395 /******************************************************************************
5396 * SetDefaultPrinterA (WINSPOOL.202)
5398 * See SetDefaultPrinterW.
5401 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5403 LPWSTR bufferW = NULL;
5406 TRACE("(%s)\n", debugstr_a(pszPrinter));
5408 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5409 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5410 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5412 res = SetDefaultPrinterW(bufferW);
5413 HeapFree(GetProcessHeap(), 0, bufferW);
5417 /******************************************************************************
5418 * SetPrinterDataExA (WINSPOOL.@)
5420 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5421 LPCSTR pValueName, DWORD Type,
5422 LPBYTE pData, DWORD cbData)
5424 HKEY hkeyPrinter, hkeySubkey;
5427 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5428 debugstr_a(pValueName), Type, pData, cbData);
5430 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5434 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5436 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5437 RegCloseKey(hkeyPrinter);
5440 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5441 RegCloseKey(hkeySubkey);
5442 RegCloseKey(hkeyPrinter);
5446 /******************************************************************************
5447 * SetPrinterDataExW (WINSPOOL.@)
5449 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5450 LPCWSTR pValueName, DWORD Type,
5451 LPBYTE pData, DWORD cbData)
5453 HKEY hkeyPrinter, hkeySubkey;
5456 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5457 debugstr_w(pValueName), Type, pData, cbData);
5459 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5463 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5465 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5466 RegCloseKey(hkeyPrinter);
5469 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5470 RegCloseKey(hkeySubkey);
5471 RegCloseKey(hkeyPrinter);
5475 /******************************************************************************
5476 * SetPrinterDataA (WINSPOOL.@)
5478 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5479 LPBYTE pData, DWORD cbData)
5481 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5485 /******************************************************************************
5486 * SetPrinterDataW (WINSPOOL.@)
5488 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5489 LPBYTE pData, DWORD cbData)
5491 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5495 /******************************************************************************
5496 * GetPrinterDataExA (WINSPOOL.@)
5498 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5499 LPCSTR pValueName, LPDWORD pType,
5500 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5502 opened_printer_t *printer;
5503 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5506 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5507 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5509 printer = get_opened_printer(hPrinter);
5510 if(!printer) return ERROR_INVALID_HANDLE;
5512 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5513 if (ret) return ret;
5515 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5517 if (printer->name) {
5519 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5521 RegCloseKey(hkeyPrinters);
5524 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5525 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5526 RegCloseKey(hkeyPrinter);
5527 RegCloseKey(hkeyPrinters);
5532 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5533 0, pType, pData, pcbNeeded);
5535 if (!ret && !pData) ret = ERROR_MORE_DATA;
5537 RegCloseKey(hkeySubkey);
5538 RegCloseKey(hkeyPrinter);
5539 RegCloseKey(hkeyPrinters);
5541 TRACE("--> %d\n", ret);
5545 /******************************************************************************
5546 * GetPrinterDataExW (WINSPOOL.@)
5548 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5549 LPCWSTR pValueName, LPDWORD pType,
5550 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5552 opened_printer_t *printer;
5553 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5556 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5557 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5559 printer = get_opened_printer(hPrinter);
5560 if(!printer) return ERROR_INVALID_HANDLE;
5562 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5563 if (ret) return ret;
5565 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5567 if (printer->name) {
5569 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5571 RegCloseKey(hkeyPrinters);
5574 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5575 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5576 RegCloseKey(hkeyPrinter);
5577 RegCloseKey(hkeyPrinters);
5582 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5583 0, pType, pData, pcbNeeded);
5585 if (!ret && !pData) ret = ERROR_MORE_DATA;
5587 RegCloseKey(hkeySubkey);
5588 RegCloseKey(hkeyPrinter);
5589 RegCloseKey(hkeyPrinters);
5591 TRACE("--> %d\n", ret);
5595 /******************************************************************************
5596 * GetPrinterDataA (WINSPOOL.@)
5598 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5599 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5601 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5602 pData, nSize, pcbNeeded);
5605 /******************************************************************************
5606 * GetPrinterDataW (WINSPOOL.@)
5608 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5609 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5611 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5612 pData, nSize, pcbNeeded);
5615 /*******************************************************************************
5616 * EnumPrinterDataExW [WINSPOOL.@]
5618 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5619 LPBYTE pEnumValues, DWORD cbEnumValues,
5620 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5622 HKEY hkPrinter, hkSubKey;
5623 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5624 cbValueNameLen, cbMaxValueLen, cbValueLen,
5629 PPRINTER_ENUM_VALUESW ppev;
5631 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5633 if (pKeyName == NULL || *pKeyName == 0)
5634 return ERROR_INVALID_PARAMETER;
5636 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5637 if (ret != ERROR_SUCCESS)
5639 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5644 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5645 if (ret != ERROR_SUCCESS)
5647 r = RegCloseKey (hkPrinter);
5648 if (r != ERROR_SUCCESS)
5649 WARN ("RegCloseKey returned %i\n", r);
5650 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5651 debugstr_w (pKeyName), ret);
5655 ret = RegCloseKey (hkPrinter);
5656 if (ret != ERROR_SUCCESS)
5658 ERR ("RegCloseKey returned %i\n", ret);
5659 r = RegCloseKey (hkSubKey);
5660 if (r != ERROR_SUCCESS)
5661 WARN ("RegCloseKey returned %i\n", r);
5665 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5666 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5667 if (ret != ERROR_SUCCESS)
5669 r = RegCloseKey (hkSubKey);
5670 if (r != ERROR_SUCCESS)
5671 WARN ("RegCloseKey returned %i\n", r);
5672 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5676 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5677 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5679 if (cValues == 0) /* empty key */
5681 r = RegCloseKey (hkSubKey);
5682 if (r != ERROR_SUCCESS)
5683 WARN ("RegCloseKey returned %i\n", r);
5684 *pcbEnumValues = *pnEnumValues = 0;
5685 return ERROR_SUCCESS;
5688 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5690 hHeap = GetProcessHeap ();
5693 ERR ("GetProcessHeap failed\n");
5694 r = RegCloseKey (hkSubKey);
5695 if (r != ERROR_SUCCESS)
5696 WARN ("RegCloseKey returned %i\n", r);
5697 return ERROR_OUTOFMEMORY;
5700 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5701 if (lpValueName == NULL)
5703 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5704 r = RegCloseKey (hkSubKey);
5705 if (r != ERROR_SUCCESS)
5706 WARN ("RegCloseKey returned %i\n", r);
5707 return ERROR_OUTOFMEMORY;
5710 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5711 if (lpValue == NULL)
5713 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5714 if (HeapFree (hHeap, 0, lpValueName) == 0)
5715 WARN ("HeapFree failed with code %i\n", GetLastError ());
5716 r = RegCloseKey (hkSubKey);
5717 if (r != ERROR_SUCCESS)
5718 WARN ("RegCloseKey returned %i\n", r);
5719 return ERROR_OUTOFMEMORY;
5722 TRACE ("pass 1: calculating buffer required for all names and values\n");
5724 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5726 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5728 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5730 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5731 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5732 NULL, NULL, lpValue, &cbValueLen);
5733 if (ret != ERROR_SUCCESS)
5735 if (HeapFree (hHeap, 0, lpValue) == 0)
5736 WARN ("HeapFree failed with code %i\n", GetLastError ());
5737 if (HeapFree (hHeap, 0, lpValueName) == 0)
5738 WARN ("HeapFree failed with code %i\n", GetLastError ());
5739 r = RegCloseKey (hkSubKey);
5740 if (r != ERROR_SUCCESS)
5741 WARN ("RegCloseKey returned %i\n", r);
5742 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5746 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5747 debugstr_w (lpValueName), dwIndex,
5748 cbValueNameLen + 1, cbValueLen);
5750 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5751 cbBufSize += cbValueLen;
5754 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5756 *pcbEnumValues = cbBufSize;
5757 *pnEnumValues = cValues;
5759 if (cbEnumValues < cbBufSize) /* buffer too small */
5761 if (HeapFree (hHeap, 0, lpValue) == 0)
5762 WARN ("HeapFree failed with code %i\n", GetLastError ());
5763 if (HeapFree (hHeap, 0, lpValueName) == 0)
5764 WARN ("HeapFree failed with code %i\n", GetLastError ());
5765 r = RegCloseKey (hkSubKey);
5766 if (r != ERROR_SUCCESS)
5767 WARN ("RegCloseKey returned %i\n", r);
5768 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5769 return ERROR_MORE_DATA;
5772 TRACE ("pass 2: copying all names and values to buffer\n");
5774 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5775 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5777 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5779 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5780 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5781 NULL, &dwType, lpValue, &cbValueLen);
5782 if (ret != ERROR_SUCCESS)
5784 if (HeapFree (hHeap, 0, lpValue) == 0)
5785 WARN ("HeapFree failed with code %i\n", GetLastError ());
5786 if (HeapFree (hHeap, 0, lpValueName) == 0)
5787 WARN ("HeapFree failed with code %i\n", GetLastError ());
5788 r = RegCloseKey (hkSubKey);
5789 if (r != ERROR_SUCCESS)
5790 WARN ("RegCloseKey returned %i\n", r);
5791 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5795 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5796 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5797 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5798 pEnumValues += cbValueNameLen;
5800 /* return # of *bytes* (including trailing \0), not # of chars */
5801 ppev[dwIndex].cbValueName = cbValueNameLen;
5803 ppev[dwIndex].dwType = dwType;
5805 memcpy (pEnumValues, lpValue, cbValueLen);
5806 ppev[dwIndex].pData = pEnumValues;
5807 pEnumValues += cbValueLen;
5809 ppev[dwIndex].cbData = cbValueLen;
5811 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5812 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5815 if (HeapFree (hHeap, 0, lpValue) == 0)
5817 ret = GetLastError ();
5818 ERR ("HeapFree failed with code %i\n", ret);
5819 if (HeapFree (hHeap, 0, lpValueName) == 0)
5820 WARN ("HeapFree failed with code %i\n", GetLastError ());
5821 r = RegCloseKey (hkSubKey);
5822 if (r != ERROR_SUCCESS)
5823 WARN ("RegCloseKey returned %i\n", r);
5827 if (HeapFree (hHeap, 0, lpValueName) == 0)
5829 ret = GetLastError ();
5830 ERR ("HeapFree failed with code %i\n", ret);
5831 r = RegCloseKey (hkSubKey);
5832 if (r != ERROR_SUCCESS)
5833 WARN ("RegCloseKey returned %i\n", r);
5837 ret = RegCloseKey (hkSubKey);
5838 if (ret != ERROR_SUCCESS)
5840 ERR ("RegCloseKey returned %i\n", ret);
5844 return ERROR_SUCCESS;
5847 /*******************************************************************************
5848 * EnumPrinterDataExA [WINSPOOL.@]
5850 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5851 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5852 * what Windows 2000 SP1 does.
5855 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5856 LPBYTE pEnumValues, DWORD cbEnumValues,
5857 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5861 DWORD ret, dwIndex, dwBufSize;
5865 TRACE ("%p %s\n", hPrinter, pKeyName);
5867 if (pKeyName == NULL || *pKeyName == 0)
5868 return ERROR_INVALID_PARAMETER;
5870 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5873 ret = GetLastError ();
5874 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5878 hHeap = GetProcessHeap ();
5881 ERR ("GetProcessHeap failed\n");
5882 return ERROR_OUTOFMEMORY;
5885 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5886 if (pKeyNameW == NULL)
5888 ERR ("Failed to allocate %i bytes from process heap\n",
5889 (LONG)(len * sizeof (WCHAR)));
5890 return ERROR_OUTOFMEMORY;
5893 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5895 ret = GetLastError ();
5896 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5897 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5898 WARN ("HeapFree failed with code %i\n", GetLastError ());
5902 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5903 pcbEnumValues, pnEnumValues);
5904 if (ret != ERROR_SUCCESS)
5906 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5907 WARN ("HeapFree failed with code %i\n", GetLastError ());
5908 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5912 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5914 ret = GetLastError ();
5915 ERR ("HeapFree failed with code %i\n", ret);
5919 if (*pnEnumValues == 0) /* empty key */
5920 return ERROR_SUCCESS;
5923 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5925 PPRINTER_ENUM_VALUESW ppev =
5926 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5928 if (dwBufSize < ppev->cbValueName)
5929 dwBufSize = ppev->cbValueName;
5931 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5932 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5933 dwBufSize = ppev->cbData;
5936 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5938 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5939 if (pBuffer == NULL)
5941 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5942 return ERROR_OUTOFMEMORY;
5945 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5947 PPRINTER_ENUM_VALUESW ppev =
5948 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5950 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5951 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5955 ret = GetLastError ();
5956 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5957 if (HeapFree (hHeap, 0, pBuffer) == 0)
5958 WARN ("HeapFree failed with code %i\n", GetLastError ());
5962 memcpy (ppev->pValueName, pBuffer, len);
5964 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5966 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5967 ppev->dwType != REG_MULTI_SZ)
5970 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5971 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5974 ret = GetLastError ();
5975 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5976 if (HeapFree (hHeap, 0, pBuffer) == 0)
5977 WARN ("HeapFree failed with code %i\n", GetLastError ());
5981 memcpy (ppev->pData, pBuffer, len);
5983 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5984 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5987 if (HeapFree (hHeap, 0, pBuffer) == 0)
5989 ret = GetLastError ();
5990 ERR ("HeapFree failed with code %i\n", ret);
5994 return ERROR_SUCCESS;
5997 /******************************************************************************
5998 * AbortPrinter (WINSPOOL.@)
6000 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6002 FIXME("(%p), stub!\n", hPrinter);
6006 /******************************************************************************
6007 * AddPortA (WINSPOOL.@)
6012 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6014 LPWSTR nameW = NULL;
6015 LPWSTR monitorW = NULL;
6019 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6022 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6023 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6024 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6028 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6029 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6030 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6032 res = AddPortW(nameW, hWnd, monitorW);
6033 HeapFree(GetProcessHeap(), 0, nameW);
6034 HeapFree(GetProcessHeap(), 0, monitorW);
6038 /******************************************************************************
6039 * AddPortW (WINSPOOL.@)
6041 * Add a Port for a specific Monitor
6044 * pName [I] Servername or NULL (local Computer)
6045 * hWnd [I] Handle to parent Window for the Dialog-Box
6046 * pMonitorName [I] Name of the Monitor that manage the Port
6053 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6055 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6057 if ((backend == NULL) && !load_backend()) return FALSE;
6059 if (!pMonitorName) {
6060 SetLastError(RPC_X_NULL_REF_POINTER);
6064 return backend->fpAddPort(pName, hWnd, pMonitorName);
6067 /******************************************************************************
6068 * AddPortExA (WINSPOOL.@)
6073 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6076 PORT_INFO_2A * pi2A;
6077 LPWSTR nameW = NULL;
6078 LPWSTR monitorW = NULL;
6082 pi2A = (PORT_INFO_2A *) pBuffer;
6084 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6085 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6087 if ((level < 1) || (level > 2)) {
6088 SetLastError(ERROR_INVALID_LEVEL);
6093 SetLastError(ERROR_INVALID_PARAMETER);
6098 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6099 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6100 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6104 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6105 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6106 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6109 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6111 if (pi2A->pPortName) {
6112 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6113 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6114 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6118 if (pi2A->pMonitorName) {
6119 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6120 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6121 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6124 if (pi2A->pDescription) {
6125 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6126 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6127 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6129 pi2W.fPortType = pi2A->fPortType;
6130 pi2W.Reserved = pi2A->Reserved;
6133 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6135 HeapFree(GetProcessHeap(), 0, nameW);
6136 HeapFree(GetProcessHeap(), 0, monitorW);
6137 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6138 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6139 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6144 /******************************************************************************
6145 * AddPortExW (WINSPOOL.@)
6147 * Add a Port for a specific Monitor, without presenting a user interface
6150 * pName [I] Servername or NULL (local Computer)
6151 * level [I] Structure-Level (1 or 2) for pBuffer
6152 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6153 * pMonitorName [I] Name of the Monitor that manage the Port
6160 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6164 pi2 = (PORT_INFO_2W *) pBuffer;
6166 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6167 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6168 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6169 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6171 if ((backend == NULL) && !load_backend()) return FALSE;
6173 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6174 SetLastError(ERROR_INVALID_PARAMETER);
6178 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6181 /******************************************************************************
6182 * AddPrinterConnectionA (WINSPOOL.@)
6184 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6186 FIXME("%s\n", debugstr_a(pName));
6190 /******************************************************************************
6191 * AddPrinterConnectionW (WINSPOOL.@)
6193 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6195 FIXME("%s\n", debugstr_w(pName));
6199 /******************************************************************************
6200 * AddPrinterDriverExW (WINSPOOL.@)
6202 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6205 * pName [I] Servername or NULL (local Computer)
6206 * level [I] Level for the supplied DRIVER_INFO_*W struct
6207 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6208 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6215 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6217 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6219 if ((backend == NULL) && !load_backend()) return FALSE;
6221 if (level < 2 || level == 5 || level == 7 || level > 8) {
6222 SetLastError(ERROR_INVALID_LEVEL);
6227 SetLastError(ERROR_INVALID_PARAMETER);
6231 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6234 /******************************************************************************
6235 * AddPrinterDriverExA (WINSPOOL.@)
6237 * See AddPrinterDriverExW.
6240 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6242 DRIVER_INFO_8A *diA;
6244 LPWSTR nameW = NULL;
6249 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6251 diA = (DRIVER_INFO_8A *) pDriverInfo;
6252 ZeroMemory(&diW, sizeof(diW));
6254 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6255 SetLastError(ERROR_INVALID_LEVEL);
6260 SetLastError(ERROR_INVALID_PARAMETER);
6264 /* convert servername to unicode */
6266 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6267 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6268 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6272 diW.cVersion = diA->cVersion;
6275 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6276 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6277 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6280 if (diA->pEnvironment) {
6281 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6282 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6283 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6286 if (diA->pDriverPath) {
6287 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6288 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6289 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6292 if (diA->pDataFile) {
6293 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6294 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6295 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6298 if (diA->pConfigFile) {
6299 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6300 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6301 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6304 if ((Level > 2) && diA->pDependentFiles) {
6305 lenA = multi_sz_lenA(diA->pDependentFiles);
6306 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6307 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6308 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6311 if ((Level > 2) && diA->pMonitorName) {
6312 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6313 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6314 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6317 if ((Level > 3) && diA->pDefaultDataType) {
6318 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6319 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6320 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6323 if ((Level > 3) && diA->pszzPreviousNames) {
6324 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6325 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6326 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6327 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6330 if ((Level > 5) && diA->pszMfgName) {
6331 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6332 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6333 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6336 if ((Level > 5) && diA->pszOEMUrl) {
6337 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6338 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6339 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6342 if ((Level > 5) && diA->pszHardwareID) {
6343 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6344 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6345 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6348 if ((Level > 5) && diA->pszProvider) {
6349 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6350 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6351 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6355 FIXME("level %u is incomplete\n", Level);
6358 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6359 TRACE("got %u with %u\n", res, GetLastError());
6360 HeapFree(GetProcessHeap(), 0, nameW);
6361 HeapFree(GetProcessHeap(), 0, diW.pName);
6362 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6363 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6364 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6365 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6366 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6367 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6368 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6369 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6370 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6371 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6372 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6373 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6375 TRACE("=> %u with %u\n", res, GetLastError());
6379 /******************************************************************************
6380 * ConfigurePortA (WINSPOOL.@)
6382 * See ConfigurePortW.
6385 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6387 LPWSTR nameW = NULL;
6388 LPWSTR portW = NULL;
6392 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6394 /* convert servername to unicode */
6396 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6397 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6398 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6401 /* convert portname to unicode */
6403 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6404 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6405 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6408 res = ConfigurePortW(nameW, hWnd, portW);
6409 HeapFree(GetProcessHeap(), 0, nameW);
6410 HeapFree(GetProcessHeap(), 0, portW);
6414 /******************************************************************************
6415 * ConfigurePortW (WINSPOOL.@)
6417 * Display the Configuration-Dialog for a specific Port
6420 * pName [I] Servername or NULL (local Computer)
6421 * hWnd [I] Handle to parent Window for the Dialog-Box
6422 * pPortName [I] Name of the Port, that should be configured
6429 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6432 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6434 if ((backend == NULL) && !load_backend()) return FALSE;
6437 SetLastError(RPC_X_NULL_REF_POINTER);
6441 return backend->fpConfigurePort(pName, hWnd, pPortName);
6444 /******************************************************************************
6445 * ConnectToPrinterDlg (WINSPOOL.@)
6447 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6449 FIXME("%p %x\n", hWnd, Flags);
6453 /******************************************************************************
6454 * DeletePrinterConnectionA (WINSPOOL.@)
6456 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6458 FIXME("%s\n", debugstr_a(pName));
6462 /******************************************************************************
6463 * DeletePrinterConnectionW (WINSPOOL.@)
6465 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6467 FIXME("%s\n", debugstr_w(pName));
6471 /******************************************************************************
6472 * DeletePrinterDriverExW (WINSPOOL.@)
6474 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6475 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6480 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6481 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6483 if(pName && pName[0])
6485 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6486 SetLastError(ERROR_INVALID_PARAMETER);
6492 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6493 SetLastError(ERROR_INVALID_PARAMETER);
6497 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6501 ERR("Can't open drivers key\n");
6505 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6508 RegCloseKey(hkey_drivers);
6513 /******************************************************************************
6514 * DeletePrinterDriverExA (WINSPOOL.@)
6516 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6517 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6519 UNICODE_STRING NameW, EnvW, DriverW;
6522 asciitounicode(&NameW, pName);
6523 asciitounicode(&EnvW, pEnvironment);
6524 asciitounicode(&DriverW, pDriverName);
6526 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6528 RtlFreeUnicodeString(&DriverW);
6529 RtlFreeUnicodeString(&EnvW);
6530 RtlFreeUnicodeString(&NameW);
6535 /******************************************************************************
6536 * DeletePrinterDataExW (WINSPOOL.@)
6538 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6541 FIXME("%p %s %s\n", hPrinter,
6542 debugstr_w(pKeyName), debugstr_w(pValueName));
6543 return ERROR_INVALID_PARAMETER;
6546 /******************************************************************************
6547 * DeletePrinterDataExA (WINSPOOL.@)
6549 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6552 FIXME("%p %s %s\n", hPrinter,
6553 debugstr_a(pKeyName), debugstr_a(pValueName));
6554 return ERROR_INVALID_PARAMETER;
6557 /******************************************************************************
6558 * DeletePrintProcessorA (WINSPOOL.@)
6560 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6562 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6563 debugstr_a(pPrintProcessorName));
6567 /******************************************************************************
6568 * DeletePrintProcessorW (WINSPOOL.@)
6570 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6572 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6573 debugstr_w(pPrintProcessorName));
6577 /******************************************************************************
6578 * DeletePrintProvidorA (WINSPOOL.@)
6580 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6582 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6583 debugstr_a(pPrintProviderName));
6587 /******************************************************************************
6588 * DeletePrintProvidorW (WINSPOOL.@)
6590 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6592 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6593 debugstr_w(pPrintProviderName));
6597 /******************************************************************************
6598 * EnumFormsA (WINSPOOL.@)
6600 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6601 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6603 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6604 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6608 /******************************************************************************
6609 * EnumFormsW (WINSPOOL.@)
6611 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6612 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6614 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6615 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6619 /*****************************************************************************
6620 * EnumMonitorsA [WINSPOOL.@]
6622 * See EnumMonitorsW.
6625 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6626 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6629 LPBYTE bufferW = NULL;
6630 LPWSTR nameW = NULL;
6632 DWORD numentries = 0;
6635 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6636 cbBuf, pcbNeeded, pcReturned);
6638 /* convert servername to unicode */
6640 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6641 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6642 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6644 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6645 needed = cbBuf * sizeof(WCHAR);
6646 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6647 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6649 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6650 if (pcbNeeded) needed = *pcbNeeded;
6651 /* HeapReAlloc return NULL, when bufferW was NULL */
6652 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6653 HeapAlloc(GetProcessHeap(), 0, needed);
6655 /* Try again with the large Buffer */
6656 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6658 numentries = pcReturned ? *pcReturned : 0;
6661 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6662 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6665 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6666 DWORD entrysize = 0;
6669 LPMONITOR_INFO_2W mi2w;
6670 LPMONITOR_INFO_2A mi2a;
6672 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6673 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6675 /* First pass: calculate the size for all Entries */
6676 mi2w = (LPMONITOR_INFO_2W) bufferW;
6677 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6679 while (index < numentries) {
6681 needed += entrysize; /* MONITOR_INFO_?A */
6682 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6684 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6685 NULL, 0, NULL, NULL);
6687 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6688 NULL, 0, NULL, NULL);
6689 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6690 NULL, 0, NULL, NULL);
6692 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6693 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6694 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6697 /* check for errors and quit on failure */
6698 if (cbBuf < needed) {
6699 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6703 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6704 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6705 cbBuf -= len ; /* free Bytes in the user-Buffer */
6706 mi2w = (LPMONITOR_INFO_2W) bufferW;
6707 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6709 /* Second Pass: Fill the User Buffer (if we have one) */
6710 while ((index < numentries) && pMonitors) {
6712 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6714 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6715 ptr, cbBuf , NULL, NULL);
6719 mi2a->pEnvironment = ptr;
6720 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6721 ptr, cbBuf, NULL, NULL);
6725 mi2a->pDLLName = ptr;
6726 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6727 ptr, cbBuf, NULL, NULL);
6731 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6732 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6733 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6737 if (pcbNeeded) *pcbNeeded = needed;
6738 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6740 HeapFree(GetProcessHeap(), 0, nameW);
6741 HeapFree(GetProcessHeap(), 0, bufferW);
6743 TRACE("returning %d with %d (%d byte for %d entries)\n",
6744 (res), GetLastError(), needed, numentries);
6750 /*****************************************************************************
6751 * EnumMonitorsW [WINSPOOL.@]
6753 * Enumerate available Port-Monitors
6756 * pName [I] Servername or NULL (local Computer)
6757 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6758 * pMonitors [O] PTR to Buffer that receives the Result
6759 * cbBuf [I] Size of Buffer at pMonitors
6760 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6761 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6765 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6768 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6769 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6772 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6773 cbBuf, pcbNeeded, pcReturned);
6775 if ((backend == NULL) && !load_backend()) return FALSE;
6777 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6778 SetLastError(RPC_X_NULL_REF_POINTER);
6782 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6785 /******************************************************************************
6786 * SpoolerInit (WINSPOOL.@)
6788 * Initialize the Spooler
6795 * The function fails on windows, when the spooler service is not running
6798 BOOL WINAPI SpoolerInit(void)
6801 if ((backend == NULL) && !load_backend()) return FALSE;
6805 /******************************************************************************
6806 * XcvDataW (WINSPOOL.@)
6808 * Execute commands in the Printmonitor DLL
6811 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6812 * pszDataName [i] Name of the command to execute
6813 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6814 * cbInputData [i] Size in Bytes of Buffer at pInputData
6815 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6816 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6817 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6818 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6825 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6826 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6828 * Minimal List of commands, that a Printmonitor DLL should support:
6830 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6831 *| "AddPort" : Add a Port
6832 *| "DeletePort": Delete a Port
6834 * Many Printmonitors support additional commands. Examples for localspl.dll:
6835 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6836 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6839 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6840 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6841 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6843 opened_printer_t *printer;
6845 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6846 pInputData, cbInputData, pOutputData,
6847 cbOutputData, pcbOutputNeeded, pdwStatus);
6849 if ((backend == NULL) && !load_backend()) return FALSE;
6851 printer = get_opened_printer(hXcv);
6852 if (!printer || (!printer->backend_printer)) {
6853 SetLastError(ERROR_INVALID_HANDLE);
6857 if (!pcbOutputNeeded) {
6858 SetLastError(ERROR_INVALID_PARAMETER);
6862 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6863 SetLastError(RPC_X_NULL_REF_POINTER);
6867 *pcbOutputNeeded = 0;
6869 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6870 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6874 /*****************************************************************************
6875 * EnumPrinterDataA [WINSPOOL.@]
6878 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6879 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6880 DWORD cbData, LPDWORD pcbData )
6882 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6883 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6884 return ERROR_NO_MORE_ITEMS;
6887 /*****************************************************************************
6888 * EnumPrinterDataW [WINSPOOL.@]
6891 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6892 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6893 DWORD cbData, LPDWORD pcbData )
6895 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6896 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6897 return ERROR_NO_MORE_ITEMS;
6900 /*****************************************************************************
6901 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6904 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6905 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6906 LPDWORD pcbNeeded, LPDWORD pcReturned)
6908 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6909 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6910 pcbNeeded, pcReturned);
6914 /*****************************************************************************
6915 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6918 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6919 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6920 LPDWORD pcbNeeded, LPDWORD pcReturned)
6922 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6923 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6924 pcbNeeded, pcReturned);
6928 /*****************************************************************************
6929 * EnumPrintProcessorsA [WINSPOOL.@]
6931 * See EnumPrintProcessorsW.
6934 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6935 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6938 LPBYTE bufferW = NULL;
6939 LPWSTR nameW = NULL;
6942 DWORD numentries = 0;
6945 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6946 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6948 /* convert names to unicode */
6950 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6951 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6952 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6955 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6956 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6957 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6960 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6961 needed = cbBuf * sizeof(WCHAR);
6962 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6963 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6965 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6966 if (pcbNeeded) needed = *pcbNeeded;
6967 /* HeapReAlloc return NULL, when bufferW was NULL */
6968 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6969 HeapAlloc(GetProcessHeap(), 0, needed);
6971 /* Try again with the large Buffer */
6972 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6974 numentries = pcReturned ? *pcReturned : 0;
6978 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6981 PPRINTPROCESSOR_INFO_1W ppiw;
6982 PPRINTPROCESSOR_INFO_1A ppia;
6984 /* First pass: calculate the size for all Entries */
6985 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6986 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6988 while (index < numentries) {
6990 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6991 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6993 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6994 NULL, 0, NULL, NULL);
6996 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6997 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7000 /* check for errors and quit on failure */
7001 if (cbBuf < needed) {
7002 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7007 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7008 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7009 cbBuf -= len ; /* free Bytes in the user-Buffer */
7010 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7011 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7013 /* Second Pass: Fill the User Buffer (if we have one) */
7014 while ((index < numentries) && pPPInfo) {
7016 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7018 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7019 ptr, cbBuf , NULL, NULL);
7023 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7024 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7029 if (pcbNeeded) *pcbNeeded = needed;
7030 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7032 HeapFree(GetProcessHeap(), 0, nameW);
7033 HeapFree(GetProcessHeap(), 0, envW);
7034 HeapFree(GetProcessHeap(), 0, bufferW);
7036 TRACE("returning %d with %d (%d byte for %d entries)\n",
7037 (res), GetLastError(), needed, numentries);
7042 /*****************************************************************************
7043 * EnumPrintProcessorsW [WINSPOOL.@]
7045 * Enumerate available Print Processors
7048 * pName [I] Servername or NULL (local Computer)
7049 * pEnvironment [I] Printing-Environment or NULL (Default)
7050 * Level [I] Structure-Level (Only 1 is allowed)
7051 * pPPInfo [O] PTR to Buffer that receives the Result
7052 * cbBuf [I] Size of Buffer at pPPInfo
7053 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7054 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7058 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7061 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7062 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7065 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7066 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7068 if ((backend == NULL) && !load_backend()) return FALSE;
7070 if (!pcbNeeded || !pcReturned) {
7071 SetLastError(RPC_X_NULL_REF_POINTER);
7075 if (!pPPInfo && (cbBuf > 0)) {
7076 SetLastError(ERROR_INVALID_USER_BUFFER);
7080 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7081 cbBuf, pcbNeeded, pcReturned);
7084 /*****************************************************************************
7085 * ExtDeviceMode [WINSPOOL.@]
7088 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7089 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7092 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7093 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7094 debugstr_a(pProfile), fMode);
7098 /*****************************************************************************
7099 * FindClosePrinterChangeNotification [WINSPOOL.@]
7102 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7104 FIXME("Stub: %p\n", hChange);
7108 /*****************************************************************************
7109 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7112 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7113 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7115 FIXME("Stub: %p %x %x %p\n",
7116 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7117 return INVALID_HANDLE_VALUE;
7120 /*****************************************************************************
7121 * FindNextPrinterChangeNotification [WINSPOOL.@]
7124 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7125 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7127 FIXME("Stub: %p %p %p %p\n",
7128 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7132 /*****************************************************************************
7133 * FreePrinterNotifyInfo [WINSPOOL.@]
7136 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7138 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7142 /*****************************************************************************
7145 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7146 * ansi depending on the unicode parameter.
7148 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7158 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7161 memcpy(ptr, str, *size);
7168 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7171 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7178 /*****************************************************************************
7181 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7182 LPDWORD pcbNeeded, BOOL unicode)
7184 DWORD size, left = cbBuf;
7185 BOOL space = (cbBuf > 0);
7192 ji1->JobId = job->job_id;
7195 string_to_buf(job->document_title, ptr, left, &size, unicode);
7196 if(space && size <= left)
7198 ji1->pDocument = (LPWSTR)ptr;
7206 if (job->printer_name)
7208 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7209 if(space && size <= left)
7211 ji1->pPrinterName = (LPWSTR)ptr;
7223 /*****************************************************************************
7226 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7227 LPDWORD pcbNeeded, BOOL unicode)
7229 DWORD size, left = cbBuf;
7231 BOOL space = (cbBuf > 0);
7233 LPDEVMODEA dmA = NULL;
7240 ji2->JobId = job->job_id;
7243 string_to_buf(job->document_title, ptr, left, &size, unicode);
7244 if(space && size <= left)
7246 ji2->pDocument = (LPWSTR)ptr;
7254 if (job->printer_name)
7256 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7257 if(space && size <= left)
7259 ji2->pPrinterName = (LPWSTR)ptr;
7272 dmA = DEVMODEdupWtoA(job->devmode);
7273 devmode = (LPDEVMODEW) dmA;
7274 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7278 devmode = job->devmode;
7279 size = devmode->dmSize + devmode->dmDriverExtra;
7283 FIXME("Can't convert DEVMODE W to A\n");
7286 /* align DEVMODE to a DWORD boundary */
7287 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7293 memcpy(ptr, devmode, size-shift);
7294 ji2->pDevMode = (LPDEVMODEW)ptr;
7295 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7308 /*****************************************************************************
7311 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7312 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7315 DWORD needed = 0, size;
7319 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7321 EnterCriticalSection(&printer_handles_cs);
7322 job = get_job(hPrinter, JobId);
7329 size = sizeof(JOB_INFO_1W);
7334 memset(pJob, 0, size);
7338 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7343 size = sizeof(JOB_INFO_2W);
7348 memset(pJob, 0, size);
7352 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7357 size = sizeof(JOB_INFO_3);
7361 memset(pJob, 0, size);
7370 SetLastError(ERROR_INVALID_LEVEL);
7374 *pcbNeeded = needed;
7376 LeaveCriticalSection(&printer_handles_cs);
7380 /*****************************************************************************
7381 * GetJobA [WINSPOOL.@]
7384 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7385 DWORD cbBuf, LPDWORD pcbNeeded)
7387 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7390 /*****************************************************************************
7391 * GetJobW [WINSPOOL.@]
7394 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7395 DWORD cbBuf, LPDWORD pcbNeeded)
7397 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7400 /*****************************************************************************
7403 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7406 char *unixname, *cmdA;
7408 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7412 if(!(unixname = wine_get_unix_file_name(filename)))
7415 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7416 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7417 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7419 TRACE("printing with: %s\n", cmdA);
7421 if((file_fd = open(unixname, O_RDONLY)) == -1)
7426 ERR("pipe() failed!\n");
7436 /* reset signals that we previously set to SIG_IGN */
7437 signal(SIGPIPE, SIG_DFL);
7438 signal(SIGCHLD, SIG_DFL);
7440 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7444 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7445 write(fds[1], buf, no_read);
7450 if(file_fd != -1) close(file_fd);
7451 if(fds[0] != -1) close(fds[0]);
7452 if(fds[1] != -1) close(fds[1]);
7454 HeapFree(GetProcessHeap(), 0, cmdA);
7455 HeapFree(GetProcessHeap(), 0, unixname);
7462 /*****************************************************************************
7465 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7468 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7471 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7472 sprintfW(cmd, fmtW, printer_name);
7474 r = schedule_pipe(cmd, filename);
7476 HeapFree(GetProcessHeap(), 0, cmd);
7480 /*****************************************************************************
7483 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7485 #ifdef SONAME_LIBCUPS
7488 char *unixname, *queue, *unix_doc_title;
7492 if(!(unixname = wine_get_unix_file_name(filename)))
7495 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7496 queue = HeapAlloc(GetProcessHeap(), 0, len);
7497 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7499 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7500 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7501 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7503 TRACE("printing via cups\n");
7504 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7505 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7506 HeapFree(GetProcessHeap(), 0, queue);
7507 HeapFree(GetProcessHeap(), 0, unixname);
7513 return schedule_lpr(printer_name, filename);
7517 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7524 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7528 if(HIWORD(wparam) == BN_CLICKED)
7530 if(LOWORD(wparam) == IDOK)
7533 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7536 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7537 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7539 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7541 WCHAR caption[200], message[200];
7544 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7545 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7546 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7547 if(mb_ret == IDCANCEL)
7549 HeapFree(GetProcessHeap(), 0, filename);
7553 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7554 if(hf == INVALID_HANDLE_VALUE)
7556 WCHAR caption[200], message[200];
7558 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7559 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7560 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7561 HeapFree(GetProcessHeap(), 0, filename);
7565 DeleteFileW(filename);
7566 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7568 EndDialog(hwnd, IDOK);
7571 if(LOWORD(wparam) == IDCANCEL)
7573 EndDialog(hwnd, IDCANCEL);
7582 /*****************************************************************************
7585 static BOOL get_filename(LPWSTR *filename)
7587 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7588 file_dlg_proc, (LPARAM)filename) == IDOK;
7591 /*****************************************************************************
7594 static BOOL schedule_file(LPCWSTR filename)
7596 LPWSTR output = NULL;
7598 if(get_filename(&output))
7601 TRACE("copy to %s\n", debugstr_w(output));
7602 r = CopyFileW(filename, output, FALSE);
7603 HeapFree(GetProcessHeap(), 0, output);
7609 /*****************************************************************************
7612 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7614 int in_fd, out_fd, no_read;
7617 char *unixname, *outputA;
7620 if(!(unixname = wine_get_unix_file_name(filename)))
7623 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7624 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7625 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7627 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7628 in_fd = open(unixname, O_RDONLY);
7629 if(out_fd == -1 || in_fd == -1)
7632 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7633 write(out_fd, buf, no_read);
7637 if(in_fd != -1) close(in_fd);
7638 if(out_fd != -1) close(out_fd);
7639 HeapFree(GetProcessHeap(), 0, outputA);
7640 HeapFree(GetProcessHeap(), 0, unixname);
7644 /*****************************************************************************
7645 * ScheduleJob [WINSPOOL.@]
7648 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7650 opened_printer_t *printer;
7652 struct list *cursor, *cursor2;
7654 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7655 EnterCriticalSection(&printer_handles_cs);
7656 printer = get_opened_printer(hPrinter);
7660 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7662 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7665 if(job->job_id != dwJobID) continue;
7667 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7668 if(hf != INVALID_HANDLE_VALUE)
7670 PRINTER_INFO_5W *pi5 = NULL;
7671 LPWSTR portname = job->portname;
7675 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7676 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7680 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7681 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7682 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7683 portname = pi5->pPortName;
7685 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7686 debugstr_w(portname));
7690 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7691 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7693 DWORD type, count = sizeof(output);
7694 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7697 if(output[0] == '|')
7699 ret = schedule_pipe(output + 1, job->filename);
7703 ret = schedule_unixfile(output, job->filename);
7705 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7707 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7709 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7711 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7713 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7715 ret = schedule_file(job->filename);
7719 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7721 HeapFree(GetProcessHeap(), 0, pi5);
7723 DeleteFileW(job->filename);
7725 list_remove(cursor);
7726 HeapFree(GetProcessHeap(), 0, job->document_title);
7727 HeapFree(GetProcessHeap(), 0, job->printer_name);
7728 HeapFree(GetProcessHeap(), 0, job->portname);
7729 HeapFree(GetProcessHeap(), 0, job->filename);
7730 HeapFree(GetProcessHeap(), 0, job->devmode);
7731 HeapFree(GetProcessHeap(), 0, job);
7735 LeaveCriticalSection(&printer_handles_cs);
7739 /*****************************************************************************
7740 * StartDocDlgA [WINSPOOL.@]
7742 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7744 UNICODE_STRING usBuffer;
7747 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7750 docW.cbSize = sizeof(docW);
7751 if (doc->lpszDocName)
7753 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7754 if (!(docW.lpszDocName = docnameW)) return NULL;
7756 if (doc->lpszOutput)
7758 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7759 if (!(docW.lpszOutput = outputW)) return NULL;
7761 if (doc->lpszDatatype)
7763 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7764 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7766 docW.fwType = doc->fwType;
7768 retW = StartDocDlgW(hPrinter, &docW);
7772 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7773 ret = HeapAlloc(GetProcessHeap(), 0, len);
7774 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7775 HeapFree(GetProcessHeap(), 0, retW);
7778 HeapFree(GetProcessHeap(), 0, datatypeW);
7779 HeapFree(GetProcessHeap(), 0, outputW);
7780 HeapFree(GetProcessHeap(), 0, docnameW);
7785 /*****************************************************************************
7786 * StartDocDlgW [WINSPOOL.@]
7788 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7789 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7790 * port is "FILE:". Also returns the full path if passed a relative path.
7792 * The caller should free the returned string from the process heap.
7794 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7799 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7801 PRINTER_INFO_5W *pi5;
7802 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7803 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7805 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7806 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7807 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7809 HeapFree(GetProcessHeap(), 0, pi5);
7812 HeapFree(GetProcessHeap(), 0, pi5);
7815 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7819 if (get_filename(&name))
7821 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7823 HeapFree(GetProcessHeap(), 0, name);
7826 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7827 GetFullPathNameW(name, len, ret, NULL);
7828 HeapFree(GetProcessHeap(), 0, name);
7833 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7836 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7837 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7839 attr = GetFileAttributesW(ret);
7840 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7842 HeapFree(GetProcessHeap(), 0, ret);