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 const 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 const 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;
428 PRINTER_INFO_2A pinfo2a;
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_ACP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
462 port = HeapAlloc(GetProcessHeap(), 0, strlen("CUPS:") + strlen(dests[i].name)+1);
463 sprintf(port,"CUPS:%s", dests[i].name);
465 TRACE("Printer %d: %s\n", i, dests[i].name);
466 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
467 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
469 TRACE("Printer already exists\n");
470 RegSetValueExA(hkeyPrinter, "Port", 0, REG_SZ, (LPBYTE)port, strlen(port) + 1); /* overwrite LPR:* port */
471 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
472 RegCloseKey(hkeyPrinter);
474 static CHAR data_type[] = "RAW",
475 print_proc[] = "WinPrint",
476 comment[] = "WINEPS Printer using CUPS",
477 location[] = "<physical location of printer>",
478 params[] = "<parameters?>",
479 share_name[] = "<share name?>",
480 sep_file[] = "<sep file?>";
482 add_printer_driver(nameW);
484 memset(&pinfo2a,0,sizeof(pinfo2a));
485 pinfo2a.pPrinterName = dests[i].name;
486 pinfo2a.pDatatype = data_type;
487 pinfo2a.pPrintProcessor = print_proc;
488 pinfo2a.pDriverName = dests[i].name;
489 pinfo2a.pComment = comment;
490 pinfo2a.pLocation = location;
491 pinfo2a.pPortName = port;
492 pinfo2a.pParameters = params;
493 pinfo2a.pShareName = share_name;
494 pinfo2a.pSepFile = sep_file;
496 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
497 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
498 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
501 HeapFree(GetProcessHeap(),0,port);
504 if (dests[i].is_default) {
505 SetDefaultPrinterA(dests[i].name);
509 if (hadprinter & !haddefault)
510 SetDefaultPrinterA(dests[0].name);
511 pcupsFreeDests(nrofdests, dests);
512 RegCloseKey(hkeyPrinters);
518 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
519 PRINTER_INFO_2A pinfo2a;
520 char *e,*s,*name,*prettyname,*devname;
521 BOOL ret = FALSE, set_default = FALSE;
522 char *port = NULL, *env_default;
523 HKEY hkeyPrinter, hkeyPrinters;
524 WCHAR devnameW[MAX_PATH];
526 while (isspace(*pent)) pent++;
527 s = strchr(pent,':');
529 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
537 TRACE("name=%s entry=%s\n",name, pent);
539 if(ispunct(*name)) { /* a tc entry, not a real printer */
540 TRACE("skipping tc entry\n");
544 if(strstr(pent,":server")) { /* server only version so skip */
545 TRACE("skipping server entry\n");
549 /* Determine whether this is a postscript printer. */
552 env_default = getenv("PRINTER");
554 /* Get longest name, usually the one at the right for later display. */
555 while((s=strchr(prettyname,'|'))) {
558 while(isspace(*--e)) *e = '\0';
559 TRACE("\t%s\n", debugstr_a(prettyname));
560 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
561 for(prettyname = s+1; isspace(*prettyname); prettyname++)
564 e = prettyname + strlen(prettyname);
565 while(isspace(*--e)) *e = '\0';
566 TRACE("\t%s\n", debugstr_a(prettyname));
567 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
569 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
570 * if it is too long, we use it as comment below. */
571 devname = prettyname;
572 if (strlen(devname)>=CCHDEVICENAME-1)
574 if (strlen(devname)>=CCHDEVICENAME-1) {
579 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
580 sprintf(port,"LPR:%s",name);
582 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
584 ERR("Can't create Printers key\n");
589 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
591 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
592 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
594 TRACE("Printer already exists\n");
595 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
596 RegCloseKey(hkeyPrinter);
598 static CHAR data_type[] = "RAW",
599 print_proc[] = "WinPrint",
600 comment[] = "WINEPS Printer using LPR",
601 params[] = "<parameters?>",
602 share_name[] = "<share name?>",
603 sep_file[] = "<sep file?>";
605 add_printer_driver(devnameW);
607 memset(&pinfo2a,0,sizeof(pinfo2a));
608 pinfo2a.pPrinterName = devname;
609 pinfo2a.pDatatype = data_type;
610 pinfo2a.pPrintProcessor = print_proc;
611 pinfo2a.pDriverName = devname;
612 pinfo2a.pComment = comment;
613 pinfo2a.pLocation = prettyname;
614 pinfo2a.pPortName = port;
615 pinfo2a.pParameters = params;
616 pinfo2a.pShareName = share_name;
617 pinfo2a.pSepFile = sep_file;
619 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
620 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
621 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
624 RegCloseKey(hkeyPrinters);
626 if (isfirst || set_default)
627 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
630 HeapFree(GetProcessHeap(), 0, port);
631 HeapFree(GetProcessHeap(), 0, name);
636 PRINTCAP_LoadPrinters(void) {
637 BOOL hadprinter = FALSE;
641 BOOL had_bash = FALSE;
643 f = fopen("/etc/printcap","r");
647 while(fgets(buf,sizeof(buf),f)) {
650 end=strchr(buf,'\n');
654 while(isspace(*start)) start++;
655 if(*start == '#' || *start == '\0')
658 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
659 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
660 HeapFree(GetProcessHeap(),0,pent);
664 if (end && *--end == '\\') {
671 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
674 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
680 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
681 HeapFree(GetProcessHeap(),0,pent);
687 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
690 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
691 (lstrlenW(value) + 1) * sizeof(WCHAR));
693 return ERROR_FILE_NOT_FOUND;
696 /******************************************************************
697 * get_servername_from_name (internal)
699 * for an external server, a copy of the serverpart from the full name is returned
702 static LPWSTR get_servername_from_name(LPCWSTR name)
706 WCHAR buffer[MAX_PATH];
709 if (name == NULL) return NULL;
710 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
712 server = strdupW(&name[2]); /* skip over both backslash */
713 if (server == NULL) return NULL;
715 /* strip '\' and the printername */
716 ptr = strchrW(server, '\\');
717 if (ptr) ptr[0] = '\0';
719 TRACE("found %s\n", debugstr_w(server));
721 len = sizeof(buffer)/sizeof(buffer[0]);
722 if (GetComputerNameW(buffer, &len)) {
723 if (lstrcmpW(buffer, server) == 0) {
724 /* The requested Servername is our computername */
725 HeapFree(GetProcessHeap(), 0, server);
732 /******************************************************************
733 * get_basename_from_name (internal)
735 * skip over the serverpart from the full name
738 static LPCWSTR get_basename_from_name(LPCWSTR name)
740 if (name == NULL) return NULL;
741 if ((name[0] == '\\') && (name[1] == '\\')) {
742 /* skip over the servername and search for the following '\' */
743 name = strchrW(&name[2], '\\');
744 if ((name) && (name[1])) {
745 /* found a separator ('\') followed by a name:
746 skip over the separator and return the rest */
751 /* no basename present (we found only a servername) */
758 /******************************************************************
759 * get_opened_printer_entry
760 * Get the first place empty in the opened printer table
763 * - pDefault is ignored
765 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
767 UINT_PTR handle = nb_printer_handles, i;
768 jobqueue_t *queue = NULL;
769 opened_printer_t *printer = NULL;
773 if ((backend == NULL) && !load_backend()) return NULL;
775 servername = get_servername_from_name(name);
777 FIXME("server %s not supported\n", debugstr_w(servername));
778 HeapFree(GetProcessHeap(), 0, servername);
779 SetLastError(ERROR_INVALID_PRINTER_NAME);
783 printername = get_basename_from_name(name);
784 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
786 /* an empty printername is invalid */
787 if (printername && (!printername[0])) {
788 SetLastError(ERROR_INVALID_PARAMETER);
792 EnterCriticalSection(&printer_handles_cs);
794 for (i = 0; i < nb_printer_handles; i++)
796 if (!printer_handles[i])
798 if(handle == nb_printer_handles)
803 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
804 queue = printer_handles[i]->queue;
808 if (handle >= nb_printer_handles)
810 opened_printer_t **new_array;
812 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
813 (nb_printer_handles + 16) * sizeof(*new_array) );
815 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
816 (nb_printer_handles + 16) * sizeof(*new_array) );
823 printer_handles = new_array;
824 nb_printer_handles += 16;
827 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
833 /* get a printer handle from the backend */
834 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
839 /* clone the base name. This is NULL for the printserver */
840 printer->printername = strdupW(printername);
842 /* clone the full name */
843 printer->name = strdupW(name);
844 if (name && (!printer->name)) {
850 printer->queue = queue;
853 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
854 if (!printer->queue) {
858 list_init(&printer->queue->jobs);
859 printer->queue->ref = 0;
861 InterlockedIncrement(&printer->queue->ref);
863 printer_handles[handle] = printer;
866 LeaveCriticalSection(&printer_handles_cs);
867 if (!handle && printer) {
868 /* Something failed: Free all resources */
869 HeapFree(GetProcessHeap(), 0, printer->printername);
870 HeapFree(GetProcessHeap(), 0, printer->name);
871 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
872 HeapFree(GetProcessHeap(), 0, printer);
875 return (HANDLE)handle;
878 /******************************************************************
880 * Get the pointer to the opened printer referred by the handle
882 static opened_printer_t *get_opened_printer(HANDLE hprn)
884 UINT_PTR idx = (UINT_PTR)hprn;
885 opened_printer_t *ret = NULL;
887 EnterCriticalSection(&printer_handles_cs);
889 if ((idx > 0) && (idx <= nb_printer_handles)) {
890 ret = printer_handles[idx - 1];
892 LeaveCriticalSection(&printer_handles_cs);
896 /******************************************************************
897 * get_opened_printer_name
898 * Get the pointer to the opened printer name referred by the handle
900 static LPCWSTR get_opened_printer_name(HANDLE hprn)
902 opened_printer_t *printer = get_opened_printer(hprn);
903 if(!printer) return NULL;
904 return printer->name;
907 /******************************************************************
908 * WINSPOOL_GetOpenedPrinterRegKey
911 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
913 LPCWSTR name = get_opened_printer_name(hPrinter);
917 if(!name) return ERROR_INVALID_HANDLE;
919 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
923 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
925 ERR("Can't find opened printer %s in registry\n",
927 RegCloseKey(hkeyPrinters);
928 return ERROR_INVALID_PRINTER_NAME; /* ? */
930 RegCloseKey(hkeyPrinters);
931 return ERROR_SUCCESS;
934 void WINSPOOL_LoadSystemPrinters(void)
936 HKEY hkey, hkeyPrinters;
938 DWORD needed, num, i;
939 WCHAR PrinterName[256];
942 /* This ensures that all printer entries have a valid Name value. If causes
943 problems later if they don't. If one is found to be missed we create one
944 and set it equal to the name of the key */
945 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
946 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
947 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
948 for(i = 0; i < num; i++) {
949 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
950 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
951 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
952 set_reg_szW(hkey, NameW, PrinterName);
959 RegCloseKey(hkeyPrinters);
962 /* We want to avoid calling AddPrinter on printers as much as
963 possible, because on cups printers this will (eventually) lead
964 to a call to cupsGetPPD which takes forever, even with non-cups
965 printers AddPrinter takes a while. So we'll tag all printers that
966 were automatically added last time around, if they still exist
967 we'll leave them be otherwise we'll delete them. */
968 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
970 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
971 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
972 for(i = 0; i < num; i++) {
973 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
974 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
975 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
977 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
985 HeapFree(GetProcessHeap(), 0, pi);
989 #ifdef SONAME_LIBCUPS
990 done = CUPS_LoadPrinters();
993 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
994 PRINTCAP_LoadPrinters();
996 /* Now enumerate the list again and delete any printers that are still tagged */
997 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
999 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1000 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1001 for(i = 0; i < num; i++) {
1002 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1003 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1004 BOOL delete_driver = FALSE;
1005 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1006 DWORD dw, type, size = sizeof(dw);
1007 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1008 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1009 DeletePrinter(hprn);
1010 delete_driver = TRUE;
1016 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1021 HeapFree(GetProcessHeap(), 0, pi);
1028 /******************************************************************
1031 * Get the pointer to the specified job.
1032 * Should hold the printer_handles_cs before calling.
1034 static job_t *get_job(HANDLE hprn, DWORD JobId)
1036 opened_printer_t *printer = get_opened_printer(hprn);
1039 if(!printer) return NULL;
1040 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1042 if(job->job_id == JobId)
1048 /***********************************************************
1051 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1054 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1057 Formname = (dmA->dmSize > off_formname);
1058 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1059 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1060 dmW->dmDeviceName, CCHDEVICENAME);
1062 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1063 dmA->dmSize - CCHDEVICENAME);
1065 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1066 off_formname - CCHDEVICENAME);
1067 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1068 dmW->dmFormName, CCHFORMNAME);
1069 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1070 (off_formname + CCHFORMNAME));
1073 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1074 dmA->dmDriverExtra);
1078 /***********************************************************
1080 * Creates an ansi copy of supplied devmode
1082 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1087 if (!dmW) return NULL;
1088 size = dmW->dmSize - CCHDEVICENAME -
1089 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1091 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1092 if (!dmA) return NULL;
1094 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1095 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1097 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1098 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1099 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1103 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1104 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1105 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1106 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1108 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1112 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1116 /******************************************************************
1117 * convert_printerinfo_W_to_A [internal]
1120 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1121 DWORD level, DWORD outlen, DWORD numentries)
1127 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1129 len = pi_sizeof[level] * numentries;
1130 ptr = (LPSTR) out + len;
1133 /* copy the numbers of all PRINTER_INFO_* first */
1134 memcpy(out, pPrintersW, len);
1136 while (id < numentries) {
1140 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1141 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1143 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1144 if (piW->pDescription) {
1145 piA->pDescription = ptr;
1146 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1147 ptr, outlen, NULL, NULL);
1153 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1154 ptr, outlen, NULL, NULL);
1158 if (piW->pComment) {
1159 piA->pComment = ptr;
1160 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1161 ptr, outlen, NULL, NULL);
1170 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1171 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1174 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1175 if (piW->pServerName) {
1176 piA->pServerName = ptr;
1177 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1178 ptr, outlen, NULL, NULL);
1182 if (piW->pPrinterName) {
1183 piA->pPrinterName = ptr;
1184 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1185 ptr, outlen, NULL, NULL);
1189 if (piW->pShareName) {
1190 piA->pShareName = ptr;
1191 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1192 ptr, outlen, NULL, NULL);
1196 if (piW->pPortName) {
1197 piA->pPortName = ptr;
1198 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1199 ptr, outlen, NULL, NULL);
1203 if (piW->pDriverName) {
1204 piA->pDriverName = ptr;
1205 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1206 ptr, outlen, NULL, NULL);
1210 if (piW->pComment) {
1211 piA->pComment = ptr;
1212 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1213 ptr, outlen, NULL, NULL);
1217 if (piW->pLocation) {
1218 piA->pLocation = ptr;
1219 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1220 ptr, outlen, NULL, NULL);
1225 dmA = DEVMODEdupWtoA(piW->pDevMode);
1227 /* align DEVMODEA to a DWORD boundary */
1228 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1232 piA->pDevMode = (LPDEVMODEA) ptr;
1233 len = dmA->dmSize + dmA->dmDriverExtra;
1234 memcpy(ptr, dmA, len);
1235 HeapFree(GetProcessHeap(), 0, dmA);
1241 if (piW->pSepFile) {
1242 piA->pSepFile = ptr;
1243 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1244 ptr, outlen, NULL, NULL);
1248 if (piW->pPrintProcessor) {
1249 piA->pPrintProcessor = ptr;
1250 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1251 ptr, outlen, NULL, NULL);
1255 if (piW->pDatatype) {
1256 piA->pDatatype = ptr;
1257 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1258 ptr, outlen, NULL, NULL);
1262 if (piW->pParameters) {
1263 piA->pParameters = ptr;
1264 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1265 ptr, outlen, NULL, NULL);
1269 if (piW->pSecurityDescriptor) {
1270 piA->pSecurityDescriptor = NULL;
1271 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1278 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1279 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1281 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1283 if (piW->pPrinterName) {
1284 piA->pPrinterName = ptr;
1285 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1286 ptr, outlen, NULL, NULL);
1290 if (piW->pServerName) {
1291 piA->pServerName = ptr;
1292 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1293 ptr, outlen, NULL, NULL);
1302 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1303 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1305 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1307 if (piW->pPrinterName) {
1308 piA->pPrinterName = ptr;
1309 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1310 ptr, outlen, NULL, NULL);
1314 if (piW->pPortName) {
1315 piA->pPortName = ptr;
1316 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1317 ptr, outlen, NULL, NULL);
1324 case 6: /* 6A and 6W are the same structure */
1329 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1330 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1332 TRACE("(%u) #%u\n", level, id);
1333 if (piW->pszObjectGUID) {
1334 piA->pszObjectGUID = ptr;
1335 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1336 ptr, outlen, NULL, NULL);
1345 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1346 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1349 TRACE("(%u) #%u\n", level, id);
1350 dmA = DEVMODEdupWtoA(piW->pDevMode);
1352 /* align DEVMODEA to a DWORD boundary */
1353 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1357 piA->pDevMode = (LPDEVMODEA) ptr;
1358 len = dmA->dmSize + dmA->dmDriverExtra;
1359 memcpy(ptr, dmA, len);
1360 HeapFree(GetProcessHeap(), 0, dmA);
1370 FIXME("for level %u\n", level);
1372 pPrintersW += pi_sizeof[level];
1373 out += pi_sizeof[level];
1378 /******************************************************************
1379 * convert_driverinfo_W_to_A [internal]
1382 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1383 DWORD level, DWORD outlen, DWORD numentries)
1389 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1391 len = di_sizeof[level] * numentries;
1392 ptr = (LPSTR) out + len;
1395 /* copy the numbers of all PRINTER_INFO_* first */
1396 memcpy(out, pDriversW, len);
1398 #define COPY_STRING(fld) \
1401 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1402 ptr += len; outlen -= len;\
1404 #define COPY_MULTIZ_STRING(fld) \
1405 { LPWSTR p = diW->fld; if (p){ \
1408 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1409 ptr += len; outlen -= len; p += len;\
1411 while(len > 1 && outlen > 0); \
1414 while (id < numentries)
1420 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1421 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1423 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1430 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1431 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1433 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1436 COPY_STRING(pEnvironment);
1437 COPY_STRING(pDriverPath);
1438 COPY_STRING(pDataFile);
1439 COPY_STRING(pConfigFile);
1444 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1445 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1447 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1450 COPY_STRING(pEnvironment);
1451 COPY_STRING(pDriverPath);
1452 COPY_STRING(pDataFile);
1453 COPY_STRING(pConfigFile);
1454 COPY_STRING(pHelpFile);
1455 COPY_MULTIZ_STRING(pDependentFiles);
1456 COPY_STRING(pMonitorName);
1457 COPY_STRING(pDefaultDataType);
1462 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1463 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1465 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1468 COPY_STRING(pEnvironment);
1469 COPY_STRING(pDriverPath);
1470 COPY_STRING(pDataFile);
1471 COPY_STRING(pConfigFile);
1472 COPY_STRING(pHelpFile);
1473 COPY_MULTIZ_STRING(pDependentFiles);
1474 COPY_STRING(pMonitorName);
1475 COPY_STRING(pDefaultDataType);
1476 COPY_MULTIZ_STRING(pszzPreviousNames);
1481 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1482 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1484 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1487 COPY_STRING(pEnvironment);
1488 COPY_STRING(pDriverPath);
1489 COPY_STRING(pDataFile);
1490 COPY_STRING(pConfigFile);
1495 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1496 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1498 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1501 COPY_STRING(pEnvironment);
1502 COPY_STRING(pDriverPath);
1503 COPY_STRING(pDataFile);
1504 COPY_STRING(pConfigFile);
1505 COPY_STRING(pHelpFile);
1506 COPY_MULTIZ_STRING(pDependentFiles);
1507 COPY_STRING(pMonitorName);
1508 COPY_STRING(pDefaultDataType);
1509 COPY_MULTIZ_STRING(pszzPreviousNames);
1510 COPY_STRING(pszMfgName);
1511 COPY_STRING(pszOEMUrl);
1512 COPY_STRING(pszHardwareID);
1513 COPY_STRING(pszProvider);
1518 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1519 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1521 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1524 COPY_STRING(pEnvironment);
1525 COPY_STRING(pDriverPath);
1526 COPY_STRING(pDataFile);
1527 COPY_STRING(pConfigFile);
1528 COPY_STRING(pHelpFile);
1529 COPY_MULTIZ_STRING(pDependentFiles);
1530 COPY_STRING(pMonitorName);
1531 COPY_STRING(pDefaultDataType);
1532 COPY_MULTIZ_STRING(pszzPreviousNames);
1533 COPY_STRING(pszMfgName);
1534 COPY_STRING(pszOEMUrl);
1535 COPY_STRING(pszHardwareID);
1536 COPY_STRING(pszProvider);
1537 COPY_STRING(pszPrintProcessor);
1538 COPY_STRING(pszVendorSetup);
1539 COPY_MULTIZ_STRING(pszzColorProfiles);
1540 COPY_STRING(pszInfPath);
1541 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1547 FIXME("for level %u\n", level);
1550 pDriversW += di_sizeof[level];
1551 out += di_sizeof[level];
1556 #undef COPY_MULTIZ_STRING
1560 /***********************************************************
1561 * PRINTER_INFO_2AtoW
1562 * Creates a unicode copy of PRINTER_INFO_2A on heap
1564 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1566 LPPRINTER_INFO_2W piW;
1567 UNICODE_STRING usBuffer;
1569 if(!piA) return NULL;
1570 piW = HeapAlloc(heap, 0, sizeof(*piW));
1571 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1573 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1574 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1575 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1576 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1577 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1578 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1579 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1580 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1581 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1582 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1583 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1584 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1588 /***********************************************************
1589 * FREE_PRINTER_INFO_2W
1590 * Free PRINTER_INFO_2W and all strings
1592 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1596 HeapFree(heap,0,piW->pServerName);
1597 HeapFree(heap,0,piW->pPrinterName);
1598 HeapFree(heap,0,piW->pShareName);
1599 HeapFree(heap,0,piW->pPortName);
1600 HeapFree(heap,0,piW->pDriverName);
1601 HeapFree(heap,0,piW->pComment);
1602 HeapFree(heap,0,piW->pLocation);
1603 HeapFree(heap,0,piW->pDevMode);
1604 HeapFree(heap,0,piW->pSepFile);
1605 HeapFree(heap,0,piW->pPrintProcessor);
1606 HeapFree(heap,0,piW->pDatatype);
1607 HeapFree(heap,0,piW->pParameters);
1608 HeapFree(heap,0,piW);
1612 /******************************************************************
1613 * DeviceCapabilities [WINSPOOL.@]
1614 * DeviceCapabilitiesA [WINSPOOL.@]
1617 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1618 LPSTR pOutput, LPDEVMODEA lpdm)
1622 if (!GDI_CallDeviceCapabilities16)
1624 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1626 if (!GDI_CallDeviceCapabilities16) return -1;
1628 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1630 /* If DC_PAPERSIZE map POINT16s to POINTs */
1631 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1632 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1633 POINT *pt = (POINT *)pOutput;
1635 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1636 for(i = 0; i < ret; i++, pt++)
1641 HeapFree( GetProcessHeap(), 0, tmp );
1647 /*****************************************************************************
1648 * DeviceCapabilitiesW [WINSPOOL.@]
1650 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1653 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1654 WORD fwCapability, LPWSTR pOutput,
1655 const DEVMODEW *pDevMode)
1657 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1658 LPSTR pDeviceA = strdupWtoA(pDevice);
1659 LPSTR pPortA = strdupWtoA(pPort);
1662 if(pOutput && (fwCapability == DC_BINNAMES ||
1663 fwCapability == DC_FILEDEPENDENCIES ||
1664 fwCapability == DC_PAPERNAMES)) {
1665 /* These need A -> W translation */
1668 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1672 switch(fwCapability) {
1677 case DC_FILEDEPENDENCIES:
1681 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1682 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1684 for(i = 0; i < ret; i++)
1685 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1686 pOutput + (i * size), size);
1687 HeapFree(GetProcessHeap(), 0, pOutputA);
1689 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1690 (LPSTR)pOutput, dmA);
1692 HeapFree(GetProcessHeap(),0,pPortA);
1693 HeapFree(GetProcessHeap(),0,pDeviceA);
1694 HeapFree(GetProcessHeap(),0,dmA);
1698 /******************************************************************
1699 * DocumentPropertiesA [WINSPOOL.@]
1701 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1703 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1704 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1705 LPDEVMODEA pDevModeInput,DWORD fMode )
1707 LPSTR lpName = pDeviceName;
1708 static CHAR port[] = "LPT1:";
1711 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1712 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1716 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1718 ERR("no name from hPrinter?\n");
1719 SetLastError(ERROR_INVALID_HANDLE);
1722 lpName = strdupWtoA(lpNameW);
1725 if (!GDI_CallExtDeviceMode16)
1727 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1729 if (!GDI_CallExtDeviceMode16) {
1730 ERR("No CallExtDeviceMode16?\n");
1734 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1735 pDevModeInput, NULL, fMode);
1738 HeapFree(GetProcessHeap(),0,lpName);
1743 /*****************************************************************************
1744 * DocumentPropertiesW (WINSPOOL.@)
1746 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1748 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1750 LPDEVMODEW pDevModeOutput,
1751 LPDEVMODEW pDevModeInput, DWORD fMode)
1754 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1755 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1756 LPDEVMODEA pDevModeOutputA = NULL;
1759 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1760 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1762 if(pDevModeOutput) {
1763 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1764 if(ret < 0) return ret;
1765 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1767 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1768 pDevModeInputA, fMode);
1769 if(pDevModeOutput) {
1770 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1771 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1773 if(fMode == 0 && ret > 0)
1774 ret += (CCHDEVICENAME + CCHFORMNAME);
1775 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1776 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1780 /******************************************************************
1781 * OpenPrinterA [WINSPOOL.@]
1786 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1787 LPPRINTER_DEFAULTSA pDefault)
1789 UNICODE_STRING lpPrinterNameW;
1790 UNICODE_STRING usBuffer;
1791 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1792 PWSTR pwstrPrinterNameW;
1795 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1798 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1799 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1800 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1801 pDefaultW = &DefaultW;
1803 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1805 RtlFreeUnicodeString(&usBuffer);
1806 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1808 RtlFreeUnicodeString(&lpPrinterNameW);
1812 /******************************************************************
1813 * OpenPrinterW [WINSPOOL.@]
1815 * Open a Printer / Printserver or a Printer-Object
1818 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1819 * phPrinter [O] The resulting Handle is stored here
1820 * pDefault [I] PTR to Default Printer Settings or NULL
1827 * lpPrinterName is one of:
1828 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1829 *| Printer: "PrinterName"
1830 *| Printer-Object: "PrinterName,Job xxx"
1831 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1832 *| XcvPort: "Servername,XcvPort PortName"
1835 *| Printer-Object not supported
1836 *| pDefaults is ignored
1839 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1842 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1844 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1845 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1849 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1850 SetLastError(ERROR_INVALID_PARAMETER);
1854 /* Get the unique handle of the printer or Printserver */
1855 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1856 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1857 return (*phPrinter != 0);
1860 /******************************************************************
1861 * AddMonitorA [WINSPOOL.@]
1866 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1868 LPWSTR nameW = NULL;
1871 LPMONITOR_INFO_2A mi2a;
1872 MONITOR_INFO_2W mi2w;
1874 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1875 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1876 debugstr_a(mi2a ? mi2a->pName : NULL),
1877 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1878 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1881 SetLastError(ERROR_INVALID_LEVEL);
1885 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1891 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1892 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1893 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1896 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1898 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1899 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1900 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1902 if (mi2a->pEnvironment) {
1903 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1904 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1905 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1907 if (mi2a->pDLLName) {
1908 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1909 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1910 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1913 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1915 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1916 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1917 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1919 HeapFree(GetProcessHeap(), 0, nameW);
1923 /******************************************************************************
1924 * AddMonitorW [WINSPOOL.@]
1926 * Install a Printmonitor
1929 * pName [I] Servername or NULL (local Computer)
1930 * Level [I] Structure-Level (Must be 2)
1931 * pMonitors [I] PTR to MONITOR_INFO_2
1938 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1941 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1943 LPMONITOR_INFO_2W mi2w;
1945 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1946 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1947 debugstr_w(mi2w ? mi2w->pName : NULL),
1948 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1949 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1951 if ((backend == NULL) && !load_backend()) return FALSE;
1954 SetLastError(ERROR_INVALID_LEVEL);
1958 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1963 return backend->fpAddMonitor(pName, Level, pMonitors);
1966 /******************************************************************
1967 * DeletePrinterDriverA [WINSPOOL.@]
1970 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1972 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
1975 /******************************************************************
1976 * DeletePrinterDriverW [WINSPOOL.@]
1979 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1981 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
1984 /******************************************************************
1985 * DeleteMonitorA [WINSPOOL.@]
1987 * See DeleteMonitorW.
1990 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1992 LPWSTR nameW = NULL;
1993 LPWSTR EnvironmentW = NULL;
1994 LPWSTR MonitorNameW = NULL;
1999 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2000 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2001 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2005 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2006 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2007 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2010 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2011 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2012 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2015 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2017 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2018 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2019 HeapFree(GetProcessHeap(), 0, nameW);
2023 /******************************************************************
2024 * DeleteMonitorW [WINSPOOL.@]
2026 * Delete a specific Printmonitor from a Printing-Environment
2029 * pName [I] Servername or NULL (local Computer)
2030 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2031 * pMonitorName [I] Name of the Monitor, that should be deleted
2038 * pEnvironment is ignored in Windows for the local Computer.
2041 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2044 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2045 debugstr_w(pMonitorName));
2047 if ((backend == NULL) && !load_backend()) return FALSE;
2049 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2053 /******************************************************************
2054 * DeletePortA [WINSPOOL.@]
2059 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2061 LPWSTR nameW = NULL;
2062 LPWSTR portW = NULL;
2066 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2068 /* convert servername to unicode */
2070 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2071 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2072 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2075 /* convert portname to unicode */
2077 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2078 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2079 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2082 res = DeletePortW(nameW, hWnd, portW);
2083 HeapFree(GetProcessHeap(), 0, nameW);
2084 HeapFree(GetProcessHeap(), 0, portW);
2088 /******************************************************************
2089 * DeletePortW [WINSPOOL.@]
2091 * Delete a specific Port
2094 * pName [I] Servername or NULL (local Computer)
2095 * hWnd [I] Handle to parent Window for the Dialog-Box
2096 * pPortName [I] Name of the Port, that should be deleted
2103 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2105 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2107 if ((backend == NULL) && !load_backend()) return FALSE;
2110 SetLastError(RPC_X_NULL_REF_POINTER);
2114 return backend->fpDeletePort(pName, hWnd, pPortName);
2117 /******************************************************************************
2118 * SetPrinterW [WINSPOOL.@]
2120 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2122 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2123 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2127 /******************************************************************************
2128 * WritePrinter [WINSPOOL.@]
2130 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2132 opened_printer_t *printer;
2135 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2137 EnterCriticalSection(&printer_handles_cs);
2138 printer = get_opened_printer(hPrinter);
2141 SetLastError(ERROR_INVALID_HANDLE);
2147 SetLastError(ERROR_SPL_NO_STARTDOC);
2151 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2153 LeaveCriticalSection(&printer_handles_cs);
2157 /*****************************************************************************
2158 * AddFormA [WINSPOOL.@]
2160 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2162 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2166 /*****************************************************************************
2167 * AddFormW [WINSPOOL.@]
2169 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2171 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2175 /*****************************************************************************
2176 * AddJobA [WINSPOOL.@]
2178 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2181 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2185 SetLastError(ERROR_INVALID_LEVEL);
2189 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2192 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2193 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2194 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2195 if(*pcbNeeded > cbBuf) {
2196 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2199 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2200 addjobA->JobId = addjobW->JobId;
2201 addjobA->Path = (char *)(addjobA + 1);
2202 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2208 /*****************************************************************************
2209 * AddJobW [WINSPOOL.@]
2211 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2213 opened_printer_t *printer;
2216 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2217 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2218 WCHAR path[MAX_PATH], filename[MAX_PATH];
2220 ADDJOB_INFO_1W *addjob;
2222 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2224 EnterCriticalSection(&printer_handles_cs);
2226 printer = get_opened_printer(hPrinter);
2229 SetLastError(ERROR_INVALID_HANDLE);
2234 SetLastError(ERROR_INVALID_LEVEL);
2238 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2242 job->job_id = InterlockedIncrement(&next_job_id);
2244 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2245 if(path[len - 1] != '\\')
2247 memcpy(path + len, spool_path, sizeof(spool_path));
2248 sprintfW(filename, fmtW, path, job->job_id);
2250 len = strlenW(filename);
2251 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2252 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2253 job->document_title = strdupW(default_doc_title);
2254 job->printer_name = strdupW(printer->name);
2255 job->devmode = NULL;
2256 list_add_tail(&printer->queue->jobs, &job->entry);
2258 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2259 if(*pcbNeeded <= cbBuf) {
2260 addjob = (ADDJOB_INFO_1W*)pData;
2261 addjob->JobId = job->job_id;
2262 addjob->Path = (WCHAR *)(addjob + 1);
2263 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2266 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2269 LeaveCriticalSection(&printer_handles_cs);
2273 /*****************************************************************************
2274 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2276 * Return the PATH for the Print-Processors
2278 * See GetPrintProcessorDirectoryW.
2282 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2283 DWORD level, LPBYTE Info,
2284 DWORD cbBuf, LPDWORD pcbNeeded)
2286 LPWSTR serverW = NULL;
2291 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2292 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2296 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2297 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2298 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2302 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2303 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2304 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2307 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2308 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2310 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2313 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2314 cbBuf, NULL, NULL) > 0;
2317 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2318 HeapFree(GetProcessHeap(), 0, envW);
2319 HeapFree(GetProcessHeap(), 0, serverW);
2323 /*****************************************************************************
2324 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2326 * Return the PATH for the Print-Processors
2329 * server [I] Servername (NT only) or NULL (local Computer)
2330 * env [I] Printing-Environment (see below) or NULL (Default)
2331 * level [I] Structure-Level (must be 1)
2332 * Info [O] PTR to Buffer that receives the Result
2333 * cbBuf [I] Size of Buffer at "Info"
2334 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2335 * required for the Buffer at "Info"
2338 * Success: TRUE and in pcbNeeded the Bytes used in Info
2339 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2340 * if cbBuf is too small
2342 * Native Values returned in Info on Success:
2343 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2344 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2345 *| win9x(Windows 4.0): "%winsysdir%"
2347 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2350 * Only NULL or "" is supported for server
2353 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2354 DWORD level, LPBYTE Info,
2355 DWORD cbBuf, LPDWORD pcbNeeded)
2358 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2359 Info, cbBuf, pcbNeeded);
2361 if ((backend == NULL) && !load_backend()) return FALSE;
2364 /* (Level != 1) is ignored in win9x */
2365 SetLastError(ERROR_INVALID_LEVEL);
2369 if (pcbNeeded == NULL) {
2370 /* (pcbNeeded == NULL) is ignored in win9x */
2371 SetLastError(RPC_X_NULL_REF_POINTER);
2375 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2378 /*****************************************************************************
2379 * WINSPOOL_OpenDriverReg [internal]
2381 * opens the registry for the printer drivers depending on the given input
2382 * variable pEnvironment
2385 * the opened hkey on success
2388 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2392 const printenv_t * env;
2394 TRACE("(%s)\n", debugstr_w(pEnvironment));
2396 env = validate_envW(pEnvironment);
2397 if (!env) return NULL;
2399 buffer = HeapAlloc( GetProcessHeap(), 0,
2400 (strlenW(DriversW) + strlenW(env->envname) +
2401 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2403 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2404 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2405 HeapFree(GetProcessHeap(), 0, buffer);
2410 /*****************************************************************************
2411 * set_devices_and_printerports [internal]
2413 * set the [Devices] and [PrinterPorts] entries for a printer.
2416 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2418 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2422 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2424 /* FIXME: the driver must change to "winspool" */
2425 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2427 lstrcpyW(devline, driver_nt);
2428 lstrcatW(devline, commaW);
2429 lstrcatW(devline, pi->pPortName);
2431 TRACE("using %s\n", debugstr_w(devline));
2432 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2433 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2434 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2435 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2439 lstrcatW(devline, timeout_15_45);
2440 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2441 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2442 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2443 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2446 HeapFree(GetProcessHeap(), 0, devline);
2450 /*****************************************************************************
2451 * AddPrinterW [WINSPOOL.@]
2453 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2455 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2459 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2461 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2462 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2463 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2464 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2465 statusW[] = {'S','t','a','t','u','s',0},
2466 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2468 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2471 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2472 SetLastError(ERROR_INVALID_PARAMETER);
2476 ERR("Level = %d, unsupported!\n", Level);
2477 SetLastError(ERROR_INVALID_LEVEL);
2481 SetLastError(ERROR_INVALID_PARAMETER);
2484 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2486 ERR("Can't create Printers key\n");
2489 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2490 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2491 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2492 RegCloseKey(hkeyPrinter);
2493 RegCloseKey(hkeyPrinters);
2496 RegCloseKey(hkeyPrinter);
2498 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2500 ERR("Can't create Drivers key\n");
2501 RegCloseKey(hkeyPrinters);
2504 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2506 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2507 RegCloseKey(hkeyPrinters);
2508 RegCloseKey(hkeyDrivers);
2509 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2512 RegCloseKey(hkeyDriver);
2513 RegCloseKey(hkeyDrivers);
2515 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2516 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2517 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2518 RegCloseKey(hkeyPrinters);
2522 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2524 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2525 SetLastError(ERROR_INVALID_PRINTER_NAME);
2526 RegCloseKey(hkeyPrinters);
2530 set_devices_and_printerports(pi);
2531 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2532 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2533 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2535 /* See if we can load the driver. We may need the devmode structure anyway
2538 * Note that DocumentPropertiesW will briefly try to open the printer we
2539 * just create to find a DEVMODEA struct (it will use the WINEPS default
2540 * one in case it is not there, so we are ok).
2542 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2545 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2546 size = sizeof(DEVMODEW);
2552 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2554 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2556 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2557 HeapFree(GetProcessHeap(),0,dmW);
2562 /* set devmode to printer name */
2563 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2567 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2568 and we support these drivers. NT writes DEVMODEW so somehow
2569 we'll need to distinguish between these when we support NT
2573 dmA = DEVMODEdupWtoA(dmW);
2574 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2575 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2576 HeapFree(GetProcessHeap(), 0, dmA);
2578 HeapFree(GetProcessHeap(), 0, dmW);
2580 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2581 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2582 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2583 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2585 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2586 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2587 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2588 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2589 (LPBYTE)&pi->Priority, sizeof(DWORD));
2590 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2591 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2592 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2593 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2594 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2595 (LPBYTE)&pi->Status, sizeof(DWORD));
2596 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2597 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2599 RegCloseKey(hkeyPrinter);
2600 RegCloseKey(hkeyPrinters);
2601 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2602 ERR("OpenPrinter failing\n");
2608 /*****************************************************************************
2609 * AddPrinterA [WINSPOOL.@]
2611 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2613 UNICODE_STRING pNameW;
2615 PRINTER_INFO_2W *piW;
2616 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2619 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2621 ERR("Level = %d, unsupported!\n", Level);
2622 SetLastError(ERROR_INVALID_LEVEL);
2625 pwstrNameW = asciitounicode(&pNameW,pName);
2626 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2628 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2630 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2631 RtlFreeUnicodeString(&pNameW);
2636 /*****************************************************************************
2637 * ClosePrinter [WINSPOOL.@]
2639 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2641 UINT_PTR i = (UINT_PTR)hPrinter;
2642 opened_printer_t *printer = NULL;
2645 TRACE("(%p)\n", hPrinter);
2647 EnterCriticalSection(&printer_handles_cs);
2649 if ((i > 0) && (i <= nb_printer_handles))
2650 printer = printer_handles[i - 1];
2655 struct list *cursor, *cursor2;
2657 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2659 if (printer->backend_printer) {
2660 backend->fpClosePrinter(printer->backend_printer);
2664 EndDocPrinter(hPrinter);
2666 if(InterlockedDecrement(&printer->queue->ref) == 0)
2668 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2670 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2671 ScheduleJob(hPrinter, job->job_id);
2673 HeapFree(GetProcessHeap(), 0, printer->queue);
2676 HeapFree(GetProcessHeap(), 0, printer->printername);
2677 HeapFree(GetProcessHeap(), 0, printer->name);
2678 HeapFree(GetProcessHeap(), 0, printer);
2679 printer_handles[i - 1] = NULL;
2682 LeaveCriticalSection(&printer_handles_cs);
2686 /*****************************************************************************
2687 * DeleteFormA [WINSPOOL.@]
2689 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2691 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2695 /*****************************************************************************
2696 * DeleteFormW [WINSPOOL.@]
2698 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2700 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2704 /*****************************************************************************
2705 * DeletePrinter [WINSPOOL.@]
2707 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2709 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2710 HKEY hkeyPrinters, hkey;
2713 SetLastError(ERROR_INVALID_HANDLE);
2716 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2717 RegDeleteTreeW(hkeyPrinters, lpNameW);
2718 RegCloseKey(hkeyPrinters);
2720 WriteProfileStringW(devicesW, lpNameW, NULL);
2721 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2723 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2724 RegDeleteValueW(hkey, lpNameW);
2728 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2729 RegDeleteValueW(hkey, lpNameW);
2735 /*****************************************************************************
2736 * SetPrinterA [WINSPOOL.@]
2738 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2741 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2745 /*****************************************************************************
2746 * SetJobA [WINSPOOL.@]
2748 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2749 LPBYTE pJob, DWORD Command)
2753 UNICODE_STRING usBuffer;
2755 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2757 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2758 are all ignored by SetJob, so we don't bother copying them */
2766 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2767 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2769 JobW = (LPBYTE)info1W;
2770 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2771 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2772 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2773 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2774 info1W->Status = info1A->Status;
2775 info1W->Priority = info1A->Priority;
2776 info1W->Position = info1A->Position;
2777 info1W->PagesPrinted = info1A->PagesPrinted;
2782 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2783 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2785 JobW = (LPBYTE)info2W;
2786 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2787 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2788 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2789 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2790 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2791 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2792 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2793 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2794 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2795 info2W->Status = info2A->Status;
2796 info2W->Priority = info2A->Priority;
2797 info2W->Position = info2A->Position;
2798 info2W->StartTime = info2A->StartTime;
2799 info2W->UntilTime = info2A->UntilTime;
2800 info2W->PagesPrinted = info2A->PagesPrinted;
2804 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2805 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2808 SetLastError(ERROR_INVALID_LEVEL);
2812 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2818 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2819 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2820 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2821 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2822 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2827 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2828 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2829 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2830 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2831 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2832 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2833 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2834 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2835 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2839 HeapFree(GetProcessHeap(), 0, JobW);
2844 /*****************************************************************************
2845 * SetJobW [WINSPOOL.@]
2847 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2848 LPBYTE pJob, DWORD Command)
2854 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2855 FIXME("Ignoring everything other than document title\n");
2857 EnterCriticalSection(&printer_handles_cs);
2858 job = get_job(hPrinter, JobId);
2868 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2869 HeapFree(GetProcessHeap(), 0, job->document_title);
2870 job->document_title = strdupW(info1->pDocument);
2875 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2876 HeapFree(GetProcessHeap(), 0, job->document_title);
2877 job->document_title = strdupW(info2->pDocument);
2878 HeapFree(GetProcessHeap(), 0, job->devmode);
2879 if (info2->pDevMode)
2881 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2882 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2883 memcpy(job->devmode, info2->pDevMode, size);
2886 job->devmode = NULL;
2892 SetLastError(ERROR_INVALID_LEVEL);
2897 LeaveCriticalSection(&printer_handles_cs);
2901 /*****************************************************************************
2902 * EndDocPrinter [WINSPOOL.@]
2904 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2906 opened_printer_t *printer;
2908 TRACE("(%p)\n", hPrinter);
2910 EnterCriticalSection(&printer_handles_cs);
2912 printer = get_opened_printer(hPrinter);
2915 SetLastError(ERROR_INVALID_HANDLE);
2921 SetLastError(ERROR_SPL_NO_STARTDOC);
2925 CloseHandle(printer->doc->hf);
2926 ScheduleJob(hPrinter, printer->doc->job_id);
2927 HeapFree(GetProcessHeap(), 0, printer->doc);
2928 printer->doc = NULL;
2931 LeaveCriticalSection(&printer_handles_cs);
2935 /*****************************************************************************
2936 * EndPagePrinter [WINSPOOL.@]
2938 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2940 FIXME("(%p): stub\n", hPrinter);
2944 /*****************************************************************************
2945 * StartDocPrinterA [WINSPOOL.@]
2947 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2949 UNICODE_STRING usBuffer;
2951 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2954 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2955 or one (DOC_INFO_3) extra DWORDs */
2959 doc2W.JobId = doc2->JobId;
2962 doc2W.dwMode = doc2->dwMode;
2965 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2966 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2967 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2971 SetLastError(ERROR_INVALID_LEVEL);
2975 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2977 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2978 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2979 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2984 /*****************************************************************************
2985 * StartDocPrinterW [WINSPOOL.@]
2987 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2989 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2990 opened_printer_t *printer;
2991 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2992 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2993 JOB_INFO_1W job_info;
2994 DWORD needed, ret = 0;
2999 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3000 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3001 debugstr_w(doc->pDatatype));
3003 if(Level < 1 || Level > 3)
3005 SetLastError(ERROR_INVALID_LEVEL);
3009 EnterCriticalSection(&printer_handles_cs);
3010 printer = get_opened_printer(hPrinter);
3013 SetLastError(ERROR_INVALID_HANDLE);
3019 SetLastError(ERROR_INVALID_PRINTER_STATE);
3023 /* Even if we're printing to a file we still add a print job, we'll
3024 just ignore the spool file name */
3026 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3028 ERR("AddJob failed gle %u\n", GetLastError());
3032 /* use pOutputFile only, when it is a real filename */
3033 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3034 filename = doc->pOutputFile;
3036 filename = addjob->Path;
3038 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3039 if(hf == INVALID_HANDLE_VALUE)
3042 memset(&job_info, 0, sizeof(job_info));
3043 job_info.pDocument = doc->pDocName;
3044 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3046 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3047 printer->doc->hf = hf;
3048 ret = printer->doc->job_id = addjob->JobId;
3049 job = get_job(hPrinter, ret);
3050 job->portname = strdupW(doc->pOutputFile);
3053 LeaveCriticalSection(&printer_handles_cs);
3058 /*****************************************************************************
3059 * StartPagePrinter [WINSPOOL.@]
3061 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3063 FIXME("(%p): stub\n", hPrinter);
3067 /*****************************************************************************
3068 * GetFormA [WINSPOOL.@]
3070 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3071 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3073 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3074 Level,pForm,cbBuf,pcbNeeded);
3078 /*****************************************************************************
3079 * GetFormW [WINSPOOL.@]
3081 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3082 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3084 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3085 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3089 /*****************************************************************************
3090 * SetFormA [WINSPOOL.@]
3092 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3095 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3099 /*****************************************************************************
3100 * SetFormW [WINSPOOL.@]
3102 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3105 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3109 /*****************************************************************************
3110 * ReadPrinter [WINSPOOL.@]
3112 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3113 LPDWORD pNoBytesRead)
3115 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3119 /*****************************************************************************
3120 * ResetPrinterA [WINSPOOL.@]
3122 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3124 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3128 /*****************************************************************************
3129 * ResetPrinterW [WINSPOOL.@]
3131 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3133 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3137 /*****************************************************************************
3138 * WINSPOOL_GetDWORDFromReg
3140 * Return DWORD associated with ValueName from hkey.
3142 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3144 DWORD sz = sizeof(DWORD), type, value = 0;
3147 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3149 if(ret != ERROR_SUCCESS) {
3150 WARN("Got ret = %d on name %s\n", ret, ValueName);
3153 if(type != REG_DWORD) {
3154 ERR("Got type %d\n", type);
3161 /*****************************************************************************
3162 * get_filename_from_reg [internal]
3164 * Get ValueName from hkey storing result in out
3165 * when the Value in the registry has only a filename, use driverdir as prefix
3166 * outlen is space left in out
3167 * String is stored either as unicode or ascii
3171 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3172 LPBYTE out, DWORD outlen, LPDWORD needed)
3174 WCHAR filename[MAX_PATH];
3178 LPWSTR buffer = filename;
3182 size = sizeof(filename);
3184 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3185 if (ret == ERROR_MORE_DATA) {
3186 TRACE("need dynamic buffer: %u\n", size);
3187 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3189 /* No Memory is bad */
3193 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3196 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3197 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3203 /* do we have a full path ? */
3204 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3205 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3208 /* we must build the full Path */
3210 if ((out) && (outlen > dirlen)) {
3211 lstrcpyW((LPWSTR)out, driverdir);
3219 /* write the filename */
3220 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3221 if ((out) && (outlen >= size)) {
3222 lstrcpyW((LPWSTR)out, ptr);
3229 ptr += lstrlenW(ptr)+1;
3230 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3233 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3235 /* write the multisz-termination */
3236 if (type == REG_MULTI_SZ) {
3237 size = sizeof(WCHAR);
3240 if (out && (outlen >= size)) {
3241 memset (out, 0, size);
3247 /*****************************************************************************
3248 * WINSPOOL_GetStringFromReg
3250 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3251 * String is stored as unicode.
3253 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3254 DWORD buflen, DWORD *needed)
3256 DWORD sz = buflen, type;
3259 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3260 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3261 WARN("Got ret = %d\n", ret);
3265 /* add space for terminating '\0' */
3266 sz += sizeof(WCHAR);
3270 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3275 /*****************************************************************************
3276 * WINSPOOL_GetDefaultDevMode
3278 * Get a default DevMode values for wineps.
3282 static void WINSPOOL_GetDefaultDevMode(
3284 DWORD buflen, DWORD *needed)
3287 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3289 /* fill default DEVMODE - should be read from ppd... */
3290 ZeroMemory( &dm, sizeof(dm) );
3291 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3292 dm.dmSpecVersion = DM_SPECVERSION;
3293 dm.dmDriverVersion = 1;
3294 dm.dmSize = sizeof(DEVMODEW);
3295 dm.dmDriverExtra = 0;
3297 DM_ORIENTATION | DM_PAPERSIZE |
3298 DM_PAPERLENGTH | DM_PAPERWIDTH |
3301 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3302 DM_YRESOLUTION | DM_TTOPTION;
3304 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3305 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3306 dm.u1.s1.dmPaperLength = 2970;
3307 dm.u1.s1.dmPaperWidth = 2100;
3309 dm.u1.s1.dmScale = 100;
3310 dm.u1.s1.dmCopies = 1;
3311 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3312 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3315 dm.dmYResolution = 300; /* 300dpi */
3316 dm.dmTTOption = DMTT_BITMAP;
3319 /* dm.dmLogPixels */
3320 /* dm.dmBitsPerPel */
3321 /* dm.dmPelsWidth */
3322 /* dm.dmPelsHeight */
3323 /* dm.u2.dmDisplayFlags */
3324 /* dm.dmDisplayFrequency */
3325 /* dm.dmICMMethod */
3326 /* dm.dmICMIntent */
3327 /* dm.dmMediaType */
3328 /* dm.dmDitherType */
3329 /* dm.dmReserved1 */
3330 /* dm.dmReserved2 */
3331 /* dm.dmPanningWidth */
3332 /* dm.dmPanningHeight */
3334 if(buflen >= sizeof(DEVMODEW))
3335 memcpy(ptr, &dm, sizeof(DEVMODEW));
3336 *needed = sizeof(DEVMODEW);
3339 /*****************************************************************************
3340 * WINSPOOL_GetDevModeFromReg
3342 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3343 * DevMode is stored either as unicode or ascii.
3345 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3347 DWORD buflen, DWORD *needed)
3349 DWORD sz = buflen, type;
3352 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3353 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3354 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3355 if (sz < sizeof(DEVMODEA))
3357 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3360 /* ensures that dmSize is not erratically bogus if registry is invalid */
3361 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3362 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3363 sz += (CCHDEVICENAME + CCHFORMNAME);
3364 if (ptr && (buflen >= sz)) {
3365 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3366 memcpy(ptr, dmW, sz);
3367 HeapFree(GetProcessHeap(),0,dmW);
3373 /*********************************************************************
3374 * WINSPOOL_GetPrinter_1
3376 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3378 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3379 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3381 DWORD size, left = cbBuf;
3382 BOOL space = (cbBuf > 0);
3387 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3388 if(space && size <= left) {
3389 pi1->pName = (LPWSTR)ptr;
3397 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3398 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3399 if(space && size <= left) {
3400 pi1->pDescription = (LPWSTR)ptr;
3408 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3409 if(space && size <= left) {
3410 pi1->pComment = (LPWSTR)ptr;
3418 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3420 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3421 memset(pi1, 0, sizeof(*pi1));
3425 /*********************************************************************
3426 * WINSPOOL_GetPrinter_2
3428 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3430 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3431 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3433 DWORD size, left = cbBuf;
3434 BOOL space = (cbBuf > 0);
3439 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3440 if(space && size <= left) {
3441 pi2->pPrinterName = (LPWSTR)ptr;
3448 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3449 if(space && size <= left) {
3450 pi2->pShareName = (LPWSTR)ptr;
3457 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3458 if(space && size <= left) {
3459 pi2->pPortName = (LPWSTR)ptr;
3466 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3467 if(space && size <= left) {
3468 pi2->pDriverName = (LPWSTR)ptr;
3475 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3476 if(space && size <= left) {
3477 pi2->pComment = (LPWSTR)ptr;
3484 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3485 if(space && size <= left) {
3486 pi2->pLocation = (LPWSTR)ptr;
3493 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3494 if(space && size <= left) {
3495 pi2->pDevMode = (LPDEVMODEW)ptr;
3504 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3505 if(space && size <= left) {
3506 pi2->pDevMode = (LPDEVMODEW)ptr;
3513 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3514 if(space && size <= left) {
3515 pi2->pSepFile = (LPWSTR)ptr;
3522 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3523 if(space && size <= left) {
3524 pi2->pPrintProcessor = (LPWSTR)ptr;
3531 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3532 if(space && size <= left) {
3533 pi2->pDatatype = (LPWSTR)ptr;
3540 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3541 if(space && size <= left) {
3542 pi2->pParameters = (LPWSTR)ptr;
3550 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3551 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3552 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3553 "Default Priority");
3554 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3555 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3558 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3559 memset(pi2, 0, sizeof(*pi2));
3564 /*********************************************************************
3565 * WINSPOOL_GetPrinter_4
3567 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3569 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3570 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3572 DWORD size, left = cbBuf;
3573 BOOL space = (cbBuf > 0);
3578 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3579 if(space && size <= left) {
3580 pi4->pPrinterName = (LPWSTR)ptr;
3588 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3591 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3592 memset(pi4, 0, sizeof(*pi4));
3597 /*********************************************************************
3598 * WINSPOOL_GetPrinter_5
3600 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3602 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3603 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3605 DWORD size, left = cbBuf;
3606 BOOL space = (cbBuf > 0);
3611 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3612 if(space && size <= left) {
3613 pi5->pPrinterName = (LPWSTR)ptr;
3620 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3621 if(space && size <= left) {
3622 pi5->pPortName = (LPWSTR)ptr;
3630 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3631 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3633 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3637 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3638 memset(pi5, 0, sizeof(*pi5));
3643 /*********************************************************************
3644 * WINSPOOL_GetPrinter_7
3646 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3648 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3649 DWORD cbBuf, LPDWORD pcbNeeded)
3651 DWORD size, left = cbBuf;
3652 BOOL space = (cbBuf > 0);
3657 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3660 size = sizeof(pi7->pszObjectGUID);
3662 if (space && size <= left) {
3663 pi7->pszObjectGUID = (LPWSTR)ptr;
3670 /* We do not have a Directory Service */
3671 pi7->dwAction = DSPRINT_UNPUBLISH;
3674 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3675 memset(pi7, 0, sizeof(*pi7));
3680 /*********************************************************************
3681 * WINSPOOL_GetPrinter_9
3683 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3685 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3686 DWORD cbBuf, LPDWORD pcbNeeded)
3689 BOOL space = (cbBuf > 0);
3693 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3694 if(space && size <= cbBuf) {
3695 pi9->pDevMode = (LPDEVMODEW)buf;
3702 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3703 if(space && size <= cbBuf) {
3704 pi9->pDevMode = (LPDEVMODEW)buf;
3710 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3711 memset(pi9, 0, sizeof(*pi9));
3716 /*****************************************************************************
3717 * GetPrinterW [WINSPOOL.@]
3719 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3720 DWORD cbBuf, LPDWORD pcbNeeded)
3723 DWORD size, needed = 0;
3725 HKEY hkeyPrinter, hkeyPrinters;
3728 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3730 if (!(name = get_opened_printer_name(hPrinter))) {
3731 SetLastError(ERROR_INVALID_HANDLE);
3735 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3737 ERR("Can't create Printers key\n");
3740 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3742 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3743 RegCloseKey(hkeyPrinters);
3744 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3751 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3753 size = sizeof(PRINTER_INFO_2W);
3755 ptr = pPrinter + size;
3757 memset(pPrinter, 0, size);
3762 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3769 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3771 size = sizeof(PRINTER_INFO_4W);
3773 ptr = pPrinter + size;
3775 memset(pPrinter, 0, size);
3780 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3788 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3790 size = sizeof(PRINTER_INFO_5W);
3792 ptr = pPrinter + size;
3794 memset(pPrinter, 0, size);
3800 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3808 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3810 size = sizeof(PRINTER_INFO_6);
3811 if (size <= cbBuf) {
3812 /* FIXME: We do not update the status yet */
3813 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3825 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3827 size = sizeof(PRINTER_INFO_7W);
3828 if (size <= cbBuf) {
3829 ptr = pPrinter + size;
3831 memset(pPrinter, 0, size);
3837 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3845 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3847 size = sizeof(PRINTER_INFO_9W);
3849 ptr = pPrinter + size;
3851 memset(pPrinter, 0, size);
3857 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3864 FIXME("Unimplemented level %d\n", Level);
3865 SetLastError(ERROR_INVALID_LEVEL);
3866 RegCloseKey(hkeyPrinters);
3867 RegCloseKey(hkeyPrinter);
3871 RegCloseKey(hkeyPrinter);
3872 RegCloseKey(hkeyPrinters);
3874 TRACE("returning %d needed = %d\n", ret, needed);
3875 if(pcbNeeded) *pcbNeeded = needed;
3877 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3881 /*****************************************************************************
3882 * GetPrinterA [WINSPOOL.@]
3884 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3885 DWORD cbBuf, LPDWORD pcbNeeded)
3891 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3893 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3895 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3896 HeapFree(GetProcessHeap(), 0, buf);
3901 /*****************************************************************************
3902 * WINSPOOL_EnumPrintersW
3904 * Implementation of EnumPrintersW
3906 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3907 DWORD dwLevel, LPBYTE lpbPrinters,
3908 DWORD cbBuf, LPDWORD lpdwNeeded,
3909 LPDWORD lpdwReturned)
3912 HKEY hkeyPrinters, hkeyPrinter;
3913 WCHAR PrinterName[255];
3914 DWORD needed = 0, number = 0;
3915 DWORD used, i, left;
3919 memset(lpbPrinters, 0, cbBuf);
3925 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3926 if(dwType == PRINTER_ENUM_DEFAULT)
3929 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3930 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3931 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3933 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3939 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3940 FIXME("dwType = %08x\n", dwType);
3941 SetLastError(ERROR_INVALID_FLAGS);
3945 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3947 ERR("Can't create Printers key\n");
3951 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3952 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3953 RegCloseKey(hkeyPrinters);
3954 ERR("Can't query Printers key\n");
3957 TRACE("Found %d printers\n", number);
3961 used = number * sizeof(PRINTER_INFO_1W);
3964 used = number * sizeof(PRINTER_INFO_2W);
3967 used = number * sizeof(PRINTER_INFO_4W);
3970 used = number * sizeof(PRINTER_INFO_5W);
3974 SetLastError(ERROR_INVALID_LEVEL);
3975 RegCloseKey(hkeyPrinters);
3978 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3980 for(i = 0; i < number; i++) {
3981 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3983 ERR("Can't enum key number %d\n", i);
3984 RegCloseKey(hkeyPrinters);
3987 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3988 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3990 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3991 RegCloseKey(hkeyPrinters);
3996 buf = lpbPrinters + used;
3997 left = cbBuf - used;
4005 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4008 if(pi) pi += sizeof(PRINTER_INFO_1W);
4011 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4014 if(pi) pi += sizeof(PRINTER_INFO_2W);
4017 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4020 if(pi) pi += sizeof(PRINTER_INFO_4W);
4023 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4026 if(pi) pi += sizeof(PRINTER_INFO_5W);
4029 ERR("Shouldn't be here!\n");
4030 RegCloseKey(hkeyPrinter);
4031 RegCloseKey(hkeyPrinters);
4034 RegCloseKey(hkeyPrinter);
4036 RegCloseKey(hkeyPrinters);
4043 memset(lpbPrinters, 0, cbBuf);
4044 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4048 *lpdwReturned = number;
4049 SetLastError(ERROR_SUCCESS);
4054 /******************************************************************
4055 * EnumPrintersW [WINSPOOL.@]
4057 * Enumerates the available printers, print servers and print
4058 * providers, depending on the specified flags, name and level.
4062 * If level is set to 1:
4063 * Returns an array of PRINTER_INFO_1 data structures in the
4064 * lpbPrinters buffer.
4066 * If level is set to 2:
4067 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4068 * Returns an array of PRINTER_INFO_2 data structures in the
4069 * lpbPrinters buffer. Note that according to MSDN also an
4070 * OpenPrinter should be performed on every remote printer.
4072 * If level is set to 4 (officially WinNT only):
4073 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4074 * Fast: Only the registry is queried to retrieve printer names,
4075 * no connection to the driver is made.
4076 * Returns an array of PRINTER_INFO_4 data structures in the
4077 * lpbPrinters buffer.
4079 * If level is set to 5 (officially WinNT4/Win9x only):
4080 * Fast: Only the registry is queried to retrieve printer names,
4081 * no connection to the driver is made.
4082 * Returns an array of PRINTER_INFO_5 data structures in the
4083 * lpbPrinters buffer.
4085 * If level set to 3 or 6+:
4086 * returns zero (failure!)
4088 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4092 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4093 * - Only levels 2, 4 and 5 are implemented at the moment.
4094 * - 16-bit printer drivers are not enumerated.
4095 * - Returned amount of bytes used/needed does not match the real Windoze
4096 * implementation (as in this implementation, all strings are part
4097 * of the buffer, whereas Win32 keeps them somewhere else)
4098 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4101 * - In a regular Wine installation, no registry settings for printers
4102 * exist, which makes this function return an empty list.
4104 BOOL WINAPI EnumPrintersW(
4105 DWORD dwType, /* [in] Types of print objects to enumerate */
4106 LPWSTR lpszName, /* [in] name of objects to enumerate */
4107 DWORD dwLevel, /* [in] type of printer info structure */
4108 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4109 DWORD cbBuf, /* [in] max size of buffer in bytes */
4110 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4111 LPDWORD lpdwReturned /* [out] number of entries returned */
4114 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4115 lpdwNeeded, lpdwReturned);
4118 /******************************************************************
4119 * EnumPrintersA [WINSPOOL.@]
4124 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4125 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4128 UNICODE_STRING pNameU;
4132 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4133 pPrinters, cbBuf, pcbNeeded, pcReturned);
4135 pNameW = asciitounicode(&pNameU, pName);
4137 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4138 MS Office need this */
4139 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4141 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4143 RtlFreeUnicodeString(&pNameU);
4145 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4147 HeapFree(GetProcessHeap(), 0, pPrintersW);
4151 /*****************************************************************************
4152 * WINSPOOL_GetDriverInfoFromReg [internal]
4154 * Enters the information from the registry into the DRIVER_INFO struct
4157 * zero if the printer driver does not exist in the registry
4158 * (only if Level > 1) otherwise nonzero
4160 static BOOL WINSPOOL_GetDriverInfoFromReg(
4163 const printenv_t * env,
4165 LPBYTE ptr, /* DRIVER_INFO */
4166 LPBYTE pDriverStrings, /* strings buffer */
4167 DWORD cbBuf, /* size of string buffer */
4168 LPDWORD pcbNeeded) /* space needed for str. */
4172 WCHAR driverdir[MAX_PATH];
4174 LPBYTE strPtr = pDriverStrings;
4175 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4177 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4178 debugstr_w(DriverName), env,
4179 Level, di, pDriverStrings, cbBuf);
4181 if (di) ZeroMemory(di, di_sizeof[Level]);
4183 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4184 if (*pcbNeeded <= cbBuf)
4185 strcpyW((LPWSTR)strPtr, DriverName);
4187 /* pName for level 1 has a different offset! */
4189 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4193 /* .cVersion and .pName for level > 1 */
4195 di->cVersion = env->driverversion;
4196 di->pName = (LPWSTR) strPtr;
4197 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4200 /* Reserve Space for the largest subdir and a Backslash*/
4201 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4202 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4203 /* Should never Fail */
4206 lstrcatW(driverdir, env->versionsubdir);
4207 lstrcatW(driverdir, backslashW);
4209 /* dirlen must not include the terminating zero */
4210 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4212 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4213 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4214 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4219 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4222 if (*pcbNeeded <= cbBuf) {
4223 lstrcpyW((LPWSTR)strPtr, env->envname);
4224 if (di) di->pEnvironment = (LPWSTR)strPtr;
4225 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4228 /* .pDriverPath is the Graphics rendering engine.
4229 The full Path is required to avoid a crash in some apps */
4230 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4232 if (*pcbNeeded <= cbBuf)
4233 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4235 if (di) di->pDriverPath = (LPWSTR)strPtr;
4236 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4239 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4240 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4242 if (*pcbNeeded <= cbBuf)
4243 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4245 if (di) di->pDataFile = (LPWSTR)strPtr;
4246 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4249 /* .pConfigFile is the Driver user Interface */
4250 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4252 if (*pcbNeeded <= cbBuf)
4253 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4255 if (di) di->pConfigFile = (LPWSTR)strPtr;
4256 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4260 RegCloseKey(hkeyDriver);
4261 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4266 RegCloseKey(hkeyDriver);
4267 FIXME("level 5: incomplete\n");
4272 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4274 if (*pcbNeeded <= cbBuf)
4275 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4277 if (di) di->pHelpFile = (LPWSTR)strPtr;
4278 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4281 /* .pDependentFiles */
4282 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4284 if (*pcbNeeded <= cbBuf)
4285 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4287 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4288 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4290 else if (GetVersion() & 0x80000000) {
4291 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4292 size = 2 * sizeof(WCHAR);
4294 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4296 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4297 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4300 /* .pMonitorName is the optional Language Monitor */
4301 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4303 if (*pcbNeeded <= cbBuf)
4304 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4306 if (di) di->pMonitorName = (LPWSTR)strPtr;
4307 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4310 /* .pDefaultDataType */
4311 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4313 if(*pcbNeeded <= cbBuf)
4314 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4316 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4317 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4321 RegCloseKey(hkeyDriver);
4322 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4326 /* .pszzPreviousNames */
4327 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4329 if(*pcbNeeded <= cbBuf)
4330 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4332 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4333 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4337 RegCloseKey(hkeyDriver);
4338 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4342 /* support is missing, but not important enough for a FIXME */
4343 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4346 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4348 if(*pcbNeeded <= cbBuf)
4349 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4351 if (di) di->pszMfgName = (LPWSTR)strPtr;
4352 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4356 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4358 if(*pcbNeeded <= cbBuf)
4359 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4361 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4362 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4365 /* .pszHardwareID */
4366 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4368 if(*pcbNeeded <= cbBuf)
4369 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4371 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4372 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4376 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4378 if(*pcbNeeded <= cbBuf)
4379 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4381 if (di) di->pszProvider = (LPWSTR)strPtr;
4382 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4386 RegCloseKey(hkeyDriver);
4390 /* support is missing, but not important enough for a FIXME */
4391 TRACE("level 8: incomplete\n");
4393 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4394 RegCloseKey(hkeyDriver);
4398 /*****************************************************************************
4399 * GetPrinterDriverW [WINSPOOL.@]
4401 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4402 DWORD Level, LPBYTE pDriverInfo,
4403 DWORD cbBuf, LPDWORD pcbNeeded)
4406 WCHAR DriverName[100];
4407 DWORD ret, type, size, needed = 0;
4409 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4410 const printenv_t * env;
4412 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4413 Level,pDriverInfo,cbBuf, pcbNeeded);
4416 ZeroMemory(pDriverInfo, cbBuf);
4418 if (!(name = get_opened_printer_name(hPrinter))) {
4419 SetLastError(ERROR_INVALID_HANDLE);
4423 if (Level < 1 || Level == 7 || Level > 8) {
4424 SetLastError(ERROR_INVALID_LEVEL);
4428 env = validate_envW(pEnvironment);
4429 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4431 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4433 ERR("Can't create Printers key\n");
4436 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4438 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4439 RegCloseKey(hkeyPrinters);
4440 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4443 size = sizeof(DriverName);
4445 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4446 (LPBYTE)DriverName, &size);
4447 RegCloseKey(hkeyPrinter);
4448 RegCloseKey(hkeyPrinters);
4449 if(ret != ERROR_SUCCESS) {
4450 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4454 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4456 ERR("Can't create Drivers key\n");
4460 size = di_sizeof[Level];
4461 if ((size <= cbBuf) && pDriverInfo)
4462 ptr = pDriverInfo + size;
4464 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4465 env, Level, pDriverInfo, ptr,
4466 (cbBuf < size) ? 0 : cbBuf - size,
4468 RegCloseKey(hkeyDrivers);
4472 RegCloseKey(hkeyDrivers);
4474 if(pcbNeeded) *pcbNeeded = size + needed;
4475 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4476 if(cbBuf >= size + needed) return TRUE;
4477 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4481 /*****************************************************************************
4482 * GetPrinterDriverA [WINSPOOL.@]
4484 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4485 DWORD Level, LPBYTE pDriverInfo,
4486 DWORD cbBuf, LPDWORD pcbNeeded)
4489 UNICODE_STRING pEnvW;
4495 ZeroMemory(pDriverInfo, cbBuf);
4496 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4499 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4500 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4503 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4505 HeapFree(GetProcessHeap(), 0, buf);
4507 RtlFreeUnicodeString(&pEnvW);
4511 /*****************************************************************************
4512 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4514 * Return the PATH for the Printer-Drivers (UNICODE)
4517 * pName [I] Servername (NT only) or NULL (local Computer)
4518 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4519 * Level [I] Structure-Level (must be 1)
4520 * pDriverDirectory [O] PTR to Buffer that receives the Result
4521 * cbBuf [I] Size of Buffer at pDriverDirectory
4522 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4523 * required for pDriverDirectory
4526 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4527 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4528 * if cbBuf is too small
4530 * Native Values returned in pDriverDirectory on Success:
4531 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4532 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4533 *| win9x(Windows 4.0): "%winsysdir%"
4535 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4538 *- Only NULL or "" is supported for pName
4541 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4542 DWORD Level, LPBYTE pDriverDirectory,
4543 DWORD cbBuf, LPDWORD pcbNeeded)
4545 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4546 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4548 if ((backend == NULL) && !load_backend()) return FALSE;
4551 /* (Level != 1) is ignored in win9x */
4552 SetLastError(ERROR_INVALID_LEVEL);
4555 if (pcbNeeded == NULL) {
4556 /* (pcbNeeded == NULL) is ignored in win9x */
4557 SetLastError(RPC_X_NULL_REF_POINTER);
4561 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4562 pDriverDirectory, cbBuf, pcbNeeded);
4567 /*****************************************************************************
4568 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4570 * Return the PATH for the Printer-Drivers (ANSI)
4572 * See GetPrinterDriverDirectoryW.
4575 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4578 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4579 DWORD Level, LPBYTE pDriverDirectory,
4580 DWORD cbBuf, LPDWORD pcbNeeded)
4582 UNICODE_STRING nameW, environmentW;
4585 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4586 WCHAR *driverDirectoryW = NULL;
4588 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4589 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4591 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4593 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4594 else nameW.Buffer = NULL;
4595 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4596 else environmentW.Buffer = NULL;
4598 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4599 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4602 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4603 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4605 *pcbNeeded = needed;
4606 ret = (needed <= cbBuf) ? TRUE : FALSE;
4608 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4610 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4612 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4613 RtlFreeUnicodeString(&environmentW);
4614 RtlFreeUnicodeString(&nameW);
4619 /*****************************************************************************
4620 * AddPrinterDriverA [WINSPOOL.@]
4622 * See AddPrinterDriverW.
4625 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4627 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4628 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4631 /******************************************************************************
4632 * AddPrinterDriverW (WINSPOOL.@)
4634 * Install a Printer Driver
4637 * pName [I] Servername or NULL (local Computer)
4638 * level [I] Level for the supplied DRIVER_INFO_*W struct
4639 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4646 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4648 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4649 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4652 /*****************************************************************************
4653 * AddPrintProcessorA [WINSPOOL.@]
4655 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4656 LPSTR pPrintProcessorName)
4658 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4659 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4663 /*****************************************************************************
4664 * AddPrintProcessorW [WINSPOOL.@]
4666 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4667 LPWSTR pPrintProcessorName)
4669 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4670 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4674 /*****************************************************************************
4675 * AddPrintProvidorA [WINSPOOL.@]
4677 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4679 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4683 /*****************************************************************************
4684 * AddPrintProvidorW [WINSPOOL.@]
4686 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4688 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4692 /*****************************************************************************
4693 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4695 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4696 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4698 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4699 pDevModeOutput, pDevModeInput);
4703 /*****************************************************************************
4704 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4706 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4707 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4709 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4710 pDevModeOutput, pDevModeInput);
4714 /*****************************************************************************
4715 * PrinterProperties [WINSPOOL.@]
4717 * Displays a dialog to set the properties of the printer.
4720 * nonzero on success or zero on failure
4723 * implemented as stub only
4725 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4726 HANDLE hPrinter /* [in] handle to printer object */
4728 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4729 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4733 /*****************************************************************************
4734 * EnumJobsA [WINSPOOL.@]
4737 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4738 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4741 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4742 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4744 if(pcbNeeded) *pcbNeeded = 0;
4745 if(pcReturned) *pcReturned = 0;
4750 /*****************************************************************************
4751 * EnumJobsW [WINSPOOL.@]
4754 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4755 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4758 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4759 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4761 if(pcbNeeded) *pcbNeeded = 0;
4762 if(pcReturned) *pcReturned = 0;
4766 /*****************************************************************************
4767 * WINSPOOL_EnumPrinterDrivers [internal]
4769 * Delivers information about all printer drivers installed on the
4770 * localhost or a given server
4773 * nonzero on success or zero on failure. If the buffer for the returned
4774 * information is too small the function will return an error
4777 * - only implemented for localhost, foreign hosts will return an error
4779 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4780 DWORD Level, LPBYTE pDriverInfo,
4782 DWORD cbBuf, LPDWORD pcbNeeded,
4783 LPDWORD pcFound, DWORD data_offset)
4787 const printenv_t * env;
4789 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4790 debugstr_w(pName), debugstr_w(pEnvironment),
4791 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4793 env = validate_envW(pEnvironment);
4794 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4798 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4800 ERR("Can't open Drivers key\n");
4804 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4805 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4806 RegCloseKey(hkeyDrivers);
4807 ERR("Can't query Drivers key\n");
4810 TRACE("Found %d Drivers\n", *pcFound);
4812 /* get size of single struct
4813 * unicode and ascii structure have the same size
4815 size = di_sizeof[Level];
4817 if (data_offset == 0)
4818 data_offset = size * (*pcFound);
4819 *pcbNeeded = data_offset;
4821 for( i = 0; i < *pcFound; i++) {
4822 WCHAR DriverNameW[255];
4823 PBYTE table_ptr = NULL;
4824 PBYTE data_ptr = NULL;
4827 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4829 ERR("Can't enum key number %d\n", i);
4830 RegCloseKey(hkeyDrivers);
4834 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4835 table_ptr = pDriverInfo + (driver_index + i) * size;
4836 if (pDriverInfo && *pcbNeeded <= cbBuf)
4837 data_ptr = pDriverInfo + *pcbNeeded;
4839 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4840 env, Level, table_ptr, data_ptr,
4841 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4843 RegCloseKey(hkeyDrivers);
4847 *pcbNeeded += needed;
4850 RegCloseKey(hkeyDrivers);
4852 if(cbBuf < *pcbNeeded){
4853 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4860 /*****************************************************************************
4861 * EnumPrinterDriversW [WINSPOOL.@]
4863 * see function EnumPrinterDrivers for RETURNS, BUGS
4865 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4866 LPBYTE pDriverInfo, DWORD cbBuf,
4867 LPDWORD pcbNeeded, LPDWORD pcReturned)
4869 static const WCHAR allW[] = {'a','l','l',0};
4873 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4875 SetLastError(RPC_X_NULL_REF_POINTER);
4879 /* check for local drivers */
4880 if((pName) && (pName[0])) {
4881 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4882 SetLastError(ERROR_ACCESS_DENIED);
4886 /* check input parameter */
4887 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4888 SetLastError(ERROR_INVALID_LEVEL);
4892 if(pDriverInfo && cbBuf > 0)
4893 memset( pDriverInfo, 0, cbBuf);
4895 /* Exception: pull all printers */
4896 if (pEnvironment && !strcmpW(pEnvironment, allW))
4898 DWORD i, needed, bufsize = cbBuf;
4899 DWORD total_needed = 0;
4900 DWORD total_found = 0;
4903 /* Precompute the overall total; we need this to know
4904 where pointers end and data begins (i.e. data_offset) */
4905 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4908 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4909 NULL, 0, 0, &needed, &found, 0);
4910 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4911 total_needed += needed;
4912 total_found += found;
4915 data_offset = di_sizeof[Level] * total_found;
4920 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4923 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4924 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4925 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4927 *pcReturned += found;
4928 *pcbNeeded = needed;
4929 data_offset = needed;
4930 total_found += found;
4935 /* Normal behavior */
4936 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4937 0, cbBuf, pcbNeeded, &found, 0);
4939 *pcReturned = found;
4944 /*****************************************************************************
4945 * EnumPrinterDriversA [WINSPOOL.@]
4947 * see function EnumPrinterDrivers for RETURNS, BUGS
4949 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4950 LPBYTE pDriverInfo, DWORD cbBuf,
4951 LPDWORD pcbNeeded, LPDWORD pcReturned)
4954 UNICODE_STRING pNameW, pEnvironmentW;
4955 PWSTR pwstrNameW, pwstrEnvironmentW;
4959 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4961 pwstrNameW = asciitounicode(&pNameW, pName);
4962 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4964 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4965 buf, cbBuf, pcbNeeded, pcReturned);
4967 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4969 HeapFree(GetProcessHeap(), 0, buf);
4971 RtlFreeUnicodeString(&pNameW);
4972 RtlFreeUnicodeString(&pEnvironmentW);
4977 /******************************************************************************
4978 * EnumPortsA (WINSPOOL.@)
4983 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4984 LPDWORD pcbNeeded, LPDWORD pcReturned)
4987 LPBYTE bufferW = NULL;
4988 LPWSTR nameW = NULL;
4990 DWORD numentries = 0;
4993 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4994 cbBuf, pcbNeeded, pcReturned);
4996 /* convert servername to unicode */
4998 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4999 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5000 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5002 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5003 needed = cbBuf * sizeof(WCHAR);
5004 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5005 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5007 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5008 if (pcbNeeded) needed = *pcbNeeded;
5009 /* HeapReAlloc return NULL, when bufferW was NULL */
5010 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5011 HeapAlloc(GetProcessHeap(), 0, needed);
5013 /* Try again with the large Buffer */
5014 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5016 needed = pcbNeeded ? *pcbNeeded : 0;
5017 numentries = pcReturned ? *pcReturned : 0;
5020 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5021 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5024 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5025 DWORD entrysize = 0;
5028 LPPORT_INFO_2W pi2w;
5029 LPPORT_INFO_2A pi2a;
5032 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5034 /* First pass: calculate the size for all Entries */
5035 pi2w = (LPPORT_INFO_2W) bufferW;
5036 pi2a = (LPPORT_INFO_2A) pPorts;
5038 while (index < numentries) {
5040 needed += entrysize; /* PORT_INFO_?A */
5041 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5043 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5044 NULL, 0, NULL, NULL);
5046 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5047 NULL, 0, NULL, NULL);
5048 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5049 NULL, 0, NULL, NULL);
5051 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5052 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5053 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5056 /* check for errors and quit on failure */
5057 if (cbBuf < needed) {
5058 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5062 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5063 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5064 cbBuf -= len ; /* free Bytes in the user-Buffer */
5065 pi2w = (LPPORT_INFO_2W) bufferW;
5066 pi2a = (LPPORT_INFO_2A) pPorts;
5068 /* Second Pass: Fill the User Buffer (if we have one) */
5069 while ((index < numentries) && pPorts) {
5071 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5072 pi2a->pPortName = ptr;
5073 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5074 ptr, cbBuf , NULL, NULL);
5078 pi2a->pMonitorName = ptr;
5079 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5080 ptr, cbBuf, NULL, NULL);
5084 pi2a->pDescription = ptr;
5085 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5086 ptr, cbBuf, NULL, NULL);
5090 pi2a->fPortType = pi2w->fPortType;
5091 pi2a->Reserved = 0; /* documented: "must be zero" */
5094 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5095 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5096 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5101 if (pcbNeeded) *pcbNeeded = needed;
5102 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5104 HeapFree(GetProcessHeap(), 0, nameW);
5105 HeapFree(GetProcessHeap(), 0, bufferW);
5107 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5108 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5114 /******************************************************************************
5115 * EnumPortsW (WINSPOOL.@)
5117 * Enumerate available Ports
5120 * pName [I] Servername or NULL (local Computer)
5121 * Level [I] Structure-Level (1 or 2)
5122 * pPorts [O] PTR to Buffer that receives the Result
5123 * cbBuf [I] Size of Buffer at pPorts
5124 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5125 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5129 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5132 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5135 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5136 cbBuf, pcbNeeded, pcReturned);
5138 if ((backend == NULL) && !load_backend()) return FALSE;
5140 /* Level is not checked in win9x */
5141 if (!Level || (Level > 2)) {
5142 WARN("level (%d) is ignored in win9x\n", Level);
5143 SetLastError(ERROR_INVALID_LEVEL);
5146 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5147 SetLastError(RPC_X_NULL_REF_POINTER);
5151 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5154 /******************************************************************************
5155 * GetDefaultPrinterW (WINSPOOL.@)
5158 * This function must read the value from data 'device' of key
5159 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5161 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5165 WCHAR *buffer, *ptr;
5169 SetLastError(ERROR_INVALID_PARAMETER);
5173 /* make the buffer big enough for the stuff from the profile/registry,
5174 * the content must fit into the local buffer to compute the correct
5175 * size even if the extern buffer is too small or not given.
5176 * (20 for ,driver,port) */
5178 len = max(100, (insize + 20));
5179 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5181 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5183 SetLastError (ERROR_FILE_NOT_FOUND);
5187 TRACE("%s\n", debugstr_w(buffer));
5189 if ((ptr = strchrW(buffer, ',')) == NULL)
5191 SetLastError(ERROR_INVALID_NAME);
5197 *namesize = strlenW(buffer) + 1;
5198 if(!name || (*namesize > insize))
5200 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5204 strcpyW(name, buffer);
5207 HeapFree( GetProcessHeap(), 0, buffer);
5212 /******************************************************************************
5213 * GetDefaultPrinterA (WINSPOOL.@)
5215 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5219 WCHAR *bufferW = NULL;
5223 SetLastError(ERROR_INVALID_PARAMETER);
5227 if(name && *namesize) {
5229 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5232 if(!GetDefaultPrinterW( bufferW, namesize)) {
5237 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5241 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5244 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5247 HeapFree( GetProcessHeap(), 0, bufferW);
5252 /******************************************************************************
5253 * SetDefaultPrinterW (WINSPOOL.204)
5255 * Set the Name of the Default Printer
5258 * pszPrinter [I] Name of the Printer or NULL
5265 * When the Parameter is NULL or points to an Empty String and
5266 * a Default Printer was already present, then this Function changes nothing.
5267 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5268 * the First enumerated local Printer is used.
5271 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5273 WCHAR default_printer[MAX_PATH];
5274 LPWSTR buffer = NULL;
5280 TRACE("(%s)\n", debugstr_w(pszPrinter));
5281 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5283 default_printer[0] = '\0';
5284 size = sizeof(default_printer)/sizeof(WCHAR);
5286 /* if we have a default Printer, do nothing. */
5287 if (GetDefaultPrinterW(default_printer, &size))
5291 /* we have no default Printer: search local Printers and use the first */
5292 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5294 default_printer[0] = '\0';
5295 size = sizeof(default_printer)/sizeof(WCHAR);
5296 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5298 pszPrinter = default_printer;
5299 TRACE("using %s\n", debugstr_w(pszPrinter));
5304 if (pszPrinter == NULL) {
5305 TRACE("no local printer found\n");
5306 SetLastError(ERROR_FILE_NOT_FOUND);
5311 /* "pszPrinter" is never empty or NULL here. */
5312 namelen = lstrlenW(pszPrinter);
5313 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5314 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5316 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5317 HeapFree(GetProcessHeap(), 0, buffer);
5318 SetLastError(ERROR_FILE_NOT_FOUND);
5322 /* read the devices entry for the printer (driver,port) to build the string for the
5323 default device entry (printer,driver,port) */
5324 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5325 buffer[namelen] = ',';
5326 namelen++; /* move index to the start of the driver */
5328 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5329 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5331 TRACE("set device to %s\n", debugstr_w(buffer));
5333 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5334 TRACE("failed to set the device entry: %d\n", GetLastError());
5335 lres = ERROR_INVALID_PRINTER_NAME;
5338 /* remove the next section, when INIFileMapping is implemented */
5341 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5342 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5349 if (lres != ERROR_FILE_NOT_FOUND)
5350 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5352 SetLastError(ERROR_INVALID_PRINTER_NAME);
5356 HeapFree(GetProcessHeap(), 0, buffer);
5357 return (lres == ERROR_SUCCESS);
5360 /******************************************************************************
5361 * SetDefaultPrinterA (WINSPOOL.202)
5363 * See SetDefaultPrinterW.
5366 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5368 LPWSTR bufferW = NULL;
5371 TRACE("(%s)\n", debugstr_a(pszPrinter));
5373 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5374 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5375 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5377 res = SetDefaultPrinterW(bufferW);
5378 HeapFree(GetProcessHeap(), 0, bufferW);
5382 /******************************************************************************
5383 * SetPrinterDataExA (WINSPOOL.@)
5385 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5386 LPCSTR pValueName, DWORD Type,
5387 LPBYTE pData, DWORD cbData)
5389 HKEY hkeyPrinter, hkeySubkey;
5392 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5393 debugstr_a(pValueName), Type, pData, cbData);
5395 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5399 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5401 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5402 RegCloseKey(hkeyPrinter);
5405 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5406 RegCloseKey(hkeySubkey);
5407 RegCloseKey(hkeyPrinter);
5411 /******************************************************************************
5412 * SetPrinterDataExW (WINSPOOL.@)
5414 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5415 LPCWSTR pValueName, DWORD Type,
5416 LPBYTE pData, DWORD cbData)
5418 HKEY hkeyPrinter, hkeySubkey;
5421 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5422 debugstr_w(pValueName), Type, pData, cbData);
5424 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5428 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5430 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5431 RegCloseKey(hkeyPrinter);
5434 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5435 RegCloseKey(hkeySubkey);
5436 RegCloseKey(hkeyPrinter);
5440 /******************************************************************************
5441 * SetPrinterDataA (WINSPOOL.@)
5443 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5444 LPBYTE pData, DWORD cbData)
5446 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5450 /******************************************************************************
5451 * SetPrinterDataW (WINSPOOL.@)
5453 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5454 LPBYTE pData, DWORD cbData)
5456 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5460 /******************************************************************************
5461 * GetPrinterDataExA (WINSPOOL.@)
5463 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5464 LPCSTR pValueName, LPDWORD pType,
5465 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5467 opened_printer_t *printer;
5468 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5471 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5472 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5474 printer = get_opened_printer(hPrinter);
5475 if(!printer) return ERROR_INVALID_HANDLE;
5477 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5478 if (ret) return ret;
5480 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5482 if (printer->name) {
5484 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5486 RegCloseKey(hkeyPrinters);
5489 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5490 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5491 RegCloseKey(hkeyPrinter);
5492 RegCloseKey(hkeyPrinters);
5497 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5498 0, pType, pData, pcbNeeded);
5500 if (!ret && !pData) ret = ERROR_MORE_DATA;
5502 RegCloseKey(hkeySubkey);
5503 RegCloseKey(hkeyPrinter);
5504 RegCloseKey(hkeyPrinters);
5506 TRACE("--> %d\n", ret);
5510 /******************************************************************************
5511 * GetPrinterDataExW (WINSPOOL.@)
5513 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5514 LPCWSTR pValueName, LPDWORD pType,
5515 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5517 opened_printer_t *printer;
5518 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5521 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5522 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5524 printer = get_opened_printer(hPrinter);
5525 if(!printer) return ERROR_INVALID_HANDLE;
5527 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5528 if (ret) return ret;
5530 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5532 if (printer->name) {
5534 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5536 RegCloseKey(hkeyPrinters);
5539 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5540 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5541 RegCloseKey(hkeyPrinter);
5542 RegCloseKey(hkeyPrinters);
5547 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5548 0, pType, pData, pcbNeeded);
5550 if (!ret && !pData) ret = ERROR_MORE_DATA;
5552 RegCloseKey(hkeySubkey);
5553 RegCloseKey(hkeyPrinter);
5554 RegCloseKey(hkeyPrinters);
5556 TRACE("--> %d\n", ret);
5560 /******************************************************************************
5561 * GetPrinterDataA (WINSPOOL.@)
5563 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5564 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5566 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5567 pData, nSize, pcbNeeded);
5570 /******************************************************************************
5571 * GetPrinterDataW (WINSPOOL.@)
5573 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5574 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5576 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5577 pData, nSize, pcbNeeded);
5580 /*******************************************************************************
5581 * EnumPrinterDataExW [WINSPOOL.@]
5583 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5584 LPBYTE pEnumValues, DWORD cbEnumValues,
5585 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5587 HKEY hkPrinter, hkSubKey;
5588 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5589 cbValueNameLen, cbMaxValueLen, cbValueLen,
5594 PPRINTER_ENUM_VALUESW ppev;
5596 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5598 if (pKeyName == NULL || *pKeyName == 0)
5599 return ERROR_INVALID_PARAMETER;
5601 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5602 if (ret != ERROR_SUCCESS)
5604 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5609 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5610 if (ret != ERROR_SUCCESS)
5612 r = RegCloseKey (hkPrinter);
5613 if (r != ERROR_SUCCESS)
5614 WARN ("RegCloseKey returned %i\n", r);
5615 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5616 debugstr_w (pKeyName), ret);
5620 ret = RegCloseKey (hkPrinter);
5621 if (ret != ERROR_SUCCESS)
5623 ERR ("RegCloseKey returned %i\n", ret);
5624 r = RegCloseKey (hkSubKey);
5625 if (r != ERROR_SUCCESS)
5626 WARN ("RegCloseKey returned %i\n", r);
5630 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5631 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5632 if (ret != ERROR_SUCCESS)
5634 r = RegCloseKey (hkSubKey);
5635 if (r != ERROR_SUCCESS)
5636 WARN ("RegCloseKey returned %i\n", r);
5637 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5641 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5642 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5644 if (cValues == 0) /* empty key */
5646 r = RegCloseKey (hkSubKey);
5647 if (r != ERROR_SUCCESS)
5648 WARN ("RegCloseKey returned %i\n", r);
5649 *pcbEnumValues = *pnEnumValues = 0;
5650 return ERROR_SUCCESS;
5653 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5655 hHeap = GetProcessHeap ();
5658 ERR ("GetProcessHeap failed\n");
5659 r = RegCloseKey (hkSubKey);
5660 if (r != ERROR_SUCCESS)
5661 WARN ("RegCloseKey returned %i\n", r);
5662 return ERROR_OUTOFMEMORY;
5665 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5666 if (lpValueName == NULL)
5668 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5669 r = RegCloseKey (hkSubKey);
5670 if (r != ERROR_SUCCESS)
5671 WARN ("RegCloseKey returned %i\n", r);
5672 return ERROR_OUTOFMEMORY;
5675 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5676 if (lpValue == NULL)
5678 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5679 if (HeapFree (hHeap, 0, lpValueName) == 0)
5680 WARN ("HeapFree failed with code %i\n", GetLastError ());
5681 r = RegCloseKey (hkSubKey);
5682 if (r != ERROR_SUCCESS)
5683 WARN ("RegCloseKey returned %i\n", r);
5684 return ERROR_OUTOFMEMORY;
5687 TRACE ("pass 1: calculating buffer required for all names and values\n");
5689 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5691 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5693 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5695 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5696 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5697 NULL, NULL, lpValue, &cbValueLen);
5698 if (ret != ERROR_SUCCESS)
5700 if (HeapFree (hHeap, 0, lpValue) == 0)
5701 WARN ("HeapFree failed with code %i\n", GetLastError ());
5702 if (HeapFree (hHeap, 0, lpValueName) == 0)
5703 WARN ("HeapFree failed with code %i\n", GetLastError ());
5704 r = RegCloseKey (hkSubKey);
5705 if (r != ERROR_SUCCESS)
5706 WARN ("RegCloseKey returned %i\n", r);
5707 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5711 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5712 debugstr_w (lpValueName), dwIndex,
5713 cbValueNameLen + 1, cbValueLen);
5715 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5716 cbBufSize += cbValueLen;
5719 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5721 *pcbEnumValues = cbBufSize;
5722 *pnEnumValues = cValues;
5724 if (cbEnumValues < cbBufSize) /* buffer too small */
5726 if (HeapFree (hHeap, 0, lpValue) == 0)
5727 WARN ("HeapFree failed with code %i\n", GetLastError ());
5728 if (HeapFree (hHeap, 0, lpValueName) == 0)
5729 WARN ("HeapFree failed with code %i\n", GetLastError ());
5730 r = RegCloseKey (hkSubKey);
5731 if (r != ERROR_SUCCESS)
5732 WARN ("RegCloseKey returned %i\n", r);
5733 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5734 return ERROR_MORE_DATA;
5737 TRACE ("pass 2: copying all names and values to buffer\n");
5739 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5740 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5742 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5744 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5745 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5746 NULL, &dwType, lpValue, &cbValueLen);
5747 if (ret != ERROR_SUCCESS)
5749 if (HeapFree (hHeap, 0, lpValue) == 0)
5750 WARN ("HeapFree failed with code %i\n", GetLastError ());
5751 if (HeapFree (hHeap, 0, lpValueName) == 0)
5752 WARN ("HeapFree failed with code %i\n", GetLastError ());
5753 r = RegCloseKey (hkSubKey);
5754 if (r != ERROR_SUCCESS)
5755 WARN ("RegCloseKey returned %i\n", r);
5756 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5760 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5761 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5762 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5763 pEnumValues += cbValueNameLen;
5765 /* return # of *bytes* (including trailing \0), not # of chars */
5766 ppev[dwIndex].cbValueName = cbValueNameLen;
5768 ppev[dwIndex].dwType = dwType;
5770 memcpy (pEnumValues, lpValue, cbValueLen);
5771 ppev[dwIndex].pData = pEnumValues;
5772 pEnumValues += cbValueLen;
5774 ppev[dwIndex].cbData = cbValueLen;
5776 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5777 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5780 if (HeapFree (hHeap, 0, lpValue) == 0)
5782 ret = GetLastError ();
5783 ERR ("HeapFree failed with code %i\n", ret);
5784 if (HeapFree (hHeap, 0, lpValueName) == 0)
5785 WARN ("HeapFree failed with code %i\n", GetLastError ());
5786 r = RegCloseKey (hkSubKey);
5787 if (r != ERROR_SUCCESS)
5788 WARN ("RegCloseKey returned %i\n", r);
5792 if (HeapFree (hHeap, 0, lpValueName) == 0)
5794 ret = GetLastError ();
5795 ERR ("HeapFree failed with code %i\n", ret);
5796 r = RegCloseKey (hkSubKey);
5797 if (r != ERROR_SUCCESS)
5798 WARN ("RegCloseKey returned %i\n", r);
5802 ret = RegCloseKey (hkSubKey);
5803 if (ret != ERROR_SUCCESS)
5805 ERR ("RegCloseKey returned %i\n", ret);
5809 return ERROR_SUCCESS;
5812 /*******************************************************************************
5813 * EnumPrinterDataExA [WINSPOOL.@]
5815 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5816 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5817 * what Windows 2000 SP1 does.
5820 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5821 LPBYTE pEnumValues, DWORD cbEnumValues,
5822 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5826 DWORD ret, dwIndex, dwBufSize;
5830 TRACE ("%p %s\n", hPrinter, pKeyName);
5832 if (pKeyName == NULL || *pKeyName == 0)
5833 return ERROR_INVALID_PARAMETER;
5835 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5838 ret = GetLastError ();
5839 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5843 hHeap = GetProcessHeap ();
5846 ERR ("GetProcessHeap failed\n");
5847 return ERROR_OUTOFMEMORY;
5850 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5851 if (pKeyNameW == NULL)
5853 ERR ("Failed to allocate %i bytes from process heap\n",
5854 (LONG)(len * sizeof (WCHAR)));
5855 return ERROR_OUTOFMEMORY;
5858 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5860 ret = GetLastError ();
5861 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5862 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5863 WARN ("HeapFree failed with code %i\n", GetLastError ());
5867 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5868 pcbEnumValues, pnEnumValues);
5869 if (ret != ERROR_SUCCESS)
5871 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5872 WARN ("HeapFree failed with code %i\n", GetLastError ());
5873 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5877 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5879 ret = GetLastError ();
5880 ERR ("HeapFree failed with code %i\n", ret);
5884 if (*pnEnumValues == 0) /* empty key */
5885 return ERROR_SUCCESS;
5888 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5890 PPRINTER_ENUM_VALUESW ppev =
5891 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5893 if (dwBufSize < ppev->cbValueName)
5894 dwBufSize = ppev->cbValueName;
5896 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5897 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5898 dwBufSize = ppev->cbData;
5901 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5903 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5904 if (pBuffer == NULL)
5906 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5907 return ERROR_OUTOFMEMORY;
5910 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5912 PPRINTER_ENUM_VALUESW ppev =
5913 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5915 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5916 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5920 ret = GetLastError ();
5921 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5922 if (HeapFree (hHeap, 0, pBuffer) == 0)
5923 WARN ("HeapFree failed with code %i\n", GetLastError ());
5927 memcpy (ppev->pValueName, pBuffer, len);
5929 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5931 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5932 ppev->dwType != REG_MULTI_SZ)
5935 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5936 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5939 ret = GetLastError ();
5940 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5941 if (HeapFree (hHeap, 0, pBuffer) == 0)
5942 WARN ("HeapFree failed with code %i\n", GetLastError ());
5946 memcpy (ppev->pData, pBuffer, len);
5948 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5949 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5952 if (HeapFree (hHeap, 0, pBuffer) == 0)
5954 ret = GetLastError ();
5955 ERR ("HeapFree failed with code %i\n", ret);
5959 return ERROR_SUCCESS;
5962 /******************************************************************************
5963 * AbortPrinter (WINSPOOL.@)
5965 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5967 FIXME("(%p), stub!\n", hPrinter);
5971 /******************************************************************************
5972 * AddPortA (WINSPOOL.@)
5977 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5979 LPWSTR nameW = NULL;
5980 LPWSTR monitorW = NULL;
5984 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5987 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5988 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5989 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5993 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5994 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5995 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5997 res = AddPortW(nameW, hWnd, monitorW);
5998 HeapFree(GetProcessHeap(), 0, nameW);
5999 HeapFree(GetProcessHeap(), 0, monitorW);
6003 /******************************************************************************
6004 * AddPortW (WINSPOOL.@)
6006 * Add a Port for a specific Monitor
6009 * pName [I] Servername or NULL (local Computer)
6010 * hWnd [I] Handle to parent Window for the Dialog-Box
6011 * pMonitorName [I] Name of the Monitor that manage the Port
6018 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6020 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6022 if ((backend == NULL) && !load_backend()) return FALSE;
6024 if (!pMonitorName) {
6025 SetLastError(RPC_X_NULL_REF_POINTER);
6029 return backend->fpAddPort(pName, hWnd, pMonitorName);
6032 /******************************************************************************
6033 * AddPortExA (WINSPOOL.@)
6038 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6041 PORT_INFO_2A * pi2A;
6042 LPWSTR nameW = NULL;
6043 LPWSTR monitorW = NULL;
6047 pi2A = (PORT_INFO_2A *) pBuffer;
6049 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6050 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6052 if ((level < 1) || (level > 2)) {
6053 SetLastError(ERROR_INVALID_LEVEL);
6058 SetLastError(ERROR_INVALID_PARAMETER);
6063 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6064 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6065 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6069 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6070 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6071 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6074 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6076 if (pi2A->pPortName) {
6077 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6078 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6079 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6083 if (pi2A->pMonitorName) {
6084 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6085 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6086 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6089 if (pi2A->pDescription) {
6090 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6091 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6092 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6094 pi2W.fPortType = pi2A->fPortType;
6095 pi2W.Reserved = pi2A->Reserved;
6098 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6100 HeapFree(GetProcessHeap(), 0, nameW);
6101 HeapFree(GetProcessHeap(), 0, monitorW);
6102 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6103 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6104 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6109 /******************************************************************************
6110 * AddPortExW (WINSPOOL.@)
6112 * Add a Port for a specific Monitor, without presenting a user interface
6115 * pName [I] Servername or NULL (local Computer)
6116 * level [I] Structure-Level (1 or 2) for pBuffer
6117 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6118 * pMonitorName [I] Name of the Monitor that manage the Port
6125 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6129 pi2 = (PORT_INFO_2W *) pBuffer;
6131 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6132 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6133 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6134 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6136 if ((backend == NULL) && !load_backend()) return FALSE;
6138 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6139 SetLastError(ERROR_INVALID_PARAMETER);
6143 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6146 /******************************************************************************
6147 * AddPrinterConnectionA (WINSPOOL.@)
6149 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6151 FIXME("%s\n", debugstr_a(pName));
6155 /******************************************************************************
6156 * AddPrinterConnectionW (WINSPOOL.@)
6158 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6160 FIXME("%s\n", debugstr_w(pName));
6164 /******************************************************************************
6165 * AddPrinterDriverExW (WINSPOOL.@)
6167 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6170 * pName [I] Servername or NULL (local Computer)
6171 * level [I] Level for the supplied DRIVER_INFO_*W struct
6172 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6173 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6180 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6182 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6184 if ((backend == NULL) && !load_backend()) return FALSE;
6186 if (level < 2 || level == 5 || level == 7 || level > 8) {
6187 SetLastError(ERROR_INVALID_LEVEL);
6192 SetLastError(ERROR_INVALID_PARAMETER);
6196 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6199 /******************************************************************************
6200 * AddPrinterDriverExA (WINSPOOL.@)
6202 * See AddPrinterDriverExW.
6205 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6207 DRIVER_INFO_8A *diA;
6209 LPWSTR nameW = NULL;
6214 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6216 diA = (DRIVER_INFO_8A *) pDriverInfo;
6217 ZeroMemory(&diW, sizeof(diW));
6219 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6220 SetLastError(ERROR_INVALID_LEVEL);
6225 SetLastError(ERROR_INVALID_PARAMETER);
6229 /* convert servername to unicode */
6231 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6232 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6233 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6237 diW.cVersion = diA->cVersion;
6240 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6241 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6242 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6245 if (diA->pEnvironment) {
6246 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6247 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6248 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6251 if (diA->pDriverPath) {
6252 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6253 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6254 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6257 if (diA->pDataFile) {
6258 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6259 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6260 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6263 if (diA->pConfigFile) {
6264 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6265 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6266 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6269 if ((Level > 2) && diA->pDependentFiles) {
6270 lenA = multi_sz_lenA(diA->pDependentFiles);
6271 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6272 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6273 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6276 if ((Level > 2) && diA->pMonitorName) {
6277 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6278 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6279 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6282 if ((Level > 3) && diA->pDefaultDataType) {
6283 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6284 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6285 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6288 if ((Level > 3) && diA->pszzPreviousNames) {
6289 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6290 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6291 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6292 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6295 if ((Level > 5) && diA->pszMfgName) {
6296 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6297 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6298 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6301 if ((Level > 5) && diA->pszOEMUrl) {
6302 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6303 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6304 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6307 if ((Level > 5) && diA->pszHardwareID) {
6308 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6309 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6310 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6313 if ((Level > 5) && diA->pszProvider) {
6314 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6315 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6316 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6320 FIXME("level %u is incomplete\n", Level);
6323 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6324 TRACE("got %u with %u\n", res, GetLastError());
6325 HeapFree(GetProcessHeap(), 0, nameW);
6326 HeapFree(GetProcessHeap(), 0, diW.pName);
6327 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6328 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6329 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6330 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6331 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6332 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6333 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6334 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6335 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6336 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6337 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6338 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6340 TRACE("=> %u with %u\n", res, GetLastError());
6344 /******************************************************************************
6345 * ConfigurePortA (WINSPOOL.@)
6347 * See ConfigurePortW.
6350 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6352 LPWSTR nameW = NULL;
6353 LPWSTR portW = NULL;
6357 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6359 /* convert servername to unicode */
6361 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6362 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6363 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6366 /* convert portname to unicode */
6368 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6369 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6370 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6373 res = ConfigurePortW(nameW, hWnd, portW);
6374 HeapFree(GetProcessHeap(), 0, nameW);
6375 HeapFree(GetProcessHeap(), 0, portW);
6379 /******************************************************************************
6380 * ConfigurePortW (WINSPOOL.@)
6382 * Display the Configuration-Dialog for a specific Port
6385 * pName [I] Servername or NULL (local Computer)
6386 * hWnd [I] Handle to parent Window for the Dialog-Box
6387 * pPortName [I] Name of the Port, that should be configured
6394 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6397 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6399 if ((backend == NULL) && !load_backend()) return FALSE;
6402 SetLastError(RPC_X_NULL_REF_POINTER);
6406 return backend->fpConfigurePort(pName, hWnd, pPortName);
6409 /******************************************************************************
6410 * ConnectToPrinterDlg (WINSPOOL.@)
6412 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6414 FIXME("%p %x\n", hWnd, Flags);
6418 /******************************************************************************
6419 * DeletePrinterConnectionA (WINSPOOL.@)
6421 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6423 FIXME("%s\n", debugstr_a(pName));
6427 /******************************************************************************
6428 * DeletePrinterConnectionW (WINSPOOL.@)
6430 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6432 FIXME("%s\n", debugstr_w(pName));
6436 /******************************************************************************
6437 * DeletePrinterDriverExW (WINSPOOL.@)
6439 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6440 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6445 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6446 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6448 if(pName && pName[0])
6450 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6451 SetLastError(ERROR_INVALID_PARAMETER);
6457 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6458 SetLastError(ERROR_INVALID_PARAMETER);
6462 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6466 ERR("Can't open drivers key\n");
6470 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6473 RegCloseKey(hkey_drivers);
6478 /******************************************************************************
6479 * DeletePrinterDriverExA (WINSPOOL.@)
6481 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6482 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6484 UNICODE_STRING NameW, EnvW, DriverW;
6487 asciitounicode(&NameW, pName);
6488 asciitounicode(&EnvW, pEnvironment);
6489 asciitounicode(&DriverW, pDriverName);
6491 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6493 RtlFreeUnicodeString(&DriverW);
6494 RtlFreeUnicodeString(&EnvW);
6495 RtlFreeUnicodeString(&NameW);
6500 /******************************************************************************
6501 * DeletePrinterDataExW (WINSPOOL.@)
6503 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6506 FIXME("%p %s %s\n", hPrinter,
6507 debugstr_w(pKeyName), debugstr_w(pValueName));
6508 return ERROR_INVALID_PARAMETER;
6511 /******************************************************************************
6512 * DeletePrinterDataExA (WINSPOOL.@)
6514 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6517 FIXME("%p %s %s\n", hPrinter,
6518 debugstr_a(pKeyName), debugstr_a(pValueName));
6519 return ERROR_INVALID_PARAMETER;
6522 /******************************************************************************
6523 * DeletePrintProcessorA (WINSPOOL.@)
6525 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6527 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6528 debugstr_a(pPrintProcessorName));
6532 /******************************************************************************
6533 * DeletePrintProcessorW (WINSPOOL.@)
6535 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6537 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6538 debugstr_w(pPrintProcessorName));
6542 /******************************************************************************
6543 * DeletePrintProvidorA (WINSPOOL.@)
6545 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6547 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6548 debugstr_a(pPrintProviderName));
6552 /******************************************************************************
6553 * DeletePrintProvidorW (WINSPOOL.@)
6555 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6557 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6558 debugstr_w(pPrintProviderName));
6562 /******************************************************************************
6563 * EnumFormsA (WINSPOOL.@)
6565 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6566 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6568 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6569 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6573 /******************************************************************************
6574 * EnumFormsW (WINSPOOL.@)
6576 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6577 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6579 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6580 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6584 /*****************************************************************************
6585 * EnumMonitorsA [WINSPOOL.@]
6587 * See EnumMonitorsW.
6590 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6591 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6594 LPBYTE bufferW = NULL;
6595 LPWSTR nameW = NULL;
6597 DWORD numentries = 0;
6600 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6601 cbBuf, pcbNeeded, pcReturned);
6603 /* convert servername to unicode */
6605 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6606 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6607 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6609 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6610 needed = cbBuf * sizeof(WCHAR);
6611 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6612 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6614 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6615 if (pcbNeeded) needed = *pcbNeeded;
6616 /* HeapReAlloc return NULL, when bufferW was NULL */
6617 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6618 HeapAlloc(GetProcessHeap(), 0, needed);
6620 /* Try again with the large Buffer */
6621 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6623 numentries = pcReturned ? *pcReturned : 0;
6626 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6627 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6630 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6631 DWORD entrysize = 0;
6634 LPMONITOR_INFO_2W mi2w;
6635 LPMONITOR_INFO_2A mi2a;
6637 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6638 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6640 /* First pass: calculate the size for all Entries */
6641 mi2w = (LPMONITOR_INFO_2W) bufferW;
6642 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6644 while (index < numentries) {
6646 needed += entrysize; /* MONITOR_INFO_?A */
6647 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6649 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6650 NULL, 0, NULL, NULL);
6652 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6653 NULL, 0, NULL, NULL);
6654 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6655 NULL, 0, NULL, NULL);
6657 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6658 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6659 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6662 /* check for errors and quit on failure */
6663 if (cbBuf < needed) {
6664 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6668 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6669 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6670 cbBuf -= len ; /* free Bytes in the user-Buffer */
6671 mi2w = (LPMONITOR_INFO_2W) bufferW;
6672 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6674 /* Second Pass: Fill the User Buffer (if we have one) */
6675 while ((index < numentries) && pMonitors) {
6677 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6679 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6680 ptr, cbBuf , NULL, NULL);
6684 mi2a->pEnvironment = ptr;
6685 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6686 ptr, cbBuf, NULL, NULL);
6690 mi2a->pDLLName = ptr;
6691 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6692 ptr, cbBuf, NULL, NULL);
6696 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6697 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6698 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6702 if (pcbNeeded) *pcbNeeded = needed;
6703 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6705 HeapFree(GetProcessHeap(), 0, nameW);
6706 HeapFree(GetProcessHeap(), 0, bufferW);
6708 TRACE("returning %d with %d (%d byte for %d entries)\n",
6709 (res), GetLastError(), needed, numentries);
6715 /*****************************************************************************
6716 * EnumMonitorsW [WINSPOOL.@]
6718 * Enumerate available Port-Monitors
6721 * pName [I] Servername or NULL (local Computer)
6722 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6723 * pMonitors [O] PTR to Buffer that receives the Result
6724 * cbBuf [I] Size of Buffer at pMonitors
6725 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6726 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6730 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6733 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6734 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6737 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6738 cbBuf, pcbNeeded, pcReturned);
6740 if ((backend == NULL) && !load_backend()) return FALSE;
6742 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6743 SetLastError(RPC_X_NULL_REF_POINTER);
6747 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6750 /******************************************************************************
6751 * SpoolerInit (WINSPOOL.@)
6753 * Initialize the Spooler
6760 * The function fails on windows, when the spooler service is not running
6763 BOOL WINAPI SpoolerInit(void)
6766 if ((backend == NULL) && !load_backend()) return FALSE;
6770 /******************************************************************************
6771 * XcvDataW (WINSPOOL.@)
6773 * Execute commands in the Printmonitor DLL
6776 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6777 * pszDataName [i] Name of the command to execute
6778 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6779 * cbInputData [i] Size in Bytes of Buffer at pInputData
6780 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6781 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6782 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6783 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6790 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6791 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6793 * Minimal List of commands, that a Printmonitor DLL should support:
6795 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6796 *| "AddPort" : Add a Port
6797 *| "DeletePort": Delete a Port
6799 * Many Printmonitors support additional commands. Examples for localspl.dll:
6800 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6801 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6804 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6805 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6806 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6808 opened_printer_t *printer;
6810 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6811 pInputData, cbInputData, pOutputData,
6812 cbOutputData, pcbOutputNeeded, pdwStatus);
6814 if ((backend == NULL) && !load_backend()) return FALSE;
6816 printer = get_opened_printer(hXcv);
6817 if (!printer || (!printer->backend_printer)) {
6818 SetLastError(ERROR_INVALID_HANDLE);
6822 if (!pcbOutputNeeded) {
6823 SetLastError(ERROR_INVALID_PARAMETER);
6827 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6828 SetLastError(RPC_X_NULL_REF_POINTER);
6832 *pcbOutputNeeded = 0;
6834 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6835 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6839 /*****************************************************************************
6840 * EnumPrinterDataA [WINSPOOL.@]
6843 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6844 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6845 DWORD cbData, LPDWORD pcbData )
6847 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6848 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6849 return ERROR_NO_MORE_ITEMS;
6852 /*****************************************************************************
6853 * EnumPrinterDataW [WINSPOOL.@]
6856 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6857 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6858 DWORD cbData, LPDWORD pcbData )
6860 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6861 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6862 return ERROR_NO_MORE_ITEMS;
6865 /*****************************************************************************
6866 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6869 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6870 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6871 LPDWORD pcbNeeded, LPDWORD pcReturned)
6873 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6874 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6875 pcbNeeded, pcReturned);
6879 /*****************************************************************************
6880 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6883 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6884 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6885 LPDWORD pcbNeeded, LPDWORD pcReturned)
6887 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6888 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6889 pcbNeeded, pcReturned);
6893 /*****************************************************************************
6894 * EnumPrintProcessorsA [WINSPOOL.@]
6896 * See EnumPrintProcessorsW.
6899 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6900 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6903 LPBYTE bufferW = NULL;
6904 LPWSTR nameW = NULL;
6907 DWORD numentries = 0;
6910 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6911 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6913 /* convert names to unicode */
6915 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6916 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6917 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6920 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6921 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6922 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6925 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6926 needed = cbBuf * sizeof(WCHAR);
6927 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6928 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6930 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6931 if (pcbNeeded) needed = *pcbNeeded;
6932 /* HeapReAlloc return NULL, when bufferW was NULL */
6933 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6934 HeapAlloc(GetProcessHeap(), 0, needed);
6936 /* Try again with the large Buffer */
6937 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6939 numentries = pcReturned ? *pcReturned : 0;
6943 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6946 PPRINTPROCESSOR_INFO_1W ppiw;
6947 PPRINTPROCESSOR_INFO_1A ppia;
6949 /* First pass: calculate the size for all Entries */
6950 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6951 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6953 while (index < numentries) {
6955 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6956 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6958 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6959 NULL, 0, NULL, NULL);
6961 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6962 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6965 /* check for errors and quit on failure */
6966 if (cbBuf < needed) {
6967 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6972 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6973 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6974 cbBuf -= len ; /* free Bytes in the user-Buffer */
6975 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6976 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6978 /* Second Pass: Fill the User Buffer (if we have one) */
6979 while ((index < numentries) && pPPInfo) {
6981 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6983 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6984 ptr, cbBuf , NULL, NULL);
6988 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6989 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6994 if (pcbNeeded) *pcbNeeded = needed;
6995 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6997 HeapFree(GetProcessHeap(), 0, nameW);
6998 HeapFree(GetProcessHeap(), 0, envW);
6999 HeapFree(GetProcessHeap(), 0, bufferW);
7001 TRACE("returning %d with %d (%d byte for %d entries)\n",
7002 (res), GetLastError(), needed, numentries);
7007 /*****************************************************************************
7008 * EnumPrintProcessorsW [WINSPOOL.@]
7010 * Enumerate available Print Processors
7013 * pName [I] Servername or NULL (local Computer)
7014 * pEnvironment [I] Printing-Environment or NULL (Default)
7015 * Level [I] Structure-Level (Only 1 is allowed)
7016 * pPPInfo [O] PTR to Buffer that receives the Result
7017 * cbBuf [I] Size of Buffer at pPPInfo
7018 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7019 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7023 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7026 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7027 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7030 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7031 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7033 if ((backend == NULL) && !load_backend()) return FALSE;
7035 if (!pcbNeeded || !pcReturned) {
7036 SetLastError(RPC_X_NULL_REF_POINTER);
7040 if (!pPPInfo && (cbBuf > 0)) {
7041 SetLastError(ERROR_INVALID_USER_BUFFER);
7045 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7046 cbBuf, pcbNeeded, pcReturned);
7049 /*****************************************************************************
7050 * ExtDeviceMode [WINSPOOL.@]
7053 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7054 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7057 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7058 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7059 debugstr_a(pProfile), fMode);
7063 /*****************************************************************************
7064 * FindClosePrinterChangeNotification [WINSPOOL.@]
7067 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7069 FIXME("Stub: %p\n", hChange);
7073 /*****************************************************************************
7074 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7077 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7078 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7080 FIXME("Stub: %p %x %x %p\n",
7081 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7082 return INVALID_HANDLE_VALUE;
7085 /*****************************************************************************
7086 * FindNextPrinterChangeNotification [WINSPOOL.@]
7089 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7090 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7092 FIXME("Stub: %p %p %p %p\n",
7093 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7097 /*****************************************************************************
7098 * FreePrinterNotifyInfo [WINSPOOL.@]
7101 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7103 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7107 /*****************************************************************************
7110 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7111 * ansi depending on the unicode parameter.
7113 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7123 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7126 memcpy(ptr, str, *size);
7133 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7136 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7143 /*****************************************************************************
7146 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7147 LPDWORD pcbNeeded, BOOL unicode)
7149 DWORD size, left = cbBuf;
7150 BOOL space = (cbBuf > 0);
7157 ji1->JobId = job->job_id;
7160 string_to_buf(job->document_title, ptr, left, &size, unicode);
7161 if(space && size <= left)
7163 ji1->pDocument = (LPWSTR)ptr;
7171 if (job->printer_name)
7173 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7174 if(space && size <= left)
7176 ji1->pPrinterName = (LPWSTR)ptr;
7188 /*****************************************************************************
7191 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7192 LPDWORD pcbNeeded, BOOL unicode)
7194 DWORD size, left = cbBuf;
7196 BOOL space = (cbBuf > 0);
7205 ji2->JobId = job->job_id;
7208 string_to_buf(job->document_title, ptr, left, &size, unicode);
7209 if(space && size <= left)
7211 ji2->pDocument = (LPWSTR)ptr;
7219 if (job->printer_name)
7221 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7222 if(space && size <= left)
7224 ji2->pPrinterName = (LPWSTR)ptr;
7237 dmA = DEVMODEdupWtoA(job->devmode);
7238 devmode = (LPDEVMODEW) dmA;
7239 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7243 devmode = job->devmode;
7244 size = devmode->dmSize + devmode->dmDriverExtra;
7248 FIXME("Can't convert DEVMODE W to A\n");
7251 /* align DEVMODE to a DWORD boundary */
7252 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7258 memcpy(ptr, devmode, size-shift);
7259 ji2->pDevMode = (LPDEVMODEW)ptr;
7260 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7273 /*****************************************************************************
7276 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7277 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7280 DWORD needed = 0, size;
7284 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7286 EnterCriticalSection(&printer_handles_cs);
7287 job = get_job(hPrinter, JobId);
7294 size = sizeof(JOB_INFO_1W);
7299 memset(pJob, 0, size);
7303 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7308 size = sizeof(JOB_INFO_2W);
7313 memset(pJob, 0, size);
7317 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7322 size = sizeof(JOB_INFO_3);
7326 memset(pJob, 0, size);
7335 SetLastError(ERROR_INVALID_LEVEL);
7339 *pcbNeeded = needed;
7341 LeaveCriticalSection(&printer_handles_cs);
7345 /*****************************************************************************
7346 * GetJobA [WINSPOOL.@]
7349 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7350 DWORD cbBuf, LPDWORD pcbNeeded)
7352 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7355 /*****************************************************************************
7356 * GetJobW [WINSPOOL.@]
7359 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7360 DWORD cbBuf, LPDWORD pcbNeeded)
7362 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7365 /*****************************************************************************
7368 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7370 char *unixname, *queue, *cmd;
7371 char fmt[] = "lpr -P'%s' '%s'";
7375 if(!(unixname = wine_get_unix_file_name(filename)))
7378 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7379 queue = HeapAlloc(GetProcessHeap(), 0, len);
7380 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7382 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7383 sprintf(cmd, fmt, queue, unixname);
7385 TRACE("printing with: %s\n", cmd);
7388 HeapFree(GetProcessHeap(), 0, cmd);
7389 HeapFree(GetProcessHeap(), 0, queue);
7390 HeapFree(GetProcessHeap(), 0, unixname);
7394 /*****************************************************************************
7397 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7399 #ifdef SONAME_LIBCUPS
7402 char *unixname, *queue, *unix_doc_title;
7406 if(!(unixname = wine_get_unix_file_name(filename)))
7409 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7410 queue = HeapAlloc(GetProcessHeap(), 0, len);
7411 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7413 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7414 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7415 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7417 TRACE("printing via cups\n");
7418 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7419 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7420 HeapFree(GetProcessHeap(), 0, queue);
7421 HeapFree(GetProcessHeap(), 0, unixname);
7427 return schedule_lpr(printer_name, filename);
7431 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7438 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7442 if(HIWORD(wparam) == BN_CLICKED)
7444 if(LOWORD(wparam) == IDOK)
7447 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7450 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7451 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7453 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7455 WCHAR caption[200], message[200];
7458 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7459 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7460 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7461 if(mb_ret == IDCANCEL)
7463 HeapFree(GetProcessHeap(), 0, filename);
7467 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7468 if(hf == INVALID_HANDLE_VALUE)
7470 WCHAR caption[200], message[200];
7472 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7473 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7474 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7475 HeapFree(GetProcessHeap(), 0, filename);
7479 DeleteFileW(filename);
7480 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7482 EndDialog(hwnd, IDOK);
7485 if(LOWORD(wparam) == IDCANCEL)
7487 EndDialog(hwnd, IDCANCEL);
7496 /*****************************************************************************
7499 static BOOL get_filename(LPWSTR *filename)
7501 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7502 file_dlg_proc, (LPARAM)filename) == IDOK;
7505 /*****************************************************************************
7508 static BOOL schedule_file(LPCWSTR filename)
7510 LPWSTR output = NULL;
7512 if(get_filename(&output))
7515 TRACE("copy to %s\n", debugstr_w(output));
7516 r = CopyFileW(filename, output, FALSE);
7517 HeapFree(GetProcessHeap(), 0, output);
7523 /*****************************************************************************
7526 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7529 char *unixname, *cmdA;
7531 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7535 if(!(unixname = wine_get_unix_file_name(filename)))
7538 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7539 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7540 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7542 TRACE("printing with: %s\n", cmdA);
7544 if((file_fd = open(unixname, O_RDONLY)) == -1)
7549 ERR("pipe() failed!\n");
7559 /* reset signals that we previously set to SIG_IGN */
7560 signal(SIGPIPE, SIG_DFL);
7561 signal(SIGCHLD, SIG_DFL);
7563 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7567 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7568 write(fds[1], buf, no_read);
7573 if(file_fd != -1) close(file_fd);
7574 if(fds[0] != -1) close(fds[0]);
7575 if(fds[1] != -1) close(fds[1]);
7577 HeapFree(GetProcessHeap(), 0, cmdA);
7578 HeapFree(GetProcessHeap(), 0, unixname);
7585 /*****************************************************************************
7588 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7590 int in_fd, out_fd, no_read;
7593 char *unixname, *outputA;
7596 if(!(unixname = wine_get_unix_file_name(filename)))
7599 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7600 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7601 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7603 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7604 in_fd = open(unixname, O_RDONLY);
7605 if(out_fd == -1 || in_fd == -1)
7608 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7609 write(out_fd, buf, no_read);
7613 if(in_fd != -1) close(in_fd);
7614 if(out_fd != -1) close(out_fd);
7615 HeapFree(GetProcessHeap(), 0, outputA);
7616 HeapFree(GetProcessHeap(), 0, unixname);
7620 /*****************************************************************************
7621 * ScheduleJob [WINSPOOL.@]
7624 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7626 opened_printer_t *printer;
7628 struct list *cursor, *cursor2;
7630 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7631 EnterCriticalSection(&printer_handles_cs);
7632 printer = get_opened_printer(hPrinter);
7636 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7638 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7641 if(job->job_id != dwJobID) continue;
7643 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7644 if(hf != INVALID_HANDLE_VALUE)
7646 PRINTER_INFO_5W *pi5 = NULL;
7647 LPWSTR portname = job->portname;
7651 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7652 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7656 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7657 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7658 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7659 portname = pi5->pPortName;
7661 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7662 debugstr_w(portname));
7666 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7667 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7669 DWORD type, count = sizeof(output);
7670 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7673 if(output[0] == '|')
7675 ret = schedule_pipe(output + 1, job->filename);
7679 ret = schedule_unixfile(output, job->filename);
7681 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7683 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7685 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7687 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7689 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7691 ret = schedule_file(job->filename);
7695 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7697 HeapFree(GetProcessHeap(), 0, pi5);
7699 DeleteFileW(job->filename);
7701 list_remove(cursor);
7702 HeapFree(GetProcessHeap(), 0, job->document_title);
7703 HeapFree(GetProcessHeap(), 0, job->printer_name);
7704 HeapFree(GetProcessHeap(), 0, job->portname);
7705 HeapFree(GetProcessHeap(), 0, job->filename);
7706 HeapFree(GetProcessHeap(), 0, job->devmode);
7707 HeapFree(GetProcessHeap(), 0, job);
7711 LeaveCriticalSection(&printer_handles_cs);
7715 /*****************************************************************************
7716 * StartDocDlgA [WINSPOOL.@]
7718 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7720 UNICODE_STRING usBuffer;
7723 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7726 docW.cbSize = sizeof(docW);
7727 if (doc->lpszDocName)
7729 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7730 if (!(docW.lpszDocName = docnameW)) return NULL;
7732 if (doc->lpszOutput)
7734 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7735 if (!(docW.lpszOutput = outputW)) return NULL;
7737 if (doc->lpszDatatype)
7739 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7740 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7742 docW.fwType = doc->fwType;
7744 retW = StartDocDlgW(hPrinter, &docW);
7748 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7749 ret = HeapAlloc(GetProcessHeap(), 0, len);
7750 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7751 HeapFree(GetProcessHeap(), 0, retW);
7754 HeapFree(GetProcessHeap(), 0, datatypeW);
7755 HeapFree(GetProcessHeap(), 0, outputW);
7756 HeapFree(GetProcessHeap(), 0, docnameW);
7761 /*****************************************************************************
7762 * StartDocDlgW [WINSPOOL.@]
7764 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7765 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7766 * port is "FILE:". Also returns the full path if passed a relative path.
7768 * The caller should free the returned string from the process heap.
7770 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7775 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7777 PRINTER_INFO_5W *pi5;
7778 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7779 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7781 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7782 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7783 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7785 HeapFree(GetProcessHeap(), 0, pi5);
7788 HeapFree(GetProcessHeap(), 0, pi5);
7791 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7795 if (get_filename(&name))
7797 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7799 HeapFree(GetProcessHeap(), 0, name);
7802 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7803 GetFullPathNameW(name, len, ret, NULL);
7804 HeapFree(GetProcessHeap(), 0, name);
7809 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7812 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7813 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7815 attr = GetFileAttributesW(ret);
7816 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7818 HeapFree(GetProcessHeap(), 0, ret);