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;
519 char *e,*s,*name,*prettyname,*devname;
520 BOOL ret = FALSE, set_default = FALSE;
521 char *port = NULL, *env_default;
522 HKEY hkeyPrinter, hkeyPrinters;
523 WCHAR devnameW[MAX_PATH];
525 while (isspace(*pent)) pent++;
526 s = strchr(pent,':');
528 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
536 TRACE("name=%s entry=%s\n",name, pent);
538 if(ispunct(*name)) { /* a tc entry, not a real printer */
539 TRACE("skipping tc entry\n");
543 if(strstr(pent,":server")) { /* server only version so skip */
544 TRACE("skipping server entry\n");
548 /* Determine whether this is a postscript printer. */
551 env_default = getenv("PRINTER");
553 /* Get longest name, usually the one at the right for later display. */
554 while((s=strchr(prettyname,'|'))) {
557 while(isspace(*--e)) *e = '\0';
558 TRACE("\t%s\n", debugstr_a(prettyname));
559 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
560 for(prettyname = s+1; isspace(*prettyname); prettyname++)
563 e = prettyname + strlen(prettyname);
564 while(isspace(*--e)) *e = '\0';
565 TRACE("\t%s\n", debugstr_a(prettyname));
566 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
568 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
569 * if it is too long, we use it as comment below. */
570 devname = prettyname;
571 if (strlen(devname)>=CCHDEVICENAME-1)
573 if (strlen(devname)>=CCHDEVICENAME-1) {
578 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
579 sprintf(port,"LPR:%s",name);
581 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
583 ERR("Can't create Printers key\n");
588 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
590 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
591 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
593 TRACE("Printer already exists\n");
594 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
595 RegCloseKey(hkeyPrinter);
597 static CHAR data_type[] = "RAW",
598 print_proc[] = "WinPrint",
599 comment[] = "WINEPS Printer using LPR",
600 params[] = "<parameters?>",
601 share_name[] = "<share name?>",
602 sep_file[] = "<sep file?>";
604 add_printer_driver(devnameW);
606 memset(&pinfo2a,0,sizeof(pinfo2a));
607 pinfo2a.pPrinterName = devname;
608 pinfo2a.pDatatype = data_type;
609 pinfo2a.pPrintProcessor = print_proc;
610 pinfo2a.pDriverName = devname;
611 pinfo2a.pComment = comment;
612 pinfo2a.pLocation = prettyname;
613 pinfo2a.pPortName = port;
614 pinfo2a.pParameters = params;
615 pinfo2a.pShareName = share_name;
616 pinfo2a.pSepFile = sep_file;
618 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
619 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
620 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
623 RegCloseKey(hkeyPrinters);
625 if (isfirst || set_default)
626 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
629 HeapFree(GetProcessHeap(), 0, port);
630 HeapFree(GetProcessHeap(), 0, name);
635 PRINTCAP_LoadPrinters(void) {
636 BOOL hadprinter = FALSE;
640 BOOL had_bash = FALSE;
642 f = fopen("/etc/printcap","r");
646 while(fgets(buf,sizeof(buf),f)) {
649 end=strchr(buf,'\n');
653 while(isspace(*start)) start++;
654 if(*start == '#' || *start == '\0')
657 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
658 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
659 HeapFree(GetProcessHeap(),0,pent);
663 if (end && *--end == '\\') {
670 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
673 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
679 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
680 HeapFree(GetProcessHeap(),0,pent);
686 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
689 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
690 (lstrlenW(value) + 1) * sizeof(WCHAR));
692 return ERROR_FILE_NOT_FOUND;
695 /******************************************************************
696 * get_servername_from_name (internal)
698 * for an external server, a copy of the serverpart from the full name is returned
701 static LPWSTR get_servername_from_name(LPCWSTR name)
705 WCHAR buffer[MAX_PATH];
708 if (name == NULL) return NULL;
709 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
711 server = strdupW(&name[2]); /* skip over both backslash */
712 if (server == NULL) return NULL;
714 /* strip '\' and the printername */
715 ptr = strchrW(server, '\\');
716 if (ptr) ptr[0] = '\0';
718 TRACE("found %s\n", debugstr_w(server));
720 len = sizeof(buffer)/sizeof(buffer[0]);
721 if (GetComputerNameW(buffer, &len)) {
722 if (lstrcmpW(buffer, server) == 0) {
723 /* The requested Servername is our computername */
724 HeapFree(GetProcessHeap(), 0, server);
731 /******************************************************************
732 * get_basename_from_name (internal)
734 * skip over the serverpart from the full name
737 static LPCWSTR get_basename_from_name(LPCWSTR name)
739 if (name == NULL) return NULL;
740 if ((name[0] == '\\') && (name[1] == '\\')) {
741 /* skip over the servername and search for the following '\' */
742 name = strchrW(&name[2], '\\');
743 if ((name) && (name[1])) {
744 /* found a separator ('\') followed by a name:
745 skip over the separator and return the rest */
750 /* no basename present (we found only a servername) */
757 /******************************************************************
758 * get_opened_printer_entry
759 * Get the first place empty in the opened printer table
762 * - pDefault is ignored
764 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
766 UINT_PTR handle = nb_printer_handles, i;
767 jobqueue_t *queue = NULL;
768 opened_printer_t *printer = NULL;
772 if ((backend == NULL) && !load_backend()) return NULL;
774 servername = get_servername_from_name(name);
776 FIXME("server %s not supported\n", debugstr_w(servername));
777 HeapFree(GetProcessHeap(), 0, servername);
778 SetLastError(ERROR_INVALID_PRINTER_NAME);
782 printername = get_basename_from_name(name);
783 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
785 /* an empty printername is invalid */
786 if (printername && (!printername[0])) {
787 SetLastError(ERROR_INVALID_PARAMETER);
791 EnterCriticalSection(&printer_handles_cs);
793 for (i = 0; i < nb_printer_handles; i++)
795 if (!printer_handles[i])
797 if(handle == nb_printer_handles)
802 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
803 queue = printer_handles[i]->queue;
807 if (handle >= nb_printer_handles)
809 opened_printer_t **new_array;
811 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
812 (nb_printer_handles + 16) * sizeof(*new_array) );
814 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
815 (nb_printer_handles + 16) * sizeof(*new_array) );
822 printer_handles = new_array;
823 nb_printer_handles += 16;
826 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
832 /* get a printer handle from the backend */
833 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
838 /* clone the base name. This is NULL for the printserver */
839 printer->printername = strdupW(printername);
841 /* clone the full name */
842 printer->name = strdupW(name);
843 if (name && (!printer->name)) {
849 printer->queue = queue;
852 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
853 if (!printer->queue) {
857 list_init(&printer->queue->jobs);
858 printer->queue->ref = 0;
860 InterlockedIncrement(&printer->queue->ref);
862 printer_handles[handle] = printer;
865 LeaveCriticalSection(&printer_handles_cs);
866 if (!handle && printer) {
867 /* Something failed: Free all resources */
868 HeapFree(GetProcessHeap(), 0, printer->printername);
869 HeapFree(GetProcessHeap(), 0, printer->name);
870 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
871 HeapFree(GetProcessHeap(), 0, printer);
874 return (HANDLE)handle;
877 /******************************************************************
879 * Get the pointer to the opened printer referred by the handle
881 static opened_printer_t *get_opened_printer(HANDLE hprn)
883 UINT_PTR idx = (UINT_PTR)hprn;
884 opened_printer_t *ret = NULL;
886 EnterCriticalSection(&printer_handles_cs);
888 if ((idx > 0) && (idx <= nb_printer_handles)) {
889 ret = printer_handles[idx - 1];
891 LeaveCriticalSection(&printer_handles_cs);
895 /******************************************************************
896 * get_opened_printer_name
897 * Get the pointer to the opened printer name referred by the handle
899 static LPCWSTR get_opened_printer_name(HANDLE hprn)
901 opened_printer_t *printer = get_opened_printer(hprn);
902 if(!printer) return NULL;
903 return printer->name;
906 /******************************************************************
907 * WINSPOOL_GetOpenedPrinterRegKey
910 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
912 LPCWSTR name = get_opened_printer_name(hPrinter);
916 if(!name) return ERROR_INVALID_HANDLE;
918 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
922 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
924 ERR("Can't find opened printer %s in registry\n",
926 RegCloseKey(hkeyPrinters);
927 return ERROR_INVALID_PRINTER_NAME; /* ? */
929 RegCloseKey(hkeyPrinters);
930 return ERROR_SUCCESS;
933 void WINSPOOL_LoadSystemPrinters(void)
935 HKEY hkey, hkeyPrinters;
937 DWORD needed, num, i;
938 WCHAR PrinterName[256];
941 /* This ensures that all printer entries have a valid Name value. If causes
942 problems later if they don't. If one is found to be missed we create one
943 and set it equal to the name of the key */
944 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
945 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
946 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
947 for(i = 0; i < num; i++) {
948 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
949 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
950 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
951 set_reg_szW(hkey, NameW, PrinterName);
958 RegCloseKey(hkeyPrinters);
961 /* We want to avoid calling AddPrinter on printers as much as
962 possible, because on cups printers this will (eventually) lead
963 to a call to cupsGetPPD which takes forever, even with non-cups
964 printers AddPrinter takes a while. So we'll tag all printers that
965 were automatically added last time around, if they still exist
966 we'll leave them be otherwise we'll delete them. */
967 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num) && needed) {
968 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
969 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
970 for(i = 0; i < num; i++) {
971 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
972 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
973 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
975 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
983 HeapFree(GetProcessHeap(), 0, pi);
987 #ifdef SONAME_LIBCUPS
988 done = CUPS_LoadPrinters();
991 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
992 PRINTCAP_LoadPrinters();
994 /* Now enumerate the list again and delete any printers that are still tagged */
995 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
997 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
998 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
999 for(i = 0; i < num; i++) {
1000 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1001 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1002 BOOL delete_driver = FALSE;
1003 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1004 DWORD dw, type, size = sizeof(dw);
1005 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1006 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1007 DeletePrinter(hprn);
1008 delete_driver = TRUE;
1014 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1019 HeapFree(GetProcessHeap(), 0, pi);
1026 /******************************************************************
1029 * Get the pointer to the specified job.
1030 * Should hold the printer_handles_cs before calling.
1032 static job_t *get_job(HANDLE hprn, DWORD JobId)
1034 opened_printer_t *printer = get_opened_printer(hprn);
1037 if(!printer) return NULL;
1038 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1040 if(job->job_id == JobId)
1046 /***********************************************************
1049 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1052 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1055 Formname = (dmA->dmSize > off_formname);
1056 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1057 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1058 dmW->dmDeviceName, CCHDEVICENAME);
1060 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1061 dmA->dmSize - CCHDEVICENAME);
1063 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1064 off_formname - CCHDEVICENAME);
1065 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1066 dmW->dmFormName, CCHFORMNAME);
1067 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1068 (off_formname + CCHFORMNAME));
1071 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1072 dmA->dmDriverExtra);
1076 /***********************************************************
1078 * Creates an ansi copy of supplied devmode
1080 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1085 if (!dmW) return NULL;
1086 size = dmW->dmSize - CCHDEVICENAME -
1087 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1089 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1090 if (!dmA) return NULL;
1092 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1093 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1095 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1096 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1097 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1101 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1102 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1103 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1104 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1106 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1110 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1114 /******************************************************************
1115 * convert_printerinfo_W_to_A [internal]
1118 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1119 DWORD level, DWORD outlen, DWORD numentries)
1125 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1127 len = pi_sizeof[level] * numentries;
1128 ptr = (LPSTR) out + len;
1131 /* copy the numbers of all PRINTER_INFO_* first */
1132 memcpy(out, pPrintersW, len);
1134 while (id < numentries) {
1138 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1139 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1141 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1142 if (piW->pDescription) {
1143 piA->pDescription = ptr;
1144 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1145 ptr, outlen, NULL, NULL);
1151 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1152 ptr, outlen, NULL, NULL);
1156 if (piW->pComment) {
1157 piA->pComment = ptr;
1158 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1159 ptr, outlen, NULL, NULL);
1168 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1169 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1172 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1173 if (piW->pServerName) {
1174 piA->pServerName = ptr;
1175 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1176 ptr, outlen, NULL, NULL);
1180 if (piW->pPrinterName) {
1181 piA->pPrinterName = ptr;
1182 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1183 ptr, outlen, NULL, NULL);
1187 if (piW->pShareName) {
1188 piA->pShareName = ptr;
1189 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1190 ptr, outlen, NULL, NULL);
1194 if (piW->pPortName) {
1195 piA->pPortName = ptr;
1196 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1197 ptr, outlen, NULL, NULL);
1201 if (piW->pDriverName) {
1202 piA->pDriverName = ptr;
1203 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1204 ptr, outlen, NULL, NULL);
1208 if (piW->pComment) {
1209 piA->pComment = ptr;
1210 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1211 ptr, outlen, NULL, NULL);
1215 if (piW->pLocation) {
1216 piA->pLocation = ptr;
1217 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1218 ptr, outlen, NULL, NULL);
1223 dmA = DEVMODEdupWtoA(piW->pDevMode);
1225 /* align DEVMODEA to a DWORD boundary */
1226 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1230 piA->pDevMode = (LPDEVMODEA) ptr;
1231 len = dmA->dmSize + dmA->dmDriverExtra;
1232 memcpy(ptr, dmA, len);
1233 HeapFree(GetProcessHeap(), 0, dmA);
1239 if (piW->pSepFile) {
1240 piA->pSepFile = ptr;
1241 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1242 ptr, outlen, NULL, NULL);
1246 if (piW->pPrintProcessor) {
1247 piA->pPrintProcessor = ptr;
1248 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1249 ptr, outlen, NULL, NULL);
1253 if (piW->pDatatype) {
1254 piA->pDatatype = ptr;
1255 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1256 ptr, outlen, NULL, NULL);
1260 if (piW->pParameters) {
1261 piA->pParameters = ptr;
1262 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1263 ptr, outlen, NULL, NULL);
1267 if (piW->pSecurityDescriptor) {
1268 piA->pSecurityDescriptor = NULL;
1269 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1276 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1277 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1279 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1281 if (piW->pPrinterName) {
1282 piA->pPrinterName = ptr;
1283 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1284 ptr, outlen, NULL, NULL);
1288 if (piW->pServerName) {
1289 piA->pServerName = ptr;
1290 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1291 ptr, outlen, NULL, NULL);
1300 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1301 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1303 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1305 if (piW->pPrinterName) {
1306 piA->pPrinterName = ptr;
1307 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1308 ptr, outlen, NULL, NULL);
1312 if (piW->pPortName) {
1313 piA->pPortName = ptr;
1314 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1315 ptr, outlen, NULL, NULL);
1322 case 6: /* 6A and 6W are the same structure */
1327 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1328 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1330 TRACE("(%u) #%u\n", level, id);
1331 if (piW->pszObjectGUID) {
1332 piA->pszObjectGUID = ptr;
1333 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1334 ptr, outlen, NULL, NULL);
1343 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1344 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1347 TRACE("(%u) #%u\n", level, id);
1348 dmA = DEVMODEdupWtoA(piW->pDevMode);
1350 /* align DEVMODEA to a DWORD boundary */
1351 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1355 piA->pDevMode = (LPDEVMODEA) ptr;
1356 len = dmA->dmSize + dmA->dmDriverExtra;
1357 memcpy(ptr, dmA, len);
1358 HeapFree(GetProcessHeap(), 0, dmA);
1368 FIXME("for level %u\n", level);
1370 pPrintersW += pi_sizeof[level];
1371 out += pi_sizeof[level];
1376 /******************************************************************
1377 * convert_driverinfo_W_to_A [internal]
1380 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1381 DWORD level, DWORD outlen, DWORD numentries)
1387 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1389 len = di_sizeof[level] * numentries;
1390 ptr = (LPSTR) out + len;
1393 /* copy the numbers of all PRINTER_INFO_* first */
1394 memcpy(out, pDriversW, len);
1396 #define COPY_STRING(fld) \
1399 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1400 ptr += len; outlen -= len;\
1402 #define COPY_MULTIZ_STRING(fld) \
1403 { LPWSTR p = diW->fld; if (p){ \
1406 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1407 ptr += len; outlen -= len; p += len;\
1409 while(len > 1 && outlen > 0); \
1412 while (id < numentries)
1418 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1419 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1421 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1428 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1429 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1431 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1434 COPY_STRING(pEnvironment);
1435 COPY_STRING(pDriverPath);
1436 COPY_STRING(pDataFile);
1437 COPY_STRING(pConfigFile);
1442 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1443 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1445 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1448 COPY_STRING(pEnvironment);
1449 COPY_STRING(pDriverPath);
1450 COPY_STRING(pDataFile);
1451 COPY_STRING(pConfigFile);
1452 COPY_STRING(pHelpFile);
1453 COPY_MULTIZ_STRING(pDependentFiles);
1454 COPY_STRING(pMonitorName);
1455 COPY_STRING(pDefaultDataType);
1460 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1461 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1463 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1466 COPY_STRING(pEnvironment);
1467 COPY_STRING(pDriverPath);
1468 COPY_STRING(pDataFile);
1469 COPY_STRING(pConfigFile);
1470 COPY_STRING(pHelpFile);
1471 COPY_MULTIZ_STRING(pDependentFiles);
1472 COPY_STRING(pMonitorName);
1473 COPY_STRING(pDefaultDataType);
1474 COPY_MULTIZ_STRING(pszzPreviousNames);
1479 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1480 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1482 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1485 COPY_STRING(pEnvironment);
1486 COPY_STRING(pDriverPath);
1487 COPY_STRING(pDataFile);
1488 COPY_STRING(pConfigFile);
1493 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1494 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1496 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1499 COPY_STRING(pEnvironment);
1500 COPY_STRING(pDriverPath);
1501 COPY_STRING(pDataFile);
1502 COPY_STRING(pConfigFile);
1503 COPY_STRING(pHelpFile);
1504 COPY_MULTIZ_STRING(pDependentFiles);
1505 COPY_STRING(pMonitorName);
1506 COPY_STRING(pDefaultDataType);
1507 COPY_MULTIZ_STRING(pszzPreviousNames);
1508 COPY_STRING(pszMfgName);
1509 COPY_STRING(pszOEMUrl);
1510 COPY_STRING(pszHardwareID);
1511 COPY_STRING(pszProvider);
1516 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1517 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1519 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1522 COPY_STRING(pEnvironment);
1523 COPY_STRING(pDriverPath);
1524 COPY_STRING(pDataFile);
1525 COPY_STRING(pConfigFile);
1526 COPY_STRING(pHelpFile);
1527 COPY_MULTIZ_STRING(pDependentFiles);
1528 COPY_STRING(pMonitorName);
1529 COPY_STRING(pDefaultDataType);
1530 COPY_MULTIZ_STRING(pszzPreviousNames);
1531 COPY_STRING(pszMfgName);
1532 COPY_STRING(pszOEMUrl);
1533 COPY_STRING(pszHardwareID);
1534 COPY_STRING(pszProvider);
1535 COPY_STRING(pszPrintProcessor);
1536 COPY_STRING(pszVendorSetup);
1537 COPY_MULTIZ_STRING(pszzColorProfiles);
1538 COPY_STRING(pszInfPath);
1539 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1545 FIXME("for level %u\n", level);
1548 pDriversW += di_sizeof[level];
1549 out += di_sizeof[level];
1554 #undef COPY_MULTIZ_STRING
1558 /***********************************************************
1559 * PRINTER_INFO_2AtoW
1560 * Creates a unicode copy of PRINTER_INFO_2A on heap
1562 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1564 LPPRINTER_INFO_2W piW;
1565 UNICODE_STRING usBuffer;
1567 if(!piA) return NULL;
1568 piW = HeapAlloc(heap, 0, sizeof(*piW));
1569 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1571 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1572 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1573 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1574 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1575 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1576 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1577 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1578 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1579 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1580 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1581 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1582 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1586 /***********************************************************
1587 * FREE_PRINTER_INFO_2W
1588 * Free PRINTER_INFO_2W and all strings
1590 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1594 HeapFree(heap,0,piW->pServerName);
1595 HeapFree(heap,0,piW->pPrinterName);
1596 HeapFree(heap,0,piW->pShareName);
1597 HeapFree(heap,0,piW->pPortName);
1598 HeapFree(heap,0,piW->pDriverName);
1599 HeapFree(heap,0,piW->pComment);
1600 HeapFree(heap,0,piW->pLocation);
1601 HeapFree(heap,0,piW->pDevMode);
1602 HeapFree(heap,0,piW->pSepFile);
1603 HeapFree(heap,0,piW->pPrintProcessor);
1604 HeapFree(heap,0,piW->pDatatype);
1605 HeapFree(heap,0,piW->pParameters);
1606 HeapFree(heap,0,piW);
1610 /******************************************************************
1611 * DeviceCapabilities [WINSPOOL.@]
1612 * DeviceCapabilitiesA [WINSPOOL.@]
1615 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1616 LPSTR pOutput, LPDEVMODEA lpdm)
1620 if (!GDI_CallDeviceCapabilities16)
1622 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1624 if (!GDI_CallDeviceCapabilities16) return -1;
1626 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1628 /* If DC_PAPERSIZE map POINT16s to POINTs */
1629 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1630 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1631 POINT *pt = (POINT *)pOutput;
1633 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1634 for(i = 0; i < ret; i++, pt++)
1639 HeapFree( GetProcessHeap(), 0, tmp );
1645 /*****************************************************************************
1646 * DeviceCapabilitiesW [WINSPOOL.@]
1648 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1651 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1652 WORD fwCapability, LPWSTR pOutput,
1653 const DEVMODEW *pDevMode)
1655 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1656 LPSTR pDeviceA = strdupWtoA(pDevice);
1657 LPSTR pPortA = strdupWtoA(pPort);
1660 if(pOutput && (fwCapability == DC_BINNAMES ||
1661 fwCapability == DC_FILEDEPENDENCIES ||
1662 fwCapability == DC_PAPERNAMES)) {
1663 /* These need A -> W translation */
1666 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1670 switch(fwCapability) {
1675 case DC_FILEDEPENDENCIES:
1679 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1680 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1682 for(i = 0; i < ret; i++)
1683 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1684 pOutput + (i * size), size);
1685 HeapFree(GetProcessHeap(), 0, pOutputA);
1687 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1688 (LPSTR)pOutput, dmA);
1690 HeapFree(GetProcessHeap(),0,pPortA);
1691 HeapFree(GetProcessHeap(),0,pDeviceA);
1692 HeapFree(GetProcessHeap(),0,dmA);
1696 /******************************************************************
1697 * DocumentPropertiesA [WINSPOOL.@]
1699 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1701 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1702 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1703 LPDEVMODEA pDevModeInput,DWORD fMode )
1705 LPSTR lpName = pDeviceName;
1706 static CHAR port[] = "LPT1:";
1709 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1710 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1714 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1716 ERR("no name from hPrinter?\n");
1717 SetLastError(ERROR_INVALID_HANDLE);
1720 lpName = strdupWtoA(lpNameW);
1723 if (!GDI_CallExtDeviceMode16)
1725 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1727 if (!GDI_CallExtDeviceMode16) {
1728 ERR("No CallExtDeviceMode16?\n");
1732 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1733 pDevModeInput, NULL, fMode);
1736 HeapFree(GetProcessHeap(),0,lpName);
1741 /*****************************************************************************
1742 * DocumentPropertiesW (WINSPOOL.@)
1744 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1746 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1748 LPDEVMODEW pDevModeOutput,
1749 LPDEVMODEW pDevModeInput, DWORD fMode)
1752 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1753 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1754 LPDEVMODEA pDevModeOutputA = NULL;
1757 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1758 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1760 if(pDevModeOutput) {
1761 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1762 if(ret < 0) return ret;
1763 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1765 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1766 pDevModeInputA, fMode);
1767 if(pDevModeOutput) {
1768 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1769 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1771 if(fMode == 0 && ret > 0)
1772 ret += (CCHDEVICENAME + CCHFORMNAME);
1773 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1774 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1778 /******************************************************************
1779 * OpenPrinterA [WINSPOOL.@]
1784 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1785 LPPRINTER_DEFAULTSA pDefault)
1787 UNICODE_STRING lpPrinterNameW;
1788 UNICODE_STRING usBuffer;
1789 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1790 PWSTR pwstrPrinterNameW;
1793 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1796 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1797 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1798 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1799 pDefaultW = &DefaultW;
1801 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1803 RtlFreeUnicodeString(&usBuffer);
1804 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1806 RtlFreeUnicodeString(&lpPrinterNameW);
1810 /******************************************************************
1811 * OpenPrinterW [WINSPOOL.@]
1813 * Open a Printer / Printserver or a Printer-Object
1816 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1817 * phPrinter [O] The resulting Handle is stored here
1818 * pDefault [I] PTR to Default Printer Settings or NULL
1825 * lpPrinterName is one of:
1826 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1827 *| Printer: "PrinterName"
1828 *| Printer-Object: "PrinterName,Job xxx"
1829 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1830 *| XcvPort: "Servername,XcvPort PortName"
1833 *| Printer-Object not supported
1834 *| pDefaults is ignored
1837 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1840 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1842 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1843 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1847 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1848 SetLastError(ERROR_INVALID_PARAMETER);
1852 /* Get the unique handle of the printer or Printserver */
1853 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1854 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1855 return (*phPrinter != 0);
1858 /******************************************************************
1859 * AddMonitorA [WINSPOOL.@]
1864 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1866 LPWSTR nameW = NULL;
1869 LPMONITOR_INFO_2A mi2a;
1870 MONITOR_INFO_2W mi2w;
1872 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1873 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1874 debugstr_a(mi2a ? mi2a->pName : NULL),
1875 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1876 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1879 SetLastError(ERROR_INVALID_LEVEL);
1883 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1889 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1890 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1891 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1894 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1896 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1897 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1898 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1900 if (mi2a->pEnvironment) {
1901 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1902 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1903 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1905 if (mi2a->pDLLName) {
1906 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1907 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1908 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1911 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1913 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1914 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1915 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1917 HeapFree(GetProcessHeap(), 0, nameW);
1921 /******************************************************************************
1922 * AddMonitorW [WINSPOOL.@]
1924 * Install a Printmonitor
1927 * pName [I] Servername or NULL (local Computer)
1928 * Level [I] Structure-Level (Must be 2)
1929 * pMonitors [I] PTR to MONITOR_INFO_2
1936 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1939 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1941 LPMONITOR_INFO_2W mi2w;
1943 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1944 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1945 debugstr_w(mi2w ? mi2w->pName : NULL),
1946 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1947 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1949 if ((backend == NULL) && !load_backend()) return FALSE;
1952 SetLastError(ERROR_INVALID_LEVEL);
1956 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1961 return backend->fpAddMonitor(pName, Level, pMonitors);
1964 /******************************************************************
1965 * DeletePrinterDriverA [WINSPOOL.@]
1968 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1970 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
1973 /******************************************************************
1974 * DeletePrinterDriverW [WINSPOOL.@]
1977 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1979 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
1982 /******************************************************************
1983 * DeleteMonitorA [WINSPOOL.@]
1985 * See DeleteMonitorW.
1988 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1990 LPWSTR nameW = NULL;
1991 LPWSTR EnvironmentW = NULL;
1992 LPWSTR MonitorNameW = NULL;
1997 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1998 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1999 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2003 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2004 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2005 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2008 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2009 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2010 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2013 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2015 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2016 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2017 HeapFree(GetProcessHeap(), 0, nameW);
2021 /******************************************************************
2022 * DeleteMonitorW [WINSPOOL.@]
2024 * Delete a specific Printmonitor from a Printing-Environment
2027 * pName [I] Servername or NULL (local Computer)
2028 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2029 * pMonitorName [I] Name of the Monitor, that should be deleted
2036 * pEnvironment is ignored in Windows for the local Computer.
2039 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2042 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2043 debugstr_w(pMonitorName));
2045 if ((backend == NULL) && !load_backend()) return FALSE;
2047 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2051 /******************************************************************
2052 * DeletePortA [WINSPOOL.@]
2057 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2059 LPWSTR nameW = NULL;
2060 LPWSTR portW = NULL;
2064 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2066 /* convert servername to unicode */
2068 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2069 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2070 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2073 /* convert portname to unicode */
2075 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2076 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2077 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2080 res = DeletePortW(nameW, hWnd, portW);
2081 HeapFree(GetProcessHeap(), 0, nameW);
2082 HeapFree(GetProcessHeap(), 0, portW);
2086 /******************************************************************
2087 * DeletePortW [WINSPOOL.@]
2089 * Delete a specific Port
2092 * pName [I] Servername or NULL (local Computer)
2093 * hWnd [I] Handle to parent Window for the Dialog-Box
2094 * pPortName [I] Name of the Port, that should be deleted
2101 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2103 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2105 if ((backend == NULL) && !load_backend()) return FALSE;
2108 SetLastError(RPC_X_NULL_REF_POINTER);
2112 return backend->fpDeletePort(pName, hWnd, pPortName);
2115 /******************************************************************************
2116 * SetPrinterW [WINSPOOL.@]
2118 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2120 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2121 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2125 /******************************************************************************
2126 * WritePrinter [WINSPOOL.@]
2128 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2130 opened_printer_t *printer;
2133 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2135 EnterCriticalSection(&printer_handles_cs);
2136 printer = get_opened_printer(hPrinter);
2139 SetLastError(ERROR_INVALID_HANDLE);
2145 SetLastError(ERROR_SPL_NO_STARTDOC);
2149 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2151 LeaveCriticalSection(&printer_handles_cs);
2155 /*****************************************************************************
2156 * AddFormA [WINSPOOL.@]
2158 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2160 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2164 /*****************************************************************************
2165 * AddFormW [WINSPOOL.@]
2167 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2169 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2173 /*****************************************************************************
2174 * AddJobA [WINSPOOL.@]
2176 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2179 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2183 SetLastError(ERROR_INVALID_LEVEL);
2187 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2190 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2191 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2192 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2193 if(*pcbNeeded > cbBuf) {
2194 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2197 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2198 addjobA->JobId = addjobW->JobId;
2199 addjobA->Path = (char *)(addjobA + 1);
2200 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2206 /*****************************************************************************
2207 * AddJobW [WINSPOOL.@]
2209 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2211 opened_printer_t *printer;
2214 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2215 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2216 WCHAR path[MAX_PATH], filename[MAX_PATH];
2218 ADDJOB_INFO_1W *addjob;
2220 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2222 EnterCriticalSection(&printer_handles_cs);
2224 printer = get_opened_printer(hPrinter);
2227 SetLastError(ERROR_INVALID_HANDLE);
2232 SetLastError(ERROR_INVALID_LEVEL);
2236 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2240 job->job_id = InterlockedIncrement(&next_job_id);
2242 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2243 if(path[len - 1] != '\\')
2245 memcpy(path + len, spool_path, sizeof(spool_path));
2246 sprintfW(filename, fmtW, path, job->job_id);
2248 len = strlenW(filename);
2249 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2250 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2251 job->document_title = strdupW(default_doc_title);
2252 job->printer_name = strdupW(printer->name);
2253 job->devmode = NULL;
2254 list_add_tail(&printer->queue->jobs, &job->entry);
2256 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2257 if(*pcbNeeded <= cbBuf) {
2258 addjob = (ADDJOB_INFO_1W*)pData;
2259 addjob->JobId = job->job_id;
2260 addjob->Path = (WCHAR *)(addjob + 1);
2261 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2264 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2267 LeaveCriticalSection(&printer_handles_cs);
2271 /*****************************************************************************
2272 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2274 * Return the PATH for the Print-Processors
2276 * See GetPrintProcessorDirectoryW.
2280 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2281 DWORD level, LPBYTE Info,
2282 DWORD cbBuf, LPDWORD pcbNeeded)
2284 LPWSTR serverW = NULL;
2289 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2290 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2294 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2295 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2296 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2300 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2301 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2302 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2305 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2306 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2308 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2311 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2312 cbBuf, NULL, NULL) > 0;
2315 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2316 HeapFree(GetProcessHeap(), 0, envW);
2317 HeapFree(GetProcessHeap(), 0, serverW);
2321 /*****************************************************************************
2322 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2324 * Return the PATH for the Print-Processors
2327 * server [I] Servername (NT only) or NULL (local Computer)
2328 * env [I] Printing-Environment (see below) or NULL (Default)
2329 * level [I] Structure-Level (must be 1)
2330 * Info [O] PTR to Buffer that receives the Result
2331 * cbBuf [I] Size of Buffer at "Info"
2332 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2333 * required for the Buffer at "Info"
2336 * Success: TRUE and in pcbNeeded the Bytes used in Info
2337 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2338 * if cbBuf is too small
2340 * Native Values returned in Info on Success:
2341 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2342 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2343 *| win9x(Windows 4.0): "%winsysdir%"
2345 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2348 * Only NULL or "" is supported for server
2351 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2352 DWORD level, LPBYTE Info,
2353 DWORD cbBuf, LPDWORD pcbNeeded)
2356 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2357 Info, cbBuf, pcbNeeded);
2359 if ((backend == NULL) && !load_backend()) return FALSE;
2362 /* (Level != 1) is ignored in win9x */
2363 SetLastError(ERROR_INVALID_LEVEL);
2367 if (pcbNeeded == NULL) {
2368 /* (pcbNeeded == NULL) is ignored in win9x */
2369 SetLastError(RPC_X_NULL_REF_POINTER);
2373 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2376 /*****************************************************************************
2377 * WINSPOOL_OpenDriverReg [internal]
2379 * opens the registry for the printer drivers depending on the given input
2380 * variable pEnvironment
2383 * the opened hkey on success
2386 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2390 const printenv_t * env;
2392 TRACE("(%s)\n", debugstr_w(pEnvironment));
2394 env = validate_envW(pEnvironment);
2395 if (!env) return NULL;
2397 buffer = HeapAlloc( GetProcessHeap(), 0,
2398 (strlenW(DriversW) + strlenW(env->envname) +
2399 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2401 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2402 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2403 HeapFree(GetProcessHeap(), 0, buffer);
2408 /*****************************************************************************
2409 * set_devices_and_printerports [internal]
2411 * set the [Devices] and [PrinterPorts] entries for a printer.
2414 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2416 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2420 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2422 /* FIXME: the driver must change to "winspool" */
2423 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2425 lstrcpyW(devline, driver_nt);
2426 lstrcatW(devline, commaW);
2427 lstrcatW(devline, pi->pPortName);
2429 TRACE("using %s\n", debugstr_w(devline));
2430 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2431 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2432 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2433 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2437 lstrcatW(devline, timeout_15_45);
2438 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2439 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2440 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2441 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2444 HeapFree(GetProcessHeap(), 0, devline);
2448 /*****************************************************************************
2449 * AddPrinterW [WINSPOOL.@]
2451 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2453 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2457 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2459 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2460 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2461 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2462 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2463 statusW[] = {'S','t','a','t','u','s',0},
2464 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2466 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2469 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2470 SetLastError(ERROR_INVALID_PARAMETER);
2474 ERR("Level = %d, unsupported!\n", Level);
2475 SetLastError(ERROR_INVALID_LEVEL);
2479 SetLastError(ERROR_INVALID_PARAMETER);
2482 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2484 ERR("Can't create Printers key\n");
2487 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2488 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2489 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2490 RegCloseKey(hkeyPrinter);
2491 RegCloseKey(hkeyPrinters);
2494 RegCloseKey(hkeyPrinter);
2496 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2498 ERR("Can't create Drivers key\n");
2499 RegCloseKey(hkeyPrinters);
2502 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2504 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2505 RegCloseKey(hkeyPrinters);
2506 RegCloseKey(hkeyDrivers);
2507 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2510 RegCloseKey(hkeyDriver);
2511 RegCloseKey(hkeyDrivers);
2513 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2514 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2515 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2516 RegCloseKey(hkeyPrinters);
2520 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2522 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2523 SetLastError(ERROR_INVALID_PRINTER_NAME);
2524 RegCloseKey(hkeyPrinters);
2528 set_devices_and_printerports(pi);
2529 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2530 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2531 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2533 /* See if we can load the driver. We may need the devmode structure anyway
2536 * Note that DocumentPropertiesW will briefly try to open the printer we
2537 * just create to find a DEVMODEA struct (it will use the WINEPS default
2538 * one in case it is not there, so we are ok).
2540 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2543 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2544 size = sizeof(DEVMODEW);
2550 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2552 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2554 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2555 HeapFree(GetProcessHeap(),0,dmW);
2560 /* set devmode to printer name */
2561 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2565 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2566 and we support these drivers. NT writes DEVMODEW so somehow
2567 we'll need to distinguish between these when we support NT
2571 dmA = DEVMODEdupWtoA(dmW);
2572 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2573 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2574 HeapFree(GetProcessHeap(), 0, dmA);
2576 HeapFree(GetProcessHeap(), 0, dmW);
2578 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2579 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2580 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2581 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2583 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2584 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2585 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2586 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2587 (LPBYTE)&pi->Priority, sizeof(DWORD));
2588 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2589 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2590 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2591 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2592 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2593 (LPBYTE)&pi->Status, sizeof(DWORD));
2594 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2595 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2597 RegCloseKey(hkeyPrinter);
2598 RegCloseKey(hkeyPrinters);
2599 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2600 ERR("OpenPrinter failing\n");
2606 /*****************************************************************************
2607 * AddPrinterA [WINSPOOL.@]
2609 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2611 UNICODE_STRING pNameW;
2613 PRINTER_INFO_2W *piW;
2614 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2617 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2619 ERR("Level = %d, unsupported!\n", Level);
2620 SetLastError(ERROR_INVALID_LEVEL);
2623 pwstrNameW = asciitounicode(&pNameW,pName);
2624 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2626 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2628 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2629 RtlFreeUnicodeString(&pNameW);
2634 /*****************************************************************************
2635 * ClosePrinter [WINSPOOL.@]
2637 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2639 UINT_PTR i = (UINT_PTR)hPrinter;
2640 opened_printer_t *printer = NULL;
2643 TRACE("(%p)\n", hPrinter);
2645 EnterCriticalSection(&printer_handles_cs);
2647 if ((i > 0) && (i <= nb_printer_handles))
2648 printer = printer_handles[i - 1];
2653 struct list *cursor, *cursor2;
2655 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2657 if (printer->backend_printer) {
2658 backend->fpClosePrinter(printer->backend_printer);
2662 EndDocPrinter(hPrinter);
2664 if(InterlockedDecrement(&printer->queue->ref) == 0)
2666 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2668 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2669 ScheduleJob(hPrinter, job->job_id);
2671 HeapFree(GetProcessHeap(), 0, printer->queue);
2674 HeapFree(GetProcessHeap(), 0, printer->printername);
2675 HeapFree(GetProcessHeap(), 0, printer->name);
2676 HeapFree(GetProcessHeap(), 0, printer);
2677 printer_handles[i - 1] = NULL;
2680 LeaveCriticalSection(&printer_handles_cs);
2684 /*****************************************************************************
2685 * DeleteFormA [WINSPOOL.@]
2687 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2689 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2693 /*****************************************************************************
2694 * DeleteFormW [WINSPOOL.@]
2696 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2698 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2702 /*****************************************************************************
2703 * DeletePrinter [WINSPOOL.@]
2705 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2707 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2708 HKEY hkeyPrinters, hkey;
2711 SetLastError(ERROR_INVALID_HANDLE);
2714 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2715 RegDeleteTreeW(hkeyPrinters, lpNameW);
2716 RegCloseKey(hkeyPrinters);
2718 WriteProfileStringW(devicesW, lpNameW, NULL);
2719 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2721 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2722 RegDeleteValueW(hkey, lpNameW);
2726 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2727 RegDeleteValueW(hkey, lpNameW);
2733 /*****************************************************************************
2734 * SetPrinterA [WINSPOOL.@]
2736 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2739 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2743 /*****************************************************************************
2744 * SetJobA [WINSPOOL.@]
2746 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2747 LPBYTE pJob, DWORD Command)
2751 UNICODE_STRING usBuffer;
2753 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2755 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2756 are all ignored by SetJob, so we don't bother copying them */
2764 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2765 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2767 JobW = (LPBYTE)info1W;
2768 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2769 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2770 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2771 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2772 info1W->Status = info1A->Status;
2773 info1W->Priority = info1A->Priority;
2774 info1W->Position = info1A->Position;
2775 info1W->PagesPrinted = info1A->PagesPrinted;
2780 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2781 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2783 JobW = (LPBYTE)info2W;
2784 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2785 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2786 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2787 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2788 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2789 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2790 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2791 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2792 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2793 info2W->Status = info2A->Status;
2794 info2W->Priority = info2A->Priority;
2795 info2W->Position = info2A->Position;
2796 info2W->StartTime = info2A->StartTime;
2797 info2W->UntilTime = info2A->UntilTime;
2798 info2W->PagesPrinted = info2A->PagesPrinted;
2802 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2803 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2806 SetLastError(ERROR_INVALID_LEVEL);
2810 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2816 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2817 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2818 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2819 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2820 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2825 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2826 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2827 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2828 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2829 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2830 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2831 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2832 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2833 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2837 HeapFree(GetProcessHeap(), 0, JobW);
2842 /*****************************************************************************
2843 * SetJobW [WINSPOOL.@]
2845 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2846 LPBYTE pJob, DWORD Command)
2852 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2853 FIXME("Ignoring everything other than document title\n");
2855 EnterCriticalSection(&printer_handles_cs);
2856 job = get_job(hPrinter, JobId);
2866 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2867 HeapFree(GetProcessHeap(), 0, job->document_title);
2868 job->document_title = strdupW(info1->pDocument);
2873 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2874 HeapFree(GetProcessHeap(), 0, job->document_title);
2875 job->document_title = strdupW(info2->pDocument);
2876 HeapFree(GetProcessHeap(), 0, job->devmode);
2877 if (info2->pDevMode)
2879 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2880 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2881 memcpy(job->devmode, info2->pDevMode, size);
2884 job->devmode = NULL;
2890 SetLastError(ERROR_INVALID_LEVEL);
2895 LeaveCriticalSection(&printer_handles_cs);
2899 /*****************************************************************************
2900 * EndDocPrinter [WINSPOOL.@]
2902 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2904 opened_printer_t *printer;
2906 TRACE("(%p)\n", hPrinter);
2908 EnterCriticalSection(&printer_handles_cs);
2910 printer = get_opened_printer(hPrinter);
2913 SetLastError(ERROR_INVALID_HANDLE);
2919 SetLastError(ERROR_SPL_NO_STARTDOC);
2923 CloseHandle(printer->doc->hf);
2924 ScheduleJob(hPrinter, printer->doc->job_id);
2925 HeapFree(GetProcessHeap(), 0, printer->doc);
2926 printer->doc = NULL;
2929 LeaveCriticalSection(&printer_handles_cs);
2933 /*****************************************************************************
2934 * EndPagePrinter [WINSPOOL.@]
2936 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2938 FIXME("(%p): stub\n", hPrinter);
2942 /*****************************************************************************
2943 * StartDocPrinterA [WINSPOOL.@]
2945 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2947 UNICODE_STRING usBuffer;
2949 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2952 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2953 or one (DOC_INFO_3) extra DWORDs */
2957 doc2W.JobId = doc2->JobId;
2960 doc2W.dwMode = doc2->dwMode;
2963 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2964 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2965 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2969 SetLastError(ERROR_INVALID_LEVEL);
2973 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2975 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2976 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2977 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2982 /*****************************************************************************
2983 * StartDocPrinterW [WINSPOOL.@]
2985 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2987 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2988 opened_printer_t *printer;
2989 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2990 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2991 JOB_INFO_1W job_info;
2992 DWORD needed, ret = 0;
2997 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2998 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2999 debugstr_w(doc->pDatatype));
3001 if(Level < 1 || Level > 3)
3003 SetLastError(ERROR_INVALID_LEVEL);
3007 EnterCriticalSection(&printer_handles_cs);
3008 printer = get_opened_printer(hPrinter);
3011 SetLastError(ERROR_INVALID_HANDLE);
3017 SetLastError(ERROR_INVALID_PRINTER_STATE);
3021 /* Even if we're printing to a file we still add a print job, we'll
3022 just ignore the spool file name */
3024 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3026 ERR("AddJob failed gle %u\n", GetLastError());
3030 /* use pOutputFile only, when it is a real filename */
3031 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3032 filename = doc->pOutputFile;
3034 filename = addjob->Path;
3036 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3037 if(hf == INVALID_HANDLE_VALUE)
3040 memset(&job_info, 0, sizeof(job_info));
3041 job_info.pDocument = doc->pDocName;
3042 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3044 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3045 printer->doc->hf = hf;
3046 ret = printer->doc->job_id = addjob->JobId;
3047 job = get_job(hPrinter, ret);
3048 job->portname = strdupW(doc->pOutputFile);
3051 LeaveCriticalSection(&printer_handles_cs);
3056 /*****************************************************************************
3057 * StartPagePrinter [WINSPOOL.@]
3059 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3061 FIXME("(%p): stub\n", hPrinter);
3065 /*****************************************************************************
3066 * GetFormA [WINSPOOL.@]
3068 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3069 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3071 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3072 Level,pForm,cbBuf,pcbNeeded);
3076 /*****************************************************************************
3077 * GetFormW [WINSPOOL.@]
3079 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3080 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3082 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3083 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3087 /*****************************************************************************
3088 * SetFormA [WINSPOOL.@]
3090 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3093 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3097 /*****************************************************************************
3098 * SetFormW [WINSPOOL.@]
3100 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3103 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3107 /*****************************************************************************
3108 * ReadPrinter [WINSPOOL.@]
3110 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3111 LPDWORD pNoBytesRead)
3113 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3117 /*****************************************************************************
3118 * ResetPrinterA [WINSPOOL.@]
3120 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3122 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3126 /*****************************************************************************
3127 * ResetPrinterW [WINSPOOL.@]
3129 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3131 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3135 /*****************************************************************************
3136 * WINSPOOL_GetDWORDFromReg
3138 * Return DWORD associated with ValueName from hkey.
3140 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3142 DWORD sz = sizeof(DWORD), type, value = 0;
3145 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3147 if(ret != ERROR_SUCCESS) {
3148 WARN("Got ret = %d on name %s\n", ret, ValueName);
3151 if(type != REG_DWORD) {
3152 ERR("Got type %d\n", type);
3159 /*****************************************************************************
3160 * get_filename_from_reg [internal]
3162 * Get ValueName from hkey storing result in out
3163 * when the Value in the registry has only a filename, use driverdir as prefix
3164 * outlen is space left in out
3165 * String is stored either as unicode or ascii
3169 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3170 LPBYTE out, DWORD outlen, LPDWORD needed)
3172 WCHAR filename[MAX_PATH];
3176 LPWSTR buffer = filename;
3180 size = sizeof(filename);
3182 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3183 if (ret == ERROR_MORE_DATA) {
3184 TRACE("need dynamic buffer: %u\n", size);
3185 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3187 /* No Memory is bad */
3191 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3194 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3195 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3201 /* do we have a full path ? */
3202 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3203 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3206 /* we must build the full Path */
3208 if ((out) && (outlen > dirlen)) {
3209 lstrcpyW((LPWSTR)out, driverdir);
3217 /* write the filename */
3218 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3219 if ((out) && (outlen >= size)) {
3220 lstrcpyW((LPWSTR)out, ptr);
3227 ptr += lstrlenW(ptr)+1;
3228 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3231 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3233 /* write the multisz-termination */
3234 if (type == REG_MULTI_SZ) {
3235 size = sizeof(WCHAR);
3238 if (out && (outlen >= size)) {
3239 memset (out, 0, size);
3245 /*****************************************************************************
3246 * WINSPOOL_GetStringFromReg
3248 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3249 * String is stored as unicode.
3251 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3252 DWORD buflen, DWORD *needed)
3254 DWORD sz = buflen, type;
3257 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3258 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3259 WARN("Got ret = %d\n", ret);
3263 /* add space for terminating '\0' */
3264 sz += sizeof(WCHAR);
3268 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3273 /*****************************************************************************
3274 * WINSPOOL_GetDefaultDevMode
3276 * Get a default DevMode values for wineps.
3280 static void WINSPOOL_GetDefaultDevMode(
3282 DWORD buflen, DWORD *needed)
3285 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3287 /* fill default DEVMODE - should be read from ppd... */
3288 ZeroMemory( &dm, sizeof(dm) );
3289 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3290 dm.dmSpecVersion = DM_SPECVERSION;
3291 dm.dmDriverVersion = 1;
3292 dm.dmSize = sizeof(DEVMODEW);
3293 dm.dmDriverExtra = 0;
3295 DM_ORIENTATION | DM_PAPERSIZE |
3296 DM_PAPERLENGTH | DM_PAPERWIDTH |
3299 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3300 DM_YRESOLUTION | DM_TTOPTION;
3302 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3303 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3304 dm.u1.s1.dmPaperLength = 2970;
3305 dm.u1.s1.dmPaperWidth = 2100;
3307 dm.u1.s1.dmScale = 100;
3308 dm.u1.s1.dmCopies = 1;
3309 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3310 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3313 dm.dmYResolution = 300; /* 300dpi */
3314 dm.dmTTOption = DMTT_BITMAP;
3317 /* dm.dmLogPixels */
3318 /* dm.dmBitsPerPel */
3319 /* dm.dmPelsWidth */
3320 /* dm.dmPelsHeight */
3321 /* dm.u2.dmDisplayFlags */
3322 /* dm.dmDisplayFrequency */
3323 /* dm.dmICMMethod */
3324 /* dm.dmICMIntent */
3325 /* dm.dmMediaType */
3326 /* dm.dmDitherType */
3327 /* dm.dmReserved1 */
3328 /* dm.dmReserved2 */
3329 /* dm.dmPanningWidth */
3330 /* dm.dmPanningHeight */
3332 if(buflen >= sizeof(DEVMODEW))
3333 memcpy(ptr, &dm, sizeof(DEVMODEW));
3334 *needed = sizeof(DEVMODEW);
3337 /*****************************************************************************
3338 * WINSPOOL_GetDevModeFromReg
3340 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3341 * DevMode is stored either as unicode or ascii.
3343 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3345 DWORD buflen, DWORD *needed)
3347 DWORD sz = buflen, type;
3350 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3351 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3352 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3353 if (sz < sizeof(DEVMODEA))
3355 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3358 /* ensures that dmSize is not erratically bogus if registry is invalid */
3359 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3360 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3361 sz += (CCHDEVICENAME + CCHFORMNAME);
3362 if (ptr && (buflen >= sz)) {
3363 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3364 memcpy(ptr, dmW, sz);
3365 HeapFree(GetProcessHeap(),0,dmW);
3371 /*********************************************************************
3372 * WINSPOOL_GetPrinter_1
3374 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3376 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3377 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3379 DWORD size, left = cbBuf;
3380 BOOL space = (cbBuf > 0);
3385 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3386 if(space && size <= left) {
3387 pi1->pName = (LPWSTR)ptr;
3395 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3396 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3397 if(space && size <= left) {
3398 pi1->pDescription = (LPWSTR)ptr;
3406 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3407 if(space && size <= left) {
3408 pi1->pComment = (LPWSTR)ptr;
3416 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3418 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3419 memset(pi1, 0, sizeof(*pi1));
3423 /*********************************************************************
3424 * WINSPOOL_GetPrinter_2
3426 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3428 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3429 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3431 DWORD size, left = cbBuf;
3432 BOOL space = (cbBuf > 0);
3437 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3438 if(space && size <= left) {
3439 pi2->pPrinterName = (LPWSTR)ptr;
3446 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3447 if(space && size <= left) {
3448 pi2->pShareName = (LPWSTR)ptr;
3455 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3456 if(space && size <= left) {
3457 pi2->pPortName = (LPWSTR)ptr;
3464 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3465 if(space && size <= left) {
3466 pi2->pDriverName = (LPWSTR)ptr;
3473 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3474 if(space && size <= left) {
3475 pi2->pComment = (LPWSTR)ptr;
3482 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3483 if(space && size <= left) {
3484 pi2->pLocation = (LPWSTR)ptr;
3491 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3492 if(space && size <= left) {
3493 pi2->pDevMode = (LPDEVMODEW)ptr;
3502 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3503 if(space && size <= left) {
3504 pi2->pDevMode = (LPDEVMODEW)ptr;
3511 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3512 if(space && size <= left) {
3513 pi2->pSepFile = (LPWSTR)ptr;
3520 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3521 if(space && size <= left) {
3522 pi2->pPrintProcessor = (LPWSTR)ptr;
3529 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3530 if(space && size <= left) {
3531 pi2->pDatatype = (LPWSTR)ptr;
3538 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3539 if(space && size <= left) {
3540 pi2->pParameters = (LPWSTR)ptr;
3548 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3549 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3550 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3551 "Default Priority");
3552 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3553 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3556 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3557 memset(pi2, 0, sizeof(*pi2));
3562 /*********************************************************************
3563 * WINSPOOL_GetPrinter_4
3565 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3567 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3568 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3570 DWORD size, left = cbBuf;
3571 BOOL space = (cbBuf > 0);
3576 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3577 if(space && size <= left) {
3578 pi4->pPrinterName = (LPWSTR)ptr;
3586 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3589 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3590 memset(pi4, 0, sizeof(*pi4));
3595 /*********************************************************************
3596 * WINSPOOL_GetPrinter_5
3598 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3600 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3601 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3603 DWORD size, left = cbBuf;
3604 BOOL space = (cbBuf > 0);
3609 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3610 if(space && size <= left) {
3611 pi5->pPrinterName = (LPWSTR)ptr;
3618 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3619 if(space && size <= left) {
3620 pi5->pPortName = (LPWSTR)ptr;
3628 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3629 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3631 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3635 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3636 memset(pi5, 0, sizeof(*pi5));
3641 /*********************************************************************
3642 * WINSPOOL_GetPrinter_7
3644 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3646 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3647 DWORD cbBuf, LPDWORD pcbNeeded)
3649 DWORD size, left = cbBuf;
3650 BOOL space = (cbBuf > 0);
3655 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3658 size = sizeof(pi7->pszObjectGUID);
3660 if (space && size <= left) {
3661 pi7->pszObjectGUID = (LPWSTR)ptr;
3668 /* We do not have a Directory Service */
3669 pi7->dwAction = DSPRINT_UNPUBLISH;
3672 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3673 memset(pi7, 0, sizeof(*pi7));
3678 /*********************************************************************
3679 * WINSPOOL_GetPrinter_9
3681 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3683 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3684 DWORD cbBuf, LPDWORD pcbNeeded)
3687 BOOL space = (cbBuf > 0);
3691 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3692 if(space && size <= cbBuf) {
3693 pi9->pDevMode = (LPDEVMODEW)buf;
3700 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3701 if(space && size <= cbBuf) {
3702 pi9->pDevMode = (LPDEVMODEW)buf;
3708 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3709 memset(pi9, 0, sizeof(*pi9));
3714 /*****************************************************************************
3715 * GetPrinterW [WINSPOOL.@]
3717 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3718 DWORD cbBuf, LPDWORD pcbNeeded)
3721 DWORD size, needed = 0;
3723 HKEY hkeyPrinter, hkeyPrinters;
3726 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3728 if (!(name = get_opened_printer_name(hPrinter))) {
3729 SetLastError(ERROR_INVALID_HANDLE);
3733 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3735 ERR("Can't create Printers key\n");
3738 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3740 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3741 RegCloseKey(hkeyPrinters);
3742 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3749 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3751 size = sizeof(PRINTER_INFO_2W);
3753 ptr = pPrinter + size;
3755 memset(pPrinter, 0, size);
3760 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3767 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3769 size = sizeof(PRINTER_INFO_4W);
3771 ptr = pPrinter + size;
3773 memset(pPrinter, 0, size);
3778 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3786 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3788 size = sizeof(PRINTER_INFO_5W);
3790 ptr = pPrinter + size;
3792 memset(pPrinter, 0, size);
3798 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3806 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3808 size = sizeof(PRINTER_INFO_6);
3809 if (size <= cbBuf) {
3810 /* FIXME: We do not update the status yet */
3811 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3823 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3825 size = sizeof(PRINTER_INFO_7W);
3826 if (size <= cbBuf) {
3827 ptr = pPrinter + size;
3829 memset(pPrinter, 0, size);
3835 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3843 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3845 size = sizeof(PRINTER_INFO_9W);
3847 ptr = pPrinter + size;
3849 memset(pPrinter, 0, size);
3855 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3862 FIXME("Unimplemented level %d\n", Level);
3863 SetLastError(ERROR_INVALID_LEVEL);
3864 RegCloseKey(hkeyPrinters);
3865 RegCloseKey(hkeyPrinter);
3869 RegCloseKey(hkeyPrinter);
3870 RegCloseKey(hkeyPrinters);
3872 TRACE("returning %d needed = %d\n", ret, needed);
3873 if(pcbNeeded) *pcbNeeded = needed;
3875 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3879 /*****************************************************************************
3880 * GetPrinterA [WINSPOOL.@]
3882 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3883 DWORD cbBuf, LPDWORD pcbNeeded)
3889 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3891 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3893 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3894 HeapFree(GetProcessHeap(), 0, buf);
3899 /*****************************************************************************
3900 * WINSPOOL_EnumPrintersW
3902 * Implementation of EnumPrintersW
3904 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3905 DWORD dwLevel, LPBYTE lpbPrinters,
3906 DWORD cbBuf, LPDWORD lpdwNeeded,
3907 LPDWORD lpdwReturned)
3910 HKEY hkeyPrinters, hkeyPrinter;
3911 WCHAR PrinterName[255];
3912 DWORD needed = 0, number = 0;
3913 DWORD used, i, left;
3917 memset(lpbPrinters, 0, cbBuf);
3923 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3924 if(dwType == PRINTER_ENUM_DEFAULT)
3927 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3928 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3929 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3931 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3937 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3938 FIXME("dwType = %08x\n", dwType);
3939 SetLastError(ERROR_INVALID_FLAGS);
3943 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3945 ERR("Can't create Printers key\n");
3949 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3950 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3951 RegCloseKey(hkeyPrinters);
3952 ERR("Can't query Printers key\n");
3955 TRACE("Found %d printers\n", number);
3959 used = number * sizeof(PRINTER_INFO_1W);
3962 used = number * sizeof(PRINTER_INFO_2W);
3965 used = number * sizeof(PRINTER_INFO_4W);
3968 used = number * sizeof(PRINTER_INFO_5W);
3972 SetLastError(ERROR_INVALID_LEVEL);
3973 RegCloseKey(hkeyPrinters);
3976 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3978 for(i = 0; i < number; i++) {
3979 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3981 ERR("Can't enum key number %d\n", i);
3982 RegCloseKey(hkeyPrinters);
3985 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3986 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3988 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3989 RegCloseKey(hkeyPrinters);
3994 buf = lpbPrinters + used;
3995 left = cbBuf - used;
4003 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4006 if(pi) pi += sizeof(PRINTER_INFO_1W);
4009 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4012 if(pi) pi += sizeof(PRINTER_INFO_2W);
4015 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4018 if(pi) pi += sizeof(PRINTER_INFO_4W);
4021 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4024 if(pi) pi += sizeof(PRINTER_INFO_5W);
4027 ERR("Shouldn't be here!\n");
4028 RegCloseKey(hkeyPrinter);
4029 RegCloseKey(hkeyPrinters);
4032 RegCloseKey(hkeyPrinter);
4034 RegCloseKey(hkeyPrinters);
4041 memset(lpbPrinters, 0, cbBuf);
4042 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4046 *lpdwReturned = number;
4047 SetLastError(ERROR_SUCCESS);
4052 /******************************************************************
4053 * EnumPrintersW [WINSPOOL.@]
4055 * Enumerates the available printers, print servers and print
4056 * providers, depending on the specified flags, name and level.
4060 * If level is set to 1:
4061 * Returns an array of PRINTER_INFO_1 data structures in the
4062 * lpbPrinters buffer.
4064 * If level is set to 2:
4065 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4066 * Returns an array of PRINTER_INFO_2 data structures in the
4067 * lpbPrinters buffer. Note that according to MSDN also an
4068 * OpenPrinter should be performed on every remote printer.
4070 * If level is set to 4 (officially WinNT only):
4071 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4072 * Fast: Only the registry is queried to retrieve printer names,
4073 * no connection to the driver is made.
4074 * Returns an array of PRINTER_INFO_4 data structures in the
4075 * lpbPrinters buffer.
4077 * If level is set to 5 (officially WinNT4/Win9x only):
4078 * Fast: Only the registry is queried to retrieve printer names,
4079 * no connection to the driver is made.
4080 * Returns an array of PRINTER_INFO_5 data structures in the
4081 * lpbPrinters buffer.
4083 * If level set to 3 or 6+:
4084 * returns zero (failure!)
4086 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4090 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4091 * - Only levels 2, 4 and 5 are implemented at the moment.
4092 * - 16-bit printer drivers are not enumerated.
4093 * - Returned amount of bytes used/needed does not match the real Windoze
4094 * implementation (as in this implementation, all strings are part
4095 * of the buffer, whereas Win32 keeps them somewhere else)
4096 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4099 * - In a regular Wine installation, no registry settings for printers
4100 * exist, which makes this function return an empty list.
4102 BOOL WINAPI EnumPrintersW(
4103 DWORD dwType, /* [in] Types of print objects to enumerate */
4104 LPWSTR lpszName, /* [in] name of objects to enumerate */
4105 DWORD dwLevel, /* [in] type of printer info structure */
4106 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4107 DWORD cbBuf, /* [in] max size of buffer in bytes */
4108 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4109 LPDWORD lpdwReturned /* [out] number of entries returned */
4112 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4113 lpdwNeeded, lpdwReturned);
4116 /******************************************************************
4117 * EnumPrintersA [WINSPOOL.@]
4122 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4123 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4126 UNICODE_STRING pNameU;
4130 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4131 pPrinters, cbBuf, pcbNeeded, pcReturned);
4133 pNameW = asciitounicode(&pNameU, pName);
4135 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4136 MS Office need this */
4137 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4139 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4141 RtlFreeUnicodeString(&pNameU);
4143 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4145 HeapFree(GetProcessHeap(), 0, pPrintersW);
4149 /*****************************************************************************
4150 * WINSPOOL_GetDriverInfoFromReg [internal]
4152 * Enters the information from the registry into the DRIVER_INFO struct
4155 * zero if the printer driver does not exist in the registry
4156 * (only if Level > 1) otherwise nonzero
4158 static BOOL WINSPOOL_GetDriverInfoFromReg(
4161 const printenv_t * env,
4163 LPBYTE ptr, /* DRIVER_INFO */
4164 LPBYTE pDriverStrings, /* strings buffer */
4165 DWORD cbBuf, /* size of string buffer */
4166 LPDWORD pcbNeeded) /* space needed for str. */
4170 WCHAR driverdir[MAX_PATH];
4172 LPBYTE strPtr = pDriverStrings;
4173 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4175 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4176 debugstr_w(DriverName), env,
4177 Level, di, pDriverStrings, cbBuf);
4179 if (di) ZeroMemory(di, di_sizeof[Level]);
4181 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4182 if (*pcbNeeded <= cbBuf)
4183 strcpyW((LPWSTR)strPtr, DriverName);
4185 /* pName for level 1 has a different offset! */
4187 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4191 /* .cVersion and .pName for level > 1 */
4193 di->cVersion = env->driverversion;
4194 di->pName = (LPWSTR) strPtr;
4195 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4198 /* Reserve Space for the largest subdir and a Backslash*/
4199 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4200 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4201 /* Should never Fail */
4204 lstrcatW(driverdir, env->versionsubdir);
4205 lstrcatW(driverdir, backslashW);
4207 /* dirlen must not include the terminating zero */
4208 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4210 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4211 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4212 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4217 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4220 if (*pcbNeeded <= cbBuf) {
4221 lstrcpyW((LPWSTR)strPtr, env->envname);
4222 if (di) di->pEnvironment = (LPWSTR)strPtr;
4223 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4226 /* .pDriverPath is the Graphics rendering engine.
4227 The full Path is required to avoid a crash in some apps */
4228 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4230 if (*pcbNeeded <= cbBuf)
4231 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4233 if (di) di->pDriverPath = (LPWSTR)strPtr;
4234 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4237 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4238 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4240 if (*pcbNeeded <= cbBuf)
4241 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4243 if (di) di->pDataFile = (LPWSTR)strPtr;
4244 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4247 /* .pConfigFile is the Driver user Interface */
4248 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4250 if (*pcbNeeded <= cbBuf)
4251 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4253 if (di) di->pConfigFile = (LPWSTR)strPtr;
4254 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4258 RegCloseKey(hkeyDriver);
4259 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4264 RegCloseKey(hkeyDriver);
4265 FIXME("level 5: incomplete\n");
4270 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4272 if (*pcbNeeded <= cbBuf)
4273 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4275 if (di) di->pHelpFile = (LPWSTR)strPtr;
4276 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4279 /* .pDependentFiles */
4280 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4282 if (*pcbNeeded <= cbBuf)
4283 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4285 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4286 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4288 else if (GetVersion() & 0x80000000) {
4289 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4290 size = 2 * sizeof(WCHAR);
4292 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4294 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4295 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4298 /* .pMonitorName is the optional Language Monitor */
4299 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4301 if (*pcbNeeded <= cbBuf)
4302 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4304 if (di) di->pMonitorName = (LPWSTR)strPtr;
4305 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4308 /* .pDefaultDataType */
4309 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4311 if(*pcbNeeded <= cbBuf)
4312 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4314 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4315 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4319 RegCloseKey(hkeyDriver);
4320 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4324 /* .pszzPreviousNames */
4325 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4327 if(*pcbNeeded <= cbBuf)
4328 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4330 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4331 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4335 RegCloseKey(hkeyDriver);
4336 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4340 /* support is missing, but not important enough for a FIXME */
4341 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4344 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4346 if(*pcbNeeded <= cbBuf)
4347 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4349 if (di) di->pszMfgName = (LPWSTR)strPtr;
4350 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4354 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4356 if(*pcbNeeded <= cbBuf)
4357 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4359 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4360 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4363 /* .pszHardwareID */
4364 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4366 if(*pcbNeeded <= cbBuf)
4367 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4369 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4370 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4374 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4376 if(*pcbNeeded <= cbBuf)
4377 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4379 if (di) di->pszProvider = (LPWSTR)strPtr;
4380 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4384 RegCloseKey(hkeyDriver);
4388 /* support is missing, but not important enough for a FIXME */
4389 TRACE("level 8: incomplete\n");
4391 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4392 RegCloseKey(hkeyDriver);
4396 /*****************************************************************************
4397 * GetPrinterDriverW [WINSPOOL.@]
4399 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4400 DWORD Level, LPBYTE pDriverInfo,
4401 DWORD cbBuf, LPDWORD pcbNeeded)
4404 WCHAR DriverName[100];
4405 DWORD ret, type, size, needed = 0;
4407 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4408 const printenv_t * env;
4410 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4411 Level,pDriverInfo,cbBuf, pcbNeeded);
4414 ZeroMemory(pDriverInfo, cbBuf);
4416 if (!(name = get_opened_printer_name(hPrinter))) {
4417 SetLastError(ERROR_INVALID_HANDLE);
4421 if (Level < 1 || Level == 7 || Level > 8) {
4422 SetLastError(ERROR_INVALID_LEVEL);
4426 env = validate_envW(pEnvironment);
4427 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4429 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4431 ERR("Can't create Printers key\n");
4434 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4436 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4437 RegCloseKey(hkeyPrinters);
4438 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4441 size = sizeof(DriverName);
4443 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4444 (LPBYTE)DriverName, &size);
4445 RegCloseKey(hkeyPrinter);
4446 RegCloseKey(hkeyPrinters);
4447 if(ret != ERROR_SUCCESS) {
4448 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4452 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4454 ERR("Can't create Drivers key\n");
4458 size = di_sizeof[Level];
4459 if ((size <= cbBuf) && pDriverInfo)
4460 ptr = pDriverInfo + size;
4462 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4463 env, Level, pDriverInfo, ptr,
4464 (cbBuf < size) ? 0 : cbBuf - size,
4466 RegCloseKey(hkeyDrivers);
4470 RegCloseKey(hkeyDrivers);
4472 if(pcbNeeded) *pcbNeeded = size + needed;
4473 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4474 if(cbBuf >= size + needed) return TRUE;
4475 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4479 /*****************************************************************************
4480 * GetPrinterDriverA [WINSPOOL.@]
4482 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4483 DWORD Level, LPBYTE pDriverInfo,
4484 DWORD cbBuf, LPDWORD pcbNeeded)
4487 UNICODE_STRING pEnvW;
4493 ZeroMemory(pDriverInfo, cbBuf);
4494 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4497 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4498 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4501 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4503 HeapFree(GetProcessHeap(), 0, buf);
4505 RtlFreeUnicodeString(&pEnvW);
4509 /*****************************************************************************
4510 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4512 * Return the PATH for the Printer-Drivers (UNICODE)
4515 * pName [I] Servername (NT only) or NULL (local Computer)
4516 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4517 * Level [I] Structure-Level (must be 1)
4518 * pDriverDirectory [O] PTR to Buffer that receives the Result
4519 * cbBuf [I] Size of Buffer at pDriverDirectory
4520 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4521 * required for pDriverDirectory
4524 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4525 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4526 * if cbBuf is too small
4528 * Native Values returned in pDriverDirectory on Success:
4529 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4530 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4531 *| win9x(Windows 4.0): "%winsysdir%"
4533 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4536 *- Only NULL or "" is supported for pName
4539 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4540 DWORD Level, LPBYTE pDriverDirectory,
4541 DWORD cbBuf, LPDWORD pcbNeeded)
4543 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4544 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4546 if ((backend == NULL) && !load_backend()) return FALSE;
4549 /* (Level != 1) is ignored in win9x */
4550 SetLastError(ERROR_INVALID_LEVEL);
4553 if (pcbNeeded == NULL) {
4554 /* (pcbNeeded == NULL) is ignored in win9x */
4555 SetLastError(RPC_X_NULL_REF_POINTER);
4559 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4560 pDriverDirectory, cbBuf, pcbNeeded);
4565 /*****************************************************************************
4566 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4568 * Return the PATH for the Printer-Drivers (ANSI)
4570 * See GetPrinterDriverDirectoryW.
4573 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4576 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4577 DWORD Level, LPBYTE pDriverDirectory,
4578 DWORD cbBuf, LPDWORD pcbNeeded)
4580 UNICODE_STRING nameW, environmentW;
4583 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4584 WCHAR *driverDirectoryW = NULL;
4586 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4587 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4589 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4591 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4592 else nameW.Buffer = NULL;
4593 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4594 else environmentW.Buffer = NULL;
4596 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4597 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4600 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4601 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4603 *pcbNeeded = needed;
4604 ret = (needed <= cbBuf) ? TRUE : FALSE;
4606 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4608 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4610 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4611 RtlFreeUnicodeString(&environmentW);
4612 RtlFreeUnicodeString(&nameW);
4617 /*****************************************************************************
4618 * AddPrinterDriverA [WINSPOOL.@]
4620 * See AddPrinterDriverW.
4623 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4625 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4626 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4629 /******************************************************************************
4630 * AddPrinterDriverW (WINSPOOL.@)
4632 * Install a Printer Driver
4635 * pName [I] Servername or NULL (local Computer)
4636 * level [I] Level for the supplied DRIVER_INFO_*W struct
4637 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4644 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4646 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4647 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4650 /*****************************************************************************
4651 * AddPrintProcessorA [WINSPOOL.@]
4653 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4654 LPSTR pPrintProcessorName)
4656 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4657 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4661 /*****************************************************************************
4662 * AddPrintProcessorW [WINSPOOL.@]
4664 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4665 LPWSTR pPrintProcessorName)
4667 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4668 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4672 /*****************************************************************************
4673 * AddPrintProvidorA [WINSPOOL.@]
4675 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4677 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4681 /*****************************************************************************
4682 * AddPrintProvidorW [WINSPOOL.@]
4684 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4686 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4690 /*****************************************************************************
4691 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4693 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4694 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4696 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4697 pDevModeOutput, pDevModeInput);
4701 /*****************************************************************************
4702 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4704 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4705 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4707 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4708 pDevModeOutput, pDevModeInput);
4712 /*****************************************************************************
4713 * PrinterProperties [WINSPOOL.@]
4715 * Displays a dialog to set the properties of the printer.
4718 * nonzero on success or zero on failure
4721 * implemented as stub only
4723 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4724 HANDLE hPrinter /* [in] handle to printer object */
4726 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4727 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4731 /*****************************************************************************
4732 * EnumJobsA [WINSPOOL.@]
4735 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4736 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4739 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4740 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4742 if(pcbNeeded) *pcbNeeded = 0;
4743 if(pcReturned) *pcReturned = 0;
4748 /*****************************************************************************
4749 * EnumJobsW [WINSPOOL.@]
4752 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4753 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4756 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4757 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4759 if(pcbNeeded) *pcbNeeded = 0;
4760 if(pcReturned) *pcReturned = 0;
4764 /*****************************************************************************
4765 * WINSPOOL_EnumPrinterDrivers [internal]
4767 * Delivers information about all printer drivers installed on the
4768 * localhost or a given server
4771 * nonzero on success or zero on failure. If the buffer for the returned
4772 * information is too small the function will return an error
4775 * - only implemented for localhost, foreign hosts will return an error
4777 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4778 DWORD Level, LPBYTE pDriverInfo,
4780 DWORD cbBuf, LPDWORD pcbNeeded,
4781 LPDWORD pcFound, DWORD data_offset)
4785 const printenv_t * env;
4787 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4788 debugstr_w(pName), debugstr_w(pEnvironment),
4789 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4791 env = validate_envW(pEnvironment);
4792 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4796 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4798 ERR("Can't open Drivers key\n");
4802 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4803 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4804 RegCloseKey(hkeyDrivers);
4805 ERR("Can't query Drivers key\n");
4808 TRACE("Found %d Drivers\n", *pcFound);
4810 /* get size of single struct
4811 * unicode and ascii structure have the same size
4813 size = di_sizeof[Level];
4815 if (data_offset == 0)
4816 data_offset = size * (*pcFound);
4817 *pcbNeeded = data_offset;
4819 for( i = 0; i < *pcFound; i++) {
4820 WCHAR DriverNameW[255];
4821 PBYTE table_ptr = NULL;
4822 PBYTE data_ptr = NULL;
4825 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4827 ERR("Can't enum key number %d\n", i);
4828 RegCloseKey(hkeyDrivers);
4832 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4833 table_ptr = pDriverInfo + (driver_index + i) * size;
4834 if (pDriverInfo && *pcbNeeded <= cbBuf)
4835 data_ptr = pDriverInfo + *pcbNeeded;
4837 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4838 env, Level, table_ptr, data_ptr,
4839 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4841 RegCloseKey(hkeyDrivers);
4845 *pcbNeeded += needed;
4848 RegCloseKey(hkeyDrivers);
4850 if(cbBuf < *pcbNeeded){
4851 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4858 /*****************************************************************************
4859 * EnumPrinterDriversW [WINSPOOL.@]
4861 * see function EnumPrinterDrivers for RETURNS, BUGS
4863 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4864 LPBYTE pDriverInfo, DWORD cbBuf,
4865 LPDWORD pcbNeeded, LPDWORD pcReturned)
4867 static const WCHAR allW[] = {'a','l','l',0};
4871 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4873 SetLastError(RPC_X_NULL_REF_POINTER);
4877 /* check for local drivers */
4878 if((pName) && (pName[0])) {
4879 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4880 SetLastError(ERROR_ACCESS_DENIED);
4884 /* check input parameter */
4885 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4886 SetLastError(ERROR_INVALID_LEVEL);
4890 if(pDriverInfo && cbBuf > 0)
4891 memset( pDriverInfo, 0, cbBuf);
4893 /* Exception: pull all printers */
4894 if (pEnvironment && !strcmpW(pEnvironment, allW))
4896 DWORD i, needed, bufsize = cbBuf;
4897 DWORD total_needed = 0;
4898 DWORD total_found = 0;
4901 /* Precompute the overall total; we need this to know
4902 where pointers end and data begins (i.e. data_offset) */
4903 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4906 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4907 NULL, 0, 0, &needed, &found, 0);
4908 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4909 total_needed += needed;
4910 total_found += found;
4913 data_offset = di_sizeof[Level] * total_found;
4918 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4921 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4922 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4923 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4925 *pcReturned += found;
4926 *pcbNeeded = needed;
4927 data_offset = needed;
4928 total_found += found;
4933 /* Normal behavior */
4934 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4935 0, cbBuf, pcbNeeded, &found, 0);
4937 *pcReturned = found;
4942 /*****************************************************************************
4943 * EnumPrinterDriversA [WINSPOOL.@]
4945 * see function EnumPrinterDrivers for RETURNS, BUGS
4947 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4948 LPBYTE pDriverInfo, DWORD cbBuf,
4949 LPDWORD pcbNeeded, LPDWORD pcReturned)
4952 UNICODE_STRING pNameW, pEnvironmentW;
4953 PWSTR pwstrNameW, pwstrEnvironmentW;
4957 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4959 pwstrNameW = asciitounicode(&pNameW, pName);
4960 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4962 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4963 buf, cbBuf, pcbNeeded, pcReturned);
4965 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4967 HeapFree(GetProcessHeap(), 0, buf);
4969 RtlFreeUnicodeString(&pNameW);
4970 RtlFreeUnicodeString(&pEnvironmentW);
4975 /******************************************************************************
4976 * EnumPortsA (WINSPOOL.@)
4981 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4982 LPDWORD pcbNeeded, LPDWORD pcReturned)
4985 LPBYTE bufferW = NULL;
4986 LPWSTR nameW = NULL;
4988 DWORD numentries = 0;
4991 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4992 cbBuf, pcbNeeded, pcReturned);
4994 /* convert servername to unicode */
4996 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4997 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4998 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5000 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5001 needed = cbBuf * sizeof(WCHAR);
5002 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5003 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5005 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5006 if (pcbNeeded) needed = *pcbNeeded;
5007 /* HeapReAlloc return NULL, when bufferW was NULL */
5008 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5009 HeapAlloc(GetProcessHeap(), 0, needed);
5011 /* Try again with the large Buffer */
5012 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5014 needed = pcbNeeded ? *pcbNeeded : 0;
5015 numentries = pcReturned ? *pcReturned : 0;
5018 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5019 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5022 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5023 DWORD entrysize = 0;
5026 LPPORT_INFO_2W pi2w;
5027 LPPORT_INFO_2A pi2a;
5030 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5032 /* First pass: calculate the size for all Entries */
5033 pi2w = (LPPORT_INFO_2W) bufferW;
5034 pi2a = (LPPORT_INFO_2A) pPorts;
5036 while (index < numentries) {
5038 needed += entrysize; /* PORT_INFO_?A */
5039 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5041 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5042 NULL, 0, NULL, NULL);
5044 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5045 NULL, 0, NULL, NULL);
5046 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5047 NULL, 0, NULL, NULL);
5049 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5050 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5051 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5054 /* check for errors and quit on failure */
5055 if (cbBuf < needed) {
5056 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5060 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5061 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5062 cbBuf -= len ; /* free Bytes in the user-Buffer */
5063 pi2w = (LPPORT_INFO_2W) bufferW;
5064 pi2a = (LPPORT_INFO_2A) pPorts;
5066 /* Second Pass: Fill the User Buffer (if we have one) */
5067 while ((index < numentries) && pPorts) {
5069 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5070 pi2a->pPortName = ptr;
5071 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5072 ptr, cbBuf , NULL, NULL);
5076 pi2a->pMonitorName = ptr;
5077 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5078 ptr, cbBuf, NULL, NULL);
5082 pi2a->pDescription = ptr;
5083 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5084 ptr, cbBuf, NULL, NULL);
5088 pi2a->fPortType = pi2w->fPortType;
5089 pi2a->Reserved = 0; /* documented: "must be zero" */
5092 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5093 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5094 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5099 if (pcbNeeded) *pcbNeeded = needed;
5100 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5102 HeapFree(GetProcessHeap(), 0, nameW);
5103 HeapFree(GetProcessHeap(), 0, bufferW);
5105 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5106 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5112 /******************************************************************************
5113 * EnumPortsW (WINSPOOL.@)
5115 * Enumerate available Ports
5118 * pName [I] Servername or NULL (local Computer)
5119 * Level [I] Structure-Level (1 or 2)
5120 * pPorts [O] PTR to Buffer that receives the Result
5121 * cbBuf [I] Size of Buffer at pPorts
5122 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5123 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5127 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5130 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5133 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5134 cbBuf, pcbNeeded, pcReturned);
5136 if ((backend == NULL) && !load_backend()) return FALSE;
5138 /* Level is not checked in win9x */
5139 if (!Level || (Level > 2)) {
5140 WARN("level (%d) is ignored in win9x\n", Level);
5141 SetLastError(ERROR_INVALID_LEVEL);
5144 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5145 SetLastError(RPC_X_NULL_REF_POINTER);
5149 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5152 /******************************************************************************
5153 * GetDefaultPrinterW (WINSPOOL.@)
5156 * This function must read the value from data 'device' of key
5157 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5159 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5163 WCHAR *buffer, *ptr;
5167 SetLastError(ERROR_INVALID_PARAMETER);
5171 /* make the buffer big enough for the stuff from the profile/registry,
5172 * the content must fit into the local buffer to compute the correct
5173 * size even if the extern buffer is too small or not given.
5174 * (20 for ,driver,port) */
5176 len = max(100, (insize + 20));
5177 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5179 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5181 SetLastError (ERROR_FILE_NOT_FOUND);
5185 TRACE("%s\n", debugstr_w(buffer));
5187 if ((ptr = strchrW(buffer, ',')) == NULL)
5189 SetLastError(ERROR_INVALID_NAME);
5195 *namesize = strlenW(buffer) + 1;
5196 if(!name || (*namesize > insize))
5198 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5202 strcpyW(name, buffer);
5205 HeapFree( GetProcessHeap(), 0, buffer);
5210 /******************************************************************************
5211 * GetDefaultPrinterA (WINSPOOL.@)
5213 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5217 WCHAR *bufferW = NULL;
5221 SetLastError(ERROR_INVALID_PARAMETER);
5225 if(name && *namesize) {
5227 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5230 if(!GetDefaultPrinterW( bufferW, namesize)) {
5235 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5239 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5242 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5245 HeapFree( GetProcessHeap(), 0, bufferW);
5250 /******************************************************************************
5251 * SetDefaultPrinterW (WINSPOOL.204)
5253 * Set the Name of the Default Printer
5256 * pszPrinter [I] Name of the Printer or NULL
5263 * When the Parameter is NULL or points to an Empty String and
5264 * a Default Printer was already present, then this Function changes nothing.
5265 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5266 * the First enumerated local Printer is used.
5269 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5271 WCHAR default_printer[MAX_PATH];
5272 LPWSTR buffer = NULL;
5278 TRACE("(%s)\n", debugstr_w(pszPrinter));
5279 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5281 default_printer[0] = '\0';
5282 size = sizeof(default_printer)/sizeof(WCHAR);
5284 /* if we have a default Printer, do nothing. */
5285 if (GetDefaultPrinterW(default_printer, &size))
5289 /* we have no default Printer: search local Printers and use the first */
5290 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5292 default_printer[0] = '\0';
5293 size = sizeof(default_printer)/sizeof(WCHAR);
5294 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5296 pszPrinter = default_printer;
5297 TRACE("using %s\n", debugstr_w(pszPrinter));
5302 if (pszPrinter == NULL) {
5303 TRACE("no local printer found\n");
5304 SetLastError(ERROR_FILE_NOT_FOUND);
5309 /* "pszPrinter" is never empty or NULL here. */
5310 namelen = lstrlenW(pszPrinter);
5311 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5312 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5314 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5315 HeapFree(GetProcessHeap(), 0, buffer);
5316 SetLastError(ERROR_FILE_NOT_FOUND);
5320 /* read the devices entry for the printer (driver,port) to build the string for the
5321 default device entry (printer,driver,port) */
5322 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5323 buffer[namelen] = ',';
5324 namelen++; /* move index to the start of the driver */
5326 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5327 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5329 TRACE("set device to %s\n", debugstr_w(buffer));
5331 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5332 TRACE("failed to set the device entry: %d\n", GetLastError());
5333 lres = ERROR_INVALID_PRINTER_NAME;
5336 /* remove the next section, when INIFileMapping is implemented */
5339 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5340 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5347 if (lres != ERROR_FILE_NOT_FOUND)
5348 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5350 SetLastError(ERROR_INVALID_PRINTER_NAME);
5354 HeapFree(GetProcessHeap(), 0, buffer);
5355 return (lres == ERROR_SUCCESS);
5358 /******************************************************************************
5359 * SetDefaultPrinterA (WINSPOOL.202)
5361 * See SetDefaultPrinterW.
5364 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5366 LPWSTR bufferW = NULL;
5369 TRACE("(%s)\n", debugstr_a(pszPrinter));
5371 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5372 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5373 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5375 res = SetDefaultPrinterW(bufferW);
5376 HeapFree(GetProcessHeap(), 0, bufferW);
5380 /******************************************************************************
5381 * SetPrinterDataExA (WINSPOOL.@)
5383 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5384 LPCSTR pValueName, DWORD Type,
5385 LPBYTE pData, DWORD cbData)
5387 HKEY hkeyPrinter, hkeySubkey;
5390 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5391 debugstr_a(pValueName), Type, pData, cbData);
5393 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5397 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5399 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5400 RegCloseKey(hkeyPrinter);
5403 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5404 RegCloseKey(hkeySubkey);
5405 RegCloseKey(hkeyPrinter);
5409 /******************************************************************************
5410 * SetPrinterDataExW (WINSPOOL.@)
5412 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5413 LPCWSTR pValueName, DWORD Type,
5414 LPBYTE pData, DWORD cbData)
5416 HKEY hkeyPrinter, hkeySubkey;
5419 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5420 debugstr_w(pValueName), Type, pData, cbData);
5422 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5426 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5428 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5429 RegCloseKey(hkeyPrinter);
5432 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5433 RegCloseKey(hkeySubkey);
5434 RegCloseKey(hkeyPrinter);
5438 /******************************************************************************
5439 * SetPrinterDataA (WINSPOOL.@)
5441 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5442 LPBYTE pData, DWORD cbData)
5444 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5448 /******************************************************************************
5449 * SetPrinterDataW (WINSPOOL.@)
5451 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5452 LPBYTE pData, DWORD cbData)
5454 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5458 /******************************************************************************
5459 * GetPrinterDataExA (WINSPOOL.@)
5461 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5462 LPCSTR pValueName, LPDWORD pType,
5463 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5465 opened_printer_t *printer;
5466 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5469 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5470 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5472 printer = get_opened_printer(hPrinter);
5473 if(!printer) return ERROR_INVALID_HANDLE;
5475 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5476 if (ret) return ret;
5478 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5480 if (printer->name) {
5482 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5484 RegCloseKey(hkeyPrinters);
5487 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5488 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5489 RegCloseKey(hkeyPrinter);
5490 RegCloseKey(hkeyPrinters);
5495 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5496 0, pType, pData, pcbNeeded);
5498 if (!ret && !pData) ret = ERROR_MORE_DATA;
5500 RegCloseKey(hkeySubkey);
5501 RegCloseKey(hkeyPrinter);
5502 RegCloseKey(hkeyPrinters);
5504 TRACE("--> %d\n", ret);
5508 /******************************************************************************
5509 * GetPrinterDataExW (WINSPOOL.@)
5511 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5512 LPCWSTR pValueName, LPDWORD pType,
5513 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5515 opened_printer_t *printer;
5516 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5519 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5520 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5522 printer = get_opened_printer(hPrinter);
5523 if(!printer) return ERROR_INVALID_HANDLE;
5525 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5526 if (ret) return ret;
5528 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5530 if (printer->name) {
5532 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5534 RegCloseKey(hkeyPrinters);
5537 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5538 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5539 RegCloseKey(hkeyPrinter);
5540 RegCloseKey(hkeyPrinters);
5545 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5546 0, pType, pData, pcbNeeded);
5548 if (!ret && !pData) ret = ERROR_MORE_DATA;
5550 RegCloseKey(hkeySubkey);
5551 RegCloseKey(hkeyPrinter);
5552 RegCloseKey(hkeyPrinters);
5554 TRACE("--> %d\n", ret);
5558 /******************************************************************************
5559 * GetPrinterDataA (WINSPOOL.@)
5561 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5562 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5564 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5565 pData, nSize, pcbNeeded);
5568 /******************************************************************************
5569 * GetPrinterDataW (WINSPOOL.@)
5571 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5572 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5574 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5575 pData, nSize, pcbNeeded);
5578 /*******************************************************************************
5579 * EnumPrinterDataExW [WINSPOOL.@]
5581 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5582 LPBYTE pEnumValues, DWORD cbEnumValues,
5583 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5585 HKEY hkPrinter, hkSubKey;
5586 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5587 cbValueNameLen, cbMaxValueLen, cbValueLen,
5592 PPRINTER_ENUM_VALUESW ppev;
5594 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5596 if (pKeyName == NULL || *pKeyName == 0)
5597 return ERROR_INVALID_PARAMETER;
5599 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5600 if (ret != ERROR_SUCCESS)
5602 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5607 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5608 if (ret != ERROR_SUCCESS)
5610 r = RegCloseKey (hkPrinter);
5611 if (r != ERROR_SUCCESS)
5612 WARN ("RegCloseKey returned %i\n", r);
5613 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5614 debugstr_w (pKeyName), ret);
5618 ret = RegCloseKey (hkPrinter);
5619 if (ret != ERROR_SUCCESS)
5621 ERR ("RegCloseKey returned %i\n", ret);
5622 r = RegCloseKey (hkSubKey);
5623 if (r != ERROR_SUCCESS)
5624 WARN ("RegCloseKey returned %i\n", r);
5628 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5629 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5630 if (ret != ERROR_SUCCESS)
5632 r = RegCloseKey (hkSubKey);
5633 if (r != ERROR_SUCCESS)
5634 WARN ("RegCloseKey returned %i\n", r);
5635 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5639 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5640 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5642 if (cValues == 0) /* empty key */
5644 r = RegCloseKey (hkSubKey);
5645 if (r != ERROR_SUCCESS)
5646 WARN ("RegCloseKey returned %i\n", r);
5647 *pcbEnumValues = *pnEnumValues = 0;
5648 return ERROR_SUCCESS;
5651 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5653 hHeap = GetProcessHeap ();
5656 ERR ("GetProcessHeap failed\n");
5657 r = RegCloseKey (hkSubKey);
5658 if (r != ERROR_SUCCESS)
5659 WARN ("RegCloseKey returned %i\n", r);
5660 return ERROR_OUTOFMEMORY;
5663 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5664 if (lpValueName == NULL)
5666 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5667 r = RegCloseKey (hkSubKey);
5668 if (r != ERROR_SUCCESS)
5669 WARN ("RegCloseKey returned %i\n", r);
5670 return ERROR_OUTOFMEMORY;
5673 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5674 if (lpValue == NULL)
5676 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5677 if (HeapFree (hHeap, 0, lpValueName) == 0)
5678 WARN ("HeapFree failed with code %i\n", GetLastError ());
5679 r = RegCloseKey (hkSubKey);
5680 if (r != ERROR_SUCCESS)
5681 WARN ("RegCloseKey returned %i\n", r);
5682 return ERROR_OUTOFMEMORY;
5685 TRACE ("pass 1: calculating buffer required for all names and values\n");
5687 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5689 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5691 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5693 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5694 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5695 NULL, NULL, lpValue, &cbValueLen);
5696 if (ret != ERROR_SUCCESS)
5698 if (HeapFree (hHeap, 0, lpValue) == 0)
5699 WARN ("HeapFree failed with code %i\n", GetLastError ());
5700 if (HeapFree (hHeap, 0, lpValueName) == 0)
5701 WARN ("HeapFree failed with code %i\n", GetLastError ());
5702 r = RegCloseKey (hkSubKey);
5703 if (r != ERROR_SUCCESS)
5704 WARN ("RegCloseKey returned %i\n", r);
5705 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5709 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5710 debugstr_w (lpValueName), dwIndex,
5711 cbValueNameLen + 1, cbValueLen);
5713 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5714 cbBufSize += cbValueLen;
5717 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5719 *pcbEnumValues = cbBufSize;
5720 *pnEnumValues = cValues;
5722 if (cbEnumValues < cbBufSize) /* buffer too small */
5724 if (HeapFree (hHeap, 0, lpValue) == 0)
5725 WARN ("HeapFree failed with code %i\n", GetLastError ());
5726 if (HeapFree (hHeap, 0, lpValueName) == 0)
5727 WARN ("HeapFree failed with code %i\n", GetLastError ());
5728 r = RegCloseKey (hkSubKey);
5729 if (r != ERROR_SUCCESS)
5730 WARN ("RegCloseKey returned %i\n", r);
5731 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5732 return ERROR_MORE_DATA;
5735 TRACE ("pass 2: copying all names and values to buffer\n");
5737 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5738 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5740 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5742 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5743 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5744 NULL, &dwType, lpValue, &cbValueLen);
5745 if (ret != ERROR_SUCCESS)
5747 if (HeapFree (hHeap, 0, lpValue) == 0)
5748 WARN ("HeapFree failed with code %i\n", GetLastError ());
5749 if (HeapFree (hHeap, 0, lpValueName) == 0)
5750 WARN ("HeapFree failed with code %i\n", GetLastError ());
5751 r = RegCloseKey (hkSubKey);
5752 if (r != ERROR_SUCCESS)
5753 WARN ("RegCloseKey returned %i\n", r);
5754 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5758 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5759 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5760 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5761 pEnumValues += cbValueNameLen;
5763 /* return # of *bytes* (including trailing \0), not # of chars */
5764 ppev[dwIndex].cbValueName = cbValueNameLen;
5766 ppev[dwIndex].dwType = dwType;
5768 memcpy (pEnumValues, lpValue, cbValueLen);
5769 ppev[dwIndex].pData = pEnumValues;
5770 pEnumValues += cbValueLen;
5772 ppev[dwIndex].cbData = cbValueLen;
5774 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5775 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5778 if (HeapFree (hHeap, 0, lpValue) == 0)
5780 ret = GetLastError ();
5781 ERR ("HeapFree failed with code %i\n", ret);
5782 if (HeapFree (hHeap, 0, lpValueName) == 0)
5783 WARN ("HeapFree failed with code %i\n", GetLastError ());
5784 r = RegCloseKey (hkSubKey);
5785 if (r != ERROR_SUCCESS)
5786 WARN ("RegCloseKey returned %i\n", r);
5790 if (HeapFree (hHeap, 0, lpValueName) == 0)
5792 ret = GetLastError ();
5793 ERR ("HeapFree failed with code %i\n", ret);
5794 r = RegCloseKey (hkSubKey);
5795 if (r != ERROR_SUCCESS)
5796 WARN ("RegCloseKey returned %i\n", r);
5800 ret = RegCloseKey (hkSubKey);
5801 if (ret != ERROR_SUCCESS)
5803 ERR ("RegCloseKey returned %i\n", ret);
5807 return ERROR_SUCCESS;
5810 /*******************************************************************************
5811 * EnumPrinterDataExA [WINSPOOL.@]
5813 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5814 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5815 * what Windows 2000 SP1 does.
5818 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5819 LPBYTE pEnumValues, DWORD cbEnumValues,
5820 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5824 DWORD ret, dwIndex, dwBufSize;
5828 TRACE ("%p %s\n", hPrinter, pKeyName);
5830 if (pKeyName == NULL || *pKeyName == 0)
5831 return ERROR_INVALID_PARAMETER;
5833 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5836 ret = GetLastError ();
5837 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5841 hHeap = GetProcessHeap ();
5844 ERR ("GetProcessHeap failed\n");
5845 return ERROR_OUTOFMEMORY;
5848 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5849 if (pKeyNameW == NULL)
5851 ERR ("Failed to allocate %i bytes from process heap\n",
5852 (LONG)(len * sizeof (WCHAR)));
5853 return ERROR_OUTOFMEMORY;
5856 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5858 ret = GetLastError ();
5859 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5860 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5861 WARN ("HeapFree failed with code %i\n", GetLastError ());
5865 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5866 pcbEnumValues, pnEnumValues);
5867 if (ret != ERROR_SUCCESS)
5869 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5870 WARN ("HeapFree failed with code %i\n", GetLastError ());
5871 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5875 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5877 ret = GetLastError ();
5878 ERR ("HeapFree failed with code %i\n", ret);
5882 if (*pnEnumValues == 0) /* empty key */
5883 return ERROR_SUCCESS;
5886 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5888 PPRINTER_ENUM_VALUESW ppev =
5889 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5891 if (dwBufSize < ppev->cbValueName)
5892 dwBufSize = ppev->cbValueName;
5894 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5895 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5896 dwBufSize = ppev->cbData;
5899 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5901 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5902 if (pBuffer == NULL)
5904 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5905 return ERROR_OUTOFMEMORY;
5908 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5910 PPRINTER_ENUM_VALUESW ppev =
5911 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5913 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5914 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5918 ret = GetLastError ();
5919 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5920 if (HeapFree (hHeap, 0, pBuffer) == 0)
5921 WARN ("HeapFree failed with code %i\n", GetLastError ());
5925 memcpy (ppev->pValueName, pBuffer, len);
5927 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5929 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5930 ppev->dwType != REG_MULTI_SZ)
5933 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5934 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5937 ret = GetLastError ();
5938 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5939 if (HeapFree (hHeap, 0, pBuffer) == 0)
5940 WARN ("HeapFree failed with code %i\n", GetLastError ());
5944 memcpy (ppev->pData, pBuffer, len);
5946 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5947 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5950 if (HeapFree (hHeap, 0, pBuffer) == 0)
5952 ret = GetLastError ();
5953 ERR ("HeapFree failed with code %i\n", ret);
5957 return ERROR_SUCCESS;
5960 /******************************************************************************
5961 * AbortPrinter (WINSPOOL.@)
5963 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5965 FIXME("(%p), stub!\n", hPrinter);
5969 /******************************************************************************
5970 * AddPortA (WINSPOOL.@)
5975 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5977 LPWSTR nameW = NULL;
5978 LPWSTR monitorW = NULL;
5982 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5985 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5986 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5987 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5991 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5992 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5993 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5995 res = AddPortW(nameW, hWnd, monitorW);
5996 HeapFree(GetProcessHeap(), 0, nameW);
5997 HeapFree(GetProcessHeap(), 0, monitorW);
6001 /******************************************************************************
6002 * AddPortW (WINSPOOL.@)
6004 * Add a Port for a specific Monitor
6007 * pName [I] Servername or NULL (local Computer)
6008 * hWnd [I] Handle to parent Window for the Dialog-Box
6009 * pMonitorName [I] Name of the Monitor that manage the Port
6016 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6018 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6020 if ((backend == NULL) && !load_backend()) return FALSE;
6022 if (!pMonitorName) {
6023 SetLastError(RPC_X_NULL_REF_POINTER);
6027 return backend->fpAddPort(pName, hWnd, pMonitorName);
6030 /******************************************************************************
6031 * AddPortExA (WINSPOOL.@)
6036 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6039 PORT_INFO_2A * pi2A;
6040 LPWSTR nameW = NULL;
6041 LPWSTR monitorW = NULL;
6045 pi2A = (PORT_INFO_2A *) pBuffer;
6047 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6048 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6050 if ((level < 1) || (level > 2)) {
6051 SetLastError(ERROR_INVALID_LEVEL);
6056 SetLastError(ERROR_INVALID_PARAMETER);
6061 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6062 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6063 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6067 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6068 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6069 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6072 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6074 if (pi2A->pPortName) {
6075 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6076 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6077 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6081 if (pi2A->pMonitorName) {
6082 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6083 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6084 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6087 if (pi2A->pDescription) {
6088 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6089 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6090 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6092 pi2W.fPortType = pi2A->fPortType;
6093 pi2W.Reserved = pi2A->Reserved;
6096 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6098 HeapFree(GetProcessHeap(), 0, nameW);
6099 HeapFree(GetProcessHeap(), 0, monitorW);
6100 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6101 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6102 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6107 /******************************************************************************
6108 * AddPortExW (WINSPOOL.@)
6110 * Add a Port for a specific Monitor, without presenting a user interface
6113 * pName [I] Servername or NULL (local Computer)
6114 * level [I] Structure-Level (1 or 2) for pBuffer
6115 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6116 * pMonitorName [I] Name of the Monitor that manage the Port
6123 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6127 pi2 = (PORT_INFO_2W *) pBuffer;
6129 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6130 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6131 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6132 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6134 if ((backend == NULL) && !load_backend()) return FALSE;
6136 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6137 SetLastError(ERROR_INVALID_PARAMETER);
6141 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6144 /******************************************************************************
6145 * AddPrinterConnectionA (WINSPOOL.@)
6147 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6149 FIXME("%s\n", debugstr_a(pName));
6153 /******************************************************************************
6154 * AddPrinterConnectionW (WINSPOOL.@)
6156 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6158 FIXME("%s\n", debugstr_w(pName));
6162 /******************************************************************************
6163 * AddPrinterDriverExW (WINSPOOL.@)
6165 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6168 * pName [I] Servername or NULL (local Computer)
6169 * level [I] Level for the supplied DRIVER_INFO_*W struct
6170 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6171 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6178 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6180 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6182 if ((backend == NULL) && !load_backend()) return FALSE;
6184 if (level < 2 || level == 5 || level == 7 || level > 8) {
6185 SetLastError(ERROR_INVALID_LEVEL);
6190 SetLastError(ERROR_INVALID_PARAMETER);
6194 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6197 /******************************************************************************
6198 * AddPrinterDriverExA (WINSPOOL.@)
6200 * See AddPrinterDriverExW.
6203 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6205 DRIVER_INFO_8A *diA;
6207 LPWSTR nameW = NULL;
6212 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6214 diA = (DRIVER_INFO_8A *) pDriverInfo;
6215 ZeroMemory(&diW, sizeof(diW));
6217 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6218 SetLastError(ERROR_INVALID_LEVEL);
6223 SetLastError(ERROR_INVALID_PARAMETER);
6227 /* convert servername to unicode */
6229 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6230 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6231 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6235 diW.cVersion = diA->cVersion;
6238 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6239 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6240 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6243 if (diA->pEnvironment) {
6244 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6245 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6246 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6249 if (diA->pDriverPath) {
6250 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6251 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6252 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6255 if (diA->pDataFile) {
6256 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6257 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6258 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6261 if (diA->pConfigFile) {
6262 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6263 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6264 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6267 if ((Level > 2) && diA->pDependentFiles) {
6268 lenA = multi_sz_lenA(diA->pDependentFiles);
6269 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6270 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6271 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6274 if ((Level > 2) && diA->pMonitorName) {
6275 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6276 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6277 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6280 if ((Level > 3) && diA->pDefaultDataType) {
6281 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6282 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6283 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6286 if ((Level > 3) && diA->pszzPreviousNames) {
6287 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6288 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6289 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6290 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6293 if ((Level > 5) && diA->pszMfgName) {
6294 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6295 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6296 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6299 if ((Level > 5) && diA->pszOEMUrl) {
6300 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6301 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6302 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6305 if ((Level > 5) && diA->pszHardwareID) {
6306 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6307 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6308 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6311 if ((Level > 5) && diA->pszProvider) {
6312 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6313 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6314 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6318 FIXME("level %u is incomplete\n", Level);
6321 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6322 TRACE("got %u with %u\n", res, GetLastError());
6323 HeapFree(GetProcessHeap(), 0, nameW);
6324 HeapFree(GetProcessHeap(), 0, diW.pName);
6325 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6326 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6327 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6328 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6329 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6330 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6331 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6332 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6333 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6334 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6335 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6336 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6338 TRACE("=> %u with %u\n", res, GetLastError());
6342 /******************************************************************************
6343 * ConfigurePortA (WINSPOOL.@)
6345 * See ConfigurePortW.
6348 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6350 LPWSTR nameW = NULL;
6351 LPWSTR portW = NULL;
6355 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6357 /* convert servername to unicode */
6359 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6360 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6361 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6364 /* convert portname to unicode */
6366 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6367 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6368 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6371 res = ConfigurePortW(nameW, hWnd, portW);
6372 HeapFree(GetProcessHeap(), 0, nameW);
6373 HeapFree(GetProcessHeap(), 0, portW);
6377 /******************************************************************************
6378 * ConfigurePortW (WINSPOOL.@)
6380 * Display the Configuration-Dialog for a specific Port
6383 * pName [I] Servername or NULL (local Computer)
6384 * hWnd [I] Handle to parent Window for the Dialog-Box
6385 * pPortName [I] Name of the Port, that should be configured
6392 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6395 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6397 if ((backend == NULL) && !load_backend()) return FALSE;
6400 SetLastError(RPC_X_NULL_REF_POINTER);
6404 return backend->fpConfigurePort(pName, hWnd, pPortName);
6407 /******************************************************************************
6408 * ConnectToPrinterDlg (WINSPOOL.@)
6410 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6412 FIXME("%p %x\n", hWnd, Flags);
6416 /******************************************************************************
6417 * DeletePrinterConnectionA (WINSPOOL.@)
6419 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6421 FIXME("%s\n", debugstr_a(pName));
6425 /******************************************************************************
6426 * DeletePrinterConnectionW (WINSPOOL.@)
6428 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6430 FIXME("%s\n", debugstr_w(pName));
6434 /******************************************************************************
6435 * DeletePrinterDriverExW (WINSPOOL.@)
6437 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6438 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6443 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6444 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6446 if(pName && pName[0])
6448 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6449 SetLastError(ERROR_INVALID_PARAMETER);
6455 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6456 SetLastError(ERROR_INVALID_PARAMETER);
6460 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6464 ERR("Can't open drivers key\n");
6468 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6471 RegCloseKey(hkey_drivers);
6476 /******************************************************************************
6477 * DeletePrinterDriverExA (WINSPOOL.@)
6479 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6480 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6482 UNICODE_STRING NameW, EnvW, DriverW;
6485 asciitounicode(&NameW, pName);
6486 asciitounicode(&EnvW, pEnvironment);
6487 asciitounicode(&DriverW, pDriverName);
6489 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6491 RtlFreeUnicodeString(&DriverW);
6492 RtlFreeUnicodeString(&EnvW);
6493 RtlFreeUnicodeString(&NameW);
6498 /******************************************************************************
6499 * DeletePrinterDataExW (WINSPOOL.@)
6501 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6504 FIXME("%p %s %s\n", hPrinter,
6505 debugstr_w(pKeyName), debugstr_w(pValueName));
6506 return ERROR_INVALID_PARAMETER;
6509 /******************************************************************************
6510 * DeletePrinterDataExA (WINSPOOL.@)
6512 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6515 FIXME("%p %s %s\n", hPrinter,
6516 debugstr_a(pKeyName), debugstr_a(pValueName));
6517 return ERROR_INVALID_PARAMETER;
6520 /******************************************************************************
6521 * DeletePrintProcessorA (WINSPOOL.@)
6523 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6525 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6526 debugstr_a(pPrintProcessorName));
6530 /******************************************************************************
6531 * DeletePrintProcessorW (WINSPOOL.@)
6533 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6535 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6536 debugstr_w(pPrintProcessorName));
6540 /******************************************************************************
6541 * DeletePrintProvidorA (WINSPOOL.@)
6543 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6545 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6546 debugstr_a(pPrintProviderName));
6550 /******************************************************************************
6551 * DeletePrintProvidorW (WINSPOOL.@)
6553 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6555 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6556 debugstr_w(pPrintProviderName));
6560 /******************************************************************************
6561 * EnumFormsA (WINSPOOL.@)
6563 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6564 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6566 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6567 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6571 /******************************************************************************
6572 * EnumFormsW (WINSPOOL.@)
6574 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6575 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6577 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6578 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6582 /*****************************************************************************
6583 * EnumMonitorsA [WINSPOOL.@]
6585 * See EnumMonitorsW.
6588 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6589 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6592 LPBYTE bufferW = NULL;
6593 LPWSTR nameW = NULL;
6595 DWORD numentries = 0;
6598 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6599 cbBuf, pcbNeeded, pcReturned);
6601 /* convert servername to unicode */
6603 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6604 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6605 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6607 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6608 needed = cbBuf * sizeof(WCHAR);
6609 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6610 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6612 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6613 if (pcbNeeded) needed = *pcbNeeded;
6614 /* HeapReAlloc return NULL, when bufferW was NULL */
6615 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6616 HeapAlloc(GetProcessHeap(), 0, needed);
6618 /* Try again with the large Buffer */
6619 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6621 numentries = pcReturned ? *pcReturned : 0;
6624 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6625 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6628 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6629 DWORD entrysize = 0;
6632 LPMONITOR_INFO_2W mi2w;
6633 LPMONITOR_INFO_2A mi2a;
6635 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6636 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6638 /* First pass: calculate the size for all Entries */
6639 mi2w = (LPMONITOR_INFO_2W) bufferW;
6640 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6642 while (index < numentries) {
6644 needed += entrysize; /* MONITOR_INFO_?A */
6645 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6647 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6648 NULL, 0, NULL, NULL);
6650 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6651 NULL, 0, NULL, NULL);
6652 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6653 NULL, 0, NULL, NULL);
6655 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6656 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6657 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6660 /* check for errors and quit on failure */
6661 if (cbBuf < needed) {
6662 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6666 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6667 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6668 cbBuf -= len ; /* free Bytes in the user-Buffer */
6669 mi2w = (LPMONITOR_INFO_2W) bufferW;
6670 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6672 /* Second Pass: Fill the User Buffer (if we have one) */
6673 while ((index < numentries) && pMonitors) {
6675 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6677 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6678 ptr, cbBuf , NULL, NULL);
6682 mi2a->pEnvironment = ptr;
6683 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6684 ptr, cbBuf, NULL, NULL);
6688 mi2a->pDLLName = ptr;
6689 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6690 ptr, cbBuf, NULL, NULL);
6694 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6695 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6696 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6700 if (pcbNeeded) *pcbNeeded = needed;
6701 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6703 HeapFree(GetProcessHeap(), 0, nameW);
6704 HeapFree(GetProcessHeap(), 0, bufferW);
6706 TRACE("returning %d with %d (%d byte for %d entries)\n",
6707 (res), GetLastError(), needed, numentries);
6713 /*****************************************************************************
6714 * EnumMonitorsW [WINSPOOL.@]
6716 * Enumerate available Port-Monitors
6719 * pName [I] Servername or NULL (local Computer)
6720 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6721 * pMonitors [O] PTR to Buffer that receives the Result
6722 * cbBuf [I] Size of Buffer at pMonitors
6723 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6724 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6728 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6731 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6732 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6735 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6736 cbBuf, pcbNeeded, pcReturned);
6738 if ((backend == NULL) && !load_backend()) return FALSE;
6740 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6741 SetLastError(RPC_X_NULL_REF_POINTER);
6745 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6748 /******************************************************************************
6749 * SpoolerInit (WINSPOOL.@)
6751 * Initialize the Spooler
6758 * The function fails on windows, when the spooler service is not running
6761 BOOL WINAPI SpoolerInit(void)
6764 if ((backend == NULL) && !load_backend()) return FALSE;
6768 /******************************************************************************
6769 * XcvDataW (WINSPOOL.@)
6771 * Execute commands in the Printmonitor DLL
6774 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6775 * pszDataName [i] Name of the command to execute
6776 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6777 * cbInputData [i] Size in Bytes of Buffer at pInputData
6778 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6779 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6780 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6781 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6788 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6789 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6791 * Minimal List of commands, that a Printmonitor DLL should support:
6793 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6794 *| "AddPort" : Add a Port
6795 *| "DeletePort": Delete a Port
6797 * Many Printmonitors support additional commands. Examples for localspl.dll:
6798 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6799 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6802 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6803 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6804 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6806 opened_printer_t *printer;
6808 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6809 pInputData, cbInputData, pOutputData,
6810 cbOutputData, pcbOutputNeeded, pdwStatus);
6812 if ((backend == NULL) && !load_backend()) return FALSE;
6814 printer = get_opened_printer(hXcv);
6815 if (!printer || (!printer->backend_printer)) {
6816 SetLastError(ERROR_INVALID_HANDLE);
6820 if (!pcbOutputNeeded) {
6821 SetLastError(ERROR_INVALID_PARAMETER);
6825 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6826 SetLastError(RPC_X_NULL_REF_POINTER);
6830 *pcbOutputNeeded = 0;
6832 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6833 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6837 /*****************************************************************************
6838 * EnumPrinterDataA [WINSPOOL.@]
6841 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6842 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6843 DWORD cbData, LPDWORD pcbData )
6845 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6846 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6847 return ERROR_NO_MORE_ITEMS;
6850 /*****************************************************************************
6851 * EnumPrinterDataW [WINSPOOL.@]
6854 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6855 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6856 DWORD cbData, LPDWORD pcbData )
6858 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6859 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6860 return ERROR_NO_MORE_ITEMS;
6863 /*****************************************************************************
6864 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6867 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6868 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6869 LPDWORD pcbNeeded, LPDWORD pcReturned)
6871 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6872 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6873 pcbNeeded, pcReturned);
6877 /*****************************************************************************
6878 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6881 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6882 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6883 LPDWORD pcbNeeded, LPDWORD pcReturned)
6885 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6886 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6887 pcbNeeded, pcReturned);
6891 /*****************************************************************************
6892 * EnumPrintProcessorsA [WINSPOOL.@]
6894 * See EnumPrintProcessorsW.
6897 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6898 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6901 LPBYTE bufferW = NULL;
6902 LPWSTR nameW = NULL;
6905 DWORD numentries = 0;
6908 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6909 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6911 /* convert names to unicode */
6913 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6914 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6915 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6918 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6919 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6923 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6924 needed = cbBuf * sizeof(WCHAR);
6925 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6926 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6928 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6929 if (pcbNeeded) needed = *pcbNeeded;
6930 /* HeapReAlloc return NULL, when bufferW was NULL */
6931 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6932 HeapAlloc(GetProcessHeap(), 0, needed);
6934 /* Try again with the large Buffer */
6935 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6937 numentries = pcReturned ? *pcReturned : 0;
6941 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6944 PPRINTPROCESSOR_INFO_1W ppiw;
6945 PPRINTPROCESSOR_INFO_1A ppia;
6947 /* First pass: calculate the size for all Entries */
6948 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6949 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6951 while (index < numentries) {
6953 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6954 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6956 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6957 NULL, 0, NULL, NULL);
6959 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6960 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6963 /* check for errors and quit on failure */
6964 if (cbBuf < needed) {
6965 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6970 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6971 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6972 cbBuf -= len ; /* free Bytes in the user-Buffer */
6973 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6974 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6976 /* Second Pass: Fill the User Buffer (if we have one) */
6977 while ((index < numentries) && pPPInfo) {
6979 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6981 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6982 ptr, cbBuf , NULL, NULL);
6986 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6987 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6992 if (pcbNeeded) *pcbNeeded = needed;
6993 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6995 HeapFree(GetProcessHeap(), 0, nameW);
6996 HeapFree(GetProcessHeap(), 0, envW);
6997 HeapFree(GetProcessHeap(), 0, bufferW);
6999 TRACE("returning %d with %d (%d byte for %d entries)\n",
7000 (res), GetLastError(), needed, numentries);
7005 /*****************************************************************************
7006 * EnumPrintProcessorsW [WINSPOOL.@]
7008 * Enumerate available Print Processors
7011 * pName [I] Servername or NULL (local Computer)
7012 * pEnvironment [I] Printing-Environment or NULL (Default)
7013 * Level [I] Structure-Level (Only 1 is allowed)
7014 * pPPInfo [O] PTR to Buffer that receives the Result
7015 * cbBuf [I] Size of Buffer at pPPInfo
7016 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7017 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7021 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7024 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7025 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7028 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7029 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7031 if ((backend == NULL) && !load_backend()) return FALSE;
7033 if (!pcbNeeded || !pcReturned) {
7034 SetLastError(RPC_X_NULL_REF_POINTER);
7038 if (!pPPInfo && (cbBuf > 0)) {
7039 SetLastError(ERROR_INVALID_USER_BUFFER);
7043 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7044 cbBuf, pcbNeeded, pcReturned);
7047 /*****************************************************************************
7048 * ExtDeviceMode [WINSPOOL.@]
7051 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7052 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7055 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7056 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7057 debugstr_a(pProfile), fMode);
7061 /*****************************************************************************
7062 * FindClosePrinterChangeNotification [WINSPOOL.@]
7065 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7067 FIXME("Stub: %p\n", hChange);
7071 /*****************************************************************************
7072 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7075 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7076 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7078 FIXME("Stub: %p %x %x %p\n",
7079 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7080 return INVALID_HANDLE_VALUE;
7083 /*****************************************************************************
7084 * FindNextPrinterChangeNotification [WINSPOOL.@]
7087 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7088 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7090 FIXME("Stub: %p %p %p %p\n",
7091 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7095 /*****************************************************************************
7096 * FreePrinterNotifyInfo [WINSPOOL.@]
7099 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7101 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7105 /*****************************************************************************
7108 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7109 * ansi depending on the unicode parameter.
7111 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7121 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7124 memcpy(ptr, str, *size);
7131 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7134 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7141 /*****************************************************************************
7144 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7145 LPDWORD pcbNeeded, BOOL unicode)
7147 DWORD size, left = cbBuf;
7148 BOOL space = (cbBuf > 0);
7155 ji1->JobId = job->job_id;
7158 string_to_buf(job->document_title, ptr, left, &size, unicode);
7159 if(space && size <= left)
7161 ji1->pDocument = (LPWSTR)ptr;
7169 if (job->printer_name)
7171 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7172 if(space && size <= left)
7174 ji1->pPrinterName = (LPWSTR)ptr;
7186 /*****************************************************************************
7189 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7190 LPDWORD pcbNeeded, BOOL unicode)
7192 DWORD size, left = cbBuf;
7194 BOOL space = (cbBuf > 0);
7203 ji2->JobId = job->job_id;
7206 string_to_buf(job->document_title, ptr, left, &size, unicode);
7207 if(space && size <= left)
7209 ji2->pDocument = (LPWSTR)ptr;
7217 if (job->printer_name)
7219 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7220 if(space && size <= left)
7222 ji2->pPrinterName = (LPWSTR)ptr;
7235 dmA = DEVMODEdupWtoA(job->devmode);
7236 devmode = (LPDEVMODEW) dmA;
7237 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7241 devmode = job->devmode;
7242 size = devmode->dmSize + devmode->dmDriverExtra;
7246 FIXME("Can't convert DEVMODE W to A\n");
7249 /* align DEVMODE to a DWORD boundary */
7250 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7256 memcpy(ptr, devmode, size-shift);
7257 ji2->pDevMode = (LPDEVMODEW)ptr;
7258 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7271 /*****************************************************************************
7274 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7275 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7278 DWORD needed = 0, size;
7282 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7284 EnterCriticalSection(&printer_handles_cs);
7285 job = get_job(hPrinter, JobId);
7292 size = sizeof(JOB_INFO_1W);
7297 memset(pJob, 0, size);
7301 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7306 size = sizeof(JOB_INFO_2W);
7311 memset(pJob, 0, size);
7315 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7320 size = sizeof(JOB_INFO_3);
7324 memset(pJob, 0, size);
7333 SetLastError(ERROR_INVALID_LEVEL);
7337 *pcbNeeded = needed;
7339 LeaveCriticalSection(&printer_handles_cs);
7343 /*****************************************************************************
7344 * GetJobA [WINSPOOL.@]
7347 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7348 DWORD cbBuf, LPDWORD pcbNeeded)
7350 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7353 /*****************************************************************************
7354 * GetJobW [WINSPOOL.@]
7357 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7358 DWORD cbBuf, LPDWORD pcbNeeded)
7360 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7363 /*****************************************************************************
7366 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7369 char *unixname, *cmdA;
7371 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7375 if(!(unixname = wine_get_unix_file_name(filename)))
7378 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7379 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7380 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7382 TRACE("printing with: %s\n", cmdA);
7384 if((file_fd = open(unixname, O_RDONLY)) == -1)
7389 ERR("pipe() failed!\n");
7399 /* reset signals that we previously set to SIG_IGN */
7400 signal(SIGPIPE, SIG_DFL);
7401 signal(SIGCHLD, SIG_DFL);
7403 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7407 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7408 write(fds[1], buf, no_read);
7413 if(file_fd != -1) close(file_fd);
7414 if(fds[0] != -1) close(fds[0]);
7415 if(fds[1] != -1) close(fds[1]);
7417 HeapFree(GetProcessHeap(), 0, cmdA);
7418 HeapFree(GetProcessHeap(), 0, unixname);
7425 /*****************************************************************************
7428 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7431 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7434 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7435 sprintfW(cmd, fmtW, printer_name);
7437 r = schedule_pipe(cmd, filename);
7439 HeapFree(GetProcessHeap(), 0, cmd);
7443 /*****************************************************************************
7446 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7448 #ifdef SONAME_LIBCUPS
7451 char *unixname, *queue, *unix_doc_title;
7455 if(!(unixname = wine_get_unix_file_name(filename)))
7458 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7459 queue = HeapAlloc(GetProcessHeap(), 0, len);
7460 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7462 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7463 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7464 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7466 TRACE("printing via cups\n");
7467 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7468 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7469 HeapFree(GetProcessHeap(), 0, queue);
7470 HeapFree(GetProcessHeap(), 0, unixname);
7476 return schedule_lpr(printer_name, filename);
7480 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7487 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7491 if(HIWORD(wparam) == BN_CLICKED)
7493 if(LOWORD(wparam) == IDOK)
7496 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7499 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7500 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7502 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7504 WCHAR caption[200], message[200];
7507 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7508 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7509 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7510 if(mb_ret == IDCANCEL)
7512 HeapFree(GetProcessHeap(), 0, filename);
7516 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7517 if(hf == INVALID_HANDLE_VALUE)
7519 WCHAR caption[200], message[200];
7521 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7522 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7523 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7524 HeapFree(GetProcessHeap(), 0, filename);
7528 DeleteFileW(filename);
7529 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7531 EndDialog(hwnd, IDOK);
7534 if(LOWORD(wparam) == IDCANCEL)
7536 EndDialog(hwnd, IDCANCEL);
7545 /*****************************************************************************
7548 static BOOL get_filename(LPWSTR *filename)
7550 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7551 file_dlg_proc, (LPARAM)filename) == IDOK;
7554 /*****************************************************************************
7557 static BOOL schedule_file(LPCWSTR filename)
7559 LPWSTR output = NULL;
7561 if(get_filename(&output))
7564 TRACE("copy to %s\n", debugstr_w(output));
7565 r = CopyFileW(filename, output, FALSE);
7566 HeapFree(GetProcessHeap(), 0, output);
7572 /*****************************************************************************
7575 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7577 int in_fd, out_fd, no_read;
7580 char *unixname, *outputA;
7583 if(!(unixname = wine_get_unix_file_name(filename)))
7586 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7587 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7588 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7590 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7591 in_fd = open(unixname, O_RDONLY);
7592 if(out_fd == -1 || in_fd == -1)
7595 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7596 write(out_fd, buf, no_read);
7600 if(in_fd != -1) close(in_fd);
7601 if(out_fd != -1) close(out_fd);
7602 HeapFree(GetProcessHeap(), 0, outputA);
7603 HeapFree(GetProcessHeap(), 0, unixname);
7607 /*****************************************************************************
7608 * ScheduleJob [WINSPOOL.@]
7611 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7613 opened_printer_t *printer;
7615 struct list *cursor, *cursor2;
7617 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7618 EnterCriticalSection(&printer_handles_cs);
7619 printer = get_opened_printer(hPrinter);
7623 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7625 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7628 if(job->job_id != dwJobID) continue;
7630 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7631 if(hf != INVALID_HANDLE_VALUE)
7633 PRINTER_INFO_5W *pi5 = NULL;
7634 LPWSTR portname = job->portname;
7638 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7639 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7643 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7644 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7645 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7646 portname = pi5->pPortName;
7648 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7649 debugstr_w(portname));
7653 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7654 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7656 DWORD type, count = sizeof(output);
7657 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7660 if(output[0] == '|')
7662 ret = schedule_pipe(output + 1, job->filename);
7666 ret = schedule_unixfile(output, job->filename);
7668 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7670 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7672 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7674 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7676 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7678 ret = schedule_file(job->filename);
7682 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7684 HeapFree(GetProcessHeap(), 0, pi5);
7686 DeleteFileW(job->filename);
7688 list_remove(cursor);
7689 HeapFree(GetProcessHeap(), 0, job->document_title);
7690 HeapFree(GetProcessHeap(), 0, job->printer_name);
7691 HeapFree(GetProcessHeap(), 0, job->portname);
7692 HeapFree(GetProcessHeap(), 0, job->filename);
7693 HeapFree(GetProcessHeap(), 0, job->devmode);
7694 HeapFree(GetProcessHeap(), 0, job);
7698 LeaveCriticalSection(&printer_handles_cs);
7702 /*****************************************************************************
7703 * StartDocDlgA [WINSPOOL.@]
7705 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7707 UNICODE_STRING usBuffer;
7710 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7713 docW.cbSize = sizeof(docW);
7714 if (doc->lpszDocName)
7716 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7717 if (!(docW.lpszDocName = docnameW)) return NULL;
7719 if (doc->lpszOutput)
7721 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7722 if (!(docW.lpszOutput = outputW)) return NULL;
7724 if (doc->lpszDatatype)
7726 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7727 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7729 docW.fwType = doc->fwType;
7731 retW = StartDocDlgW(hPrinter, &docW);
7735 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7736 ret = HeapAlloc(GetProcessHeap(), 0, len);
7737 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7738 HeapFree(GetProcessHeap(), 0, retW);
7741 HeapFree(GetProcessHeap(), 0, datatypeW);
7742 HeapFree(GetProcessHeap(), 0, outputW);
7743 HeapFree(GetProcessHeap(), 0, docnameW);
7748 /*****************************************************************************
7749 * StartDocDlgW [WINSPOOL.@]
7751 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7752 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7753 * port is "FILE:". Also returns the full path if passed a relative path.
7755 * The caller should free the returned string from the process heap.
7757 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7762 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7764 PRINTER_INFO_5W *pi5;
7765 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7766 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7768 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7769 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7770 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7772 HeapFree(GetProcessHeap(), 0, pi5);
7775 HeapFree(GetProcessHeap(), 0, pi5);
7778 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7782 if (get_filename(&name))
7784 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7786 HeapFree(GetProcessHeap(), 0, name);
7789 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7790 GetFullPathNameW(name, len, ret, NULL);
7791 HeapFree(GetProcessHeap(), 0, name);
7796 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7799 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7800 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7802 attr = GetFileAttributesW(ret);
7803 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7805 HeapFree(GetProcessHeap(), 0, ret);