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 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
969 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
970 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
971 for(i = 0; i < num; i++) {
972 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
973 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
974 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
976 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
984 HeapFree(GetProcessHeap(), 0, pi);
988 #ifdef SONAME_LIBCUPS
989 done = CUPS_LoadPrinters();
992 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
993 PRINTCAP_LoadPrinters();
995 /* Now enumerate the list again and delete any printers that are still tagged */
996 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
998 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
999 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1000 for(i = 0; i < num; i++) {
1001 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1002 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1003 BOOL delete_driver = FALSE;
1004 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1005 DWORD dw, type, size = sizeof(dw);
1006 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1007 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1008 DeletePrinter(hprn);
1009 delete_driver = TRUE;
1015 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1020 HeapFree(GetProcessHeap(), 0, pi);
1027 /******************************************************************
1030 * Get the pointer to the specified job.
1031 * Should hold the printer_handles_cs before calling.
1033 static job_t *get_job(HANDLE hprn, DWORD JobId)
1035 opened_printer_t *printer = get_opened_printer(hprn);
1038 if(!printer) return NULL;
1039 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1041 if(job->job_id == JobId)
1047 /***********************************************************
1050 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1053 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1056 Formname = (dmA->dmSize > off_formname);
1057 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1058 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1059 dmW->dmDeviceName, CCHDEVICENAME);
1061 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1062 dmA->dmSize - CCHDEVICENAME);
1064 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1065 off_formname - CCHDEVICENAME);
1066 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1067 dmW->dmFormName, CCHFORMNAME);
1068 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1069 (off_formname + CCHFORMNAME));
1072 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1073 dmA->dmDriverExtra);
1077 /***********************************************************
1079 * Creates an ansi copy of supplied devmode
1081 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1086 if (!dmW) return NULL;
1087 size = dmW->dmSize - CCHDEVICENAME -
1088 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1090 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1091 if (!dmA) return NULL;
1093 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1094 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1096 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1097 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1098 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1102 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1103 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1104 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1105 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1107 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1111 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1115 /******************************************************************
1116 * convert_printerinfo_W_to_A [internal]
1119 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1120 DWORD level, DWORD outlen, DWORD numentries)
1126 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1128 len = pi_sizeof[level] * numentries;
1129 ptr = (LPSTR) out + len;
1132 /* copy the numbers of all PRINTER_INFO_* first */
1133 memcpy(out, pPrintersW, len);
1135 while (id < numentries) {
1139 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1140 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1142 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1143 if (piW->pDescription) {
1144 piA->pDescription = ptr;
1145 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1146 ptr, outlen, NULL, NULL);
1152 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1153 ptr, outlen, NULL, NULL);
1157 if (piW->pComment) {
1158 piA->pComment = ptr;
1159 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1160 ptr, outlen, NULL, NULL);
1169 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1170 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1173 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1174 if (piW->pServerName) {
1175 piA->pServerName = ptr;
1176 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1177 ptr, outlen, NULL, NULL);
1181 if (piW->pPrinterName) {
1182 piA->pPrinterName = ptr;
1183 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1184 ptr, outlen, NULL, NULL);
1188 if (piW->pShareName) {
1189 piA->pShareName = ptr;
1190 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1191 ptr, outlen, NULL, NULL);
1195 if (piW->pPortName) {
1196 piA->pPortName = ptr;
1197 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1198 ptr, outlen, NULL, NULL);
1202 if (piW->pDriverName) {
1203 piA->pDriverName = ptr;
1204 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1205 ptr, outlen, NULL, NULL);
1209 if (piW->pComment) {
1210 piA->pComment = ptr;
1211 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1212 ptr, outlen, NULL, NULL);
1216 if (piW->pLocation) {
1217 piA->pLocation = ptr;
1218 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1219 ptr, outlen, NULL, NULL);
1224 dmA = DEVMODEdupWtoA(piW->pDevMode);
1226 /* align DEVMODEA to a DWORD boundary */
1227 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1231 piA->pDevMode = (LPDEVMODEA) ptr;
1232 len = dmA->dmSize + dmA->dmDriverExtra;
1233 memcpy(ptr, dmA, len);
1234 HeapFree(GetProcessHeap(), 0, dmA);
1240 if (piW->pSepFile) {
1241 piA->pSepFile = ptr;
1242 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1243 ptr, outlen, NULL, NULL);
1247 if (piW->pPrintProcessor) {
1248 piA->pPrintProcessor = ptr;
1249 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1250 ptr, outlen, NULL, NULL);
1254 if (piW->pDatatype) {
1255 piA->pDatatype = ptr;
1256 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1257 ptr, outlen, NULL, NULL);
1261 if (piW->pParameters) {
1262 piA->pParameters = ptr;
1263 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1264 ptr, outlen, NULL, NULL);
1268 if (piW->pSecurityDescriptor) {
1269 piA->pSecurityDescriptor = NULL;
1270 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1277 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1278 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1280 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1282 if (piW->pPrinterName) {
1283 piA->pPrinterName = ptr;
1284 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1285 ptr, outlen, NULL, NULL);
1289 if (piW->pServerName) {
1290 piA->pServerName = ptr;
1291 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1292 ptr, outlen, NULL, NULL);
1301 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1302 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1304 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1306 if (piW->pPrinterName) {
1307 piA->pPrinterName = ptr;
1308 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1309 ptr, outlen, NULL, NULL);
1313 if (piW->pPortName) {
1314 piA->pPortName = ptr;
1315 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1316 ptr, outlen, NULL, NULL);
1323 case 6: /* 6A and 6W are the same structure */
1328 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1329 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1331 TRACE("(%u) #%u\n", level, id);
1332 if (piW->pszObjectGUID) {
1333 piA->pszObjectGUID = ptr;
1334 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1335 ptr, outlen, NULL, NULL);
1344 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1345 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1348 TRACE("(%u) #%u\n", level, id);
1349 dmA = DEVMODEdupWtoA(piW->pDevMode);
1351 /* align DEVMODEA to a DWORD boundary */
1352 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1356 piA->pDevMode = (LPDEVMODEA) ptr;
1357 len = dmA->dmSize + dmA->dmDriverExtra;
1358 memcpy(ptr, dmA, len);
1359 HeapFree(GetProcessHeap(), 0, dmA);
1369 FIXME("for level %u\n", level);
1371 pPrintersW += pi_sizeof[level];
1372 out += pi_sizeof[level];
1377 /******************************************************************
1378 * convert_driverinfo_W_to_A [internal]
1381 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1382 DWORD level, DWORD outlen, DWORD numentries)
1388 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1390 len = di_sizeof[level] * numentries;
1391 ptr = (LPSTR) out + len;
1394 /* copy the numbers of all PRINTER_INFO_* first */
1395 memcpy(out, pDriversW, len);
1397 #define COPY_STRING(fld) \
1400 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1401 ptr += len; outlen -= len;\
1403 #define COPY_MULTIZ_STRING(fld) \
1404 { LPWSTR p = diW->fld; if (p){ \
1407 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1408 ptr += len; outlen -= len; p += len;\
1410 while(len > 1 && outlen > 0); \
1413 while (id < numentries)
1419 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1420 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1422 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1429 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1430 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1432 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1435 COPY_STRING(pEnvironment);
1436 COPY_STRING(pDriverPath);
1437 COPY_STRING(pDataFile);
1438 COPY_STRING(pConfigFile);
1443 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1444 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1446 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1449 COPY_STRING(pEnvironment);
1450 COPY_STRING(pDriverPath);
1451 COPY_STRING(pDataFile);
1452 COPY_STRING(pConfigFile);
1453 COPY_STRING(pHelpFile);
1454 COPY_MULTIZ_STRING(pDependentFiles);
1455 COPY_STRING(pMonitorName);
1456 COPY_STRING(pDefaultDataType);
1461 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1462 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1464 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1467 COPY_STRING(pEnvironment);
1468 COPY_STRING(pDriverPath);
1469 COPY_STRING(pDataFile);
1470 COPY_STRING(pConfigFile);
1471 COPY_STRING(pHelpFile);
1472 COPY_MULTIZ_STRING(pDependentFiles);
1473 COPY_STRING(pMonitorName);
1474 COPY_STRING(pDefaultDataType);
1475 COPY_MULTIZ_STRING(pszzPreviousNames);
1480 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1481 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1483 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1486 COPY_STRING(pEnvironment);
1487 COPY_STRING(pDriverPath);
1488 COPY_STRING(pDataFile);
1489 COPY_STRING(pConfigFile);
1494 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1495 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1497 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1500 COPY_STRING(pEnvironment);
1501 COPY_STRING(pDriverPath);
1502 COPY_STRING(pDataFile);
1503 COPY_STRING(pConfigFile);
1504 COPY_STRING(pHelpFile);
1505 COPY_MULTIZ_STRING(pDependentFiles);
1506 COPY_STRING(pMonitorName);
1507 COPY_STRING(pDefaultDataType);
1508 COPY_MULTIZ_STRING(pszzPreviousNames);
1509 COPY_STRING(pszMfgName);
1510 COPY_STRING(pszOEMUrl);
1511 COPY_STRING(pszHardwareID);
1512 COPY_STRING(pszProvider);
1517 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1518 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1520 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1523 COPY_STRING(pEnvironment);
1524 COPY_STRING(pDriverPath);
1525 COPY_STRING(pDataFile);
1526 COPY_STRING(pConfigFile);
1527 COPY_STRING(pHelpFile);
1528 COPY_MULTIZ_STRING(pDependentFiles);
1529 COPY_STRING(pMonitorName);
1530 COPY_STRING(pDefaultDataType);
1531 COPY_MULTIZ_STRING(pszzPreviousNames);
1532 COPY_STRING(pszMfgName);
1533 COPY_STRING(pszOEMUrl);
1534 COPY_STRING(pszHardwareID);
1535 COPY_STRING(pszProvider);
1536 COPY_STRING(pszPrintProcessor);
1537 COPY_STRING(pszVendorSetup);
1538 COPY_MULTIZ_STRING(pszzColorProfiles);
1539 COPY_STRING(pszInfPath);
1540 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1546 FIXME("for level %u\n", level);
1549 pDriversW += di_sizeof[level];
1550 out += di_sizeof[level];
1555 #undef COPY_MULTIZ_STRING
1559 /***********************************************************
1560 * PRINTER_INFO_2AtoW
1561 * Creates a unicode copy of PRINTER_INFO_2A on heap
1563 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1565 LPPRINTER_INFO_2W piW;
1566 UNICODE_STRING usBuffer;
1568 if(!piA) return NULL;
1569 piW = HeapAlloc(heap, 0, sizeof(*piW));
1570 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1572 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1573 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1574 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1575 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1576 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1577 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1578 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1579 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1580 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1581 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1582 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1583 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1587 /***********************************************************
1588 * FREE_PRINTER_INFO_2W
1589 * Free PRINTER_INFO_2W and all strings
1591 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1595 HeapFree(heap,0,piW->pServerName);
1596 HeapFree(heap,0,piW->pPrinterName);
1597 HeapFree(heap,0,piW->pShareName);
1598 HeapFree(heap,0,piW->pPortName);
1599 HeapFree(heap,0,piW->pDriverName);
1600 HeapFree(heap,0,piW->pComment);
1601 HeapFree(heap,0,piW->pLocation);
1602 HeapFree(heap,0,piW->pDevMode);
1603 HeapFree(heap,0,piW->pSepFile);
1604 HeapFree(heap,0,piW->pPrintProcessor);
1605 HeapFree(heap,0,piW->pDatatype);
1606 HeapFree(heap,0,piW->pParameters);
1607 HeapFree(heap,0,piW);
1611 /******************************************************************
1612 * DeviceCapabilities [WINSPOOL.@]
1613 * DeviceCapabilitiesA [WINSPOOL.@]
1616 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1617 LPSTR pOutput, LPDEVMODEA lpdm)
1621 if (!GDI_CallDeviceCapabilities16)
1623 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1625 if (!GDI_CallDeviceCapabilities16) return -1;
1627 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1629 /* If DC_PAPERSIZE map POINT16s to POINTs */
1630 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1631 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1632 POINT *pt = (POINT *)pOutput;
1634 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1635 for(i = 0; i < ret; i++, pt++)
1640 HeapFree( GetProcessHeap(), 0, tmp );
1646 /*****************************************************************************
1647 * DeviceCapabilitiesW [WINSPOOL.@]
1649 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1652 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1653 WORD fwCapability, LPWSTR pOutput,
1654 const DEVMODEW *pDevMode)
1656 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1657 LPSTR pDeviceA = strdupWtoA(pDevice);
1658 LPSTR pPortA = strdupWtoA(pPort);
1661 if(pOutput && (fwCapability == DC_BINNAMES ||
1662 fwCapability == DC_FILEDEPENDENCIES ||
1663 fwCapability == DC_PAPERNAMES)) {
1664 /* These need A -> W translation */
1667 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1671 switch(fwCapability) {
1676 case DC_FILEDEPENDENCIES:
1680 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1681 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1683 for(i = 0; i < ret; i++)
1684 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1685 pOutput + (i * size), size);
1686 HeapFree(GetProcessHeap(), 0, pOutputA);
1688 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1689 (LPSTR)pOutput, dmA);
1691 HeapFree(GetProcessHeap(),0,pPortA);
1692 HeapFree(GetProcessHeap(),0,pDeviceA);
1693 HeapFree(GetProcessHeap(),0,dmA);
1697 /******************************************************************
1698 * DocumentPropertiesA [WINSPOOL.@]
1700 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1702 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1703 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1704 LPDEVMODEA pDevModeInput,DWORD fMode )
1706 LPSTR lpName = pDeviceName;
1707 static CHAR port[] = "LPT1:";
1710 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1711 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1715 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1717 ERR("no name from hPrinter?\n");
1718 SetLastError(ERROR_INVALID_HANDLE);
1721 lpName = strdupWtoA(lpNameW);
1724 if (!GDI_CallExtDeviceMode16)
1726 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1728 if (!GDI_CallExtDeviceMode16) {
1729 ERR("No CallExtDeviceMode16?\n");
1733 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1734 pDevModeInput, NULL, fMode);
1737 HeapFree(GetProcessHeap(),0,lpName);
1742 /*****************************************************************************
1743 * DocumentPropertiesW (WINSPOOL.@)
1745 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1747 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1749 LPDEVMODEW pDevModeOutput,
1750 LPDEVMODEW pDevModeInput, DWORD fMode)
1753 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1754 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1755 LPDEVMODEA pDevModeOutputA = NULL;
1758 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1759 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1761 if(pDevModeOutput) {
1762 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1763 if(ret < 0) return ret;
1764 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1766 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1767 pDevModeInputA, fMode);
1768 if(pDevModeOutput) {
1769 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1770 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1772 if(fMode == 0 && ret > 0)
1773 ret += (CCHDEVICENAME + CCHFORMNAME);
1774 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1775 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1779 /******************************************************************
1780 * OpenPrinterA [WINSPOOL.@]
1785 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1786 LPPRINTER_DEFAULTSA pDefault)
1788 UNICODE_STRING lpPrinterNameW;
1789 UNICODE_STRING usBuffer;
1790 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1791 PWSTR pwstrPrinterNameW;
1794 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1797 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1798 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1799 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1800 pDefaultW = &DefaultW;
1802 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1804 RtlFreeUnicodeString(&usBuffer);
1805 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1807 RtlFreeUnicodeString(&lpPrinterNameW);
1811 /******************************************************************
1812 * OpenPrinterW [WINSPOOL.@]
1814 * Open a Printer / Printserver or a Printer-Object
1817 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1818 * phPrinter [O] The resulting Handle is stored here
1819 * pDefault [I] PTR to Default Printer Settings or NULL
1826 * lpPrinterName is one of:
1827 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1828 *| Printer: "PrinterName"
1829 *| Printer-Object: "PrinterName,Job xxx"
1830 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1831 *| XcvPort: "Servername,XcvPort PortName"
1834 *| Printer-Object not supported
1835 *| pDefaults is ignored
1838 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1841 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1843 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1844 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1848 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1849 SetLastError(ERROR_INVALID_PARAMETER);
1853 /* Get the unique handle of the printer or Printserver */
1854 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1855 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1856 return (*phPrinter != 0);
1859 /******************************************************************
1860 * AddMonitorA [WINSPOOL.@]
1865 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1867 LPWSTR nameW = NULL;
1870 LPMONITOR_INFO_2A mi2a;
1871 MONITOR_INFO_2W mi2w;
1873 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1874 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1875 debugstr_a(mi2a ? mi2a->pName : NULL),
1876 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1877 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1880 SetLastError(ERROR_INVALID_LEVEL);
1884 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1890 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1891 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1892 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1895 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1897 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1898 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1899 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1901 if (mi2a->pEnvironment) {
1902 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1903 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1904 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1906 if (mi2a->pDLLName) {
1907 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1908 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1909 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1912 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1914 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1915 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1916 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1918 HeapFree(GetProcessHeap(), 0, nameW);
1922 /******************************************************************************
1923 * AddMonitorW [WINSPOOL.@]
1925 * Install a Printmonitor
1928 * pName [I] Servername or NULL (local Computer)
1929 * Level [I] Structure-Level (Must be 2)
1930 * pMonitors [I] PTR to MONITOR_INFO_2
1937 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1940 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1942 LPMONITOR_INFO_2W mi2w;
1944 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1945 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1946 debugstr_w(mi2w ? mi2w->pName : NULL),
1947 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1948 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1950 if ((backend == NULL) && !load_backend()) return FALSE;
1953 SetLastError(ERROR_INVALID_LEVEL);
1957 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1962 return backend->fpAddMonitor(pName, Level, pMonitors);
1965 /******************************************************************
1966 * DeletePrinterDriverA [WINSPOOL.@]
1969 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1971 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
1974 /******************************************************************
1975 * DeletePrinterDriverW [WINSPOOL.@]
1978 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1980 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
1983 /******************************************************************
1984 * DeleteMonitorA [WINSPOOL.@]
1986 * See DeleteMonitorW.
1989 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1991 LPWSTR nameW = NULL;
1992 LPWSTR EnvironmentW = NULL;
1993 LPWSTR MonitorNameW = NULL;
1998 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1999 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2000 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2004 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2005 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2006 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2009 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2010 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2011 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2014 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2016 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2017 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2018 HeapFree(GetProcessHeap(), 0, nameW);
2022 /******************************************************************
2023 * DeleteMonitorW [WINSPOOL.@]
2025 * Delete a specific Printmonitor from a Printing-Environment
2028 * pName [I] Servername or NULL (local Computer)
2029 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2030 * pMonitorName [I] Name of the Monitor, that should be deleted
2037 * pEnvironment is ignored in Windows for the local Computer.
2040 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2043 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2044 debugstr_w(pMonitorName));
2046 if ((backend == NULL) && !load_backend()) return FALSE;
2048 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2052 /******************************************************************
2053 * DeletePortA [WINSPOOL.@]
2058 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2060 LPWSTR nameW = NULL;
2061 LPWSTR portW = NULL;
2065 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2067 /* convert servername to unicode */
2069 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2070 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2071 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2074 /* convert portname to unicode */
2076 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2077 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2078 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2081 res = DeletePortW(nameW, hWnd, portW);
2082 HeapFree(GetProcessHeap(), 0, nameW);
2083 HeapFree(GetProcessHeap(), 0, portW);
2087 /******************************************************************
2088 * DeletePortW [WINSPOOL.@]
2090 * Delete a specific Port
2093 * pName [I] Servername or NULL (local Computer)
2094 * hWnd [I] Handle to parent Window for the Dialog-Box
2095 * pPortName [I] Name of the Port, that should be deleted
2102 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2104 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2106 if ((backend == NULL) && !load_backend()) return FALSE;
2109 SetLastError(RPC_X_NULL_REF_POINTER);
2113 return backend->fpDeletePort(pName, hWnd, pPortName);
2116 /******************************************************************************
2117 * SetPrinterW [WINSPOOL.@]
2119 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2121 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2122 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2126 /******************************************************************************
2127 * WritePrinter [WINSPOOL.@]
2129 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2131 opened_printer_t *printer;
2134 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2136 EnterCriticalSection(&printer_handles_cs);
2137 printer = get_opened_printer(hPrinter);
2140 SetLastError(ERROR_INVALID_HANDLE);
2146 SetLastError(ERROR_SPL_NO_STARTDOC);
2150 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2152 LeaveCriticalSection(&printer_handles_cs);
2156 /*****************************************************************************
2157 * AddFormA [WINSPOOL.@]
2159 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2161 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2165 /*****************************************************************************
2166 * AddFormW [WINSPOOL.@]
2168 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2170 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2174 /*****************************************************************************
2175 * AddJobA [WINSPOOL.@]
2177 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2180 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2184 SetLastError(ERROR_INVALID_LEVEL);
2188 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2191 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2192 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2193 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2194 if(*pcbNeeded > cbBuf) {
2195 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2198 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2199 addjobA->JobId = addjobW->JobId;
2200 addjobA->Path = (char *)(addjobA + 1);
2201 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2207 /*****************************************************************************
2208 * AddJobW [WINSPOOL.@]
2210 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2212 opened_printer_t *printer;
2215 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2216 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2217 WCHAR path[MAX_PATH], filename[MAX_PATH];
2219 ADDJOB_INFO_1W *addjob;
2221 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2223 EnterCriticalSection(&printer_handles_cs);
2225 printer = get_opened_printer(hPrinter);
2228 SetLastError(ERROR_INVALID_HANDLE);
2233 SetLastError(ERROR_INVALID_LEVEL);
2237 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2241 job->job_id = InterlockedIncrement(&next_job_id);
2243 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2244 if(path[len - 1] != '\\')
2246 memcpy(path + len, spool_path, sizeof(spool_path));
2247 sprintfW(filename, fmtW, path, job->job_id);
2249 len = strlenW(filename);
2250 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2251 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2252 job->document_title = strdupW(default_doc_title);
2253 job->printer_name = strdupW(printer->name);
2254 job->devmode = NULL;
2255 list_add_tail(&printer->queue->jobs, &job->entry);
2257 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2258 if(*pcbNeeded <= cbBuf) {
2259 addjob = (ADDJOB_INFO_1W*)pData;
2260 addjob->JobId = job->job_id;
2261 addjob->Path = (WCHAR *)(addjob + 1);
2262 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2265 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2268 LeaveCriticalSection(&printer_handles_cs);
2272 /*****************************************************************************
2273 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2275 * Return the PATH for the Print-Processors
2277 * See GetPrintProcessorDirectoryW.
2281 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2282 DWORD level, LPBYTE Info,
2283 DWORD cbBuf, LPDWORD pcbNeeded)
2285 LPWSTR serverW = NULL;
2290 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2291 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2295 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2296 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2297 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2301 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2302 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2303 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2306 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2307 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2309 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2312 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2313 cbBuf, NULL, NULL) > 0;
2316 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2317 HeapFree(GetProcessHeap(), 0, envW);
2318 HeapFree(GetProcessHeap(), 0, serverW);
2322 /*****************************************************************************
2323 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2325 * Return the PATH for the Print-Processors
2328 * server [I] Servername (NT only) or NULL (local Computer)
2329 * env [I] Printing-Environment (see below) or NULL (Default)
2330 * level [I] Structure-Level (must be 1)
2331 * Info [O] PTR to Buffer that receives the Result
2332 * cbBuf [I] Size of Buffer at "Info"
2333 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2334 * required for the Buffer at "Info"
2337 * Success: TRUE and in pcbNeeded the Bytes used in Info
2338 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2339 * if cbBuf is too small
2341 * Native Values returned in Info on Success:
2342 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2343 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2344 *| win9x(Windows 4.0): "%winsysdir%"
2346 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2349 * Only NULL or "" is supported for server
2352 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2353 DWORD level, LPBYTE Info,
2354 DWORD cbBuf, LPDWORD pcbNeeded)
2357 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2358 Info, cbBuf, pcbNeeded);
2360 if ((backend == NULL) && !load_backend()) return FALSE;
2363 /* (Level != 1) is ignored in win9x */
2364 SetLastError(ERROR_INVALID_LEVEL);
2368 if (pcbNeeded == NULL) {
2369 /* (pcbNeeded == NULL) is ignored in win9x */
2370 SetLastError(RPC_X_NULL_REF_POINTER);
2374 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2377 /*****************************************************************************
2378 * WINSPOOL_OpenDriverReg [internal]
2380 * opens the registry for the printer drivers depending on the given input
2381 * variable pEnvironment
2384 * the opened hkey on success
2387 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2391 const printenv_t * env;
2393 TRACE("(%s)\n", debugstr_w(pEnvironment));
2395 env = validate_envW(pEnvironment);
2396 if (!env) return NULL;
2398 buffer = HeapAlloc( GetProcessHeap(), 0,
2399 (strlenW(DriversW) + strlenW(env->envname) +
2400 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2402 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2403 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2404 HeapFree(GetProcessHeap(), 0, buffer);
2409 /*****************************************************************************
2410 * set_devices_and_printerports [internal]
2412 * set the [Devices] and [PrinterPorts] entries for a printer.
2415 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2417 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2421 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2423 /* FIXME: the driver must change to "winspool" */
2424 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2426 lstrcpyW(devline, driver_nt);
2427 lstrcatW(devline, commaW);
2428 lstrcatW(devline, pi->pPortName);
2430 TRACE("using %s\n", debugstr_w(devline));
2431 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2432 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2433 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2434 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2438 lstrcatW(devline, timeout_15_45);
2439 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2440 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2441 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2442 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2445 HeapFree(GetProcessHeap(), 0, devline);
2449 /*****************************************************************************
2450 * AddPrinterW [WINSPOOL.@]
2452 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2454 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2458 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2460 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2461 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2462 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2463 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2464 statusW[] = {'S','t','a','t','u','s',0},
2465 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2467 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2470 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2471 SetLastError(ERROR_INVALID_PARAMETER);
2475 ERR("Level = %d, unsupported!\n", Level);
2476 SetLastError(ERROR_INVALID_LEVEL);
2480 SetLastError(ERROR_INVALID_PARAMETER);
2483 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2485 ERR("Can't create Printers key\n");
2488 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2489 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2490 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2491 RegCloseKey(hkeyPrinter);
2492 RegCloseKey(hkeyPrinters);
2495 RegCloseKey(hkeyPrinter);
2497 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2499 ERR("Can't create Drivers key\n");
2500 RegCloseKey(hkeyPrinters);
2503 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2505 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2506 RegCloseKey(hkeyPrinters);
2507 RegCloseKey(hkeyDrivers);
2508 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2511 RegCloseKey(hkeyDriver);
2512 RegCloseKey(hkeyDrivers);
2514 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2515 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2516 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2517 RegCloseKey(hkeyPrinters);
2521 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2523 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2524 SetLastError(ERROR_INVALID_PRINTER_NAME);
2525 RegCloseKey(hkeyPrinters);
2529 set_devices_and_printerports(pi);
2530 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2531 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2532 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2534 /* See if we can load the driver. We may need the devmode structure anyway
2537 * Note that DocumentPropertiesW will briefly try to open the printer we
2538 * just create to find a DEVMODEA struct (it will use the WINEPS default
2539 * one in case it is not there, so we are ok).
2541 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2544 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2545 size = sizeof(DEVMODEW);
2551 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2553 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2555 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2556 HeapFree(GetProcessHeap(),0,dmW);
2561 /* set devmode to printer name */
2562 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2566 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2567 and we support these drivers. NT writes DEVMODEW so somehow
2568 we'll need to distinguish between these when we support NT
2572 dmA = DEVMODEdupWtoA(dmW);
2573 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2574 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2575 HeapFree(GetProcessHeap(), 0, dmA);
2577 HeapFree(GetProcessHeap(), 0, dmW);
2579 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2580 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2581 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2582 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2584 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2585 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2586 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2587 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2588 (LPBYTE)&pi->Priority, sizeof(DWORD));
2589 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2590 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2591 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2592 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2593 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2594 (LPBYTE)&pi->Status, sizeof(DWORD));
2595 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2596 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2598 RegCloseKey(hkeyPrinter);
2599 RegCloseKey(hkeyPrinters);
2600 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2601 ERR("OpenPrinter failing\n");
2607 /*****************************************************************************
2608 * AddPrinterA [WINSPOOL.@]
2610 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2612 UNICODE_STRING pNameW;
2614 PRINTER_INFO_2W *piW;
2615 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2618 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2620 ERR("Level = %d, unsupported!\n", Level);
2621 SetLastError(ERROR_INVALID_LEVEL);
2624 pwstrNameW = asciitounicode(&pNameW,pName);
2625 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2627 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2629 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2630 RtlFreeUnicodeString(&pNameW);
2635 /*****************************************************************************
2636 * ClosePrinter [WINSPOOL.@]
2638 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2640 UINT_PTR i = (UINT_PTR)hPrinter;
2641 opened_printer_t *printer = NULL;
2644 TRACE("(%p)\n", hPrinter);
2646 EnterCriticalSection(&printer_handles_cs);
2648 if ((i > 0) && (i <= nb_printer_handles))
2649 printer = printer_handles[i - 1];
2654 struct list *cursor, *cursor2;
2656 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2658 if (printer->backend_printer) {
2659 backend->fpClosePrinter(printer->backend_printer);
2663 EndDocPrinter(hPrinter);
2665 if(InterlockedDecrement(&printer->queue->ref) == 0)
2667 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2669 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2670 ScheduleJob(hPrinter, job->job_id);
2672 HeapFree(GetProcessHeap(), 0, printer->queue);
2675 HeapFree(GetProcessHeap(), 0, printer->printername);
2676 HeapFree(GetProcessHeap(), 0, printer->name);
2677 HeapFree(GetProcessHeap(), 0, printer);
2678 printer_handles[i - 1] = NULL;
2681 LeaveCriticalSection(&printer_handles_cs);
2685 /*****************************************************************************
2686 * DeleteFormA [WINSPOOL.@]
2688 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2690 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2694 /*****************************************************************************
2695 * DeleteFormW [WINSPOOL.@]
2697 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2699 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2703 /*****************************************************************************
2704 * DeletePrinter [WINSPOOL.@]
2706 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2708 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2709 HKEY hkeyPrinters, hkey;
2712 SetLastError(ERROR_INVALID_HANDLE);
2715 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2716 RegDeleteTreeW(hkeyPrinters, lpNameW);
2717 RegCloseKey(hkeyPrinters);
2719 WriteProfileStringW(devicesW, lpNameW, NULL);
2720 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2722 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2723 RegDeleteValueW(hkey, lpNameW);
2727 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2728 RegDeleteValueW(hkey, lpNameW);
2734 /*****************************************************************************
2735 * SetPrinterA [WINSPOOL.@]
2737 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2740 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2744 /*****************************************************************************
2745 * SetJobA [WINSPOOL.@]
2747 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2748 LPBYTE pJob, DWORD Command)
2752 UNICODE_STRING usBuffer;
2754 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2756 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2757 are all ignored by SetJob, so we don't bother copying them */
2765 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2766 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2768 JobW = (LPBYTE)info1W;
2769 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2770 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2771 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2772 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2773 info1W->Status = info1A->Status;
2774 info1W->Priority = info1A->Priority;
2775 info1W->Position = info1A->Position;
2776 info1W->PagesPrinted = info1A->PagesPrinted;
2781 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2782 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2784 JobW = (LPBYTE)info2W;
2785 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2786 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2787 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2788 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2789 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2790 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2791 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2792 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2793 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2794 info2W->Status = info2A->Status;
2795 info2W->Priority = info2A->Priority;
2796 info2W->Position = info2A->Position;
2797 info2W->StartTime = info2A->StartTime;
2798 info2W->UntilTime = info2A->UntilTime;
2799 info2W->PagesPrinted = info2A->PagesPrinted;
2803 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2804 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2807 SetLastError(ERROR_INVALID_LEVEL);
2811 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2817 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2818 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2819 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2820 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2821 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2826 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2827 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2828 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2829 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2830 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2831 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2832 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2833 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2834 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2838 HeapFree(GetProcessHeap(), 0, JobW);
2843 /*****************************************************************************
2844 * SetJobW [WINSPOOL.@]
2846 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2847 LPBYTE pJob, DWORD Command)
2853 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2854 FIXME("Ignoring everything other than document title\n");
2856 EnterCriticalSection(&printer_handles_cs);
2857 job = get_job(hPrinter, JobId);
2867 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2868 HeapFree(GetProcessHeap(), 0, job->document_title);
2869 job->document_title = strdupW(info1->pDocument);
2874 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2875 HeapFree(GetProcessHeap(), 0, job->document_title);
2876 job->document_title = strdupW(info2->pDocument);
2877 HeapFree(GetProcessHeap(), 0, job->devmode);
2878 if (info2->pDevMode)
2880 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2881 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2882 memcpy(job->devmode, info2->pDevMode, size);
2885 job->devmode = NULL;
2891 SetLastError(ERROR_INVALID_LEVEL);
2896 LeaveCriticalSection(&printer_handles_cs);
2900 /*****************************************************************************
2901 * EndDocPrinter [WINSPOOL.@]
2903 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2905 opened_printer_t *printer;
2907 TRACE("(%p)\n", hPrinter);
2909 EnterCriticalSection(&printer_handles_cs);
2911 printer = get_opened_printer(hPrinter);
2914 SetLastError(ERROR_INVALID_HANDLE);
2920 SetLastError(ERROR_SPL_NO_STARTDOC);
2924 CloseHandle(printer->doc->hf);
2925 ScheduleJob(hPrinter, printer->doc->job_id);
2926 HeapFree(GetProcessHeap(), 0, printer->doc);
2927 printer->doc = NULL;
2930 LeaveCriticalSection(&printer_handles_cs);
2934 /*****************************************************************************
2935 * EndPagePrinter [WINSPOOL.@]
2937 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2939 FIXME("(%p): stub\n", hPrinter);
2943 /*****************************************************************************
2944 * StartDocPrinterA [WINSPOOL.@]
2946 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2948 UNICODE_STRING usBuffer;
2950 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2953 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2954 or one (DOC_INFO_3) extra DWORDs */
2958 doc2W.JobId = doc2->JobId;
2961 doc2W.dwMode = doc2->dwMode;
2964 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2965 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2966 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2970 SetLastError(ERROR_INVALID_LEVEL);
2974 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2976 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2977 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2978 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2983 /*****************************************************************************
2984 * StartDocPrinterW [WINSPOOL.@]
2986 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2988 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2989 opened_printer_t *printer;
2990 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2991 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2992 JOB_INFO_1W job_info;
2993 DWORD needed, ret = 0;
2998 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2999 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3000 debugstr_w(doc->pDatatype));
3002 if(Level < 1 || Level > 3)
3004 SetLastError(ERROR_INVALID_LEVEL);
3008 EnterCriticalSection(&printer_handles_cs);
3009 printer = get_opened_printer(hPrinter);
3012 SetLastError(ERROR_INVALID_HANDLE);
3018 SetLastError(ERROR_INVALID_PRINTER_STATE);
3022 /* Even if we're printing to a file we still add a print job, we'll
3023 just ignore the spool file name */
3025 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3027 ERR("AddJob failed gle %u\n", GetLastError());
3031 /* use pOutputFile only, when it is a real filename */
3032 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3033 filename = doc->pOutputFile;
3035 filename = addjob->Path;
3037 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3038 if(hf == INVALID_HANDLE_VALUE)
3041 memset(&job_info, 0, sizeof(job_info));
3042 job_info.pDocument = doc->pDocName;
3043 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3045 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3046 printer->doc->hf = hf;
3047 ret = printer->doc->job_id = addjob->JobId;
3048 job = get_job(hPrinter, ret);
3049 job->portname = strdupW(doc->pOutputFile);
3052 LeaveCriticalSection(&printer_handles_cs);
3057 /*****************************************************************************
3058 * StartPagePrinter [WINSPOOL.@]
3060 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3062 FIXME("(%p): stub\n", hPrinter);
3066 /*****************************************************************************
3067 * GetFormA [WINSPOOL.@]
3069 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3070 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3072 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3073 Level,pForm,cbBuf,pcbNeeded);
3077 /*****************************************************************************
3078 * GetFormW [WINSPOOL.@]
3080 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3081 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3083 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3084 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3088 /*****************************************************************************
3089 * SetFormA [WINSPOOL.@]
3091 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3094 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3098 /*****************************************************************************
3099 * SetFormW [WINSPOOL.@]
3101 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3104 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3108 /*****************************************************************************
3109 * ReadPrinter [WINSPOOL.@]
3111 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3112 LPDWORD pNoBytesRead)
3114 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3118 /*****************************************************************************
3119 * ResetPrinterA [WINSPOOL.@]
3121 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3123 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3127 /*****************************************************************************
3128 * ResetPrinterW [WINSPOOL.@]
3130 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3132 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3136 /*****************************************************************************
3137 * WINSPOOL_GetDWORDFromReg
3139 * Return DWORD associated with ValueName from hkey.
3141 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3143 DWORD sz = sizeof(DWORD), type, value = 0;
3146 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3148 if(ret != ERROR_SUCCESS) {
3149 WARN("Got ret = %d on name %s\n", ret, ValueName);
3152 if(type != REG_DWORD) {
3153 ERR("Got type %d\n", type);
3160 /*****************************************************************************
3161 * get_filename_from_reg [internal]
3163 * Get ValueName from hkey storing result in out
3164 * when the Value in the registry has only a filename, use driverdir as prefix
3165 * outlen is space left in out
3166 * String is stored either as unicode or ascii
3170 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3171 LPBYTE out, DWORD outlen, LPDWORD needed)
3173 WCHAR filename[MAX_PATH];
3177 LPWSTR buffer = filename;
3181 size = sizeof(filename);
3183 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3184 if (ret == ERROR_MORE_DATA) {
3185 TRACE("need dynamic buffer: %u\n", size);
3186 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3188 /* No Memory is bad */
3192 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3195 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3196 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3202 /* do we have a full path ? */
3203 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3204 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3207 /* we must build the full Path */
3209 if ((out) && (outlen > dirlen)) {
3210 lstrcpyW((LPWSTR)out, driverdir);
3218 /* write the filename */
3219 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3220 if ((out) && (outlen >= size)) {
3221 lstrcpyW((LPWSTR)out, ptr);
3228 ptr += lstrlenW(ptr)+1;
3229 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3232 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3234 /* write the multisz-termination */
3235 if (type == REG_MULTI_SZ) {
3236 size = sizeof(WCHAR);
3239 if (out && (outlen >= size)) {
3240 memset (out, 0, size);
3246 /*****************************************************************************
3247 * WINSPOOL_GetStringFromReg
3249 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3250 * String is stored as unicode.
3252 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3253 DWORD buflen, DWORD *needed)
3255 DWORD sz = buflen, type;
3258 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3259 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3260 WARN("Got ret = %d\n", ret);
3264 /* add space for terminating '\0' */
3265 sz += sizeof(WCHAR);
3269 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3274 /*****************************************************************************
3275 * WINSPOOL_GetDefaultDevMode
3277 * Get a default DevMode values for wineps.
3281 static void WINSPOOL_GetDefaultDevMode(
3283 DWORD buflen, DWORD *needed)
3286 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3288 /* fill default DEVMODE - should be read from ppd... */
3289 ZeroMemory( &dm, sizeof(dm) );
3290 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3291 dm.dmSpecVersion = DM_SPECVERSION;
3292 dm.dmDriverVersion = 1;
3293 dm.dmSize = sizeof(DEVMODEW);
3294 dm.dmDriverExtra = 0;
3296 DM_ORIENTATION | DM_PAPERSIZE |
3297 DM_PAPERLENGTH | DM_PAPERWIDTH |
3300 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3301 DM_YRESOLUTION | DM_TTOPTION;
3303 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3304 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3305 dm.u1.s1.dmPaperLength = 2970;
3306 dm.u1.s1.dmPaperWidth = 2100;
3308 dm.u1.s1.dmScale = 100;
3309 dm.u1.s1.dmCopies = 1;
3310 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3311 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3314 dm.dmYResolution = 300; /* 300dpi */
3315 dm.dmTTOption = DMTT_BITMAP;
3318 /* dm.dmLogPixels */
3319 /* dm.dmBitsPerPel */
3320 /* dm.dmPelsWidth */
3321 /* dm.dmPelsHeight */
3322 /* dm.u2.dmDisplayFlags */
3323 /* dm.dmDisplayFrequency */
3324 /* dm.dmICMMethod */
3325 /* dm.dmICMIntent */
3326 /* dm.dmMediaType */
3327 /* dm.dmDitherType */
3328 /* dm.dmReserved1 */
3329 /* dm.dmReserved2 */
3330 /* dm.dmPanningWidth */
3331 /* dm.dmPanningHeight */
3333 if(buflen >= sizeof(DEVMODEW))
3334 memcpy(ptr, &dm, sizeof(DEVMODEW));
3335 *needed = sizeof(DEVMODEW);
3338 /*****************************************************************************
3339 * WINSPOOL_GetDevModeFromReg
3341 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3342 * DevMode is stored either as unicode or ascii.
3344 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3346 DWORD buflen, DWORD *needed)
3348 DWORD sz = buflen, type;
3351 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3352 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3353 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3354 if (sz < sizeof(DEVMODEA))
3356 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3359 /* ensures that dmSize is not erratically bogus if registry is invalid */
3360 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3361 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3362 sz += (CCHDEVICENAME + CCHFORMNAME);
3363 if (ptr && (buflen >= sz)) {
3364 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3365 memcpy(ptr, dmW, sz);
3366 HeapFree(GetProcessHeap(),0,dmW);
3372 /*********************************************************************
3373 * WINSPOOL_GetPrinter_1
3375 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3377 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3378 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3380 DWORD size, left = cbBuf;
3381 BOOL space = (cbBuf > 0);
3386 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3387 if(space && size <= left) {
3388 pi1->pName = (LPWSTR)ptr;
3396 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3397 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3398 if(space && size <= left) {
3399 pi1->pDescription = (LPWSTR)ptr;
3407 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3408 if(space && size <= left) {
3409 pi1->pComment = (LPWSTR)ptr;
3417 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3419 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3420 memset(pi1, 0, sizeof(*pi1));
3424 /*********************************************************************
3425 * WINSPOOL_GetPrinter_2
3427 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3429 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3430 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3432 DWORD size, left = cbBuf;
3433 BOOL space = (cbBuf > 0);
3438 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3439 if(space && size <= left) {
3440 pi2->pPrinterName = (LPWSTR)ptr;
3447 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3448 if(space && size <= left) {
3449 pi2->pShareName = (LPWSTR)ptr;
3456 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3457 if(space && size <= left) {
3458 pi2->pPortName = (LPWSTR)ptr;
3465 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3466 if(space && size <= left) {
3467 pi2->pDriverName = (LPWSTR)ptr;
3474 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3475 if(space && size <= left) {
3476 pi2->pComment = (LPWSTR)ptr;
3483 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3484 if(space && size <= left) {
3485 pi2->pLocation = (LPWSTR)ptr;
3492 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3493 if(space && size <= left) {
3494 pi2->pDevMode = (LPDEVMODEW)ptr;
3503 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3504 if(space && size <= left) {
3505 pi2->pDevMode = (LPDEVMODEW)ptr;
3512 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3513 if(space && size <= left) {
3514 pi2->pSepFile = (LPWSTR)ptr;
3521 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3522 if(space && size <= left) {
3523 pi2->pPrintProcessor = (LPWSTR)ptr;
3530 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3531 if(space && size <= left) {
3532 pi2->pDatatype = (LPWSTR)ptr;
3539 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3540 if(space && size <= left) {
3541 pi2->pParameters = (LPWSTR)ptr;
3549 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3550 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3551 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3552 "Default Priority");
3553 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3554 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3557 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3558 memset(pi2, 0, sizeof(*pi2));
3563 /*********************************************************************
3564 * WINSPOOL_GetPrinter_4
3566 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3568 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3569 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3571 DWORD size, left = cbBuf;
3572 BOOL space = (cbBuf > 0);
3577 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3578 if(space && size <= left) {
3579 pi4->pPrinterName = (LPWSTR)ptr;
3587 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3590 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3591 memset(pi4, 0, sizeof(*pi4));
3596 /*********************************************************************
3597 * WINSPOOL_GetPrinter_5
3599 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3601 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3602 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3604 DWORD size, left = cbBuf;
3605 BOOL space = (cbBuf > 0);
3610 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3611 if(space && size <= left) {
3612 pi5->pPrinterName = (LPWSTR)ptr;
3619 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3620 if(space && size <= left) {
3621 pi5->pPortName = (LPWSTR)ptr;
3629 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3630 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3632 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3636 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3637 memset(pi5, 0, sizeof(*pi5));
3642 /*********************************************************************
3643 * WINSPOOL_GetPrinter_7
3645 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3647 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3648 DWORD cbBuf, LPDWORD pcbNeeded)
3650 DWORD size, left = cbBuf;
3651 BOOL space = (cbBuf > 0);
3656 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3659 size = sizeof(pi7->pszObjectGUID);
3661 if (space && size <= left) {
3662 pi7->pszObjectGUID = (LPWSTR)ptr;
3669 /* We do not have a Directory Service */
3670 pi7->dwAction = DSPRINT_UNPUBLISH;
3673 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3674 memset(pi7, 0, sizeof(*pi7));
3679 /*********************************************************************
3680 * WINSPOOL_GetPrinter_9
3682 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3684 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3685 DWORD cbBuf, LPDWORD pcbNeeded)
3688 BOOL space = (cbBuf > 0);
3692 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3693 if(space && size <= cbBuf) {
3694 pi9->pDevMode = (LPDEVMODEW)buf;
3701 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3702 if(space && size <= cbBuf) {
3703 pi9->pDevMode = (LPDEVMODEW)buf;
3709 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3710 memset(pi9, 0, sizeof(*pi9));
3715 /*****************************************************************************
3716 * GetPrinterW [WINSPOOL.@]
3718 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3719 DWORD cbBuf, LPDWORD pcbNeeded)
3722 DWORD size, needed = 0;
3724 HKEY hkeyPrinter, hkeyPrinters;
3727 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3729 if (!(name = get_opened_printer_name(hPrinter))) {
3730 SetLastError(ERROR_INVALID_HANDLE);
3734 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3736 ERR("Can't create Printers key\n");
3739 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3741 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3742 RegCloseKey(hkeyPrinters);
3743 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3750 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3752 size = sizeof(PRINTER_INFO_2W);
3754 ptr = pPrinter + size;
3756 memset(pPrinter, 0, size);
3761 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3768 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3770 size = sizeof(PRINTER_INFO_4W);
3772 ptr = pPrinter + size;
3774 memset(pPrinter, 0, size);
3779 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3787 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3789 size = sizeof(PRINTER_INFO_5W);
3791 ptr = pPrinter + size;
3793 memset(pPrinter, 0, size);
3799 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3807 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3809 size = sizeof(PRINTER_INFO_6);
3810 if (size <= cbBuf) {
3811 /* FIXME: We do not update the status yet */
3812 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3824 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3826 size = sizeof(PRINTER_INFO_7W);
3827 if (size <= cbBuf) {
3828 ptr = pPrinter + size;
3830 memset(pPrinter, 0, size);
3836 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3844 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3846 size = sizeof(PRINTER_INFO_9W);
3848 ptr = pPrinter + size;
3850 memset(pPrinter, 0, size);
3856 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3863 FIXME("Unimplemented level %d\n", Level);
3864 SetLastError(ERROR_INVALID_LEVEL);
3865 RegCloseKey(hkeyPrinters);
3866 RegCloseKey(hkeyPrinter);
3870 RegCloseKey(hkeyPrinter);
3871 RegCloseKey(hkeyPrinters);
3873 TRACE("returning %d needed = %d\n", ret, needed);
3874 if(pcbNeeded) *pcbNeeded = needed;
3876 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3880 /*****************************************************************************
3881 * GetPrinterA [WINSPOOL.@]
3883 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3884 DWORD cbBuf, LPDWORD pcbNeeded)
3890 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3892 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3894 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3895 HeapFree(GetProcessHeap(), 0, buf);
3900 /*****************************************************************************
3901 * WINSPOOL_EnumPrintersW
3903 * Implementation of EnumPrintersW
3905 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3906 DWORD dwLevel, LPBYTE lpbPrinters,
3907 DWORD cbBuf, LPDWORD lpdwNeeded,
3908 LPDWORD lpdwReturned)
3911 HKEY hkeyPrinters, hkeyPrinter;
3912 WCHAR PrinterName[255];
3913 DWORD needed = 0, number = 0;
3914 DWORD used, i, left;
3918 memset(lpbPrinters, 0, cbBuf);
3924 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3925 if(dwType == PRINTER_ENUM_DEFAULT)
3928 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3929 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3930 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3932 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3938 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3939 FIXME("dwType = %08x\n", dwType);
3940 SetLastError(ERROR_INVALID_FLAGS);
3944 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3946 ERR("Can't create Printers key\n");
3950 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3951 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3952 RegCloseKey(hkeyPrinters);
3953 ERR("Can't query Printers key\n");
3956 TRACE("Found %d printers\n", number);
3960 used = number * sizeof(PRINTER_INFO_1W);
3963 used = number * sizeof(PRINTER_INFO_2W);
3966 used = number * sizeof(PRINTER_INFO_4W);
3969 used = number * sizeof(PRINTER_INFO_5W);
3973 SetLastError(ERROR_INVALID_LEVEL);
3974 RegCloseKey(hkeyPrinters);
3977 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3979 for(i = 0; i < number; i++) {
3980 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3982 ERR("Can't enum key number %d\n", i);
3983 RegCloseKey(hkeyPrinters);
3986 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3987 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3989 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3990 RegCloseKey(hkeyPrinters);
3995 buf = lpbPrinters + used;
3996 left = cbBuf - used;
4004 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4007 if(pi) pi += sizeof(PRINTER_INFO_1W);
4010 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4013 if(pi) pi += sizeof(PRINTER_INFO_2W);
4016 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4019 if(pi) pi += sizeof(PRINTER_INFO_4W);
4022 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4025 if(pi) pi += sizeof(PRINTER_INFO_5W);
4028 ERR("Shouldn't be here!\n");
4029 RegCloseKey(hkeyPrinter);
4030 RegCloseKey(hkeyPrinters);
4033 RegCloseKey(hkeyPrinter);
4035 RegCloseKey(hkeyPrinters);
4042 memset(lpbPrinters, 0, cbBuf);
4043 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4047 *lpdwReturned = number;
4048 SetLastError(ERROR_SUCCESS);
4053 /******************************************************************
4054 * EnumPrintersW [WINSPOOL.@]
4056 * Enumerates the available printers, print servers and print
4057 * providers, depending on the specified flags, name and level.
4061 * If level is set to 1:
4062 * Returns an array of PRINTER_INFO_1 data structures in the
4063 * lpbPrinters buffer.
4065 * If level is set to 2:
4066 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4067 * Returns an array of PRINTER_INFO_2 data structures in the
4068 * lpbPrinters buffer. Note that according to MSDN also an
4069 * OpenPrinter should be performed on every remote printer.
4071 * If level is set to 4 (officially WinNT only):
4072 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4073 * Fast: Only the registry is queried to retrieve printer names,
4074 * no connection to the driver is made.
4075 * Returns an array of PRINTER_INFO_4 data structures in the
4076 * lpbPrinters buffer.
4078 * If level is set to 5 (officially WinNT4/Win9x only):
4079 * Fast: Only the registry is queried to retrieve printer names,
4080 * no connection to the driver is made.
4081 * Returns an array of PRINTER_INFO_5 data structures in the
4082 * lpbPrinters buffer.
4084 * If level set to 3 or 6+:
4085 * returns zero (failure!)
4087 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4091 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4092 * - Only levels 2, 4 and 5 are implemented at the moment.
4093 * - 16-bit printer drivers are not enumerated.
4094 * - Returned amount of bytes used/needed does not match the real Windoze
4095 * implementation (as in this implementation, all strings are part
4096 * of the buffer, whereas Win32 keeps them somewhere else)
4097 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4100 * - In a regular Wine installation, no registry settings for printers
4101 * exist, which makes this function return an empty list.
4103 BOOL WINAPI EnumPrintersW(
4104 DWORD dwType, /* [in] Types of print objects to enumerate */
4105 LPWSTR lpszName, /* [in] name of objects to enumerate */
4106 DWORD dwLevel, /* [in] type of printer info structure */
4107 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4108 DWORD cbBuf, /* [in] max size of buffer in bytes */
4109 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4110 LPDWORD lpdwReturned /* [out] number of entries returned */
4113 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4114 lpdwNeeded, lpdwReturned);
4117 /******************************************************************
4118 * EnumPrintersA [WINSPOOL.@]
4123 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4124 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4127 UNICODE_STRING pNameU;
4131 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4132 pPrinters, cbBuf, pcbNeeded, pcReturned);
4134 pNameW = asciitounicode(&pNameU, pName);
4136 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4137 MS Office need this */
4138 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4140 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4142 RtlFreeUnicodeString(&pNameU);
4144 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4146 HeapFree(GetProcessHeap(), 0, pPrintersW);
4150 /*****************************************************************************
4151 * WINSPOOL_GetDriverInfoFromReg [internal]
4153 * Enters the information from the registry into the DRIVER_INFO struct
4156 * zero if the printer driver does not exist in the registry
4157 * (only if Level > 1) otherwise nonzero
4159 static BOOL WINSPOOL_GetDriverInfoFromReg(
4162 const printenv_t * env,
4164 LPBYTE ptr, /* DRIVER_INFO */
4165 LPBYTE pDriverStrings, /* strings buffer */
4166 DWORD cbBuf, /* size of string buffer */
4167 LPDWORD pcbNeeded) /* space needed for str. */
4171 WCHAR driverdir[MAX_PATH];
4173 LPBYTE strPtr = pDriverStrings;
4174 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4176 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4177 debugstr_w(DriverName), env,
4178 Level, di, pDriverStrings, cbBuf);
4180 if (di) ZeroMemory(di, di_sizeof[Level]);
4182 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4183 if (*pcbNeeded <= cbBuf)
4184 strcpyW((LPWSTR)strPtr, DriverName);
4186 /* pName for level 1 has a different offset! */
4188 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4192 /* .cVersion and .pName for level > 1 */
4194 di->cVersion = env->driverversion;
4195 di->pName = (LPWSTR) strPtr;
4196 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4199 /* Reserve Space for the largest subdir and a Backslash*/
4200 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4201 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4202 /* Should never Fail */
4205 lstrcatW(driverdir, env->versionsubdir);
4206 lstrcatW(driverdir, backslashW);
4208 /* dirlen must not include the terminating zero */
4209 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4211 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4212 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4213 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4218 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4221 if (*pcbNeeded <= cbBuf) {
4222 lstrcpyW((LPWSTR)strPtr, env->envname);
4223 if (di) di->pEnvironment = (LPWSTR)strPtr;
4224 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4227 /* .pDriverPath is the Graphics rendering engine.
4228 The full Path is required to avoid a crash in some apps */
4229 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4231 if (*pcbNeeded <= cbBuf)
4232 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4234 if (di) di->pDriverPath = (LPWSTR)strPtr;
4235 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4238 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4239 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4241 if (*pcbNeeded <= cbBuf)
4242 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4244 if (di) di->pDataFile = (LPWSTR)strPtr;
4245 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4248 /* .pConfigFile is the Driver user Interface */
4249 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4251 if (*pcbNeeded <= cbBuf)
4252 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4254 if (di) di->pConfigFile = (LPWSTR)strPtr;
4255 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4259 RegCloseKey(hkeyDriver);
4260 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4265 RegCloseKey(hkeyDriver);
4266 FIXME("level 5: incomplete\n");
4271 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4273 if (*pcbNeeded <= cbBuf)
4274 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4276 if (di) di->pHelpFile = (LPWSTR)strPtr;
4277 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4280 /* .pDependentFiles */
4281 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4283 if (*pcbNeeded <= cbBuf)
4284 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4286 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4287 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4289 else if (GetVersion() & 0x80000000) {
4290 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4291 size = 2 * sizeof(WCHAR);
4293 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4295 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4296 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4299 /* .pMonitorName is the optional Language Monitor */
4300 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4302 if (*pcbNeeded <= cbBuf)
4303 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4305 if (di) di->pMonitorName = (LPWSTR)strPtr;
4306 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4309 /* .pDefaultDataType */
4310 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4312 if(*pcbNeeded <= cbBuf)
4313 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4315 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4316 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4320 RegCloseKey(hkeyDriver);
4321 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4325 /* .pszzPreviousNames */
4326 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4328 if(*pcbNeeded <= cbBuf)
4329 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4331 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4332 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4336 RegCloseKey(hkeyDriver);
4337 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4341 /* support is missing, but not important enough for a FIXME */
4342 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4345 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4347 if(*pcbNeeded <= cbBuf)
4348 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4350 if (di) di->pszMfgName = (LPWSTR)strPtr;
4351 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4355 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4357 if(*pcbNeeded <= cbBuf)
4358 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4360 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4361 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4364 /* .pszHardwareID */
4365 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4367 if(*pcbNeeded <= cbBuf)
4368 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4370 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4371 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4375 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4377 if(*pcbNeeded <= cbBuf)
4378 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4380 if (di) di->pszProvider = (LPWSTR)strPtr;
4381 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4385 RegCloseKey(hkeyDriver);
4389 /* support is missing, but not important enough for a FIXME */
4390 TRACE("level 8: incomplete\n");
4392 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4393 RegCloseKey(hkeyDriver);
4397 /*****************************************************************************
4398 * GetPrinterDriverW [WINSPOOL.@]
4400 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4401 DWORD Level, LPBYTE pDriverInfo,
4402 DWORD cbBuf, LPDWORD pcbNeeded)
4405 WCHAR DriverName[100];
4406 DWORD ret, type, size, needed = 0;
4408 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4409 const printenv_t * env;
4411 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4412 Level,pDriverInfo,cbBuf, pcbNeeded);
4415 ZeroMemory(pDriverInfo, cbBuf);
4417 if (!(name = get_opened_printer_name(hPrinter))) {
4418 SetLastError(ERROR_INVALID_HANDLE);
4422 if (Level < 1 || Level == 7 || Level > 8) {
4423 SetLastError(ERROR_INVALID_LEVEL);
4427 env = validate_envW(pEnvironment);
4428 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4430 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4432 ERR("Can't create Printers key\n");
4435 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4437 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4438 RegCloseKey(hkeyPrinters);
4439 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4442 size = sizeof(DriverName);
4444 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4445 (LPBYTE)DriverName, &size);
4446 RegCloseKey(hkeyPrinter);
4447 RegCloseKey(hkeyPrinters);
4448 if(ret != ERROR_SUCCESS) {
4449 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4453 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4455 ERR("Can't create Drivers key\n");
4459 size = di_sizeof[Level];
4460 if ((size <= cbBuf) && pDriverInfo)
4461 ptr = pDriverInfo + size;
4463 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4464 env, Level, pDriverInfo, ptr,
4465 (cbBuf < size) ? 0 : cbBuf - size,
4467 RegCloseKey(hkeyDrivers);
4471 RegCloseKey(hkeyDrivers);
4473 if(pcbNeeded) *pcbNeeded = size + needed;
4474 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4475 if(cbBuf >= size + needed) return TRUE;
4476 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4480 /*****************************************************************************
4481 * GetPrinterDriverA [WINSPOOL.@]
4483 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4484 DWORD Level, LPBYTE pDriverInfo,
4485 DWORD cbBuf, LPDWORD pcbNeeded)
4488 UNICODE_STRING pEnvW;
4494 ZeroMemory(pDriverInfo, cbBuf);
4495 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4498 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4499 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4502 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4504 HeapFree(GetProcessHeap(), 0, buf);
4506 RtlFreeUnicodeString(&pEnvW);
4510 /*****************************************************************************
4511 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4513 * Return the PATH for the Printer-Drivers (UNICODE)
4516 * pName [I] Servername (NT only) or NULL (local Computer)
4517 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4518 * Level [I] Structure-Level (must be 1)
4519 * pDriverDirectory [O] PTR to Buffer that receives the Result
4520 * cbBuf [I] Size of Buffer at pDriverDirectory
4521 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4522 * required for pDriverDirectory
4525 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4526 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4527 * if cbBuf is too small
4529 * Native Values returned in pDriverDirectory on Success:
4530 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4531 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4532 *| win9x(Windows 4.0): "%winsysdir%"
4534 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4537 *- Only NULL or "" is supported for pName
4540 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4541 DWORD Level, LPBYTE pDriverDirectory,
4542 DWORD cbBuf, LPDWORD pcbNeeded)
4544 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4545 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4547 if ((backend == NULL) && !load_backend()) return FALSE;
4550 /* (Level != 1) is ignored in win9x */
4551 SetLastError(ERROR_INVALID_LEVEL);
4554 if (pcbNeeded == NULL) {
4555 /* (pcbNeeded == NULL) is ignored in win9x */
4556 SetLastError(RPC_X_NULL_REF_POINTER);
4560 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4561 pDriverDirectory, cbBuf, pcbNeeded);
4566 /*****************************************************************************
4567 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4569 * Return the PATH for the Printer-Drivers (ANSI)
4571 * See GetPrinterDriverDirectoryW.
4574 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4577 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4578 DWORD Level, LPBYTE pDriverDirectory,
4579 DWORD cbBuf, LPDWORD pcbNeeded)
4581 UNICODE_STRING nameW, environmentW;
4584 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4585 WCHAR *driverDirectoryW = NULL;
4587 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4588 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4590 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4592 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4593 else nameW.Buffer = NULL;
4594 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4595 else environmentW.Buffer = NULL;
4597 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4598 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4601 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4602 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4604 *pcbNeeded = needed;
4605 ret = (needed <= cbBuf) ? TRUE : FALSE;
4607 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4609 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4611 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4612 RtlFreeUnicodeString(&environmentW);
4613 RtlFreeUnicodeString(&nameW);
4618 /*****************************************************************************
4619 * AddPrinterDriverA [WINSPOOL.@]
4621 * See AddPrinterDriverW.
4624 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4626 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4627 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4630 /******************************************************************************
4631 * AddPrinterDriverW (WINSPOOL.@)
4633 * Install a Printer Driver
4636 * pName [I] Servername or NULL (local Computer)
4637 * level [I] Level for the supplied DRIVER_INFO_*W struct
4638 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4645 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4647 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4648 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4651 /*****************************************************************************
4652 * AddPrintProcessorA [WINSPOOL.@]
4654 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4655 LPSTR pPrintProcessorName)
4657 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4658 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4662 /*****************************************************************************
4663 * AddPrintProcessorW [WINSPOOL.@]
4665 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4666 LPWSTR pPrintProcessorName)
4668 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4669 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4673 /*****************************************************************************
4674 * AddPrintProvidorA [WINSPOOL.@]
4676 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4678 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4682 /*****************************************************************************
4683 * AddPrintProvidorW [WINSPOOL.@]
4685 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4687 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4691 /*****************************************************************************
4692 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4694 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4695 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4697 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4698 pDevModeOutput, pDevModeInput);
4702 /*****************************************************************************
4703 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4705 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4706 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4708 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4709 pDevModeOutput, pDevModeInput);
4713 /*****************************************************************************
4714 * PrinterProperties [WINSPOOL.@]
4716 * Displays a dialog to set the properties of the printer.
4719 * nonzero on success or zero on failure
4722 * implemented as stub only
4724 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4725 HANDLE hPrinter /* [in] handle to printer object */
4727 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4728 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4732 /*****************************************************************************
4733 * EnumJobsA [WINSPOOL.@]
4736 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4737 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4740 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4741 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4743 if(pcbNeeded) *pcbNeeded = 0;
4744 if(pcReturned) *pcReturned = 0;
4749 /*****************************************************************************
4750 * EnumJobsW [WINSPOOL.@]
4753 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4754 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4757 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4758 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4760 if(pcbNeeded) *pcbNeeded = 0;
4761 if(pcReturned) *pcReturned = 0;
4765 /*****************************************************************************
4766 * WINSPOOL_EnumPrinterDrivers [internal]
4768 * Delivers information about all printer drivers installed on the
4769 * localhost or a given server
4772 * nonzero on success or zero on failure. If the buffer for the returned
4773 * information is too small the function will return an error
4776 * - only implemented for localhost, foreign hosts will return an error
4778 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4779 DWORD Level, LPBYTE pDriverInfo,
4781 DWORD cbBuf, LPDWORD pcbNeeded,
4782 LPDWORD pcFound, DWORD data_offset)
4786 const printenv_t * env;
4788 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4789 debugstr_w(pName), debugstr_w(pEnvironment),
4790 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4792 env = validate_envW(pEnvironment);
4793 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4797 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4799 ERR("Can't open Drivers key\n");
4803 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4804 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4805 RegCloseKey(hkeyDrivers);
4806 ERR("Can't query Drivers key\n");
4809 TRACE("Found %d Drivers\n", *pcFound);
4811 /* get size of single struct
4812 * unicode and ascii structure have the same size
4814 size = di_sizeof[Level];
4816 if (data_offset == 0)
4817 data_offset = size * (*pcFound);
4818 *pcbNeeded = data_offset;
4820 for( i = 0; i < *pcFound; i++) {
4821 WCHAR DriverNameW[255];
4822 PBYTE table_ptr = NULL;
4823 PBYTE data_ptr = NULL;
4826 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4828 ERR("Can't enum key number %d\n", i);
4829 RegCloseKey(hkeyDrivers);
4833 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4834 table_ptr = pDriverInfo + (driver_index + i) * size;
4835 if (pDriverInfo && *pcbNeeded <= cbBuf)
4836 data_ptr = pDriverInfo + *pcbNeeded;
4838 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4839 env, Level, table_ptr, data_ptr,
4840 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4842 RegCloseKey(hkeyDrivers);
4846 *pcbNeeded += needed;
4849 RegCloseKey(hkeyDrivers);
4851 if(cbBuf < *pcbNeeded){
4852 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4859 /*****************************************************************************
4860 * EnumPrinterDriversW [WINSPOOL.@]
4862 * see function EnumPrinterDrivers for RETURNS, BUGS
4864 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4865 LPBYTE pDriverInfo, DWORD cbBuf,
4866 LPDWORD pcbNeeded, LPDWORD pcReturned)
4868 static const WCHAR allW[] = {'a','l','l',0};
4872 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4874 SetLastError(RPC_X_NULL_REF_POINTER);
4878 /* check for local drivers */
4879 if((pName) && (pName[0])) {
4880 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4881 SetLastError(ERROR_ACCESS_DENIED);
4885 /* check input parameter */
4886 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4887 SetLastError(ERROR_INVALID_LEVEL);
4891 if(pDriverInfo && cbBuf > 0)
4892 memset( pDriverInfo, 0, cbBuf);
4894 /* Exception: pull all printers */
4895 if (pEnvironment && !strcmpW(pEnvironment, allW))
4897 DWORD i, needed, bufsize = cbBuf;
4898 DWORD total_needed = 0;
4899 DWORD total_found = 0;
4902 /* Precompute the overall total; we need this to know
4903 where pointers end and data begins (i.e. data_offset) */
4904 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4907 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4908 NULL, 0, 0, &needed, &found, 0);
4909 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4910 total_needed += needed;
4911 total_found += found;
4914 data_offset = di_sizeof[Level] * total_found;
4919 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4922 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4923 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4924 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4926 *pcReturned += found;
4927 *pcbNeeded = needed;
4928 data_offset = needed;
4929 total_found += found;
4934 /* Normal behavior */
4935 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4936 0, cbBuf, pcbNeeded, &found, 0);
4938 *pcReturned = found;
4943 /*****************************************************************************
4944 * EnumPrinterDriversA [WINSPOOL.@]
4946 * see function EnumPrinterDrivers for RETURNS, BUGS
4948 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4949 LPBYTE pDriverInfo, DWORD cbBuf,
4950 LPDWORD pcbNeeded, LPDWORD pcReturned)
4953 UNICODE_STRING pNameW, pEnvironmentW;
4954 PWSTR pwstrNameW, pwstrEnvironmentW;
4958 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4960 pwstrNameW = asciitounicode(&pNameW, pName);
4961 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4963 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4964 buf, cbBuf, pcbNeeded, pcReturned);
4966 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4968 HeapFree(GetProcessHeap(), 0, buf);
4970 RtlFreeUnicodeString(&pNameW);
4971 RtlFreeUnicodeString(&pEnvironmentW);
4976 /******************************************************************************
4977 * EnumPortsA (WINSPOOL.@)
4982 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4983 LPDWORD pcbNeeded, LPDWORD pcReturned)
4986 LPBYTE bufferW = NULL;
4987 LPWSTR nameW = NULL;
4989 DWORD numentries = 0;
4992 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4993 cbBuf, pcbNeeded, pcReturned);
4995 /* convert servername to unicode */
4997 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4998 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4999 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5001 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5002 needed = cbBuf * sizeof(WCHAR);
5003 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5004 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5006 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5007 if (pcbNeeded) needed = *pcbNeeded;
5008 /* HeapReAlloc return NULL, when bufferW was NULL */
5009 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5010 HeapAlloc(GetProcessHeap(), 0, needed);
5012 /* Try again with the large Buffer */
5013 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5015 needed = pcbNeeded ? *pcbNeeded : 0;
5016 numentries = pcReturned ? *pcReturned : 0;
5019 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5020 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5023 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5024 DWORD entrysize = 0;
5027 LPPORT_INFO_2W pi2w;
5028 LPPORT_INFO_2A pi2a;
5031 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5033 /* First pass: calculate the size for all Entries */
5034 pi2w = (LPPORT_INFO_2W) bufferW;
5035 pi2a = (LPPORT_INFO_2A) pPorts;
5037 while (index < numentries) {
5039 needed += entrysize; /* PORT_INFO_?A */
5040 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5042 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5043 NULL, 0, NULL, NULL);
5045 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5046 NULL, 0, NULL, NULL);
5047 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5048 NULL, 0, NULL, NULL);
5050 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5051 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5052 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5055 /* check for errors and quit on failure */
5056 if (cbBuf < needed) {
5057 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5061 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5062 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5063 cbBuf -= len ; /* free Bytes in the user-Buffer */
5064 pi2w = (LPPORT_INFO_2W) bufferW;
5065 pi2a = (LPPORT_INFO_2A) pPorts;
5067 /* Second Pass: Fill the User Buffer (if we have one) */
5068 while ((index < numentries) && pPorts) {
5070 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5071 pi2a->pPortName = ptr;
5072 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5073 ptr, cbBuf , NULL, NULL);
5077 pi2a->pMonitorName = ptr;
5078 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5079 ptr, cbBuf, NULL, NULL);
5083 pi2a->pDescription = ptr;
5084 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5085 ptr, cbBuf, NULL, NULL);
5089 pi2a->fPortType = pi2w->fPortType;
5090 pi2a->Reserved = 0; /* documented: "must be zero" */
5093 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5094 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5095 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5100 if (pcbNeeded) *pcbNeeded = needed;
5101 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5103 HeapFree(GetProcessHeap(), 0, nameW);
5104 HeapFree(GetProcessHeap(), 0, bufferW);
5106 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5107 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5113 /******************************************************************************
5114 * EnumPortsW (WINSPOOL.@)
5116 * Enumerate available Ports
5119 * pName [I] Servername or NULL (local Computer)
5120 * Level [I] Structure-Level (1 or 2)
5121 * pPorts [O] PTR to Buffer that receives the Result
5122 * cbBuf [I] Size of Buffer at pPorts
5123 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5124 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5128 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5131 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5134 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5135 cbBuf, pcbNeeded, pcReturned);
5137 if ((backend == NULL) && !load_backend()) return FALSE;
5139 /* Level is not checked in win9x */
5140 if (!Level || (Level > 2)) {
5141 WARN("level (%d) is ignored in win9x\n", Level);
5142 SetLastError(ERROR_INVALID_LEVEL);
5145 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5146 SetLastError(RPC_X_NULL_REF_POINTER);
5150 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5153 /******************************************************************************
5154 * GetDefaultPrinterW (WINSPOOL.@)
5157 * This function must read the value from data 'device' of key
5158 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5160 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5164 WCHAR *buffer, *ptr;
5168 SetLastError(ERROR_INVALID_PARAMETER);
5172 /* make the buffer big enough for the stuff from the profile/registry,
5173 * the content must fit into the local buffer to compute the correct
5174 * size even if the extern buffer is too small or not given.
5175 * (20 for ,driver,port) */
5177 len = max(100, (insize + 20));
5178 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5180 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5182 SetLastError (ERROR_FILE_NOT_FOUND);
5186 TRACE("%s\n", debugstr_w(buffer));
5188 if ((ptr = strchrW(buffer, ',')) == NULL)
5190 SetLastError(ERROR_INVALID_NAME);
5196 *namesize = strlenW(buffer) + 1;
5197 if(!name || (*namesize > insize))
5199 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5203 strcpyW(name, buffer);
5206 HeapFree( GetProcessHeap(), 0, buffer);
5211 /******************************************************************************
5212 * GetDefaultPrinterA (WINSPOOL.@)
5214 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5218 WCHAR *bufferW = NULL;
5222 SetLastError(ERROR_INVALID_PARAMETER);
5226 if(name && *namesize) {
5228 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5231 if(!GetDefaultPrinterW( bufferW, namesize)) {
5236 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5240 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5243 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5246 HeapFree( GetProcessHeap(), 0, bufferW);
5251 /******************************************************************************
5252 * SetDefaultPrinterW (WINSPOOL.204)
5254 * Set the Name of the Default Printer
5257 * pszPrinter [I] Name of the Printer or NULL
5264 * When the Parameter is NULL or points to an Empty String and
5265 * a Default Printer was already present, then this Function changes nothing.
5266 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5267 * the First enumerated local Printer is used.
5270 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5272 WCHAR default_printer[MAX_PATH];
5273 LPWSTR buffer = NULL;
5279 TRACE("(%s)\n", debugstr_w(pszPrinter));
5280 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5282 default_printer[0] = '\0';
5283 size = sizeof(default_printer)/sizeof(WCHAR);
5285 /* if we have a default Printer, do nothing. */
5286 if (GetDefaultPrinterW(default_printer, &size))
5290 /* we have no default Printer: search local Printers and use the first */
5291 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5293 default_printer[0] = '\0';
5294 size = sizeof(default_printer)/sizeof(WCHAR);
5295 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5297 pszPrinter = default_printer;
5298 TRACE("using %s\n", debugstr_w(pszPrinter));
5303 if (pszPrinter == NULL) {
5304 TRACE("no local printer found\n");
5305 SetLastError(ERROR_FILE_NOT_FOUND);
5310 /* "pszPrinter" is never empty or NULL here. */
5311 namelen = lstrlenW(pszPrinter);
5312 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5313 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5315 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5316 HeapFree(GetProcessHeap(), 0, buffer);
5317 SetLastError(ERROR_FILE_NOT_FOUND);
5321 /* read the devices entry for the printer (driver,port) to build the string for the
5322 default device entry (printer,driver,port) */
5323 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5324 buffer[namelen] = ',';
5325 namelen++; /* move index to the start of the driver */
5327 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5328 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5330 TRACE("set device to %s\n", debugstr_w(buffer));
5332 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5333 TRACE("failed to set the device entry: %d\n", GetLastError());
5334 lres = ERROR_INVALID_PRINTER_NAME;
5337 /* remove the next section, when INIFileMapping is implemented */
5340 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5341 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5348 if (lres != ERROR_FILE_NOT_FOUND)
5349 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5351 SetLastError(ERROR_INVALID_PRINTER_NAME);
5355 HeapFree(GetProcessHeap(), 0, buffer);
5356 return (lres == ERROR_SUCCESS);
5359 /******************************************************************************
5360 * SetDefaultPrinterA (WINSPOOL.202)
5362 * See SetDefaultPrinterW.
5365 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5367 LPWSTR bufferW = NULL;
5370 TRACE("(%s)\n", debugstr_a(pszPrinter));
5372 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5373 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5374 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5376 res = SetDefaultPrinterW(bufferW);
5377 HeapFree(GetProcessHeap(), 0, bufferW);
5381 /******************************************************************************
5382 * SetPrinterDataExA (WINSPOOL.@)
5384 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5385 LPCSTR pValueName, DWORD Type,
5386 LPBYTE pData, DWORD cbData)
5388 HKEY hkeyPrinter, hkeySubkey;
5391 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5392 debugstr_a(pValueName), Type, pData, cbData);
5394 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5398 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5400 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5401 RegCloseKey(hkeyPrinter);
5404 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5405 RegCloseKey(hkeySubkey);
5406 RegCloseKey(hkeyPrinter);
5410 /******************************************************************************
5411 * SetPrinterDataExW (WINSPOOL.@)
5413 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5414 LPCWSTR pValueName, DWORD Type,
5415 LPBYTE pData, DWORD cbData)
5417 HKEY hkeyPrinter, hkeySubkey;
5420 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5421 debugstr_w(pValueName), Type, pData, cbData);
5423 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5427 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5429 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5430 RegCloseKey(hkeyPrinter);
5433 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5434 RegCloseKey(hkeySubkey);
5435 RegCloseKey(hkeyPrinter);
5439 /******************************************************************************
5440 * SetPrinterDataA (WINSPOOL.@)
5442 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5443 LPBYTE pData, DWORD cbData)
5445 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5449 /******************************************************************************
5450 * SetPrinterDataW (WINSPOOL.@)
5452 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5453 LPBYTE pData, DWORD cbData)
5455 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5459 /******************************************************************************
5460 * GetPrinterDataExA (WINSPOOL.@)
5462 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5463 LPCSTR pValueName, LPDWORD pType,
5464 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5466 opened_printer_t *printer;
5467 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5470 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5471 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5473 printer = get_opened_printer(hPrinter);
5474 if(!printer) return ERROR_INVALID_HANDLE;
5476 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5477 if (ret) return ret;
5479 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5481 if (printer->name) {
5483 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5485 RegCloseKey(hkeyPrinters);
5488 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5489 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5490 RegCloseKey(hkeyPrinter);
5491 RegCloseKey(hkeyPrinters);
5496 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5497 0, pType, pData, pcbNeeded);
5499 if (!ret && !pData) ret = ERROR_MORE_DATA;
5501 RegCloseKey(hkeySubkey);
5502 RegCloseKey(hkeyPrinter);
5503 RegCloseKey(hkeyPrinters);
5505 TRACE("--> %d\n", ret);
5509 /******************************************************************************
5510 * GetPrinterDataExW (WINSPOOL.@)
5512 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5513 LPCWSTR pValueName, LPDWORD pType,
5514 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5516 opened_printer_t *printer;
5517 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5520 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5521 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5523 printer = get_opened_printer(hPrinter);
5524 if(!printer) return ERROR_INVALID_HANDLE;
5526 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5527 if (ret) return ret;
5529 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5531 if (printer->name) {
5533 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5535 RegCloseKey(hkeyPrinters);
5538 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5539 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5540 RegCloseKey(hkeyPrinter);
5541 RegCloseKey(hkeyPrinters);
5546 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5547 0, pType, pData, pcbNeeded);
5549 if (!ret && !pData) ret = ERROR_MORE_DATA;
5551 RegCloseKey(hkeySubkey);
5552 RegCloseKey(hkeyPrinter);
5553 RegCloseKey(hkeyPrinters);
5555 TRACE("--> %d\n", ret);
5559 /******************************************************************************
5560 * GetPrinterDataA (WINSPOOL.@)
5562 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5563 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5565 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5566 pData, nSize, pcbNeeded);
5569 /******************************************************************************
5570 * GetPrinterDataW (WINSPOOL.@)
5572 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5573 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5575 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5576 pData, nSize, pcbNeeded);
5579 /*******************************************************************************
5580 * EnumPrinterDataExW [WINSPOOL.@]
5582 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5583 LPBYTE pEnumValues, DWORD cbEnumValues,
5584 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5586 HKEY hkPrinter, hkSubKey;
5587 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5588 cbValueNameLen, cbMaxValueLen, cbValueLen,
5593 PPRINTER_ENUM_VALUESW ppev;
5595 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5597 if (pKeyName == NULL || *pKeyName == 0)
5598 return ERROR_INVALID_PARAMETER;
5600 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5601 if (ret != ERROR_SUCCESS)
5603 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5608 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5609 if (ret != ERROR_SUCCESS)
5611 r = RegCloseKey (hkPrinter);
5612 if (r != ERROR_SUCCESS)
5613 WARN ("RegCloseKey returned %i\n", r);
5614 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5615 debugstr_w (pKeyName), ret);
5619 ret = RegCloseKey (hkPrinter);
5620 if (ret != ERROR_SUCCESS)
5622 ERR ("RegCloseKey returned %i\n", ret);
5623 r = RegCloseKey (hkSubKey);
5624 if (r != ERROR_SUCCESS)
5625 WARN ("RegCloseKey returned %i\n", r);
5629 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5630 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5631 if (ret != ERROR_SUCCESS)
5633 r = RegCloseKey (hkSubKey);
5634 if (r != ERROR_SUCCESS)
5635 WARN ("RegCloseKey returned %i\n", r);
5636 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5640 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5641 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5643 if (cValues == 0) /* empty key */
5645 r = RegCloseKey (hkSubKey);
5646 if (r != ERROR_SUCCESS)
5647 WARN ("RegCloseKey returned %i\n", r);
5648 *pcbEnumValues = *pnEnumValues = 0;
5649 return ERROR_SUCCESS;
5652 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5654 hHeap = GetProcessHeap ();
5657 ERR ("GetProcessHeap failed\n");
5658 r = RegCloseKey (hkSubKey);
5659 if (r != ERROR_SUCCESS)
5660 WARN ("RegCloseKey returned %i\n", r);
5661 return ERROR_OUTOFMEMORY;
5664 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5665 if (lpValueName == NULL)
5667 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5668 r = RegCloseKey (hkSubKey);
5669 if (r != ERROR_SUCCESS)
5670 WARN ("RegCloseKey returned %i\n", r);
5671 return ERROR_OUTOFMEMORY;
5674 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5675 if (lpValue == NULL)
5677 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5678 if (HeapFree (hHeap, 0, lpValueName) == 0)
5679 WARN ("HeapFree failed with code %i\n", GetLastError ());
5680 r = RegCloseKey (hkSubKey);
5681 if (r != ERROR_SUCCESS)
5682 WARN ("RegCloseKey returned %i\n", r);
5683 return ERROR_OUTOFMEMORY;
5686 TRACE ("pass 1: calculating buffer required for all names and values\n");
5688 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5690 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5692 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5694 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5695 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5696 NULL, NULL, lpValue, &cbValueLen);
5697 if (ret != ERROR_SUCCESS)
5699 if (HeapFree (hHeap, 0, lpValue) == 0)
5700 WARN ("HeapFree failed with code %i\n", GetLastError ());
5701 if (HeapFree (hHeap, 0, lpValueName) == 0)
5702 WARN ("HeapFree failed with code %i\n", GetLastError ());
5703 r = RegCloseKey (hkSubKey);
5704 if (r != ERROR_SUCCESS)
5705 WARN ("RegCloseKey returned %i\n", r);
5706 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5710 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5711 debugstr_w (lpValueName), dwIndex,
5712 cbValueNameLen + 1, cbValueLen);
5714 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5715 cbBufSize += cbValueLen;
5718 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5720 *pcbEnumValues = cbBufSize;
5721 *pnEnumValues = cValues;
5723 if (cbEnumValues < cbBufSize) /* buffer too small */
5725 if (HeapFree (hHeap, 0, lpValue) == 0)
5726 WARN ("HeapFree failed with code %i\n", GetLastError ());
5727 if (HeapFree (hHeap, 0, lpValueName) == 0)
5728 WARN ("HeapFree failed with code %i\n", GetLastError ());
5729 r = RegCloseKey (hkSubKey);
5730 if (r != ERROR_SUCCESS)
5731 WARN ("RegCloseKey returned %i\n", r);
5732 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5733 return ERROR_MORE_DATA;
5736 TRACE ("pass 2: copying all names and values to buffer\n");
5738 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5739 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5741 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5743 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5744 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5745 NULL, &dwType, lpValue, &cbValueLen);
5746 if (ret != ERROR_SUCCESS)
5748 if (HeapFree (hHeap, 0, lpValue) == 0)
5749 WARN ("HeapFree failed with code %i\n", GetLastError ());
5750 if (HeapFree (hHeap, 0, lpValueName) == 0)
5751 WARN ("HeapFree failed with code %i\n", GetLastError ());
5752 r = RegCloseKey (hkSubKey);
5753 if (r != ERROR_SUCCESS)
5754 WARN ("RegCloseKey returned %i\n", r);
5755 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5759 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5760 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5761 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5762 pEnumValues += cbValueNameLen;
5764 /* return # of *bytes* (including trailing \0), not # of chars */
5765 ppev[dwIndex].cbValueName = cbValueNameLen;
5767 ppev[dwIndex].dwType = dwType;
5769 memcpy (pEnumValues, lpValue, cbValueLen);
5770 ppev[dwIndex].pData = pEnumValues;
5771 pEnumValues += cbValueLen;
5773 ppev[dwIndex].cbData = cbValueLen;
5775 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5776 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5779 if (HeapFree (hHeap, 0, lpValue) == 0)
5781 ret = GetLastError ();
5782 ERR ("HeapFree failed with code %i\n", ret);
5783 if (HeapFree (hHeap, 0, lpValueName) == 0)
5784 WARN ("HeapFree failed with code %i\n", GetLastError ());
5785 r = RegCloseKey (hkSubKey);
5786 if (r != ERROR_SUCCESS)
5787 WARN ("RegCloseKey returned %i\n", r);
5791 if (HeapFree (hHeap, 0, lpValueName) == 0)
5793 ret = GetLastError ();
5794 ERR ("HeapFree failed with code %i\n", ret);
5795 r = RegCloseKey (hkSubKey);
5796 if (r != ERROR_SUCCESS)
5797 WARN ("RegCloseKey returned %i\n", r);
5801 ret = RegCloseKey (hkSubKey);
5802 if (ret != ERROR_SUCCESS)
5804 ERR ("RegCloseKey returned %i\n", ret);
5808 return ERROR_SUCCESS;
5811 /*******************************************************************************
5812 * EnumPrinterDataExA [WINSPOOL.@]
5814 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5815 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5816 * what Windows 2000 SP1 does.
5819 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5820 LPBYTE pEnumValues, DWORD cbEnumValues,
5821 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5825 DWORD ret, dwIndex, dwBufSize;
5829 TRACE ("%p %s\n", hPrinter, pKeyName);
5831 if (pKeyName == NULL || *pKeyName == 0)
5832 return ERROR_INVALID_PARAMETER;
5834 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5837 ret = GetLastError ();
5838 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5842 hHeap = GetProcessHeap ();
5845 ERR ("GetProcessHeap failed\n");
5846 return ERROR_OUTOFMEMORY;
5849 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5850 if (pKeyNameW == NULL)
5852 ERR ("Failed to allocate %i bytes from process heap\n",
5853 (LONG)(len * sizeof (WCHAR)));
5854 return ERROR_OUTOFMEMORY;
5857 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5859 ret = GetLastError ();
5860 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5861 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5862 WARN ("HeapFree failed with code %i\n", GetLastError ());
5866 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5867 pcbEnumValues, pnEnumValues);
5868 if (ret != ERROR_SUCCESS)
5870 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5871 WARN ("HeapFree failed with code %i\n", GetLastError ());
5872 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5876 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5878 ret = GetLastError ();
5879 ERR ("HeapFree failed with code %i\n", ret);
5883 if (*pnEnumValues == 0) /* empty key */
5884 return ERROR_SUCCESS;
5887 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5889 PPRINTER_ENUM_VALUESW ppev =
5890 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5892 if (dwBufSize < ppev->cbValueName)
5893 dwBufSize = ppev->cbValueName;
5895 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5896 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5897 dwBufSize = ppev->cbData;
5900 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5902 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5903 if (pBuffer == NULL)
5905 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5906 return ERROR_OUTOFMEMORY;
5909 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5911 PPRINTER_ENUM_VALUESW ppev =
5912 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5914 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5915 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5919 ret = GetLastError ();
5920 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5921 if (HeapFree (hHeap, 0, pBuffer) == 0)
5922 WARN ("HeapFree failed with code %i\n", GetLastError ());
5926 memcpy (ppev->pValueName, pBuffer, len);
5928 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5930 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5931 ppev->dwType != REG_MULTI_SZ)
5934 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5935 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5938 ret = GetLastError ();
5939 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5940 if (HeapFree (hHeap, 0, pBuffer) == 0)
5941 WARN ("HeapFree failed with code %i\n", GetLastError ());
5945 memcpy (ppev->pData, pBuffer, len);
5947 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5948 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5951 if (HeapFree (hHeap, 0, pBuffer) == 0)
5953 ret = GetLastError ();
5954 ERR ("HeapFree failed with code %i\n", ret);
5958 return ERROR_SUCCESS;
5961 /******************************************************************************
5962 * AbortPrinter (WINSPOOL.@)
5964 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5966 FIXME("(%p), stub!\n", hPrinter);
5970 /******************************************************************************
5971 * AddPortA (WINSPOOL.@)
5976 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5978 LPWSTR nameW = NULL;
5979 LPWSTR monitorW = NULL;
5983 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5986 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5987 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5988 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5992 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5993 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5994 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5996 res = AddPortW(nameW, hWnd, monitorW);
5997 HeapFree(GetProcessHeap(), 0, nameW);
5998 HeapFree(GetProcessHeap(), 0, monitorW);
6002 /******************************************************************************
6003 * AddPortW (WINSPOOL.@)
6005 * Add a Port for a specific Monitor
6008 * pName [I] Servername or NULL (local Computer)
6009 * hWnd [I] Handle to parent Window for the Dialog-Box
6010 * pMonitorName [I] Name of the Monitor that manage the Port
6017 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6019 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6021 if ((backend == NULL) && !load_backend()) return FALSE;
6023 if (!pMonitorName) {
6024 SetLastError(RPC_X_NULL_REF_POINTER);
6028 return backend->fpAddPort(pName, hWnd, pMonitorName);
6031 /******************************************************************************
6032 * AddPortExA (WINSPOOL.@)
6037 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6040 PORT_INFO_2A * pi2A;
6041 LPWSTR nameW = NULL;
6042 LPWSTR monitorW = NULL;
6046 pi2A = (PORT_INFO_2A *) pBuffer;
6048 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6049 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6051 if ((level < 1) || (level > 2)) {
6052 SetLastError(ERROR_INVALID_LEVEL);
6057 SetLastError(ERROR_INVALID_PARAMETER);
6062 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6063 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6064 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6068 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6069 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6070 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6073 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6075 if (pi2A->pPortName) {
6076 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6077 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6078 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6082 if (pi2A->pMonitorName) {
6083 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6084 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6085 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6088 if (pi2A->pDescription) {
6089 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6090 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6091 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6093 pi2W.fPortType = pi2A->fPortType;
6094 pi2W.Reserved = pi2A->Reserved;
6097 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6099 HeapFree(GetProcessHeap(), 0, nameW);
6100 HeapFree(GetProcessHeap(), 0, monitorW);
6101 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6102 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6103 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6108 /******************************************************************************
6109 * AddPortExW (WINSPOOL.@)
6111 * Add a Port for a specific Monitor, without presenting a user interface
6114 * pName [I] Servername or NULL (local Computer)
6115 * level [I] Structure-Level (1 or 2) for pBuffer
6116 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6117 * pMonitorName [I] Name of the Monitor that manage the Port
6124 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6128 pi2 = (PORT_INFO_2W *) pBuffer;
6130 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6131 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6132 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6133 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6135 if ((backend == NULL) && !load_backend()) return FALSE;
6137 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6138 SetLastError(ERROR_INVALID_PARAMETER);
6142 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6145 /******************************************************************************
6146 * AddPrinterConnectionA (WINSPOOL.@)
6148 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6150 FIXME("%s\n", debugstr_a(pName));
6154 /******************************************************************************
6155 * AddPrinterConnectionW (WINSPOOL.@)
6157 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6159 FIXME("%s\n", debugstr_w(pName));
6163 /******************************************************************************
6164 * AddPrinterDriverExW (WINSPOOL.@)
6166 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6169 * pName [I] Servername or NULL (local Computer)
6170 * level [I] Level for the supplied DRIVER_INFO_*W struct
6171 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6172 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6179 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6181 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6183 if ((backend == NULL) && !load_backend()) return FALSE;
6185 if (level < 2 || level == 5 || level == 7 || level > 8) {
6186 SetLastError(ERROR_INVALID_LEVEL);
6191 SetLastError(ERROR_INVALID_PARAMETER);
6195 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6198 /******************************************************************************
6199 * AddPrinterDriverExA (WINSPOOL.@)
6201 * See AddPrinterDriverExW.
6204 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6206 DRIVER_INFO_8A *diA;
6208 LPWSTR nameW = NULL;
6213 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6215 diA = (DRIVER_INFO_8A *) pDriverInfo;
6216 ZeroMemory(&diW, sizeof(diW));
6218 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6219 SetLastError(ERROR_INVALID_LEVEL);
6224 SetLastError(ERROR_INVALID_PARAMETER);
6228 /* convert servername to unicode */
6230 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6231 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6232 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6236 diW.cVersion = diA->cVersion;
6239 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6240 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6241 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6244 if (diA->pEnvironment) {
6245 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6246 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6247 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6250 if (diA->pDriverPath) {
6251 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6252 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6253 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6256 if (diA->pDataFile) {
6257 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6258 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6259 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6262 if (diA->pConfigFile) {
6263 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6264 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6265 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6268 if ((Level > 2) && diA->pDependentFiles) {
6269 lenA = multi_sz_lenA(diA->pDependentFiles);
6270 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6271 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6272 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6275 if ((Level > 2) && diA->pMonitorName) {
6276 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6277 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6278 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6281 if ((Level > 3) && diA->pDefaultDataType) {
6282 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6283 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6284 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6287 if ((Level > 3) && diA->pszzPreviousNames) {
6288 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6289 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6290 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6291 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6294 if ((Level > 5) && diA->pszMfgName) {
6295 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6296 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6297 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6300 if ((Level > 5) && diA->pszOEMUrl) {
6301 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6302 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6303 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6306 if ((Level > 5) && diA->pszHardwareID) {
6307 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6308 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6309 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6312 if ((Level > 5) && diA->pszProvider) {
6313 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6314 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6315 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6319 FIXME("level %u is incomplete\n", Level);
6322 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6323 TRACE("got %u with %u\n", res, GetLastError());
6324 HeapFree(GetProcessHeap(), 0, nameW);
6325 HeapFree(GetProcessHeap(), 0, diW.pName);
6326 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6327 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6328 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6329 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6330 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6331 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6332 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6333 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6334 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6335 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6336 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6337 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6339 TRACE("=> %u with %u\n", res, GetLastError());
6343 /******************************************************************************
6344 * ConfigurePortA (WINSPOOL.@)
6346 * See ConfigurePortW.
6349 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6351 LPWSTR nameW = NULL;
6352 LPWSTR portW = NULL;
6356 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6358 /* convert servername to unicode */
6360 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6361 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6362 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6365 /* convert portname to unicode */
6367 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6368 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6369 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6372 res = ConfigurePortW(nameW, hWnd, portW);
6373 HeapFree(GetProcessHeap(), 0, nameW);
6374 HeapFree(GetProcessHeap(), 0, portW);
6378 /******************************************************************************
6379 * ConfigurePortW (WINSPOOL.@)
6381 * Display the Configuration-Dialog for a specific Port
6384 * pName [I] Servername or NULL (local Computer)
6385 * hWnd [I] Handle to parent Window for the Dialog-Box
6386 * pPortName [I] Name of the Port, that should be configured
6393 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6396 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6398 if ((backend == NULL) && !load_backend()) return FALSE;
6401 SetLastError(RPC_X_NULL_REF_POINTER);
6405 return backend->fpConfigurePort(pName, hWnd, pPortName);
6408 /******************************************************************************
6409 * ConnectToPrinterDlg (WINSPOOL.@)
6411 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6413 FIXME("%p %x\n", hWnd, Flags);
6417 /******************************************************************************
6418 * DeletePrinterConnectionA (WINSPOOL.@)
6420 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6422 FIXME("%s\n", debugstr_a(pName));
6426 /******************************************************************************
6427 * DeletePrinterConnectionW (WINSPOOL.@)
6429 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6431 FIXME("%s\n", debugstr_w(pName));
6435 /******************************************************************************
6436 * DeletePrinterDriverExW (WINSPOOL.@)
6438 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6439 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6444 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6445 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6447 if(pName && pName[0])
6449 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6450 SetLastError(ERROR_INVALID_PARAMETER);
6456 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6457 SetLastError(ERROR_INVALID_PARAMETER);
6461 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6465 ERR("Can't open drivers key\n");
6469 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6472 RegCloseKey(hkey_drivers);
6477 /******************************************************************************
6478 * DeletePrinterDriverExA (WINSPOOL.@)
6480 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6481 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6483 UNICODE_STRING NameW, EnvW, DriverW;
6486 asciitounicode(&NameW, pName);
6487 asciitounicode(&EnvW, pEnvironment);
6488 asciitounicode(&DriverW, pDriverName);
6490 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6492 RtlFreeUnicodeString(&DriverW);
6493 RtlFreeUnicodeString(&EnvW);
6494 RtlFreeUnicodeString(&NameW);
6499 /******************************************************************************
6500 * DeletePrinterDataExW (WINSPOOL.@)
6502 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6505 FIXME("%p %s %s\n", hPrinter,
6506 debugstr_w(pKeyName), debugstr_w(pValueName));
6507 return ERROR_INVALID_PARAMETER;
6510 /******************************************************************************
6511 * DeletePrinterDataExA (WINSPOOL.@)
6513 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6516 FIXME("%p %s %s\n", hPrinter,
6517 debugstr_a(pKeyName), debugstr_a(pValueName));
6518 return ERROR_INVALID_PARAMETER;
6521 /******************************************************************************
6522 * DeletePrintProcessorA (WINSPOOL.@)
6524 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6526 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6527 debugstr_a(pPrintProcessorName));
6531 /******************************************************************************
6532 * DeletePrintProcessorW (WINSPOOL.@)
6534 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6536 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6537 debugstr_w(pPrintProcessorName));
6541 /******************************************************************************
6542 * DeletePrintProvidorA (WINSPOOL.@)
6544 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6546 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6547 debugstr_a(pPrintProviderName));
6551 /******************************************************************************
6552 * DeletePrintProvidorW (WINSPOOL.@)
6554 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6556 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6557 debugstr_w(pPrintProviderName));
6561 /******************************************************************************
6562 * EnumFormsA (WINSPOOL.@)
6564 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6565 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6567 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6568 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6572 /******************************************************************************
6573 * EnumFormsW (WINSPOOL.@)
6575 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6576 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6578 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6579 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6583 /*****************************************************************************
6584 * EnumMonitorsA [WINSPOOL.@]
6586 * See EnumMonitorsW.
6589 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6590 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6593 LPBYTE bufferW = NULL;
6594 LPWSTR nameW = NULL;
6596 DWORD numentries = 0;
6599 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6600 cbBuf, pcbNeeded, pcReturned);
6602 /* convert servername to unicode */
6604 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6605 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6606 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6608 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6609 needed = cbBuf * sizeof(WCHAR);
6610 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6611 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6613 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6614 if (pcbNeeded) needed = *pcbNeeded;
6615 /* HeapReAlloc return NULL, when bufferW was NULL */
6616 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6617 HeapAlloc(GetProcessHeap(), 0, needed);
6619 /* Try again with the large Buffer */
6620 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6622 numentries = pcReturned ? *pcReturned : 0;
6625 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6626 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6629 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6630 DWORD entrysize = 0;
6633 LPMONITOR_INFO_2W mi2w;
6634 LPMONITOR_INFO_2A mi2a;
6636 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6637 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6639 /* First pass: calculate the size for all Entries */
6640 mi2w = (LPMONITOR_INFO_2W) bufferW;
6641 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6643 while (index < numentries) {
6645 needed += entrysize; /* MONITOR_INFO_?A */
6646 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6648 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6649 NULL, 0, NULL, NULL);
6651 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6652 NULL, 0, NULL, NULL);
6653 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6654 NULL, 0, NULL, NULL);
6656 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6657 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6658 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6661 /* check for errors and quit on failure */
6662 if (cbBuf < needed) {
6663 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6667 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6668 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6669 cbBuf -= len ; /* free Bytes in the user-Buffer */
6670 mi2w = (LPMONITOR_INFO_2W) bufferW;
6671 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6673 /* Second Pass: Fill the User Buffer (if we have one) */
6674 while ((index < numentries) && pMonitors) {
6676 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6678 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6679 ptr, cbBuf , NULL, NULL);
6683 mi2a->pEnvironment = ptr;
6684 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6685 ptr, cbBuf, NULL, NULL);
6689 mi2a->pDLLName = ptr;
6690 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6691 ptr, cbBuf, NULL, NULL);
6695 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6696 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6697 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6701 if (pcbNeeded) *pcbNeeded = needed;
6702 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6704 HeapFree(GetProcessHeap(), 0, nameW);
6705 HeapFree(GetProcessHeap(), 0, bufferW);
6707 TRACE("returning %d with %d (%d byte for %d entries)\n",
6708 (res), GetLastError(), needed, numentries);
6714 /*****************************************************************************
6715 * EnumMonitorsW [WINSPOOL.@]
6717 * Enumerate available Port-Monitors
6720 * pName [I] Servername or NULL (local Computer)
6721 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6722 * pMonitors [O] PTR to Buffer that receives the Result
6723 * cbBuf [I] Size of Buffer at pMonitors
6724 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6725 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6729 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6732 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6733 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6736 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6737 cbBuf, pcbNeeded, pcReturned);
6739 if ((backend == NULL) && !load_backend()) return FALSE;
6741 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6742 SetLastError(RPC_X_NULL_REF_POINTER);
6746 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6749 /******************************************************************************
6750 * SpoolerInit (WINSPOOL.@)
6752 * Initialize the Spooler
6759 * The function fails on windows, when the spooler service is not running
6762 BOOL WINAPI SpoolerInit(void)
6765 if ((backend == NULL) && !load_backend()) return FALSE;
6769 /******************************************************************************
6770 * XcvDataW (WINSPOOL.@)
6772 * Execute commands in the Printmonitor DLL
6775 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6776 * pszDataName [i] Name of the command to execute
6777 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6778 * cbInputData [i] Size in Bytes of Buffer at pInputData
6779 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6780 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6781 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6782 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6789 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6790 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6792 * Minimal List of commands, that a Printmonitor DLL should support:
6794 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6795 *| "AddPort" : Add a Port
6796 *| "DeletePort": Delete a Port
6798 * Many Printmonitors support additional commands. Examples for localspl.dll:
6799 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6800 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6803 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6804 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6805 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6807 opened_printer_t *printer;
6809 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6810 pInputData, cbInputData, pOutputData,
6811 cbOutputData, pcbOutputNeeded, pdwStatus);
6813 if ((backend == NULL) && !load_backend()) return FALSE;
6815 printer = get_opened_printer(hXcv);
6816 if (!printer || (!printer->backend_printer)) {
6817 SetLastError(ERROR_INVALID_HANDLE);
6821 if (!pcbOutputNeeded) {
6822 SetLastError(ERROR_INVALID_PARAMETER);
6826 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6827 SetLastError(RPC_X_NULL_REF_POINTER);
6831 *pcbOutputNeeded = 0;
6833 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6834 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6838 /*****************************************************************************
6839 * EnumPrinterDataA [WINSPOOL.@]
6842 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6843 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6844 DWORD cbData, LPDWORD pcbData )
6846 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6847 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6848 return ERROR_NO_MORE_ITEMS;
6851 /*****************************************************************************
6852 * EnumPrinterDataW [WINSPOOL.@]
6855 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6856 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6857 DWORD cbData, LPDWORD pcbData )
6859 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6860 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6861 return ERROR_NO_MORE_ITEMS;
6864 /*****************************************************************************
6865 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6868 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6869 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6870 LPDWORD pcbNeeded, LPDWORD pcReturned)
6872 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6873 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6874 pcbNeeded, pcReturned);
6878 /*****************************************************************************
6879 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6882 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6883 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6884 LPDWORD pcbNeeded, LPDWORD pcReturned)
6886 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6887 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6888 pcbNeeded, pcReturned);
6892 /*****************************************************************************
6893 * EnumPrintProcessorsA [WINSPOOL.@]
6895 * See EnumPrintProcessorsW.
6898 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6899 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6902 LPBYTE bufferW = NULL;
6903 LPWSTR nameW = NULL;
6906 DWORD numentries = 0;
6909 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6910 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6912 /* convert names to unicode */
6914 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6915 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6916 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6919 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6920 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6921 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6924 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6925 needed = cbBuf * sizeof(WCHAR);
6926 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6927 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6929 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6930 if (pcbNeeded) needed = *pcbNeeded;
6931 /* HeapReAlloc return NULL, when bufferW was NULL */
6932 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6933 HeapAlloc(GetProcessHeap(), 0, needed);
6935 /* Try again with the large Buffer */
6936 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6938 numentries = pcReturned ? *pcReturned : 0;
6942 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6945 PPRINTPROCESSOR_INFO_1W ppiw;
6946 PPRINTPROCESSOR_INFO_1A ppia;
6948 /* First pass: calculate the size for all Entries */
6949 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6950 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6952 while (index < numentries) {
6954 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6955 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6957 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6958 NULL, 0, NULL, NULL);
6960 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6961 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6964 /* check for errors and quit on failure */
6965 if (cbBuf < needed) {
6966 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6971 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6972 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6973 cbBuf -= len ; /* free Bytes in the user-Buffer */
6974 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6975 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6977 /* Second Pass: Fill the User Buffer (if we have one) */
6978 while ((index < numentries) && pPPInfo) {
6980 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6982 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6983 ptr, cbBuf , NULL, NULL);
6987 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6988 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6993 if (pcbNeeded) *pcbNeeded = needed;
6994 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6996 HeapFree(GetProcessHeap(), 0, nameW);
6997 HeapFree(GetProcessHeap(), 0, envW);
6998 HeapFree(GetProcessHeap(), 0, bufferW);
7000 TRACE("returning %d with %d (%d byte for %d entries)\n",
7001 (res), GetLastError(), needed, numentries);
7006 /*****************************************************************************
7007 * EnumPrintProcessorsW [WINSPOOL.@]
7009 * Enumerate available Print Processors
7012 * pName [I] Servername or NULL (local Computer)
7013 * pEnvironment [I] Printing-Environment or NULL (Default)
7014 * Level [I] Structure-Level (Only 1 is allowed)
7015 * pPPInfo [O] PTR to Buffer that receives the Result
7016 * cbBuf [I] Size of Buffer at pPPInfo
7017 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7018 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7022 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7025 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7026 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7029 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7030 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7032 if ((backend == NULL) && !load_backend()) return FALSE;
7034 if (!pcbNeeded || !pcReturned) {
7035 SetLastError(RPC_X_NULL_REF_POINTER);
7039 if (!pPPInfo && (cbBuf > 0)) {
7040 SetLastError(ERROR_INVALID_USER_BUFFER);
7044 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7045 cbBuf, pcbNeeded, pcReturned);
7048 /*****************************************************************************
7049 * ExtDeviceMode [WINSPOOL.@]
7052 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7053 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7056 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7057 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7058 debugstr_a(pProfile), fMode);
7062 /*****************************************************************************
7063 * FindClosePrinterChangeNotification [WINSPOOL.@]
7066 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7068 FIXME("Stub: %p\n", hChange);
7072 /*****************************************************************************
7073 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7076 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7077 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7079 FIXME("Stub: %p %x %x %p\n",
7080 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7081 return INVALID_HANDLE_VALUE;
7084 /*****************************************************************************
7085 * FindNextPrinterChangeNotification [WINSPOOL.@]
7088 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7089 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7091 FIXME("Stub: %p %p %p %p\n",
7092 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7096 /*****************************************************************************
7097 * FreePrinterNotifyInfo [WINSPOOL.@]
7100 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7102 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7106 /*****************************************************************************
7109 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7110 * ansi depending on the unicode parameter.
7112 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7122 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7125 memcpy(ptr, str, *size);
7132 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7135 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7142 /*****************************************************************************
7145 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7146 LPDWORD pcbNeeded, BOOL unicode)
7148 DWORD size, left = cbBuf;
7149 BOOL space = (cbBuf > 0);
7156 ji1->JobId = job->job_id;
7159 string_to_buf(job->document_title, ptr, left, &size, unicode);
7160 if(space && size <= left)
7162 ji1->pDocument = (LPWSTR)ptr;
7170 if (job->printer_name)
7172 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7173 if(space && size <= left)
7175 ji1->pPrinterName = (LPWSTR)ptr;
7187 /*****************************************************************************
7190 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7191 LPDWORD pcbNeeded, BOOL unicode)
7193 DWORD size, left = cbBuf;
7195 BOOL space = (cbBuf > 0);
7204 ji2->JobId = job->job_id;
7207 string_to_buf(job->document_title, ptr, left, &size, unicode);
7208 if(space && size <= left)
7210 ji2->pDocument = (LPWSTR)ptr;
7218 if (job->printer_name)
7220 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7221 if(space && size <= left)
7223 ji2->pPrinterName = (LPWSTR)ptr;
7236 dmA = DEVMODEdupWtoA(job->devmode);
7237 devmode = (LPDEVMODEW) dmA;
7238 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7242 devmode = job->devmode;
7243 size = devmode->dmSize + devmode->dmDriverExtra;
7247 FIXME("Can't convert DEVMODE W to A\n");
7250 /* align DEVMODE to a DWORD boundary */
7251 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7257 memcpy(ptr, devmode, size-shift);
7258 ji2->pDevMode = (LPDEVMODEW)ptr;
7259 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7272 /*****************************************************************************
7275 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7276 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7279 DWORD needed = 0, size;
7283 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7285 EnterCriticalSection(&printer_handles_cs);
7286 job = get_job(hPrinter, JobId);
7293 size = sizeof(JOB_INFO_1W);
7298 memset(pJob, 0, size);
7302 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7307 size = sizeof(JOB_INFO_2W);
7312 memset(pJob, 0, size);
7316 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7321 size = sizeof(JOB_INFO_3);
7325 memset(pJob, 0, size);
7334 SetLastError(ERROR_INVALID_LEVEL);
7338 *pcbNeeded = needed;
7340 LeaveCriticalSection(&printer_handles_cs);
7344 /*****************************************************************************
7345 * GetJobA [WINSPOOL.@]
7348 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7349 DWORD cbBuf, LPDWORD pcbNeeded)
7351 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7354 /*****************************************************************************
7355 * GetJobW [WINSPOOL.@]
7358 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7359 DWORD cbBuf, LPDWORD pcbNeeded)
7361 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7364 /*****************************************************************************
7367 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7369 char *unixname, *queue, *cmd;
7370 char fmt[] = "lpr -P'%s' '%s'";
7374 if(!(unixname = wine_get_unix_file_name(filename)))
7377 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7378 queue = HeapAlloc(GetProcessHeap(), 0, len);
7379 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7381 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7382 sprintf(cmd, fmt, queue, unixname);
7384 TRACE("printing with: %s\n", cmd);
7387 HeapFree(GetProcessHeap(), 0, cmd);
7388 HeapFree(GetProcessHeap(), 0, queue);
7389 HeapFree(GetProcessHeap(), 0, unixname);
7393 /*****************************************************************************
7396 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7398 #ifdef SONAME_LIBCUPS
7401 char *unixname, *queue, *unix_doc_title;
7405 if(!(unixname = wine_get_unix_file_name(filename)))
7408 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7409 queue = HeapAlloc(GetProcessHeap(), 0, len);
7410 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7412 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7413 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7414 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7416 TRACE("printing via cups\n");
7417 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7418 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7419 HeapFree(GetProcessHeap(), 0, queue);
7420 HeapFree(GetProcessHeap(), 0, unixname);
7426 return schedule_lpr(printer_name, filename);
7430 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7437 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7441 if(HIWORD(wparam) == BN_CLICKED)
7443 if(LOWORD(wparam) == IDOK)
7446 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7449 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7450 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7452 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7454 WCHAR caption[200], message[200];
7457 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7458 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7459 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7460 if(mb_ret == IDCANCEL)
7462 HeapFree(GetProcessHeap(), 0, filename);
7466 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7467 if(hf == INVALID_HANDLE_VALUE)
7469 WCHAR caption[200], message[200];
7471 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7472 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7473 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7474 HeapFree(GetProcessHeap(), 0, filename);
7478 DeleteFileW(filename);
7479 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7481 EndDialog(hwnd, IDOK);
7484 if(LOWORD(wparam) == IDCANCEL)
7486 EndDialog(hwnd, IDCANCEL);
7495 /*****************************************************************************
7498 static BOOL get_filename(LPWSTR *filename)
7500 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7501 file_dlg_proc, (LPARAM)filename) == IDOK;
7504 /*****************************************************************************
7507 static BOOL schedule_file(LPCWSTR filename)
7509 LPWSTR output = NULL;
7511 if(get_filename(&output))
7514 TRACE("copy to %s\n", debugstr_w(output));
7515 r = CopyFileW(filename, output, FALSE);
7516 HeapFree(GetProcessHeap(), 0, output);
7522 /*****************************************************************************
7525 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7528 char *unixname, *cmdA;
7530 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7534 if(!(unixname = wine_get_unix_file_name(filename)))
7537 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7538 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7539 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7541 TRACE("printing with: %s\n", cmdA);
7543 if((file_fd = open(unixname, O_RDONLY)) == -1)
7548 ERR("pipe() failed!\n");
7558 /* reset signals that we previously set to SIG_IGN */
7559 signal(SIGPIPE, SIG_DFL);
7560 signal(SIGCHLD, SIG_DFL);
7562 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7566 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7567 write(fds[1], buf, no_read);
7572 if(file_fd != -1) close(file_fd);
7573 if(fds[0] != -1) close(fds[0]);
7574 if(fds[1] != -1) close(fds[1]);
7576 HeapFree(GetProcessHeap(), 0, cmdA);
7577 HeapFree(GetProcessHeap(), 0, unixname);
7584 /*****************************************************************************
7587 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7589 int in_fd, out_fd, no_read;
7592 char *unixname, *outputA;
7595 if(!(unixname = wine_get_unix_file_name(filename)))
7598 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7599 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7600 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7602 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7603 in_fd = open(unixname, O_RDONLY);
7604 if(out_fd == -1 || in_fd == -1)
7607 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7608 write(out_fd, buf, no_read);
7612 if(in_fd != -1) close(in_fd);
7613 if(out_fd != -1) close(out_fd);
7614 HeapFree(GetProcessHeap(), 0, outputA);
7615 HeapFree(GetProcessHeap(), 0, unixname);
7619 /*****************************************************************************
7620 * ScheduleJob [WINSPOOL.@]
7623 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7625 opened_printer_t *printer;
7627 struct list *cursor, *cursor2;
7629 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7630 EnterCriticalSection(&printer_handles_cs);
7631 printer = get_opened_printer(hPrinter);
7635 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7637 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7640 if(job->job_id != dwJobID) continue;
7642 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7643 if(hf != INVALID_HANDLE_VALUE)
7645 PRINTER_INFO_5W *pi5 = NULL;
7646 LPWSTR portname = job->portname;
7650 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7651 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7655 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7656 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7657 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7658 portname = pi5->pPortName;
7660 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7661 debugstr_w(portname));
7665 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7666 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7668 DWORD type, count = sizeof(output);
7669 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7672 if(output[0] == '|')
7674 ret = schedule_pipe(output + 1, job->filename);
7678 ret = schedule_unixfile(output, job->filename);
7680 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7682 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7684 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7686 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7688 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7690 ret = schedule_file(job->filename);
7694 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7696 HeapFree(GetProcessHeap(), 0, pi5);
7698 DeleteFileW(job->filename);
7700 list_remove(cursor);
7701 HeapFree(GetProcessHeap(), 0, job->document_title);
7702 HeapFree(GetProcessHeap(), 0, job->printer_name);
7703 HeapFree(GetProcessHeap(), 0, job->portname);
7704 HeapFree(GetProcessHeap(), 0, job->filename);
7705 HeapFree(GetProcessHeap(), 0, job->devmode);
7706 HeapFree(GetProcessHeap(), 0, job);
7710 LeaveCriticalSection(&printer_handles_cs);
7714 /*****************************************************************************
7715 * StartDocDlgA [WINSPOOL.@]
7717 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7719 UNICODE_STRING usBuffer;
7722 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7725 docW.cbSize = sizeof(docW);
7726 if (doc->lpszDocName)
7728 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7729 if (!(docW.lpszDocName = docnameW)) return NULL;
7731 if (doc->lpszOutput)
7733 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7734 if (!(docW.lpszOutput = outputW)) return NULL;
7736 if (doc->lpszDatatype)
7738 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7739 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7741 docW.fwType = doc->fwType;
7743 retW = StartDocDlgW(hPrinter, &docW);
7747 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7748 ret = HeapAlloc(GetProcessHeap(), 0, len);
7749 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7750 HeapFree(GetProcessHeap(), 0, retW);
7753 HeapFree(GetProcessHeap(), 0, datatypeW);
7754 HeapFree(GetProcessHeap(), 0, outputW);
7755 HeapFree(GetProcessHeap(), 0, docnameW);
7760 /*****************************************************************************
7761 * StartDocDlgW [WINSPOOL.@]
7763 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7764 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7765 * port is "FILE:". Also returns the full path if passed a relative path.
7767 * The caller should free the returned string from the process heap.
7769 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7774 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7776 PRINTER_INFO_5W *pi5;
7777 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7778 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7780 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7781 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7782 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7784 HeapFree(GetProcessHeap(), 0, pi5);
7787 HeapFree(GetProcessHeap(), 0, pi5);
7790 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7794 if (get_filename(&name))
7796 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7798 HeapFree(GetProcessHeap(), 0, name);
7801 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7802 GetFullPathNameW(name, len, ret, NULL);
7803 HeapFree(GetProcessHeap(), 0, name);
7808 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7811 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7812 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7814 attr = GetFileAttributesW(ret);
7815 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7817 HeapFree(GetProcessHeap(), 0, ret);