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 const 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 const 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 const WCHAR emptyStringW[] = {0};
217 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
219 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
220 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
221 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
223 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
224 'D','o','c','u','m','e','n','t',0};
226 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
227 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
228 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
229 0, sizeof(DRIVER_INFO_8W)};
232 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
233 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
234 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
235 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
236 sizeof(PRINTER_INFO_9W)};
238 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
239 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
240 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
242 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
244 /******************************************************************
245 * validate the user-supplied printing-environment [internal]
248 * env [I] PTR to Environment-String or NULL
252 * Success: PTR to printenv_t
255 * An empty string is handled the same way as NULL.
256 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
260 static const printenv_t * validate_envW(LPCWSTR env)
262 const printenv_t *result = NULL;
265 TRACE("testing %s\n", debugstr_w(env));
268 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
270 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
272 result = all_printenv[i];
277 if (result == NULL) {
278 FIXME("unsupported Environment: %s\n", debugstr_w(env));
279 SetLastError(ERROR_INVALID_ENVIRONMENT);
281 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
285 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
287 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
293 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
294 if passed a NULL string. This returns NULLs to the result.
296 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
300 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
301 return usBufferPtr->Buffer;
303 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
307 static LPWSTR strdupW(LPCWSTR p)
313 len = (strlenW(p) + 1) * sizeof(WCHAR);
314 ret = HeapAlloc(GetProcessHeap(), 0, len);
319 static LPSTR strdupWtoA( LPCWSTR str )
324 if (!str) return NULL;
325 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
326 ret = HeapAlloc( GetProcessHeap(), 0, len );
327 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
331 /******************************************************************
332 * verify, that the filename is a local file
335 static inline BOOL is_local_file(LPWSTR name)
337 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
340 /* ################################ */
342 static int multi_sz_lenA(const char *str)
344 const char *ptr = str;
348 ptr += lstrlenA(ptr) + 1;
351 return ptr - str + 1;
355 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
358 /* If forcing, or no profile string entry for device yet, set the entry
360 * The always change entry if not WINEPS yet is discussable.
363 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
365 !strstr(qbuf,"WINEPS.DRV")
367 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
370 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
371 WriteProfileStringA("windows","device",buf);
372 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
373 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
376 HeapFree(GetProcessHeap(),0,buf);
380 static BOOL add_printer_driver(const char *name)
384 static char driver_9x[] = "wineps16.drv",
385 driver_nt[] = "wineps.drv",
386 env_9x[] = "Windows 4.0",
387 env_nt[] = "Windows NT x86",
388 data_file[] = "generic.ppd",
389 default_data_type[] = "RAW";
391 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
393 di3a.pName = (char *)name;
394 di3a.pEnvironment = env_nt;
395 di3a.pDriverPath = driver_nt;
396 di3a.pDataFile = data_file;
397 di3a.pConfigFile = driver_nt;
398 di3a.pDefaultDataType = default_data_type;
400 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
401 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
404 di3a.pEnvironment = env_9x;
405 di3a.pDriverPath = driver_9x;
406 di3a.pConfigFile = driver_9x;
407 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
408 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
413 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
414 debugstr_a(di3a.pEnvironment), GetLastError());
418 #ifdef SONAME_LIBCUPS
419 static typeof(cupsFreeDests) *pcupsFreeDests;
420 static typeof(cupsGetDests) *pcupsGetDests;
421 static typeof(cupsGetPPD) *pcupsGetPPD;
422 static typeof(cupsPrintFile) *pcupsPrintFile;
423 static void *cupshandle;
425 static BOOL CUPS_LoadPrinters(void)
428 BOOL hadprinter = FALSE, haddefault = FALSE;
430 PRINTER_INFO_2A pinfo2a;
432 HKEY hkeyPrinter, hkeyPrinters, hkey;
435 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
437 TRACE("%s\n", loaderror);
440 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
443 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
444 if (!p##x) return FALSE;
446 DYNCUPS(cupsFreeDests);
448 DYNCUPS(cupsGetDests);
449 DYNCUPS(cupsPrintFile);
452 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
454 ERR("Can't create Printers key\n");
458 nrofdests = pcupsGetDests(&dests);
459 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
460 for (i=0;i<nrofdests;i++) {
461 port = HeapAlloc(GetProcessHeap(), 0, strlen("CUPS:") + strlen(dests[i].name)+1);
462 sprintf(port,"CUPS:%s", dests[i].name);
463 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
464 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
465 sprintf(devline, "WINEPS.DRV,%s", port);
466 WriteProfileStringA("devices", dests[i].name, devline);
467 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
468 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
472 lstrcatA(devline, ",15,45");
473 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
474 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
475 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
479 HeapFree(GetProcessHeap(), 0, devline);
481 TRACE("Printer %d: %s\n", i, dests[i].name);
482 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
483 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
485 TRACE("Printer already exists\n");
486 RegSetValueExA(hkeyPrinter, "Port", 0, REG_SZ, (LPBYTE)port, strlen(port) + 1); /* overwrite LPR:* port */
487 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
488 RegCloseKey(hkeyPrinter);
490 static CHAR data_type[] = "RAW",
491 print_proc[] = "WinPrint",
492 comment[] = "WINEPS Printer using CUPS",
493 location[] = "<physical location of printer>",
494 params[] = "<parameters?>",
495 share_name[] = "<share name?>",
496 sep_file[] = "<sep file?>";
498 add_printer_driver(dests[i].name);
500 memset(&pinfo2a,0,sizeof(pinfo2a));
501 pinfo2a.pPrinterName = dests[i].name;
502 pinfo2a.pDatatype = data_type;
503 pinfo2a.pPrintProcessor = print_proc;
504 pinfo2a.pDriverName = dests[i].name;
505 pinfo2a.pComment = comment;
506 pinfo2a.pLocation = location;
507 pinfo2a.pPortName = port;
508 pinfo2a.pParameters = params;
509 pinfo2a.pShareName = share_name;
510 pinfo2a.pSepFile = sep_file;
512 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
513 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
514 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
517 HeapFree(GetProcessHeap(),0,port);
520 if (dests[i].is_default) {
521 SetDefaultPrinterA(dests[i].name);
525 if (hadprinter & !haddefault)
526 SetDefaultPrinterA(dests[0].name);
527 pcupsFreeDests(nrofdests, dests);
528 RegCloseKey(hkeyPrinters);
534 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
535 PRINTER_INFO_2A pinfo2a;
536 char *e,*s,*name,*prettyname,*devname;
537 BOOL ret = FALSE, set_default = FALSE;
538 char *port = NULL, *devline,*env_default;
539 HKEY hkeyPrinter, hkeyPrinters, hkey;
541 while (isspace(*pent)) pent++;
542 s = strchr(pent,':');
544 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
552 TRACE("name=%s entry=%s\n",name, pent);
554 if(ispunct(*name)) { /* a tc entry, not a real printer */
555 TRACE("skipping tc entry\n");
559 if(strstr(pent,":server")) { /* server only version so skip */
560 TRACE("skipping server entry\n");
564 /* Determine whether this is a postscript printer. */
567 env_default = getenv("PRINTER");
569 /* Get longest name, usually the one at the right for later display. */
570 while((s=strchr(prettyname,'|'))) {
573 while(isspace(*--e)) *e = '\0';
574 TRACE("\t%s\n", debugstr_a(prettyname));
575 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
576 for(prettyname = s+1; isspace(*prettyname); prettyname++)
579 e = prettyname + strlen(prettyname);
580 while(isspace(*--e)) *e = '\0';
581 TRACE("\t%s\n", debugstr_a(prettyname));
582 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
584 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
585 * if it is too long, we use it as comment below. */
586 devname = prettyname;
587 if (strlen(devname)>=CCHDEVICENAME-1)
589 if (strlen(devname)>=CCHDEVICENAME-1) {
594 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
595 sprintf(port,"LPR:%s",name);
597 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
598 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
599 sprintf(devline, "WINEPS.DRV,%s", port);
600 WriteProfileStringA("devices", devname, devline);
601 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
602 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
606 lstrcatA(devline, ",15,45");
607 WriteProfileStringA("PrinterPorts", devname, devline);
608 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
609 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
613 HeapFree(GetProcessHeap(),0,devline);
615 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
617 ERR("Can't create Printers key\n");
621 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
622 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
624 TRACE("Printer already exists\n");
625 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
626 RegCloseKey(hkeyPrinter);
628 static CHAR data_type[] = "RAW",
629 print_proc[] = "WinPrint",
630 comment[] = "WINEPS Printer using LPR",
631 params[] = "<parameters?>",
632 share_name[] = "<share name?>",
633 sep_file[] = "<sep file?>";
635 add_printer_driver(devname);
637 memset(&pinfo2a,0,sizeof(pinfo2a));
638 pinfo2a.pPrinterName = devname;
639 pinfo2a.pDatatype = data_type;
640 pinfo2a.pPrintProcessor = print_proc;
641 pinfo2a.pDriverName = devname;
642 pinfo2a.pComment = comment;
643 pinfo2a.pLocation = prettyname;
644 pinfo2a.pPortName = port;
645 pinfo2a.pParameters = params;
646 pinfo2a.pShareName = share_name;
647 pinfo2a.pSepFile = sep_file;
649 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
650 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
651 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
654 RegCloseKey(hkeyPrinters);
656 if (isfirst || set_default)
657 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
660 HeapFree(GetProcessHeap(), 0, port);
661 HeapFree(GetProcessHeap(), 0, name);
666 PRINTCAP_LoadPrinters(void) {
667 BOOL hadprinter = FALSE;
671 BOOL had_bash = FALSE;
673 f = fopen("/etc/printcap","r");
677 while(fgets(buf,sizeof(buf),f)) {
680 end=strchr(buf,'\n');
684 while(isspace(*start)) start++;
685 if(*start == '#' || *start == '\0')
688 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
689 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
690 HeapFree(GetProcessHeap(),0,pent);
694 if (end && *--end == '\\') {
701 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
704 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
710 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
711 HeapFree(GetProcessHeap(),0,pent);
717 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
720 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
721 (lstrlenW(value) + 1) * sizeof(WCHAR));
723 return ERROR_FILE_NOT_FOUND;
726 /******************************************************************
727 * get_servername_from_name (internal)
729 * for an external server, a copy of the serverpart from the full name is returned
732 static LPWSTR get_servername_from_name(LPCWSTR name)
736 WCHAR buffer[MAX_PATH];
739 if (name == NULL) return NULL;
740 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
742 server = strdupW(&name[2]); /* skip over both backslash */
743 if (server == NULL) return NULL;
745 /* strip '\' and the printername */
746 ptr = strchrW(server, '\\');
747 if (ptr) ptr[0] = '\0';
749 TRACE("found %s\n", debugstr_w(server));
751 len = sizeof(buffer)/sizeof(buffer[0]);
752 if (GetComputerNameW(buffer, &len)) {
753 if (lstrcmpW(buffer, server) == 0) {
754 /* The requested Servername is our computername */
755 HeapFree(GetProcessHeap(), 0, server);
762 /******************************************************************
763 * get_basename_from_name (internal)
765 * skip over the serverpart from the full name
768 static LPCWSTR get_basename_from_name(LPCWSTR name)
770 if (name == NULL) return NULL;
771 if ((name[0] == '\\') && (name[1] == '\\')) {
772 /* skip over the servername and search for the following '\' */
773 name = strchrW(&name[2], '\\');
774 if ((name) && (name[1])) {
775 /* found a separator ('\') followed by a name:
776 skip over the separator and return the rest */
781 /* no basename present (we found only a servername) */
788 /******************************************************************
789 * get_opened_printer_entry
790 * Get the first place empty in the opened printer table
793 * - pDefault is ignored
795 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
797 UINT_PTR handle = nb_printer_handles, i;
798 jobqueue_t *queue = NULL;
799 opened_printer_t *printer = NULL;
803 if ((backend == NULL) && !load_backend()) return NULL;
805 servername = get_servername_from_name(name);
807 FIXME("server %s not supported\n", debugstr_w(servername));
808 HeapFree(GetProcessHeap(), 0, servername);
809 SetLastError(ERROR_INVALID_PRINTER_NAME);
813 printername = get_basename_from_name(name);
814 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
816 /* an empty printername is invalid */
817 if (printername && (!printername[0])) {
818 SetLastError(ERROR_INVALID_PARAMETER);
822 EnterCriticalSection(&printer_handles_cs);
824 for (i = 0; i < nb_printer_handles; i++)
826 if (!printer_handles[i])
828 if(handle == nb_printer_handles)
833 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
834 queue = printer_handles[i]->queue;
838 if (handle >= nb_printer_handles)
840 opened_printer_t **new_array;
842 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
843 (nb_printer_handles + 16) * sizeof(*new_array) );
845 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
846 (nb_printer_handles + 16) * sizeof(*new_array) );
853 printer_handles = new_array;
854 nb_printer_handles += 16;
857 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
863 /* get a printer handle from the backend */
864 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
869 /* clone the base name. This is NULL for the printserver */
870 printer->printername = strdupW(printername);
872 /* clone the full name */
873 printer->name = strdupW(name);
874 if (name && (!printer->name)) {
880 printer->queue = queue;
883 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
884 if (!printer->queue) {
888 list_init(&printer->queue->jobs);
889 printer->queue->ref = 0;
891 InterlockedIncrement(&printer->queue->ref);
893 printer_handles[handle] = printer;
896 LeaveCriticalSection(&printer_handles_cs);
897 if (!handle && printer) {
898 /* Something failed: Free all resources */
899 HeapFree(GetProcessHeap(), 0, printer->printername);
900 HeapFree(GetProcessHeap(), 0, printer->name);
901 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
902 HeapFree(GetProcessHeap(), 0, printer);
905 return (HANDLE)handle;
908 /******************************************************************
910 * Get the pointer to the opened printer referred by the handle
912 static opened_printer_t *get_opened_printer(HANDLE hprn)
914 UINT_PTR idx = (UINT_PTR)hprn;
915 opened_printer_t *ret = NULL;
917 EnterCriticalSection(&printer_handles_cs);
919 if ((idx > 0) && (idx <= nb_printer_handles)) {
920 ret = printer_handles[idx - 1];
922 LeaveCriticalSection(&printer_handles_cs);
926 /******************************************************************
927 * get_opened_printer_name
928 * Get the pointer to the opened printer name referred by the handle
930 static LPCWSTR get_opened_printer_name(HANDLE hprn)
932 opened_printer_t *printer = get_opened_printer(hprn);
933 if(!printer) return NULL;
934 return printer->name;
937 /******************************************************************
938 * WINSPOOL_GetOpenedPrinterRegKey
941 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
943 LPCWSTR name = get_opened_printer_name(hPrinter);
947 if(!name) return ERROR_INVALID_HANDLE;
949 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
953 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
955 ERR("Can't find opened printer %s in registry\n",
957 RegCloseKey(hkeyPrinters);
958 return ERROR_INVALID_PRINTER_NAME; /* ? */
960 RegCloseKey(hkeyPrinters);
961 return ERROR_SUCCESS;
964 void WINSPOOL_LoadSystemPrinters(void)
966 HKEY hkey, hkeyPrinters;
968 DWORD needed, num, i;
969 WCHAR PrinterName[256];
972 /* This ensures that all printer entries have a valid Name value. If causes
973 problems later if they don't. If one is found to be missed we create one
974 and set it equal to the name of the key */
975 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
976 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
977 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
978 for(i = 0; i < num; i++) {
979 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
980 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
981 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
982 set_reg_szW(hkey, NameW, PrinterName);
989 RegCloseKey(hkeyPrinters);
992 /* We want to avoid calling AddPrinter on printers as much as
993 possible, because on cups printers this will (eventually) lead
994 to a call to cupsGetPPD which takes forever, even with non-cups
995 printers AddPrinter takes a while. So we'll tag all printers that
996 were automatically added last time around, if they still exist
997 we'll leave them be otherwise we'll delete them. */
998 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1000 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1001 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1002 for(i = 0; i < num; i++) {
1003 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1004 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1005 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1007 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1015 HeapFree(GetProcessHeap(), 0, pi);
1019 #ifdef SONAME_LIBCUPS
1020 done = CUPS_LoadPrinters();
1023 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1024 PRINTCAP_LoadPrinters();
1026 /* Now enumerate the list again and delete any printers that are still tagged */
1027 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1029 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1030 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1031 for(i = 0; i < num; i++) {
1032 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1033 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1034 BOOL delete_driver = FALSE;
1035 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1036 DWORD dw, type, size = sizeof(dw);
1037 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1038 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1039 DeletePrinter(hprn);
1040 delete_driver = TRUE;
1046 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1051 HeapFree(GetProcessHeap(), 0, pi);
1058 /******************************************************************
1061 * Get the pointer to the specified job.
1062 * Should hold the printer_handles_cs before calling.
1064 static job_t *get_job(HANDLE hprn, DWORD JobId)
1066 opened_printer_t *printer = get_opened_printer(hprn);
1069 if(!printer) return NULL;
1070 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1072 if(job->job_id == JobId)
1078 /***********************************************************
1081 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1084 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1087 Formname = (dmA->dmSize > off_formname);
1088 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1089 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1090 dmW->dmDeviceName, CCHDEVICENAME);
1092 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1093 dmA->dmSize - CCHDEVICENAME);
1095 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1096 off_formname - CCHDEVICENAME);
1097 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1098 dmW->dmFormName, CCHFORMNAME);
1099 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1100 (off_formname + CCHFORMNAME));
1103 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1104 dmA->dmDriverExtra);
1108 /***********************************************************
1110 * Creates an ansi copy of supplied devmode
1112 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1117 if (!dmW) return NULL;
1118 size = dmW->dmSize - CCHDEVICENAME -
1119 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1121 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1122 if (!dmA) return NULL;
1124 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1125 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1127 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1128 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1129 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1133 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1134 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1135 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1136 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1138 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1142 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1146 /******************************************************************
1147 * convert_printerinfo_W_to_A [internal]
1150 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1151 DWORD level, DWORD outlen, DWORD numentries)
1157 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1159 len = pi_sizeof[level] * numentries;
1160 ptr = (LPSTR) out + len;
1163 /* copy the numbers of all PRINTER_INFO_* first */
1164 memcpy(out, pPrintersW, len);
1166 while (id < numentries) {
1170 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1171 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1173 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1174 if (piW->pDescription) {
1175 piA->pDescription = ptr;
1176 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1177 ptr, outlen, NULL, NULL);
1183 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1184 ptr, outlen, NULL, NULL);
1188 if (piW->pComment) {
1189 piA->pComment = ptr;
1190 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1191 ptr, outlen, NULL, NULL);
1200 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1201 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1204 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1205 if (piW->pServerName) {
1206 piA->pServerName = ptr;
1207 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1208 ptr, outlen, NULL, NULL);
1212 if (piW->pPrinterName) {
1213 piA->pPrinterName = ptr;
1214 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1215 ptr, outlen, NULL, NULL);
1219 if (piW->pShareName) {
1220 piA->pShareName = ptr;
1221 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1222 ptr, outlen, NULL, NULL);
1226 if (piW->pPortName) {
1227 piA->pPortName = ptr;
1228 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1229 ptr, outlen, NULL, NULL);
1233 if (piW->pDriverName) {
1234 piA->pDriverName = ptr;
1235 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1236 ptr, outlen, NULL, NULL);
1240 if (piW->pComment) {
1241 piA->pComment = ptr;
1242 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1243 ptr, outlen, NULL, NULL);
1247 if (piW->pLocation) {
1248 piA->pLocation = ptr;
1249 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1250 ptr, outlen, NULL, NULL);
1255 dmA = DEVMODEdupWtoA(piW->pDevMode);
1257 /* align DEVMODEA to a DWORD boundary */
1258 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1262 piA->pDevMode = (LPDEVMODEA) ptr;
1263 len = dmA->dmSize + dmA->dmDriverExtra;
1264 memcpy(ptr, dmA, len);
1265 HeapFree(GetProcessHeap(), 0, dmA);
1271 if (piW->pSepFile) {
1272 piA->pSepFile = ptr;
1273 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1274 ptr, outlen, NULL, NULL);
1278 if (piW->pPrintProcessor) {
1279 piA->pPrintProcessor = ptr;
1280 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1281 ptr, outlen, NULL, NULL);
1285 if (piW->pDatatype) {
1286 piA->pDatatype = ptr;
1287 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1288 ptr, outlen, NULL, NULL);
1292 if (piW->pParameters) {
1293 piA->pParameters = ptr;
1294 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1295 ptr, outlen, NULL, NULL);
1299 if (piW->pSecurityDescriptor) {
1300 piA->pSecurityDescriptor = NULL;
1301 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1308 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1309 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1311 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1313 if (piW->pPrinterName) {
1314 piA->pPrinterName = ptr;
1315 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1316 ptr, outlen, NULL, NULL);
1320 if (piW->pServerName) {
1321 piA->pServerName = ptr;
1322 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1323 ptr, outlen, NULL, NULL);
1332 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1333 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1335 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1337 if (piW->pPrinterName) {
1338 piA->pPrinterName = ptr;
1339 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1340 ptr, outlen, NULL, NULL);
1344 if (piW->pPortName) {
1345 piA->pPortName = ptr;
1346 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1347 ptr, outlen, NULL, NULL);
1354 case 6: /* 6A and 6W are the same structure */
1359 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1360 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1362 TRACE("(%u) #%u\n", level, id);
1363 if (piW->pszObjectGUID) {
1364 piA->pszObjectGUID = ptr;
1365 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1366 ptr, outlen, NULL, NULL);
1375 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1376 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1379 TRACE("(%u) #%u\n", level, id);
1380 dmA = DEVMODEdupWtoA(piW->pDevMode);
1382 /* align DEVMODEA to a DWORD boundary */
1383 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1387 piA->pDevMode = (LPDEVMODEA) ptr;
1388 len = dmA->dmSize + dmA->dmDriverExtra;
1389 memcpy(ptr, dmA, len);
1390 HeapFree(GetProcessHeap(), 0, dmA);
1400 FIXME("for level %u\n", level);
1402 pPrintersW += pi_sizeof[level];
1403 out += pi_sizeof[level];
1408 /******************************************************************
1409 * convert_driverinfo_W_to_A [internal]
1412 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1413 DWORD level, DWORD outlen, DWORD numentries)
1419 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1421 len = di_sizeof[level] * numentries;
1422 ptr = (LPSTR) out + len;
1425 /* copy the numbers of all PRINTER_INFO_* first */
1426 memcpy(out, pDriversW, len);
1428 #define COPY_STRING(fld) \
1431 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1432 ptr += len; outlen -= len;\
1434 #define COPY_MULTIZ_STRING(fld) \
1435 { LPWSTR p = diW->fld; if (p){ \
1438 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1439 ptr += len; outlen -= len; p += len;\
1441 while(len > 1 && outlen > 0); \
1444 while (id < numentries)
1450 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1451 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1453 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1460 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1461 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1463 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1466 COPY_STRING(pEnvironment);
1467 COPY_STRING(pDriverPath);
1468 COPY_STRING(pDataFile);
1469 COPY_STRING(pConfigFile);
1474 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1475 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1477 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1480 COPY_STRING(pEnvironment);
1481 COPY_STRING(pDriverPath);
1482 COPY_STRING(pDataFile);
1483 COPY_STRING(pConfigFile);
1484 COPY_STRING(pHelpFile);
1485 COPY_MULTIZ_STRING(pDependentFiles);
1486 COPY_STRING(pMonitorName);
1487 COPY_STRING(pDefaultDataType);
1492 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1493 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1495 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1498 COPY_STRING(pEnvironment);
1499 COPY_STRING(pDriverPath);
1500 COPY_STRING(pDataFile);
1501 COPY_STRING(pConfigFile);
1502 COPY_STRING(pHelpFile);
1503 COPY_MULTIZ_STRING(pDependentFiles);
1504 COPY_STRING(pMonitorName);
1505 COPY_STRING(pDefaultDataType);
1506 COPY_MULTIZ_STRING(pszzPreviousNames);
1511 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1512 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1514 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1517 COPY_STRING(pEnvironment);
1518 COPY_STRING(pDriverPath);
1519 COPY_STRING(pDataFile);
1520 COPY_STRING(pConfigFile);
1525 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1526 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1528 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1531 COPY_STRING(pEnvironment);
1532 COPY_STRING(pDriverPath);
1533 COPY_STRING(pDataFile);
1534 COPY_STRING(pConfigFile);
1535 COPY_STRING(pHelpFile);
1536 COPY_MULTIZ_STRING(pDependentFiles);
1537 COPY_STRING(pMonitorName);
1538 COPY_STRING(pDefaultDataType);
1539 COPY_MULTIZ_STRING(pszzPreviousNames);
1540 COPY_STRING(pszMfgName);
1541 COPY_STRING(pszOEMUrl);
1542 COPY_STRING(pszHardwareID);
1543 COPY_STRING(pszProvider);
1548 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1549 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1551 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1554 COPY_STRING(pEnvironment);
1555 COPY_STRING(pDriverPath);
1556 COPY_STRING(pDataFile);
1557 COPY_STRING(pConfigFile);
1558 COPY_STRING(pHelpFile);
1559 COPY_MULTIZ_STRING(pDependentFiles);
1560 COPY_STRING(pMonitorName);
1561 COPY_STRING(pDefaultDataType);
1562 COPY_MULTIZ_STRING(pszzPreviousNames);
1563 COPY_STRING(pszMfgName);
1564 COPY_STRING(pszOEMUrl);
1565 COPY_STRING(pszHardwareID);
1566 COPY_STRING(pszProvider);
1567 COPY_STRING(pszPrintProcessor);
1568 COPY_STRING(pszVendorSetup);
1569 COPY_MULTIZ_STRING(pszzColorProfiles);
1570 COPY_STRING(pszInfPath);
1571 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1577 FIXME("for level %u\n", level);
1580 pDriversW += di_sizeof[level];
1581 out += di_sizeof[level];
1586 #undef COPY_MULTIZ_STRING
1590 /***********************************************************
1591 * PRINTER_INFO_2AtoW
1592 * Creates a unicode copy of PRINTER_INFO_2A on heap
1594 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1596 LPPRINTER_INFO_2W piW;
1597 UNICODE_STRING usBuffer;
1599 if(!piA) return NULL;
1600 piW = HeapAlloc(heap, 0, sizeof(*piW));
1601 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1603 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1604 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1605 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1606 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1607 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1608 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1609 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1610 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1611 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1612 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1613 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1614 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1618 /***********************************************************
1619 * FREE_PRINTER_INFO_2W
1620 * Free PRINTER_INFO_2W and all strings
1622 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1626 HeapFree(heap,0,piW->pServerName);
1627 HeapFree(heap,0,piW->pPrinterName);
1628 HeapFree(heap,0,piW->pShareName);
1629 HeapFree(heap,0,piW->pPortName);
1630 HeapFree(heap,0,piW->pDriverName);
1631 HeapFree(heap,0,piW->pComment);
1632 HeapFree(heap,0,piW->pLocation);
1633 HeapFree(heap,0,piW->pDevMode);
1634 HeapFree(heap,0,piW->pSepFile);
1635 HeapFree(heap,0,piW->pPrintProcessor);
1636 HeapFree(heap,0,piW->pDatatype);
1637 HeapFree(heap,0,piW->pParameters);
1638 HeapFree(heap,0,piW);
1642 /******************************************************************
1643 * DeviceCapabilities [WINSPOOL.@]
1644 * DeviceCapabilitiesA [WINSPOOL.@]
1647 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1648 LPSTR pOutput, LPDEVMODEA lpdm)
1652 if (!GDI_CallDeviceCapabilities16)
1654 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1656 if (!GDI_CallDeviceCapabilities16) return -1;
1658 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1660 /* If DC_PAPERSIZE map POINT16s to POINTs */
1661 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1662 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1663 POINT *pt = (POINT *)pOutput;
1665 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1666 for(i = 0; i < ret; i++, pt++)
1671 HeapFree( GetProcessHeap(), 0, tmp );
1677 /*****************************************************************************
1678 * DeviceCapabilitiesW [WINSPOOL.@]
1680 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1683 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1684 WORD fwCapability, LPWSTR pOutput,
1685 const DEVMODEW *pDevMode)
1687 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1688 LPSTR pDeviceA = strdupWtoA(pDevice);
1689 LPSTR pPortA = strdupWtoA(pPort);
1692 if(pOutput && (fwCapability == DC_BINNAMES ||
1693 fwCapability == DC_FILEDEPENDENCIES ||
1694 fwCapability == DC_PAPERNAMES)) {
1695 /* These need A -> W translation */
1698 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1702 switch(fwCapability) {
1707 case DC_FILEDEPENDENCIES:
1711 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1712 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1714 for(i = 0; i < ret; i++)
1715 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1716 pOutput + (i * size), size);
1717 HeapFree(GetProcessHeap(), 0, pOutputA);
1719 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1720 (LPSTR)pOutput, dmA);
1722 HeapFree(GetProcessHeap(),0,pPortA);
1723 HeapFree(GetProcessHeap(),0,pDeviceA);
1724 HeapFree(GetProcessHeap(),0,dmA);
1728 /******************************************************************
1729 * DocumentPropertiesA [WINSPOOL.@]
1731 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1733 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1734 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1735 LPDEVMODEA pDevModeInput,DWORD fMode )
1737 LPSTR lpName = pDeviceName;
1738 static CHAR port[] = "LPT1:";
1741 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1742 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1746 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1748 ERR("no name from hPrinter?\n");
1749 SetLastError(ERROR_INVALID_HANDLE);
1752 lpName = strdupWtoA(lpNameW);
1755 if (!GDI_CallExtDeviceMode16)
1757 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1759 if (!GDI_CallExtDeviceMode16) {
1760 ERR("No CallExtDeviceMode16?\n");
1764 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1765 pDevModeInput, NULL, fMode);
1768 HeapFree(GetProcessHeap(),0,lpName);
1773 /*****************************************************************************
1774 * DocumentPropertiesW (WINSPOOL.@)
1776 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1778 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1780 LPDEVMODEW pDevModeOutput,
1781 LPDEVMODEW pDevModeInput, DWORD fMode)
1784 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1785 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1786 LPDEVMODEA pDevModeOutputA = NULL;
1789 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1790 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1792 if(pDevModeOutput) {
1793 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1794 if(ret < 0) return ret;
1795 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1797 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1798 pDevModeInputA, fMode);
1799 if(pDevModeOutput) {
1800 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1801 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1803 if(fMode == 0 && ret > 0)
1804 ret += (CCHDEVICENAME + CCHFORMNAME);
1805 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1806 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1810 /******************************************************************
1811 * OpenPrinterA [WINSPOOL.@]
1816 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1817 LPPRINTER_DEFAULTSA pDefault)
1819 UNICODE_STRING lpPrinterNameW;
1820 UNICODE_STRING usBuffer;
1821 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1822 PWSTR pwstrPrinterNameW;
1825 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1828 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1829 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1830 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1831 pDefaultW = &DefaultW;
1833 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1835 RtlFreeUnicodeString(&usBuffer);
1836 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1838 RtlFreeUnicodeString(&lpPrinterNameW);
1842 /******************************************************************
1843 * OpenPrinterW [WINSPOOL.@]
1845 * Open a Printer / Printserver or a Printer-Object
1848 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1849 * phPrinter [O] The resulting Handle is stored here
1850 * pDefault [I] PTR to Default Printer Settings or NULL
1857 * lpPrinterName is one of:
1858 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1859 *| Printer: "PrinterName"
1860 *| Printer-Object: "PrinterName,Job xxx"
1861 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1862 *| XcvPort: "Servername,XcvPort PortName"
1865 *| Printer-Object not supported
1866 *| pDefaults is ignored
1869 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1872 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1874 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1875 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1879 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1880 SetLastError(ERROR_INVALID_PARAMETER);
1884 /* Get the unique handle of the printer or Printserver */
1885 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1886 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1887 return (*phPrinter != 0);
1890 /******************************************************************
1891 * AddMonitorA [WINSPOOL.@]
1896 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1898 LPWSTR nameW = NULL;
1901 LPMONITOR_INFO_2A mi2a;
1902 MONITOR_INFO_2W mi2w;
1904 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1905 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1906 debugstr_a(mi2a ? mi2a->pName : NULL),
1907 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1908 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1911 SetLastError(ERROR_INVALID_LEVEL);
1915 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1921 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1922 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1923 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1926 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1928 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1929 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1930 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1932 if (mi2a->pEnvironment) {
1933 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1934 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1935 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1937 if (mi2a->pDLLName) {
1938 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1939 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1940 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1943 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1945 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1946 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1947 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1949 HeapFree(GetProcessHeap(), 0, nameW);
1953 /******************************************************************************
1954 * AddMonitorW [WINSPOOL.@]
1956 * Install a Printmonitor
1959 * pName [I] Servername or NULL (local Computer)
1960 * Level [I] Structure-Level (Must be 2)
1961 * pMonitors [I] PTR to MONITOR_INFO_2
1968 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1971 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1973 LPMONITOR_INFO_2W mi2w;
1975 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1976 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1977 debugstr_w(mi2w ? mi2w->pName : NULL),
1978 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1979 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1981 if ((backend == NULL) && !load_backend()) return FALSE;
1984 SetLastError(ERROR_INVALID_LEVEL);
1988 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1993 return backend->fpAddMonitor(pName, Level, pMonitors);
1996 /******************************************************************
1997 * DeletePrinterDriverA [WINSPOOL.@]
2000 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2002 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2005 /******************************************************************
2006 * DeletePrinterDriverW [WINSPOOL.@]
2009 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2011 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2014 /******************************************************************
2015 * DeleteMonitorA [WINSPOOL.@]
2017 * See DeleteMonitorW.
2020 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2022 LPWSTR nameW = NULL;
2023 LPWSTR EnvironmentW = NULL;
2024 LPWSTR MonitorNameW = NULL;
2029 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2030 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2031 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2035 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2036 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2037 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2040 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2041 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2042 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2045 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2047 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2048 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2049 HeapFree(GetProcessHeap(), 0, nameW);
2053 /******************************************************************
2054 * DeleteMonitorW [WINSPOOL.@]
2056 * Delete a specific Printmonitor from a Printing-Environment
2059 * pName [I] Servername or NULL (local Computer)
2060 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2061 * pMonitorName [I] Name of the Monitor, that should be deleted
2068 * pEnvironment is ignored in Windows for the local Computer.
2071 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2074 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2075 debugstr_w(pMonitorName));
2077 if ((backend == NULL) && !load_backend()) return FALSE;
2079 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2083 /******************************************************************
2084 * DeletePortA [WINSPOOL.@]
2089 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2091 LPWSTR nameW = NULL;
2092 LPWSTR portW = NULL;
2096 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2098 /* convert servername to unicode */
2100 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2101 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2102 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2105 /* convert portname to unicode */
2107 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2108 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2109 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2112 res = DeletePortW(nameW, hWnd, portW);
2113 HeapFree(GetProcessHeap(), 0, nameW);
2114 HeapFree(GetProcessHeap(), 0, portW);
2118 /******************************************************************
2119 * DeletePortW [WINSPOOL.@]
2121 * Delete a specific Port
2124 * pName [I] Servername or NULL (local Computer)
2125 * hWnd [I] Handle to parent Window for the Dialog-Box
2126 * pPortName [I] Name of the Port, that should be deleted
2133 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2135 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2137 if ((backend == NULL) && !load_backend()) return FALSE;
2140 SetLastError(RPC_X_NULL_REF_POINTER);
2144 return backend->fpDeletePort(pName, hWnd, pPortName);
2147 /******************************************************************************
2148 * SetPrinterW [WINSPOOL.@]
2150 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2152 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2153 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2157 /******************************************************************************
2158 * WritePrinter [WINSPOOL.@]
2160 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2162 opened_printer_t *printer;
2165 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2167 EnterCriticalSection(&printer_handles_cs);
2168 printer = get_opened_printer(hPrinter);
2171 SetLastError(ERROR_INVALID_HANDLE);
2177 SetLastError(ERROR_SPL_NO_STARTDOC);
2181 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2183 LeaveCriticalSection(&printer_handles_cs);
2187 /*****************************************************************************
2188 * AddFormA [WINSPOOL.@]
2190 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2192 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2196 /*****************************************************************************
2197 * AddFormW [WINSPOOL.@]
2199 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2201 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2205 /*****************************************************************************
2206 * AddJobA [WINSPOOL.@]
2208 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2211 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2215 SetLastError(ERROR_INVALID_LEVEL);
2219 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2222 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2223 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2224 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2225 if(*pcbNeeded > cbBuf) {
2226 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2229 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2230 addjobA->JobId = addjobW->JobId;
2231 addjobA->Path = (char *)(addjobA + 1);
2232 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2238 /*****************************************************************************
2239 * AddJobW [WINSPOOL.@]
2241 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2243 opened_printer_t *printer;
2246 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2247 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2248 WCHAR path[MAX_PATH], filename[MAX_PATH];
2250 ADDJOB_INFO_1W *addjob;
2252 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2254 EnterCriticalSection(&printer_handles_cs);
2256 printer = get_opened_printer(hPrinter);
2259 SetLastError(ERROR_INVALID_HANDLE);
2264 SetLastError(ERROR_INVALID_LEVEL);
2268 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2272 job->job_id = InterlockedIncrement(&next_job_id);
2274 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2275 if(path[len - 1] != '\\')
2277 memcpy(path + len, spool_path, sizeof(spool_path));
2278 sprintfW(filename, fmtW, path, job->job_id);
2280 len = strlenW(filename);
2281 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2282 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2283 job->document_title = strdupW(default_doc_title);
2284 job->printer_name = strdupW(printer->name);
2285 job->devmode = NULL;
2286 list_add_tail(&printer->queue->jobs, &job->entry);
2288 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2289 if(*pcbNeeded <= cbBuf) {
2290 addjob = (ADDJOB_INFO_1W*)pData;
2291 addjob->JobId = job->job_id;
2292 addjob->Path = (WCHAR *)(addjob + 1);
2293 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2296 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2299 LeaveCriticalSection(&printer_handles_cs);
2303 /*****************************************************************************
2304 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2306 * Return the PATH for the Print-Processors
2308 * See GetPrintProcessorDirectoryW.
2312 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2313 DWORD level, LPBYTE Info,
2314 DWORD cbBuf, LPDWORD pcbNeeded)
2316 LPWSTR serverW = NULL;
2321 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2322 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2326 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2327 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2328 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2332 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2333 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2334 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2337 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2338 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2340 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2343 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2344 cbBuf, NULL, NULL) > 0;
2347 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2348 HeapFree(GetProcessHeap(), 0, envW);
2349 HeapFree(GetProcessHeap(), 0, serverW);
2353 /*****************************************************************************
2354 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2356 * Return the PATH for the Print-Processors
2359 * server [I] Servername (NT only) or NULL (local Computer)
2360 * env [I] Printing-Environment (see below) or NULL (Default)
2361 * level [I] Structure-Level (must be 1)
2362 * Info [O] PTR to Buffer that receives the Result
2363 * cbBuf [I] Size of Buffer at "Info"
2364 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2365 * required for the Buffer at "Info"
2368 * Success: TRUE and in pcbNeeded the Bytes used in Info
2369 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2370 * if cbBuf is too small
2372 * Native Values returned in Info on Success:
2373 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2374 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2375 *| win9x(Windows 4.0): "%winsysdir%"
2377 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2380 * Only NULL or "" is supported for server
2383 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2384 DWORD level, LPBYTE Info,
2385 DWORD cbBuf, LPDWORD pcbNeeded)
2388 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2389 Info, cbBuf, pcbNeeded);
2391 if ((backend == NULL) && !load_backend()) return FALSE;
2394 /* (Level != 1) is ignored in win9x */
2395 SetLastError(ERROR_INVALID_LEVEL);
2399 if (pcbNeeded == NULL) {
2400 /* (pcbNeeded == NULL) is ignored in win9x */
2401 SetLastError(RPC_X_NULL_REF_POINTER);
2405 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2408 /*****************************************************************************
2409 * WINSPOOL_OpenDriverReg [internal]
2411 * opens the registry for the printer drivers depending on the given input
2412 * variable pEnvironment
2415 * the opened hkey on success
2418 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2422 const printenv_t * env;
2424 TRACE("(%s)\n", debugstr_w(pEnvironment));
2426 env = validate_envW(pEnvironment);
2427 if (!env) return NULL;
2429 buffer = HeapAlloc( GetProcessHeap(), 0,
2430 (strlenW(DriversW) + strlenW(env->envname) +
2431 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2433 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2434 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2435 HeapFree(GetProcessHeap(), 0, buffer);
2440 /*****************************************************************************
2441 * AddPrinterW [WINSPOOL.@]
2443 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2445 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2449 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2451 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2452 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2453 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2454 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2455 statusW[] = {'S','t','a','t','u','s',0},
2456 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2458 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2461 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2462 SetLastError(ERROR_INVALID_PARAMETER);
2466 ERR("Level = %d, unsupported!\n", Level);
2467 SetLastError(ERROR_INVALID_LEVEL);
2471 SetLastError(ERROR_INVALID_PARAMETER);
2474 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2476 ERR("Can't create Printers key\n");
2479 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2480 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2481 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2482 RegCloseKey(hkeyPrinter);
2483 RegCloseKey(hkeyPrinters);
2486 RegCloseKey(hkeyPrinter);
2488 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2490 ERR("Can't create Drivers key\n");
2491 RegCloseKey(hkeyPrinters);
2494 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2496 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2497 RegCloseKey(hkeyPrinters);
2498 RegCloseKey(hkeyDrivers);
2499 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2502 RegCloseKey(hkeyDriver);
2503 RegCloseKey(hkeyDrivers);
2505 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2506 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2507 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2508 RegCloseKey(hkeyPrinters);
2512 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2514 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2515 SetLastError(ERROR_INVALID_PRINTER_NAME);
2516 RegCloseKey(hkeyPrinters);
2519 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2520 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2521 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2523 /* See if we can load the driver. We may need the devmode structure anyway
2526 * Note that DocumentPropertiesW will briefly try to open the printer we
2527 * just create to find a DEVMODEA struct (it will use the WINEPS default
2528 * one in case it is not there, so we are ok).
2530 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2533 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2534 size = sizeof(DEVMODEW);
2540 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2542 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2544 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2545 HeapFree(GetProcessHeap(),0,dmW);
2550 /* set devmode to printer name */
2551 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2555 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2556 and we support these drivers. NT writes DEVMODEW so somehow
2557 we'll need to distinguish between these when we support NT
2561 dmA = DEVMODEdupWtoA(dmW);
2562 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2563 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2564 HeapFree(GetProcessHeap(), 0, dmA);
2566 HeapFree(GetProcessHeap(), 0, dmW);
2568 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2569 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2570 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2571 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2573 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2574 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2575 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2576 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2577 (LPBYTE)&pi->Priority, sizeof(DWORD));
2578 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2579 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2580 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2581 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2582 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2583 (LPBYTE)&pi->Status, sizeof(DWORD));
2584 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2585 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2587 RegCloseKey(hkeyPrinter);
2588 RegCloseKey(hkeyPrinters);
2589 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2590 ERR("OpenPrinter failing\n");
2596 /*****************************************************************************
2597 * AddPrinterA [WINSPOOL.@]
2599 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2601 UNICODE_STRING pNameW;
2603 PRINTER_INFO_2W *piW;
2604 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2607 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2609 ERR("Level = %d, unsupported!\n", Level);
2610 SetLastError(ERROR_INVALID_LEVEL);
2613 pwstrNameW = asciitounicode(&pNameW,pName);
2614 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2616 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2618 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2619 RtlFreeUnicodeString(&pNameW);
2624 /*****************************************************************************
2625 * ClosePrinter [WINSPOOL.@]
2627 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2629 UINT_PTR i = (UINT_PTR)hPrinter;
2630 opened_printer_t *printer = NULL;
2633 TRACE("(%p)\n", hPrinter);
2635 EnterCriticalSection(&printer_handles_cs);
2637 if ((i > 0) && (i <= nb_printer_handles))
2638 printer = printer_handles[i - 1];
2643 struct list *cursor, *cursor2;
2645 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2647 if (printer->backend_printer) {
2648 backend->fpClosePrinter(printer->backend_printer);
2652 EndDocPrinter(hPrinter);
2654 if(InterlockedDecrement(&printer->queue->ref) == 0)
2656 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2658 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2659 ScheduleJob(hPrinter, job->job_id);
2661 HeapFree(GetProcessHeap(), 0, printer->queue);
2664 HeapFree(GetProcessHeap(), 0, printer->printername);
2665 HeapFree(GetProcessHeap(), 0, printer->name);
2666 HeapFree(GetProcessHeap(), 0, printer);
2667 printer_handles[i - 1] = NULL;
2670 LeaveCriticalSection(&printer_handles_cs);
2674 /*****************************************************************************
2675 * DeleteFormA [WINSPOOL.@]
2677 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2679 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2683 /*****************************************************************************
2684 * DeleteFormW [WINSPOOL.@]
2686 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2688 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2692 /*****************************************************************************
2693 * DeletePrinter [WINSPOOL.@]
2695 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2697 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2698 HKEY hkeyPrinters, hkey;
2701 SetLastError(ERROR_INVALID_HANDLE);
2704 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2705 RegDeleteTreeW(hkeyPrinters, lpNameW);
2706 RegCloseKey(hkeyPrinters);
2708 WriteProfileStringW(devicesW, lpNameW, NULL);
2709 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2711 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2712 RegDeleteValueW(hkey, lpNameW);
2716 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2717 RegDeleteValueW(hkey, lpNameW);
2723 /*****************************************************************************
2724 * SetPrinterA [WINSPOOL.@]
2726 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2729 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2733 /*****************************************************************************
2734 * SetJobA [WINSPOOL.@]
2736 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2737 LPBYTE pJob, DWORD Command)
2741 UNICODE_STRING usBuffer;
2743 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2745 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2746 are all ignored by SetJob, so we don't bother copying them */
2754 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2755 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2757 JobW = (LPBYTE)info1W;
2758 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2759 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2760 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2761 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2762 info1W->Status = info1A->Status;
2763 info1W->Priority = info1A->Priority;
2764 info1W->Position = info1A->Position;
2765 info1W->PagesPrinted = info1A->PagesPrinted;
2770 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2771 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2773 JobW = (LPBYTE)info2W;
2774 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2775 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2776 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2777 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2778 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2779 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2780 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2781 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2782 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2783 info2W->Status = info2A->Status;
2784 info2W->Priority = info2A->Priority;
2785 info2W->Position = info2A->Position;
2786 info2W->StartTime = info2A->StartTime;
2787 info2W->UntilTime = info2A->UntilTime;
2788 info2W->PagesPrinted = info2A->PagesPrinted;
2792 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2793 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2796 SetLastError(ERROR_INVALID_LEVEL);
2800 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2806 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2807 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2808 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2809 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2810 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2815 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2816 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2817 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2818 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2819 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2820 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2821 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2822 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2823 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2827 HeapFree(GetProcessHeap(), 0, JobW);
2832 /*****************************************************************************
2833 * SetJobW [WINSPOOL.@]
2835 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2836 LPBYTE pJob, DWORD Command)
2842 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2843 FIXME("Ignoring everything other than document title\n");
2845 EnterCriticalSection(&printer_handles_cs);
2846 job = get_job(hPrinter, JobId);
2856 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2857 HeapFree(GetProcessHeap(), 0, job->document_title);
2858 job->document_title = strdupW(info1->pDocument);
2863 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2864 HeapFree(GetProcessHeap(), 0, job->document_title);
2865 job->document_title = strdupW(info2->pDocument);
2866 HeapFree(GetProcessHeap(), 0, job->devmode);
2867 if (info2->pDevMode)
2869 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2870 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2871 memcpy(job->devmode, info2->pDevMode, size);
2874 job->devmode = NULL;
2880 SetLastError(ERROR_INVALID_LEVEL);
2885 LeaveCriticalSection(&printer_handles_cs);
2889 /*****************************************************************************
2890 * EndDocPrinter [WINSPOOL.@]
2892 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2894 opened_printer_t *printer;
2896 TRACE("(%p)\n", hPrinter);
2898 EnterCriticalSection(&printer_handles_cs);
2900 printer = get_opened_printer(hPrinter);
2903 SetLastError(ERROR_INVALID_HANDLE);
2909 SetLastError(ERROR_SPL_NO_STARTDOC);
2913 CloseHandle(printer->doc->hf);
2914 ScheduleJob(hPrinter, printer->doc->job_id);
2915 HeapFree(GetProcessHeap(), 0, printer->doc);
2916 printer->doc = NULL;
2919 LeaveCriticalSection(&printer_handles_cs);
2923 /*****************************************************************************
2924 * EndPagePrinter [WINSPOOL.@]
2926 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2928 FIXME("(%p): stub\n", hPrinter);
2932 /*****************************************************************************
2933 * StartDocPrinterA [WINSPOOL.@]
2935 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2937 UNICODE_STRING usBuffer;
2939 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2942 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2943 or one (DOC_INFO_3) extra DWORDs */
2947 doc2W.JobId = doc2->JobId;
2950 doc2W.dwMode = doc2->dwMode;
2953 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2954 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2955 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2959 SetLastError(ERROR_INVALID_LEVEL);
2963 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2965 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2966 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2967 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2972 /*****************************************************************************
2973 * StartDocPrinterW [WINSPOOL.@]
2975 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2977 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2978 opened_printer_t *printer;
2979 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2980 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2981 JOB_INFO_1W job_info;
2982 DWORD needed, ret = 0;
2987 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2988 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2989 debugstr_w(doc->pDatatype));
2991 if(Level < 1 || Level > 3)
2993 SetLastError(ERROR_INVALID_LEVEL);
2997 EnterCriticalSection(&printer_handles_cs);
2998 printer = get_opened_printer(hPrinter);
3001 SetLastError(ERROR_INVALID_HANDLE);
3007 SetLastError(ERROR_INVALID_PRINTER_STATE);
3011 /* Even if we're printing to a file we still add a print job, we'll
3012 just ignore the spool file name */
3014 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3016 ERR("AddJob failed gle %u\n", GetLastError());
3020 /* use pOutputFile only, when it is a real filename */
3021 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3022 filename = doc->pOutputFile;
3024 filename = addjob->Path;
3026 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3027 if(hf == INVALID_HANDLE_VALUE)
3030 memset(&job_info, 0, sizeof(job_info));
3031 job_info.pDocument = doc->pDocName;
3032 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3034 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3035 printer->doc->hf = hf;
3036 ret = printer->doc->job_id = addjob->JobId;
3037 job = get_job(hPrinter, ret);
3038 job->portname = strdupW(doc->pOutputFile);
3041 LeaveCriticalSection(&printer_handles_cs);
3046 /*****************************************************************************
3047 * StartPagePrinter [WINSPOOL.@]
3049 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3051 FIXME("(%p): stub\n", hPrinter);
3055 /*****************************************************************************
3056 * GetFormA [WINSPOOL.@]
3058 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3059 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3061 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3062 Level,pForm,cbBuf,pcbNeeded);
3066 /*****************************************************************************
3067 * GetFormW [WINSPOOL.@]
3069 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3070 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3072 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3073 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3077 /*****************************************************************************
3078 * SetFormA [WINSPOOL.@]
3080 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3083 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3087 /*****************************************************************************
3088 * SetFormW [WINSPOOL.@]
3090 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3093 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3097 /*****************************************************************************
3098 * ReadPrinter [WINSPOOL.@]
3100 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3101 LPDWORD pNoBytesRead)
3103 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3107 /*****************************************************************************
3108 * ResetPrinterA [WINSPOOL.@]
3110 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3112 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3116 /*****************************************************************************
3117 * ResetPrinterW [WINSPOOL.@]
3119 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3121 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3125 /*****************************************************************************
3126 * WINSPOOL_GetDWORDFromReg
3128 * Return DWORD associated with ValueName from hkey.
3130 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3132 DWORD sz = sizeof(DWORD), type, value = 0;
3135 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3137 if(ret != ERROR_SUCCESS) {
3138 WARN("Got ret = %d on name %s\n", ret, ValueName);
3141 if(type != REG_DWORD) {
3142 ERR("Got type %d\n", type);
3149 /*****************************************************************************
3150 * get_filename_from_reg [internal]
3152 * Get ValueName from hkey storing result in out
3153 * when the Value in the registry has only a filename, use driverdir as prefix
3154 * outlen is space left in out
3155 * String is stored either as unicode or ascii
3159 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3160 LPBYTE out, DWORD outlen, LPDWORD needed)
3162 WCHAR filename[MAX_PATH];
3166 LPWSTR buffer = filename;
3170 size = sizeof(filename);
3172 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3173 if (ret == ERROR_MORE_DATA) {
3174 TRACE("need dynamic buffer: %u\n", size);
3175 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3177 /* No Memory is bad */
3181 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3184 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3185 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3191 /* do we have a full path ? */
3192 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3193 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3196 /* we must build the full Path */
3198 if ((out) && (outlen > dirlen)) {
3199 lstrcpyW((LPWSTR)out, driverdir);
3207 /* write the filename */
3208 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3209 if ((out) && (outlen >= size)) {
3210 lstrcpyW((LPWSTR)out, ptr);
3217 ptr += lstrlenW(ptr)+1;
3218 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3221 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3223 /* write the multisz-termination */
3224 if (type == REG_MULTI_SZ) {
3225 size = sizeof(WCHAR);
3228 if (out && (outlen >= size)) {
3229 memset (out, 0, size);
3235 /*****************************************************************************
3236 * WINSPOOL_GetStringFromReg
3238 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3239 * String is stored as unicode.
3241 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3242 DWORD buflen, DWORD *needed)
3244 DWORD sz = buflen, type;
3247 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3248 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3249 WARN("Got ret = %d\n", ret);
3253 /* add space for terminating '\0' */
3254 sz += sizeof(WCHAR);
3258 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3263 /*****************************************************************************
3264 * WINSPOOL_GetDefaultDevMode
3266 * Get a default DevMode values for wineps.
3270 static void WINSPOOL_GetDefaultDevMode(
3272 DWORD buflen, DWORD *needed)
3275 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3277 /* fill default DEVMODE - should be read from ppd... */
3278 ZeroMemory( &dm, sizeof(dm) );
3279 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3280 dm.dmSpecVersion = DM_SPECVERSION;
3281 dm.dmDriverVersion = 1;
3282 dm.dmSize = sizeof(DEVMODEW);
3283 dm.dmDriverExtra = 0;
3285 DM_ORIENTATION | DM_PAPERSIZE |
3286 DM_PAPERLENGTH | DM_PAPERWIDTH |
3289 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3290 DM_YRESOLUTION | DM_TTOPTION;
3292 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3293 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3294 dm.u1.s1.dmPaperLength = 2970;
3295 dm.u1.s1.dmPaperWidth = 2100;
3297 dm.u1.s1.dmScale = 100;
3298 dm.u1.s1.dmCopies = 1;
3299 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3300 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3303 dm.dmYResolution = 300; /* 300dpi */
3304 dm.dmTTOption = DMTT_BITMAP;
3307 /* dm.dmLogPixels */
3308 /* dm.dmBitsPerPel */
3309 /* dm.dmPelsWidth */
3310 /* dm.dmPelsHeight */
3311 /* dm.u2.dmDisplayFlags */
3312 /* dm.dmDisplayFrequency */
3313 /* dm.dmICMMethod */
3314 /* dm.dmICMIntent */
3315 /* dm.dmMediaType */
3316 /* dm.dmDitherType */
3317 /* dm.dmReserved1 */
3318 /* dm.dmReserved2 */
3319 /* dm.dmPanningWidth */
3320 /* dm.dmPanningHeight */
3322 if(buflen >= sizeof(DEVMODEW))
3323 memcpy(ptr, &dm, sizeof(DEVMODEW));
3324 *needed = sizeof(DEVMODEW);
3327 /*****************************************************************************
3328 * WINSPOOL_GetDevModeFromReg
3330 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3331 * DevMode is stored either as unicode or ascii.
3333 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3335 DWORD buflen, DWORD *needed)
3337 DWORD sz = buflen, type;
3340 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3341 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3342 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3343 if (sz < sizeof(DEVMODEA))
3345 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3348 /* ensures that dmSize is not erratically bogus if registry is invalid */
3349 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3350 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3351 sz += (CCHDEVICENAME + CCHFORMNAME);
3352 if (ptr && (buflen >= sz)) {
3353 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3354 memcpy(ptr, dmW, sz);
3355 HeapFree(GetProcessHeap(),0,dmW);
3361 /*********************************************************************
3362 * WINSPOOL_GetPrinter_1
3364 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3366 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3367 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3369 DWORD size, left = cbBuf;
3370 BOOL space = (cbBuf > 0);
3375 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3376 if(space && size <= left) {
3377 pi1->pName = (LPWSTR)ptr;
3385 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3386 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3387 if(space && size <= left) {
3388 pi1->pDescription = (LPWSTR)ptr;
3396 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3397 if(space && size <= left) {
3398 pi1->pComment = (LPWSTR)ptr;
3406 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3408 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3409 memset(pi1, 0, sizeof(*pi1));
3413 /*********************************************************************
3414 * WINSPOOL_GetPrinter_2
3416 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3418 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3419 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3421 DWORD size, left = cbBuf;
3422 BOOL space = (cbBuf > 0);
3427 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3428 if(space && size <= left) {
3429 pi2->pPrinterName = (LPWSTR)ptr;
3436 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3437 if(space && size <= left) {
3438 pi2->pShareName = (LPWSTR)ptr;
3445 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3446 if(space && size <= left) {
3447 pi2->pPortName = (LPWSTR)ptr;
3454 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3455 if(space && size <= left) {
3456 pi2->pDriverName = (LPWSTR)ptr;
3463 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3464 if(space && size <= left) {
3465 pi2->pComment = (LPWSTR)ptr;
3472 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3473 if(space && size <= left) {
3474 pi2->pLocation = (LPWSTR)ptr;
3481 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3482 if(space && size <= left) {
3483 pi2->pDevMode = (LPDEVMODEW)ptr;
3492 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3493 if(space && size <= left) {
3494 pi2->pDevMode = (LPDEVMODEW)ptr;
3501 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3502 if(space && size <= left) {
3503 pi2->pSepFile = (LPWSTR)ptr;
3510 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3511 if(space && size <= left) {
3512 pi2->pPrintProcessor = (LPWSTR)ptr;
3519 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3520 if(space && size <= left) {
3521 pi2->pDatatype = (LPWSTR)ptr;
3528 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3529 if(space && size <= left) {
3530 pi2->pParameters = (LPWSTR)ptr;
3538 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3539 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3540 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3541 "Default Priority");
3542 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3543 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3546 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3547 memset(pi2, 0, sizeof(*pi2));
3552 /*********************************************************************
3553 * WINSPOOL_GetPrinter_4
3555 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3557 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3558 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3560 DWORD size, left = cbBuf;
3561 BOOL space = (cbBuf > 0);
3566 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3567 if(space && size <= left) {
3568 pi4->pPrinterName = (LPWSTR)ptr;
3576 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3579 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3580 memset(pi4, 0, sizeof(*pi4));
3585 /*********************************************************************
3586 * WINSPOOL_GetPrinter_5
3588 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3590 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3591 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3593 DWORD size, left = cbBuf;
3594 BOOL space = (cbBuf > 0);
3599 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3600 if(space && size <= left) {
3601 pi5->pPrinterName = (LPWSTR)ptr;
3608 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3609 if(space && size <= left) {
3610 pi5->pPortName = (LPWSTR)ptr;
3618 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3619 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3621 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3625 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3626 memset(pi5, 0, sizeof(*pi5));
3631 /*********************************************************************
3632 * WINSPOOL_GetPrinter_7
3634 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3636 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3637 DWORD cbBuf, LPDWORD pcbNeeded)
3639 DWORD size, left = cbBuf;
3640 BOOL space = (cbBuf > 0);
3645 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3648 size = sizeof(pi7->pszObjectGUID);
3650 if (space && size <= left) {
3651 pi7->pszObjectGUID = (LPWSTR)ptr;
3658 /* We do not have a Directory Service */
3659 pi7->dwAction = DSPRINT_UNPUBLISH;
3662 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3663 memset(pi7, 0, sizeof(*pi7));
3668 /*********************************************************************
3669 * WINSPOOL_GetPrinter_9
3671 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3673 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3674 DWORD cbBuf, LPDWORD pcbNeeded)
3677 BOOL space = (cbBuf > 0);
3681 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3682 if(space && size <= cbBuf) {
3683 pi9->pDevMode = (LPDEVMODEW)buf;
3690 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3691 if(space && size <= cbBuf) {
3692 pi9->pDevMode = (LPDEVMODEW)buf;
3698 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3699 memset(pi9, 0, sizeof(*pi9));
3704 /*****************************************************************************
3705 * GetPrinterW [WINSPOOL.@]
3707 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3708 DWORD cbBuf, LPDWORD pcbNeeded)
3711 DWORD size, needed = 0;
3713 HKEY hkeyPrinter, hkeyPrinters;
3716 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3718 if (!(name = get_opened_printer_name(hPrinter))) {
3719 SetLastError(ERROR_INVALID_HANDLE);
3723 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3725 ERR("Can't create Printers key\n");
3728 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3730 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3731 RegCloseKey(hkeyPrinters);
3732 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3739 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3741 size = sizeof(PRINTER_INFO_2W);
3743 ptr = pPrinter + size;
3745 memset(pPrinter, 0, size);
3750 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3757 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3759 size = sizeof(PRINTER_INFO_4W);
3761 ptr = pPrinter + size;
3763 memset(pPrinter, 0, size);
3768 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3776 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3778 size = sizeof(PRINTER_INFO_5W);
3780 ptr = pPrinter + size;
3782 memset(pPrinter, 0, size);
3788 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3796 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3798 size = sizeof(PRINTER_INFO_6);
3799 if (size <= cbBuf) {
3800 /* FIXME: We do not update the status yet */
3801 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3813 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3815 size = sizeof(PRINTER_INFO_7W);
3816 if (size <= cbBuf) {
3817 ptr = pPrinter + size;
3819 memset(pPrinter, 0, size);
3825 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3833 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3835 size = sizeof(PRINTER_INFO_9W);
3837 ptr = pPrinter + size;
3839 memset(pPrinter, 0, size);
3845 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3852 FIXME("Unimplemented level %d\n", Level);
3853 SetLastError(ERROR_INVALID_LEVEL);
3854 RegCloseKey(hkeyPrinters);
3855 RegCloseKey(hkeyPrinter);
3859 RegCloseKey(hkeyPrinter);
3860 RegCloseKey(hkeyPrinters);
3862 TRACE("returning %d needed = %d\n", ret, needed);
3863 if(pcbNeeded) *pcbNeeded = needed;
3865 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3869 /*****************************************************************************
3870 * GetPrinterA [WINSPOOL.@]
3872 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3873 DWORD cbBuf, LPDWORD pcbNeeded)
3879 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3881 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3883 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3884 HeapFree(GetProcessHeap(), 0, buf);
3889 /*****************************************************************************
3890 * WINSPOOL_EnumPrintersW
3892 * Implementation of EnumPrintersW
3894 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3895 DWORD dwLevel, LPBYTE lpbPrinters,
3896 DWORD cbBuf, LPDWORD lpdwNeeded,
3897 LPDWORD lpdwReturned)
3900 HKEY hkeyPrinters, hkeyPrinter;
3901 WCHAR PrinterName[255];
3902 DWORD needed = 0, number = 0;
3903 DWORD used, i, left;
3907 memset(lpbPrinters, 0, cbBuf);
3913 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3914 if(dwType == PRINTER_ENUM_DEFAULT)
3917 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3918 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3919 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3921 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3927 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3928 FIXME("dwType = %08x\n", dwType);
3929 SetLastError(ERROR_INVALID_FLAGS);
3933 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3935 ERR("Can't create Printers key\n");
3939 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3940 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3941 RegCloseKey(hkeyPrinters);
3942 ERR("Can't query Printers key\n");
3945 TRACE("Found %d printers\n", number);
3949 used = number * sizeof(PRINTER_INFO_1W);
3952 used = number * sizeof(PRINTER_INFO_2W);
3955 used = number * sizeof(PRINTER_INFO_4W);
3958 used = number * sizeof(PRINTER_INFO_5W);
3962 SetLastError(ERROR_INVALID_LEVEL);
3963 RegCloseKey(hkeyPrinters);
3966 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3968 for(i = 0; i < number; i++) {
3969 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3971 ERR("Can't enum key number %d\n", i);
3972 RegCloseKey(hkeyPrinters);
3975 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3976 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3978 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3979 RegCloseKey(hkeyPrinters);
3984 buf = lpbPrinters + used;
3985 left = cbBuf - used;
3993 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3996 if(pi) pi += sizeof(PRINTER_INFO_1W);
3999 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4002 if(pi) pi += sizeof(PRINTER_INFO_2W);
4005 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4008 if(pi) pi += sizeof(PRINTER_INFO_4W);
4011 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4014 if(pi) pi += sizeof(PRINTER_INFO_5W);
4017 ERR("Shouldn't be here!\n");
4018 RegCloseKey(hkeyPrinter);
4019 RegCloseKey(hkeyPrinters);
4022 RegCloseKey(hkeyPrinter);
4024 RegCloseKey(hkeyPrinters);
4031 memset(lpbPrinters, 0, cbBuf);
4032 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4036 *lpdwReturned = number;
4037 SetLastError(ERROR_SUCCESS);
4042 /******************************************************************
4043 * EnumPrintersW [WINSPOOL.@]
4045 * Enumerates the available printers, print servers and print
4046 * providers, depending on the specified flags, name and level.
4050 * If level is set to 1:
4051 * Returns an array of PRINTER_INFO_1 data structures in the
4052 * lpbPrinters buffer.
4054 * If level is set to 2:
4055 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4056 * Returns an array of PRINTER_INFO_2 data structures in the
4057 * lpbPrinters buffer. Note that according to MSDN also an
4058 * OpenPrinter should be performed on every remote printer.
4060 * If level is set to 4 (officially WinNT only):
4061 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4062 * Fast: Only the registry is queried to retrieve printer names,
4063 * no connection to the driver is made.
4064 * Returns an array of PRINTER_INFO_4 data structures in the
4065 * lpbPrinters buffer.
4067 * If level is set to 5 (officially WinNT4/Win9x only):
4068 * Fast: Only the registry is queried to retrieve printer names,
4069 * no connection to the driver is made.
4070 * Returns an array of PRINTER_INFO_5 data structures in the
4071 * lpbPrinters buffer.
4073 * If level set to 3 or 6+:
4074 * returns zero (failure!)
4076 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4080 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4081 * - Only levels 2, 4 and 5 are implemented at the moment.
4082 * - 16-bit printer drivers are not enumerated.
4083 * - Returned amount of bytes used/needed does not match the real Windoze
4084 * implementation (as in this implementation, all strings are part
4085 * of the buffer, whereas Win32 keeps them somewhere else)
4086 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4089 * - In a regular Wine installation, no registry settings for printers
4090 * exist, which makes this function return an empty list.
4092 BOOL WINAPI EnumPrintersW(
4093 DWORD dwType, /* [in] Types of print objects to enumerate */
4094 LPWSTR lpszName, /* [in] name of objects to enumerate */
4095 DWORD dwLevel, /* [in] type of printer info structure */
4096 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4097 DWORD cbBuf, /* [in] max size of buffer in bytes */
4098 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4099 LPDWORD lpdwReturned /* [out] number of entries returned */
4102 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4103 lpdwNeeded, lpdwReturned);
4106 /******************************************************************
4107 * EnumPrintersA [WINSPOOL.@]
4112 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4113 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4116 UNICODE_STRING pNameU;
4120 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4121 pPrinters, cbBuf, pcbNeeded, pcReturned);
4123 pNameW = asciitounicode(&pNameU, pName);
4125 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4126 MS Office need this */
4127 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4129 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4131 RtlFreeUnicodeString(&pNameU);
4133 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4135 HeapFree(GetProcessHeap(), 0, pPrintersW);
4139 /*****************************************************************************
4140 * WINSPOOL_GetDriverInfoFromReg [internal]
4142 * Enters the information from the registry into the DRIVER_INFO struct
4145 * zero if the printer driver does not exist in the registry
4146 * (only if Level > 1) otherwise nonzero
4148 static BOOL WINSPOOL_GetDriverInfoFromReg(
4151 const printenv_t * env,
4153 LPBYTE ptr, /* DRIVER_INFO */
4154 LPBYTE pDriverStrings, /* strings buffer */
4155 DWORD cbBuf, /* size of string buffer */
4156 LPDWORD pcbNeeded) /* space needed for str. */
4160 WCHAR driverdir[MAX_PATH];
4162 LPBYTE strPtr = pDriverStrings;
4163 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4165 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4166 debugstr_w(DriverName), env,
4167 Level, di, pDriverStrings, cbBuf);
4169 if (di) ZeroMemory(di, di_sizeof[Level]);
4171 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4172 if (*pcbNeeded <= cbBuf)
4173 strcpyW((LPWSTR)strPtr, DriverName);
4175 /* pName for level 1 has a different offset! */
4177 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4181 /* .cVersion and .pName for level > 1 */
4183 di->cVersion = env->driverversion;
4184 di->pName = (LPWSTR) strPtr;
4185 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4188 /* Reserve Space for the largest subdir and a Backslash*/
4189 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4190 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4191 /* Should never Fail */
4194 lstrcatW(driverdir, env->versionsubdir);
4195 lstrcatW(driverdir, backslashW);
4197 /* dirlen must not include the terminating zero */
4198 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4200 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4201 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4202 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4207 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4210 if (*pcbNeeded <= cbBuf) {
4211 lstrcpyW((LPWSTR)strPtr, env->envname);
4212 if (di) di->pEnvironment = (LPWSTR)strPtr;
4213 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4216 /* .pDriverPath is the Graphics rendering engine.
4217 The full Path is required to avoid a crash in some apps */
4218 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4220 if (*pcbNeeded <= cbBuf)
4221 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4223 if (di) di->pDriverPath = (LPWSTR)strPtr;
4224 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4227 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4228 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4230 if (*pcbNeeded <= cbBuf)
4231 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4233 if (di) di->pDataFile = (LPWSTR)strPtr;
4234 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4237 /* .pConfigFile is the Driver user Interface */
4238 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4240 if (*pcbNeeded <= cbBuf)
4241 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4243 if (di) di->pConfigFile = (LPWSTR)strPtr;
4244 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4248 RegCloseKey(hkeyDriver);
4249 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4254 RegCloseKey(hkeyDriver);
4255 FIXME("level 5: incomplete\n");
4260 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4262 if (*pcbNeeded <= cbBuf)
4263 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4265 if (di) di->pHelpFile = (LPWSTR)strPtr;
4266 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4269 /* .pDependentFiles */
4270 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4272 if (*pcbNeeded <= cbBuf)
4273 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4275 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4276 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4278 else if (GetVersion() & 0x80000000) {
4279 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4280 size = 2 * sizeof(WCHAR);
4282 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4284 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4285 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4288 /* .pMonitorName is the optional Language Monitor */
4289 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4291 if (*pcbNeeded <= cbBuf)
4292 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4294 if (di) di->pMonitorName = (LPWSTR)strPtr;
4295 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4298 /* .pDefaultDataType */
4299 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4301 if(*pcbNeeded <= cbBuf)
4302 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4304 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4305 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4309 RegCloseKey(hkeyDriver);
4310 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4314 /* .pszzPreviousNames */
4315 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4317 if(*pcbNeeded <= cbBuf)
4318 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4320 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4321 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4325 RegCloseKey(hkeyDriver);
4326 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4330 /* support is missing, but not important enough for a FIXME */
4331 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4334 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4336 if(*pcbNeeded <= cbBuf)
4337 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4339 if (di) di->pszMfgName = (LPWSTR)strPtr;
4340 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4344 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4346 if(*pcbNeeded <= cbBuf)
4347 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4349 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4350 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4353 /* .pszHardwareID */
4354 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4356 if(*pcbNeeded <= cbBuf)
4357 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4359 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4360 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4364 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4366 if(*pcbNeeded <= cbBuf)
4367 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4369 if (di) di->pszProvider = (LPWSTR)strPtr;
4370 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4374 RegCloseKey(hkeyDriver);
4378 /* support is missing, but not important enough for a FIXME */
4379 TRACE("level 8: incomplete\n");
4381 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4382 RegCloseKey(hkeyDriver);
4386 /*****************************************************************************
4387 * GetPrinterDriverW [WINSPOOL.@]
4389 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4390 DWORD Level, LPBYTE pDriverInfo,
4391 DWORD cbBuf, LPDWORD pcbNeeded)
4394 WCHAR DriverName[100];
4395 DWORD ret, type, size, needed = 0;
4397 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4398 const printenv_t * env;
4400 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4401 Level,pDriverInfo,cbBuf, pcbNeeded);
4404 ZeroMemory(pDriverInfo, cbBuf);
4406 if (!(name = get_opened_printer_name(hPrinter))) {
4407 SetLastError(ERROR_INVALID_HANDLE);
4411 if (Level < 1 || Level == 7 || Level > 8) {
4412 SetLastError(ERROR_INVALID_LEVEL);
4416 env = validate_envW(pEnvironment);
4417 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4419 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4421 ERR("Can't create Printers key\n");
4424 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4426 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4427 RegCloseKey(hkeyPrinters);
4428 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4431 size = sizeof(DriverName);
4433 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4434 (LPBYTE)DriverName, &size);
4435 RegCloseKey(hkeyPrinter);
4436 RegCloseKey(hkeyPrinters);
4437 if(ret != ERROR_SUCCESS) {
4438 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4442 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4444 ERR("Can't create Drivers key\n");
4448 size = di_sizeof[Level];
4449 if ((size <= cbBuf) && pDriverInfo)
4450 ptr = pDriverInfo + size;
4452 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4453 env, Level, pDriverInfo, ptr,
4454 (cbBuf < size) ? 0 : cbBuf - size,
4456 RegCloseKey(hkeyDrivers);
4460 RegCloseKey(hkeyDrivers);
4462 if(pcbNeeded) *pcbNeeded = size + needed;
4463 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4464 if(cbBuf >= size + needed) return TRUE;
4465 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4469 /*****************************************************************************
4470 * GetPrinterDriverA [WINSPOOL.@]
4472 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4473 DWORD Level, LPBYTE pDriverInfo,
4474 DWORD cbBuf, LPDWORD pcbNeeded)
4477 UNICODE_STRING pEnvW;
4483 ZeroMemory(pDriverInfo, cbBuf);
4484 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4487 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4488 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4491 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4493 HeapFree(GetProcessHeap(), 0, buf);
4495 RtlFreeUnicodeString(&pEnvW);
4499 /*****************************************************************************
4500 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4502 * Return the PATH for the Printer-Drivers (UNICODE)
4505 * pName [I] Servername (NT only) or NULL (local Computer)
4506 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4507 * Level [I] Structure-Level (must be 1)
4508 * pDriverDirectory [O] PTR to Buffer that receives the Result
4509 * cbBuf [I] Size of Buffer at pDriverDirectory
4510 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4511 * required for pDriverDirectory
4514 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4515 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4516 * if cbBuf is too small
4518 * Native Values returned in pDriverDirectory on Success:
4519 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4520 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4521 *| win9x(Windows 4.0): "%winsysdir%"
4523 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4526 *- Only NULL or "" is supported for pName
4529 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4530 DWORD Level, LPBYTE pDriverDirectory,
4531 DWORD cbBuf, LPDWORD pcbNeeded)
4533 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4534 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4536 if ((backend == NULL) && !load_backend()) return FALSE;
4539 /* (Level != 1) is ignored in win9x */
4540 SetLastError(ERROR_INVALID_LEVEL);
4543 if (pcbNeeded == NULL) {
4544 /* (pcbNeeded == NULL) is ignored in win9x */
4545 SetLastError(RPC_X_NULL_REF_POINTER);
4549 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4550 pDriverDirectory, cbBuf, pcbNeeded);
4555 /*****************************************************************************
4556 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4558 * Return the PATH for the Printer-Drivers (ANSI)
4560 * See GetPrinterDriverDirectoryW.
4563 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4566 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4567 DWORD Level, LPBYTE pDriverDirectory,
4568 DWORD cbBuf, LPDWORD pcbNeeded)
4570 UNICODE_STRING nameW, environmentW;
4573 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4574 WCHAR *driverDirectoryW = NULL;
4576 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4577 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4579 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4581 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4582 else nameW.Buffer = NULL;
4583 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4584 else environmentW.Buffer = NULL;
4586 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4587 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4590 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4591 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4593 *pcbNeeded = needed;
4594 ret = (needed <= cbBuf) ? TRUE : FALSE;
4596 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4598 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4600 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4601 RtlFreeUnicodeString(&environmentW);
4602 RtlFreeUnicodeString(&nameW);
4607 /*****************************************************************************
4608 * AddPrinterDriverA [WINSPOOL.@]
4610 * See AddPrinterDriverW.
4613 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4615 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4616 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4619 /******************************************************************************
4620 * AddPrinterDriverW (WINSPOOL.@)
4622 * Install a Printer Driver
4625 * pName [I] Servername or NULL (local Computer)
4626 * level [I] Level for the supplied DRIVER_INFO_*W struct
4627 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4634 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4636 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4637 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4640 /*****************************************************************************
4641 * AddPrintProcessorA [WINSPOOL.@]
4643 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4644 LPSTR pPrintProcessorName)
4646 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4647 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4651 /*****************************************************************************
4652 * AddPrintProcessorW [WINSPOOL.@]
4654 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4655 LPWSTR pPrintProcessorName)
4657 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4658 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4662 /*****************************************************************************
4663 * AddPrintProvidorA [WINSPOOL.@]
4665 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4667 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4671 /*****************************************************************************
4672 * AddPrintProvidorW [WINSPOOL.@]
4674 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4676 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4680 /*****************************************************************************
4681 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4683 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4684 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4686 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4687 pDevModeOutput, pDevModeInput);
4691 /*****************************************************************************
4692 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4694 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4695 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4697 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4698 pDevModeOutput, pDevModeInput);
4702 /*****************************************************************************
4703 * PrinterProperties [WINSPOOL.@]
4705 * Displays a dialog to set the properties of the printer.
4708 * nonzero on success or zero on failure
4711 * implemented as stub only
4713 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4714 HANDLE hPrinter /* [in] handle to printer object */
4716 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4717 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4721 /*****************************************************************************
4722 * EnumJobsA [WINSPOOL.@]
4725 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4726 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4729 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4730 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4732 if(pcbNeeded) *pcbNeeded = 0;
4733 if(pcReturned) *pcReturned = 0;
4738 /*****************************************************************************
4739 * EnumJobsW [WINSPOOL.@]
4742 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4743 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4746 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4747 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4749 if(pcbNeeded) *pcbNeeded = 0;
4750 if(pcReturned) *pcReturned = 0;
4754 /*****************************************************************************
4755 * WINSPOOL_EnumPrinterDrivers [internal]
4757 * Delivers information about all printer drivers installed on the
4758 * localhost or a given server
4761 * nonzero on success or zero on failure. If the buffer for the returned
4762 * information is too small the function will return an error
4765 * - only implemented for localhost, foreign hosts will return an error
4767 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4768 DWORD Level, LPBYTE pDriverInfo,
4770 DWORD cbBuf, LPDWORD pcbNeeded,
4771 LPDWORD pcFound, DWORD data_offset)
4775 const printenv_t * env;
4777 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4778 debugstr_w(pName), debugstr_w(pEnvironment),
4779 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4781 env = validate_envW(pEnvironment);
4782 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4786 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4788 ERR("Can't open Drivers key\n");
4792 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4793 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4794 RegCloseKey(hkeyDrivers);
4795 ERR("Can't query Drivers key\n");
4798 TRACE("Found %d Drivers\n", *pcFound);
4800 /* get size of single struct
4801 * unicode and ascii structure have the same size
4803 size = di_sizeof[Level];
4805 if (data_offset == 0)
4806 data_offset = size * (*pcFound);
4807 *pcbNeeded = data_offset;
4809 for( i = 0; i < *pcFound; i++) {
4810 WCHAR DriverNameW[255];
4811 PBYTE table_ptr = NULL;
4812 PBYTE data_ptr = NULL;
4815 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4817 ERR("Can't enum key number %d\n", i);
4818 RegCloseKey(hkeyDrivers);
4822 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4823 table_ptr = pDriverInfo + (driver_index + i) * size;
4824 if (pDriverInfo && *pcbNeeded <= cbBuf)
4825 data_ptr = pDriverInfo + *pcbNeeded;
4827 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4828 env, Level, table_ptr, data_ptr,
4829 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4831 RegCloseKey(hkeyDrivers);
4835 *pcbNeeded += needed;
4838 RegCloseKey(hkeyDrivers);
4840 if(cbBuf < *pcbNeeded){
4841 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4848 /*****************************************************************************
4849 * EnumPrinterDriversW [WINSPOOL.@]
4851 * see function EnumPrinterDrivers for RETURNS, BUGS
4853 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4854 LPBYTE pDriverInfo, DWORD cbBuf,
4855 LPDWORD pcbNeeded, LPDWORD pcReturned)
4857 static const WCHAR allW[] = {'a','l','l',0};
4861 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4863 SetLastError(RPC_X_NULL_REF_POINTER);
4867 /* check for local drivers */
4868 if((pName) && (pName[0])) {
4869 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4870 SetLastError(ERROR_ACCESS_DENIED);
4874 /* check input parameter */
4875 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4876 SetLastError(ERROR_INVALID_LEVEL);
4880 if(pDriverInfo && cbBuf > 0)
4881 memset( pDriverInfo, 0, cbBuf);
4883 /* Exception: pull all printers */
4884 if (pEnvironment && !strcmpW(pEnvironment, allW))
4886 DWORD i, needed, bufsize = cbBuf;
4887 DWORD total_needed = 0;
4888 DWORD total_found = 0;
4891 /* Precompute the overall total; we need this to know
4892 where pointers end and data begins (i.e. data_offset) */
4893 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4896 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4897 NULL, 0, 0, &needed, &found, 0);
4898 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4899 total_needed += needed;
4900 total_found += found;
4903 data_offset = di_sizeof[Level] * total_found;
4908 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4911 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4912 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4913 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4915 *pcReturned += found;
4916 *pcbNeeded = needed;
4917 data_offset = needed;
4918 total_found += found;
4923 /* Normal behavior */
4924 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4925 0, cbBuf, pcbNeeded, &found, 0);
4927 *pcReturned = found;
4932 /*****************************************************************************
4933 * EnumPrinterDriversA [WINSPOOL.@]
4935 * see function EnumPrinterDrivers for RETURNS, BUGS
4937 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4938 LPBYTE pDriverInfo, DWORD cbBuf,
4939 LPDWORD pcbNeeded, LPDWORD pcReturned)
4942 UNICODE_STRING pNameW, pEnvironmentW;
4943 PWSTR pwstrNameW, pwstrEnvironmentW;
4947 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4949 pwstrNameW = asciitounicode(&pNameW, pName);
4950 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4952 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4953 buf, cbBuf, pcbNeeded, pcReturned);
4955 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4957 HeapFree(GetProcessHeap(), 0, buf);
4959 RtlFreeUnicodeString(&pNameW);
4960 RtlFreeUnicodeString(&pEnvironmentW);
4965 /******************************************************************************
4966 * EnumPortsA (WINSPOOL.@)
4971 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4972 LPDWORD pcbNeeded, LPDWORD pcReturned)
4975 LPBYTE bufferW = NULL;
4976 LPWSTR nameW = NULL;
4978 DWORD numentries = 0;
4981 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4982 cbBuf, pcbNeeded, pcReturned);
4984 /* convert servername to unicode */
4986 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4987 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4988 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4990 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4991 needed = cbBuf * sizeof(WCHAR);
4992 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4993 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4995 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4996 if (pcbNeeded) needed = *pcbNeeded;
4997 /* HeapReAlloc return NULL, when bufferW was NULL */
4998 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4999 HeapAlloc(GetProcessHeap(), 0, needed);
5001 /* Try again with the large Buffer */
5002 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5004 needed = pcbNeeded ? *pcbNeeded : 0;
5005 numentries = pcReturned ? *pcReturned : 0;
5008 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5009 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5012 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5013 DWORD entrysize = 0;
5016 LPPORT_INFO_2W pi2w;
5017 LPPORT_INFO_2A pi2a;
5020 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5022 /* First pass: calculate the size for all Entries */
5023 pi2w = (LPPORT_INFO_2W) bufferW;
5024 pi2a = (LPPORT_INFO_2A) pPorts;
5026 while (index < numentries) {
5028 needed += entrysize; /* PORT_INFO_?A */
5029 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5031 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5032 NULL, 0, NULL, NULL);
5034 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5035 NULL, 0, NULL, NULL);
5036 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5037 NULL, 0, NULL, NULL);
5039 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5040 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5041 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5044 /* check for errors and quit on failure */
5045 if (cbBuf < needed) {
5046 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5050 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5051 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5052 cbBuf -= len ; /* free Bytes in the user-Buffer */
5053 pi2w = (LPPORT_INFO_2W) bufferW;
5054 pi2a = (LPPORT_INFO_2A) pPorts;
5056 /* Second Pass: Fill the User Buffer (if we have one) */
5057 while ((index < numentries) && pPorts) {
5059 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5060 pi2a->pPortName = ptr;
5061 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5062 ptr, cbBuf , NULL, NULL);
5066 pi2a->pMonitorName = ptr;
5067 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5068 ptr, cbBuf, NULL, NULL);
5072 pi2a->pDescription = ptr;
5073 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5074 ptr, cbBuf, NULL, NULL);
5078 pi2a->fPortType = pi2w->fPortType;
5079 pi2a->Reserved = 0; /* documented: "must be zero" */
5082 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5083 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5084 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5089 if (pcbNeeded) *pcbNeeded = needed;
5090 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5092 HeapFree(GetProcessHeap(), 0, nameW);
5093 HeapFree(GetProcessHeap(), 0, bufferW);
5095 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5096 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5102 /******************************************************************************
5103 * EnumPortsW (WINSPOOL.@)
5105 * Enumerate available Ports
5108 * pName [I] Servername or NULL (local Computer)
5109 * Level [I] Structure-Level (1 or 2)
5110 * pPorts [O] PTR to Buffer that receives the Result
5111 * cbBuf [I] Size of Buffer at pPorts
5112 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5113 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5117 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5120 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5123 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5124 cbBuf, pcbNeeded, pcReturned);
5126 if ((backend == NULL) && !load_backend()) return FALSE;
5128 /* Level is not checked in win9x */
5129 if (!Level || (Level > 2)) {
5130 WARN("level (%d) is ignored in win9x\n", Level);
5131 SetLastError(ERROR_INVALID_LEVEL);
5134 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5135 SetLastError(RPC_X_NULL_REF_POINTER);
5139 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5142 /******************************************************************************
5143 * GetDefaultPrinterW (WINSPOOL.@)
5146 * This function must read the value from data 'device' of key
5147 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5149 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5153 WCHAR *buffer, *ptr;
5157 SetLastError(ERROR_INVALID_PARAMETER);
5161 /* make the buffer big enough for the stuff from the profile/registry,
5162 * the content must fit into the local buffer to compute the correct
5163 * size even if the extern buffer is too small or not given.
5164 * (20 for ,driver,port) */
5166 len = max(100, (insize + 20));
5167 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5169 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5171 SetLastError (ERROR_FILE_NOT_FOUND);
5175 TRACE("%s\n", debugstr_w(buffer));
5177 if ((ptr = strchrW(buffer, ',')) == NULL)
5179 SetLastError(ERROR_INVALID_NAME);
5185 *namesize = strlenW(buffer) + 1;
5186 if(!name || (*namesize > insize))
5188 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5192 strcpyW(name, buffer);
5195 HeapFree( GetProcessHeap(), 0, buffer);
5200 /******************************************************************************
5201 * GetDefaultPrinterA (WINSPOOL.@)
5203 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5207 WCHAR *bufferW = NULL;
5211 SetLastError(ERROR_INVALID_PARAMETER);
5215 if(name && *namesize) {
5217 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5220 if(!GetDefaultPrinterW( bufferW, namesize)) {
5225 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5229 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5232 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5235 HeapFree( GetProcessHeap(), 0, bufferW);
5240 /******************************************************************************
5241 * SetDefaultPrinterW (WINSPOOL.204)
5243 * Set the Name of the Default Printer
5246 * pszPrinter [I] Name of the Printer or NULL
5253 * When the Parameter is NULL or points to an Empty String and
5254 * a Default Printer was already present, then this Function changes nothing.
5255 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5256 * the First enumerated local Printer is used.
5259 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5261 WCHAR default_printer[MAX_PATH];
5262 LPWSTR buffer = NULL;
5268 TRACE("(%s)\n", debugstr_w(pszPrinter));
5269 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5271 default_printer[0] = '\0';
5272 size = sizeof(default_printer)/sizeof(WCHAR);
5274 /* if we have a default Printer, do nothing. */
5275 if (GetDefaultPrinterW(default_printer, &size))
5279 /* we have no default Printer: search local Printers and use the first */
5280 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5282 default_printer[0] = '\0';
5283 size = sizeof(default_printer)/sizeof(WCHAR);
5284 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5286 pszPrinter = default_printer;
5287 TRACE("using %s\n", debugstr_w(pszPrinter));
5292 if (pszPrinter == NULL) {
5293 TRACE("no local printer found\n");
5294 SetLastError(ERROR_FILE_NOT_FOUND);
5299 /* "pszPrinter" is never empty or NULL here. */
5300 namelen = lstrlenW(pszPrinter);
5301 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5302 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5304 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5305 HeapFree(GetProcessHeap(), 0, buffer);
5306 SetLastError(ERROR_FILE_NOT_FOUND);
5310 /* read the devices entry for the printer (driver,port) to build the string for the
5311 default device entry (printer,driver,port) */
5312 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5313 buffer[namelen] = ',';
5314 namelen++; /* move index to the start of the driver */
5316 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5317 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5319 TRACE("set device to %s\n", debugstr_w(buffer));
5321 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5322 TRACE("failed to set the device entry: %d\n", GetLastError());
5323 lres = ERROR_INVALID_PRINTER_NAME;
5326 /* remove the next section, when INIFileMapping is implemented */
5329 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5330 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5337 if (lres != ERROR_FILE_NOT_FOUND)
5338 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5340 SetLastError(ERROR_INVALID_PRINTER_NAME);
5344 HeapFree(GetProcessHeap(), 0, buffer);
5345 return (lres == ERROR_SUCCESS);
5348 /******************************************************************************
5349 * SetDefaultPrinterA (WINSPOOL.202)
5351 * See SetDefaultPrinterW.
5354 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5356 LPWSTR bufferW = NULL;
5359 TRACE("(%s)\n", debugstr_a(pszPrinter));
5361 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5362 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5363 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5365 res = SetDefaultPrinterW(bufferW);
5366 HeapFree(GetProcessHeap(), 0, bufferW);
5370 /******************************************************************************
5371 * SetPrinterDataExA (WINSPOOL.@)
5373 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5374 LPCSTR pValueName, DWORD Type,
5375 LPBYTE pData, DWORD cbData)
5377 HKEY hkeyPrinter, hkeySubkey;
5380 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5381 debugstr_a(pValueName), Type, pData, cbData);
5383 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5387 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5389 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5390 RegCloseKey(hkeyPrinter);
5393 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5394 RegCloseKey(hkeySubkey);
5395 RegCloseKey(hkeyPrinter);
5399 /******************************************************************************
5400 * SetPrinterDataExW (WINSPOOL.@)
5402 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5403 LPCWSTR pValueName, DWORD Type,
5404 LPBYTE pData, DWORD cbData)
5406 HKEY hkeyPrinter, hkeySubkey;
5409 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5410 debugstr_w(pValueName), Type, pData, cbData);
5412 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5416 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5418 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5419 RegCloseKey(hkeyPrinter);
5422 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5423 RegCloseKey(hkeySubkey);
5424 RegCloseKey(hkeyPrinter);
5428 /******************************************************************************
5429 * SetPrinterDataA (WINSPOOL.@)
5431 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5432 LPBYTE pData, DWORD cbData)
5434 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5438 /******************************************************************************
5439 * SetPrinterDataW (WINSPOOL.@)
5441 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5442 LPBYTE pData, DWORD cbData)
5444 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5448 /******************************************************************************
5449 * GetPrinterDataExA (WINSPOOL.@)
5451 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5452 LPCSTR pValueName, LPDWORD pType,
5453 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5455 opened_printer_t *printer;
5456 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5459 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5460 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5462 printer = get_opened_printer(hPrinter);
5463 if(!printer) return ERROR_INVALID_HANDLE;
5465 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5466 if (ret) return ret;
5468 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5470 if (printer->name) {
5472 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5474 RegCloseKey(hkeyPrinters);
5477 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5478 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5479 RegCloseKey(hkeyPrinter);
5480 RegCloseKey(hkeyPrinters);
5485 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5486 0, pType, pData, pcbNeeded);
5488 if (!ret && !pData) ret = ERROR_MORE_DATA;
5490 RegCloseKey(hkeySubkey);
5491 RegCloseKey(hkeyPrinter);
5492 RegCloseKey(hkeyPrinters);
5494 TRACE("--> %d\n", ret);
5498 /******************************************************************************
5499 * GetPrinterDataExW (WINSPOOL.@)
5501 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5502 LPCWSTR pValueName, LPDWORD pType,
5503 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5505 opened_printer_t *printer;
5506 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5509 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5510 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5512 printer = get_opened_printer(hPrinter);
5513 if(!printer) return ERROR_INVALID_HANDLE;
5515 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5516 if (ret) return ret;
5518 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5520 if (printer->name) {
5522 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5524 RegCloseKey(hkeyPrinters);
5527 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5528 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5529 RegCloseKey(hkeyPrinter);
5530 RegCloseKey(hkeyPrinters);
5535 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5536 0, pType, pData, pcbNeeded);
5538 if (!ret && !pData) ret = ERROR_MORE_DATA;
5540 RegCloseKey(hkeySubkey);
5541 RegCloseKey(hkeyPrinter);
5542 RegCloseKey(hkeyPrinters);
5544 TRACE("--> %d\n", ret);
5548 /******************************************************************************
5549 * GetPrinterDataA (WINSPOOL.@)
5551 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5552 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5554 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5555 pData, nSize, pcbNeeded);
5558 /******************************************************************************
5559 * GetPrinterDataW (WINSPOOL.@)
5561 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5562 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5564 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5565 pData, nSize, pcbNeeded);
5568 /*******************************************************************************
5569 * EnumPrinterDataExW [WINSPOOL.@]
5571 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5572 LPBYTE pEnumValues, DWORD cbEnumValues,
5573 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5575 HKEY hkPrinter, hkSubKey;
5576 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5577 cbValueNameLen, cbMaxValueLen, cbValueLen,
5582 PPRINTER_ENUM_VALUESW ppev;
5584 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5586 if (pKeyName == NULL || *pKeyName == 0)
5587 return ERROR_INVALID_PARAMETER;
5589 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5590 if (ret != ERROR_SUCCESS)
5592 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5597 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5598 if (ret != ERROR_SUCCESS)
5600 r = RegCloseKey (hkPrinter);
5601 if (r != ERROR_SUCCESS)
5602 WARN ("RegCloseKey returned %i\n", r);
5603 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5604 debugstr_w (pKeyName), ret);
5608 ret = RegCloseKey (hkPrinter);
5609 if (ret != ERROR_SUCCESS)
5611 ERR ("RegCloseKey returned %i\n", ret);
5612 r = RegCloseKey (hkSubKey);
5613 if (r != ERROR_SUCCESS)
5614 WARN ("RegCloseKey returned %i\n", r);
5618 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5619 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5620 if (ret != ERROR_SUCCESS)
5622 r = RegCloseKey (hkSubKey);
5623 if (r != ERROR_SUCCESS)
5624 WARN ("RegCloseKey returned %i\n", r);
5625 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5629 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5630 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5632 if (cValues == 0) /* empty key */
5634 r = RegCloseKey (hkSubKey);
5635 if (r != ERROR_SUCCESS)
5636 WARN ("RegCloseKey returned %i\n", r);
5637 *pcbEnumValues = *pnEnumValues = 0;
5638 return ERROR_SUCCESS;
5641 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5643 hHeap = GetProcessHeap ();
5646 ERR ("GetProcessHeap failed\n");
5647 r = RegCloseKey (hkSubKey);
5648 if (r != ERROR_SUCCESS)
5649 WARN ("RegCloseKey returned %i\n", r);
5650 return ERROR_OUTOFMEMORY;
5653 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5654 if (lpValueName == NULL)
5656 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5657 r = RegCloseKey (hkSubKey);
5658 if (r != ERROR_SUCCESS)
5659 WARN ("RegCloseKey returned %i\n", r);
5660 return ERROR_OUTOFMEMORY;
5663 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5664 if (lpValue == NULL)
5666 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5667 if (HeapFree (hHeap, 0, lpValueName) == 0)
5668 WARN ("HeapFree failed with code %i\n", GetLastError ());
5669 r = RegCloseKey (hkSubKey);
5670 if (r != ERROR_SUCCESS)
5671 WARN ("RegCloseKey returned %i\n", r);
5672 return ERROR_OUTOFMEMORY;
5675 TRACE ("pass 1: calculating buffer required for all names and values\n");
5677 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5679 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5681 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5683 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5684 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5685 NULL, NULL, lpValue, &cbValueLen);
5686 if (ret != ERROR_SUCCESS)
5688 if (HeapFree (hHeap, 0, lpValue) == 0)
5689 WARN ("HeapFree failed with code %i\n", GetLastError ());
5690 if (HeapFree (hHeap, 0, lpValueName) == 0)
5691 WARN ("HeapFree failed with code %i\n", GetLastError ());
5692 r = RegCloseKey (hkSubKey);
5693 if (r != ERROR_SUCCESS)
5694 WARN ("RegCloseKey returned %i\n", r);
5695 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5699 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5700 debugstr_w (lpValueName), dwIndex,
5701 cbValueNameLen + 1, cbValueLen);
5703 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5704 cbBufSize += cbValueLen;
5707 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5709 *pcbEnumValues = cbBufSize;
5710 *pnEnumValues = cValues;
5712 if (cbEnumValues < cbBufSize) /* buffer too small */
5714 if (HeapFree (hHeap, 0, lpValue) == 0)
5715 WARN ("HeapFree failed with code %i\n", GetLastError ());
5716 if (HeapFree (hHeap, 0, lpValueName) == 0)
5717 WARN ("HeapFree failed with code %i\n", GetLastError ());
5718 r = RegCloseKey (hkSubKey);
5719 if (r != ERROR_SUCCESS)
5720 WARN ("RegCloseKey returned %i\n", r);
5721 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5722 return ERROR_MORE_DATA;
5725 TRACE ("pass 2: copying all names and values to buffer\n");
5727 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5728 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5730 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5732 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5733 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5734 NULL, &dwType, lpValue, &cbValueLen);
5735 if (ret != ERROR_SUCCESS)
5737 if (HeapFree (hHeap, 0, lpValue) == 0)
5738 WARN ("HeapFree failed with code %i\n", GetLastError ());
5739 if (HeapFree (hHeap, 0, lpValueName) == 0)
5740 WARN ("HeapFree failed with code %i\n", GetLastError ());
5741 r = RegCloseKey (hkSubKey);
5742 if (r != ERROR_SUCCESS)
5743 WARN ("RegCloseKey returned %i\n", r);
5744 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5748 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5749 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5750 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5751 pEnumValues += cbValueNameLen;
5753 /* return # of *bytes* (including trailing \0), not # of chars */
5754 ppev[dwIndex].cbValueName = cbValueNameLen;
5756 ppev[dwIndex].dwType = dwType;
5758 memcpy (pEnumValues, lpValue, cbValueLen);
5759 ppev[dwIndex].pData = pEnumValues;
5760 pEnumValues += cbValueLen;
5762 ppev[dwIndex].cbData = cbValueLen;
5764 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5765 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5768 if (HeapFree (hHeap, 0, lpValue) == 0)
5770 ret = GetLastError ();
5771 ERR ("HeapFree failed with code %i\n", ret);
5772 if (HeapFree (hHeap, 0, lpValueName) == 0)
5773 WARN ("HeapFree failed with code %i\n", GetLastError ());
5774 r = RegCloseKey (hkSubKey);
5775 if (r != ERROR_SUCCESS)
5776 WARN ("RegCloseKey returned %i\n", r);
5780 if (HeapFree (hHeap, 0, lpValueName) == 0)
5782 ret = GetLastError ();
5783 ERR ("HeapFree failed with code %i\n", ret);
5784 r = RegCloseKey (hkSubKey);
5785 if (r != ERROR_SUCCESS)
5786 WARN ("RegCloseKey returned %i\n", r);
5790 ret = RegCloseKey (hkSubKey);
5791 if (ret != ERROR_SUCCESS)
5793 ERR ("RegCloseKey returned %i\n", ret);
5797 return ERROR_SUCCESS;
5800 /*******************************************************************************
5801 * EnumPrinterDataExA [WINSPOOL.@]
5803 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5804 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5805 * what Windows 2000 SP1 does.
5808 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5809 LPBYTE pEnumValues, DWORD cbEnumValues,
5810 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5814 DWORD ret, dwIndex, dwBufSize;
5818 TRACE ("%p %s\n", hPrinter, pKeyName);
5820 if (pKeyName == NULL || *pKeyName == 0)
5821 return ERROR_INVALID_PARAMETER;
5823 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5826 ret = GetLastError ();
5827 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5831 hHeap = GetProcessHeap ();
5834 ERR ("GetProcessHeap failed\n");
5835 return ERROR_OUTOFMEMORY;
5838 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5839 if (pKeyNameW == NULL)
5841 ERR ("Failed to allocate %i bytes from process heap\n",
5842 (LONG)(len * sizeof (WCHAR)));
5843 return ERROR_OUTOFMEMORY;
5846 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5848 ret = GetLastError ();
5849 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5850 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5855 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5856 pcbEnumValues, pnEnumValues);
5857 if (ret != ERROR_SUCCESS)
5859 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5860 WARN ("HeapFree failed with code %i\n", GetLastError ());
5861 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5865 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5867 ret = GetLastError ();
5868 ERR ("HeapFree failed with code %i\n", ret);
5872 if (*pnEnumValues == 0) /* empty key */
5873 return ERROR_SUCCESS;
5876 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5878 PPRINTER_ENUM_VALUESW ppev =
5879 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5881 if (dwBufSize < ppev->cbValueName)
5882 dwBufSize = ppev->cbValueName;
5884 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5885 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5886 dwBufSize = ppev->cbData;
5889 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5891 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5892 if (pBuffer == NULL)
5894 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5895 return ERROR_OUTOFMEMORY;
5898 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5900 PPRINTER_ENUM_VALUESW ppev =
5901 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5903 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5904 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5908 ret = GetLastError ();
5909 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5910 if (HeapFree (hHeap, 0, pBuffer) == 0)
5911 WARN ("HeapFree failed with code %i\n", GetLastError ());
5915 memcpy (ppev->pValueName, pBuffer, len);
5917 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5919 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5920 ppev->dwType != REG_MULTI_SZ)
5923 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5924 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5927 ret = GetLastError ();
5928 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5929 if (HeapFree (hHeap, 0, pBuffer) == 0)
5930 WARN ("HeapFree failed with code %i\n", GetLastError ());
5934 memcpy (ppev->pData, pBuffer, len);
5936 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5937 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5940 if (HeapFree (hHeap, 0, pBuffer) == 0)
5942 ret = GetLastError ();
5943 ERR ("HeapFree failed with code %i\n", ret);
5947 return ERROR_SUCCESS;
5950 /******************************************************************************
5951 * AbortPrinter (WINSPOOL.@)
5953 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5955 FIXME("(%p), stub!\n", hPrinter);
5959 /******************************************************************************
5960 * AddPortA (WINSPOOL.@)
5965 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5967 LPWSTR nameW = NULL;
5968 LPWSTR monitorW = NULL;
5972 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5975 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5976 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5977 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5981 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5982 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5983 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5985 res = AddPortW(nameW, hWnd, monitorW);
5986 HeapFree(GetProcessHeap(), 0, nameW);
5987 HeapFree(GetProcessHeap(), 0, monitorW);
5991 /******************************************************************************
5992 * AddPortW (WINSPOOL.@)
5994 * Add a Port for a specific Monitor
5997 * pName [I] Servername or NULL (local Computer)
5998 * hWnd [I] Handle to parent Window for the Dialog-Box
5999 * pMonitorName [I] Name of the Monitor that manage the Port
6006 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6008 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6010 if ((backend == NULL) && !load_backend()) return FALSE;
6012 if (!pMonitorName) {
6013 SetLastError(RPC_X_NULL_REF_POINTER);
6017 return backend->fpAddPort(pName, hWnd, pMonitorName);
6020 /******************************************************************************
6021 * AddPortExA (WINSPOOL.@)
6026 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6029 PORT_INFO_2A * pi2A;
6030 LPWSTR nameW = NULL;
6031 LPWSTR monitorW = NULL;
6035 pi2A = (PORT_INFO_2A *) pBuffer;
6037 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6038 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6040 if ((level < 1) || (level > 2)) {
6041 SetLastError(ERROR_INVALID_LEVEL);
6046 SetLastError(ERROR_INVALID_PARAMETER);
6051 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6052 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6053 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6057 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6058 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6059 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6062 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6064 if (pi2A->pPortName) {
6065 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6066 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6067 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6071 if (pi2A->pMonitorName) {
6072 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6073 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6074 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6077 if (pi2A->pDescription) {
6078 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6079 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6080 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6082 pi2W.fPortType = pi2A->fPortType;
6083 pi2W.Reserved = pi2A->Reserved;
6086 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6088 HeapFree(GetProcessHeap(), 0, nameW);
6089 HeapFree(GetProcessHeap(), 0, monitorW);
6090 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6091 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6092 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6097 /******************************************************************************
6098 * AddPortExW (WINSPOOL.@)
6100 * Add a Port for a specific Monitor, without presenting a user interface
6103 * pName [I] Servername or NULL (local Computer)
6104 * level [I] Structure-Level (1 or 2) for pBuffer
6105 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6106 * pMonitorName [I] Name of the Monitor that manage the Port
6113 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6117 pi2 = (PORT_INFO_2W *) pBuffer;
6119 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6120 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6121 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6122 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6124 if ((backend == NULL) && !load_backend()) return FALSE;
6126 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6127 SetLastError(ERROR_INVALID_PARAMETER);
6131 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6134 /******************************************************************************
6135 * AddPrinterConnectionA (WINSPOOL.@)
6137 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6139 FIXME("%s\n", debugstr_a(pName));
6143 /******************************************************************************
6144 * AddPrinterConnectionW (WINSPOOL.@)
6146 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6148 FIXME("%s\n", debugstr_w(pName));
6152 /******************************************************************************
6153 * AddPrinterDriverExW (WINSPOOL.@)
6155 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6158 * pName [I] Servername or NULL (local Computer)
6159 * level [I] Level for the supplied DRIVER_INFO_*W struct
6160 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6161 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6168 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6170 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6172 if ((backend == NULL) && !load_backend()) return FALSE;
6174 if (level < 2 || level == 5 || level == 7 || level > 8) {
6175 SetLastError(ERROR_INVALID_LEVEL);
6180 SetLastError(ERROR_INVALID_PARAMETER);
6184 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6187 /******************************************************************************
6188 * AddPrinterDriverExA (WINSPOOL.@)
6190 * See AddPrinterDriverExW.
6193 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6195 DRIVER_INFO_8A *diA;
6197 LPWSTR nameW = NULL;
6202 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6204 diA = (DRIVER_INFO_8A *) pDriverInfo;
6205 ZeroMemory(&diW, sizeof(diW));
6207 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6208 SetLastError(ERROR_INVALID_LEVEL);
6213 SetLastError(ERROR_INVALID_PARAMETER);
6217 /* convert servername to unicode */
6219 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6220 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6221 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6225 diW.cVersion = diA->cVersion;
6228 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6229 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6230 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6233 if (diA->pEnvironment) {
6234 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6235 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6236 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6239 if (diA->pDriverPath) {
6240 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6241 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6242 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6245 if (diA->pDataFile) {
6246 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6247 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6248 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6251 if (diA->pConfigFile) {
6252 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6253 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6254 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6257 if ((Level > 2) && diA->pDependentFiles) {
6258 lenA = multi_sz_lenA(diA->pDependentFiles);
6259 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6260 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6261 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6264 if ((Level > 2) && diA->pMonitorName) {
6265 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6266 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6267 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6270 if ((Level > 3) && diA->pDefaultDataType) {
6271 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6272 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6273 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6276 if ((Level > 3) && diA->pszzPreviousNames) {
6277 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6278 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6279 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6280 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6283 if ((Level > 5) && diA->pszMfgName) {
6284 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6285 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6286 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6289 if ((Level > 5) && diA->pszOEMUrl) {
6290 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6291 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6292 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6295 if ((Level > 5) && diA->pszHardwareID) {
6296 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6297 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6298 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6301 if ((Level > 5) && diA->pszProvider) {
6302 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6303 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6304 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6308 FIXME("level %u is incomplete\n", Level);
6311 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6312 TRACE("got %u with %u\n", res, GetLastError());
6313 HeapFree(GetProcessHeap(), 0, nameW);
6314 HeapFree(GetProcessHeap(), 0, diW.pName);
6315 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6316 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6317 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6318 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6319 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6320 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6321 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6322 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6323 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6324 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6325 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6326 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6328 TRACE("=> %u with %u\n", res, GetLastError());
6332 /******************************************************************************
6333 * ConfigurePortA (WINSPOOL.@)
6335 * See ConfigurePortW.
6338 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6340 LPWSTR nameW = NULL;
6341 LPWSTR portW = NULL;
6345 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6347 /* convert servername to unicode */
6349 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6350 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6351 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6354 /* convert portname to unicode */
6356 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6357 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6358 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6361 res = ConfigurePortW(nameW, hWnd, portW);
6362 HeapFree(GetProcessHeap(), 0, nameW);
6363 HeapFree(GetProcessHeap(), 0, portW);
6367 /******************************************************************************
6368 * ConfigurePortW (WINSPOOL.@)
6370 * Display the Configuration-Dialog for a specific Port
6373 * pName [I] Servername or NULL (local Computer)
6374 * hWnd [I] Handle to parent Window for the Dialog-Box
6375 * pPortName [I] Name of the Port, that should be configured
6382 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6385 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6387 if ((backend == NULL) && !load_backend()) return FALSE;
6390 SetLastError(RPC_X_NULL_REF_POINTER);
6394 return backend->fpConfigurePort(pName, hWnd, pPortName);
6397 /******************************************************************************
6398 * ConnectToPrinterDlg (WINSPOOL.@)
6400 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6402 FIXME("%p %x\n", hWnd, Flags);
6406 /******************************************************************************
6407 * DeletePrinterConnectionA (WINSPOOL.@)
6409 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6411 FIXME("%s\n", debugstr_a(pName));
6415 /******************************************************************************
6416 * DeletePrinterConnectionW (WINSPOOL.@)
6418 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6420 FIXME("%s\n", debugstr_w(pName));
6424 /******************************************************************************
6425 * DeletePrinterDriverExW (WINSPOOL.@)
6427 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6428 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6433 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6434 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6436 if(pName && pName[0])
6438 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6439 SetLastError(ERROR_INVALID_PARAMETER);
6445 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6446 SetLastError(ERROR_INVALID_PARAMETER);
6450 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6454 ERR("Can't open drivers key\n");
6458 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6461 RegCloseKey(hkey_drivers);
6466 /******************************************************************************
6467 * DeletePrinterDriverExA (WINSPOOL.@)
6469 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6470 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6472 UNICODE_STRING NameW, EnvW, DriverW;
6475 asciitounicode(&NameW, pName);
6476 asciitounicode(&EnvW, pEnvironment);
6477 asciitounicode(&DriverW, pDriverName);
6479 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6481 RtlFreeUnicodeString(&DriverW);
6482 RtlFreeUnicodeString(&EnvW);
6483 RtlFreeUnicodeString(&NameW);
6488 /******************************************************************************
6489 * DeletePrinterDataExW (WINSPOOL.@)
6491 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6494 FIXME("%p %s %s\n", hPrinter,
6495 debugstr_w(pKeyName), debugstr_w(pValueName));
6496 return ERROR_INVALID_PARAMETER;
6499 /******************************************************************************
6500 * DeletePrinterDataExA (WINSPOOL.@)
6502 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6505 FIXME("%p %s %s\n", hPrinter,
6506 debugstr_a(pKeyName), debugstr_a(pValueName));
6507 return ERROR_INVALID_PARAMETER;
6510 /******************************************************************************
6511 * DeletePrintProcessorA (WINSPOOL.@)
6513 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6515 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6516 debugstr_a(pPrintProcessorName));
6520 /******************************************************************************
6521 * DeletePrintProcessorW (WINSPOOL.@)
6523 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6525 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6526 debugstr_w(pPrintProcessorName));
6530 /******************************************************************************
6531 * DeletePrintProvidorA (WINSPOOL.@)
6533 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6535 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6536 debugstr_a(pPrintProviderName));
6540 /******************************************************************************
6541 * DeletePrintProvidorW (WINSPOOL.@)
6543 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6545 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6546 debugstr_w(pPrintProviderName));
6550 /******************************************************************************
6551 * EnumFormsA (WINSPOOL.@)
6553 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6554 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6556 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6557 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6561 /******************************************************************************
6562 * EnumFormsW (WINSPOOL.@)
6564 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6565 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6567 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6568 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6572 /*****************************************************************************
6573 * EnumMonitorsA [WINSPOOL.@]
6575 * See EnumMonitorsW.
6578 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6579 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6582 LPBYTE bufferW = NULL;
6583 LPWSTR nameW = NULL;
6585 DWORD numentries = 0;
6588 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6589 cbBuf, pcbNeeded, pcReturned);
6591 /* convert servername to unicode */
6593 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6594 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6595 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6597 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6598 needed = cbBuf * sizeof(WCHAR);
6599 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6600 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6602 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6603 if (pcbNeeded) needed = *pcbNeeded;
6604 /* HeapReAlloc return NULL, when bufferW was NULL */
6605 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6606 HeapAlloc(GetProcessHeap(), 0, needed);
6608 /* Try again with the large Buffer */
6609 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6611 numentries = pcReturned ? *pcReturned : 0;
6614 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6615 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6618 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6619 DWORD entrysize = 0;
6622 LPMONITOR_INFO_2W mi2w;
6623 LPMONITOR_INFO_2A mi2a;
6625 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6626 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6628 /* First pass: calculate the size for all Entries */
6629 mi2w = (LPMONITOR_INFO_2W) bufferW;
6630 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6632 while (index < numentries) {
6634 needed += entrysize; /* MONITOR_INFO_?A */
6635 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6637 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6638 NULL, 0, NULL, NULL);
6640 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6641 NULL, 0, NULL, NULL);
6642 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6643 NULL, 0, NULL, NULL);
6645 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6646 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6647 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6650 /* check for errors and quit on failure */
6651 if (cbBuf < needed) {
6652 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6656 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6657 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6658 cbBuf -= len ; /* free Bytes in the user-Buffer */
6659 mi2w = (LPMONITOR_INFO_2W) bufferW;
6660 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6662 /* Second Pass: Fill the User Buffer (if we have one) */
6663 while ((index < numentries) && pMonitors) {
6665 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6667 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6668 ptr, cbBuf , NULL, NULL);
6672 mi2a->pEnvironment = ptr;
6673 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6674 ptr, cbBuf, NULL, NULL);
6678 mi2a->pDLLName = ptr;
6679 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6680 ptr, cbBuf, NULL, NULL);
6684 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6685 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6686 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6690 if (pcbNeeded) *pcbNeeded = needed;
6691 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6693 HeapFree(GetProcessHeap(), 0, nameW);
6694 HeapFree(GetProcessHeap(), 0, bufferW);
6696 TRACE("returning %d with %d (%d byte for %d entries)\n",
6697 (res), GetLastError(), needed, numentries);
6703 /*****************************************************************************
6704 * EnumMonitorsW [WINSPOOL.@]
6706 * Enumerate available Port-Monitors
6709 * pName [I] Servername or NULL (local Computer)
6710 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6711 * pMonitors [O] PTR to Buffer that receives the Result
6712 * cbBuf [I] Size of Buffer at pMonitors
6713 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6714 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6718 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6721 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6722 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6725 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6726 cbBuf, pcbNeeded, pcReturned);
6728 if ((backend == NULL) && !load_backend()) return FALSE;
6730 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6731 SetLastError(RPC_X_NULL_REF_POINTER);
6735 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6738 /******************************************************************************
6739 * SpoolerInit (WINSPOOL.@)
6741 * Initialize the Spooler
6748 * The function fails on windows, when the spooler service is not running
6751 BOOL WINAPI SpoolerInit(void)
6754 if ((backend == NULL) && !load_backend()) return FALSE;
6758 /******************************************************************************
6759 * XcvDataW (WINSPOOL.@)
6761 * Execute commands in the Printmonitor DLL
6764 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6765 * pszDataName [i] Name of the command to execute
6766 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6767 * cbInputData [i] Size in Bytes of Buffer at pInputData
6768 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6769 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6770 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6771 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6778 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6779 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6781 * Minimal List of commands, that a Printmonitor DLL should support:
6783 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6784 *| "AddPort" : Add a Port
6785 *| "DeletePort": Delete a Port
6787 * Many Printmonitors support additional commands. Examples for localspl.dll:
6788 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6789 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6792 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6793 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6794 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6796 opened_printer_t *printer;
6798 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6799 pInputData, cbInputData, pOutputData,
6800 cbOutputData, pcbOutputNeeded, pdwStatus);
6802 if ((backend == NULL) && !load_backend()) return FALSE;
6804 printer = get_opened_printer(hXcv);
6805 if (!printer || (!printer->backend_printer)) {
6806 SetLastError(ERROR_INVALID_HANDLE);
6810 if (!pcbOutputNeeded) {
6811 SetLastError(ERROR_INVALID_PARAMETER);
6815 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6816 SetLastError(RPC_X_NULL_REF_POINTER);
6820 *pcbOutputNeeded = 0;
6822 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6823 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6827 /*****************************************************************************
6828 * EnumPrinterDataA [WINSPOOL.@]
6831 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6832 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6833 DWORD cbData, LPDWORD pcbData )
6835 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6836 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6837 return ERROR_NO_MORE_ITEMS;
6840 /*****************************************************************************
6841 * EnumPrinterDataW [WINSPOOL.@]
6844 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6845 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6846 DWORD cbData, LPDWORD pcbData )
6848 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6849 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6850 return ERROR_NO_MORE_ITEMS;
6853 /*****************************************************************************
6854 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6857 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6858 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6859 LPDWORD pcbNeeded, LPDWORD pcReturned)
6861 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6862 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6863 pcbNeeded, pcReturned);
6867 /*****************************************************************************
6868 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6871 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6872 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6873 LPDWORD pcbNeeded, LPDWORD pcReturned)
6875 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6876 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6877 pcbNeeded, pcReturned);
6881 /*****************************************************************************
6882 * EnumPrintProcessorsA [WINSPOOL.@]
6884 * See EnumPrintProcessorsW.
6887 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6888 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6891 LPBYTE bufferW = NULL;
6892 LPWSTR nameW = NULL;
6895 DWORD numentries = 0;
6898 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6899 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6901 /* convert names to unicode */
6903 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6904 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6905 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6908 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6909 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6910 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6913 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6914 needed = cbBuf * sizeof(WCHAR);
6915 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6916 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6918 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6919 if (pcbNeeded) needed = *pcbNeeded;
6920 /* HeapReAlloc return NULL, when bufferW was NULL */
6921 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6922 HeapAlloc(GetProcessHeap(), 0, needed);
6924 /* Try again with the large Buffer */
6925 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6927 numentries = pcReturned ? *pcReturned : 0;
6931 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6934 PPRINTPROCESSOR_INFO_1W ppiw;
6935 PPRINTPROCESSOR_INFO_1A ppia;
6937 /* First pass: calculate the size for all Entries */
6938 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6939 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6941 while (index < numentries) {
6943 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6944 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6946 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6947 NULL, 0, NULL, NULL);
6949 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6950 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6953 /* check for errors and quit on failure */
6954 if (cbBuf < needed) {
6955 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6960 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6961 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6962 cbBuf -= len ; /* free Bytes in the user-Buffer */
6963 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6964 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6966 /* Second Pass: Fill the User Buffer (if we have one) */
6967 while ((index < numentries) && pPPInfo) {
6969 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6971 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6972 ptr, cbBuf , NULL, NULL);
6976 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6977 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6982 if (pcbNeeded) *pcbNeeded = needed;
6983 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6985 HeapFree(GetProcessHeap(), 0, nameW);
6986 HeapFree(GetProcessHeap(), 0, envW);
6987 HeapFree(GetProcessHeap(), 0, bufferW);
6989 TRACE("returning %d with %d (%d byte for %d entries)\n",
6990 (res), GetLastError(), needed, numentries);
6995 /*****************************************************************************
6996 * EnumPrintProcessorsW [WINSPOOL.@]
6998 * Enumerate available Print Processors
7001 * pName [I] Servername or NULL (local Computer)
7002 * pEnvironment [I] Printing-Environment or NULL (Default)
7003 * Level [I] Structure-Level (Only 1 is allowed)
7004 * pPPInfo [O] PTR to Buffer that receives the Result
7005 * cbBuf [I] Size of Buffer at pPPInfo
7006 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7007 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7011 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7014 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7015 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7018 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7019 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7021 if ((backend == NULL) && !load_backend()) return FALSE;
7023 if (!pcbNeeded || !pcReturned) {
7024 SetLastError(RPC_X_NULL_REF_POINTER);
7028 if (!pPPInfo && (cbBuf > 0)) {
7029 SetLastError(ERROR_INVALID_USER_BUFFER);
7033 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7034 cbBuf, pcbNeeded, pcReturned);
7037 /*****************************************************************************
7038 * ExtDeviceMode [WINSPOOL.@]
7041 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7042 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7045 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7046 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7047 debugstr_a(pProfile), fMode);
7051 /*****************************************************************************
7052 * FindClosePrinterChangeNotification [WINSPOOL.@]
7055 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7057 FIXME("Stub: %p\n", hChange);
7061 /*****************************************************************************
7062 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7065 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7066 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7068 FIXME("Stub: %p %x %x %p\n",
7069 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7070 return INVALID_HANDLE_VALUE;
7073 /*****************************************************************************
7074 * FindNextPrinterChangeNotification [WINSPOOL.@]
7077 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7078 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7080 FIXME("Stub: %p %p %p %p\n",
7081 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7085 /*****************************************************************************
7086 * FreePrinterNotifyInfo [WINSPOOL.@]
7089 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7091 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7095 /*****************************************************************************
7098 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7099 * ansi depending on the unicode parameter.
7101 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7111 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7114 memcpy(ptr, str, *size);
7121 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7124 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7131 /*****************************************************************************
7134 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7135 LPDWORD pcbNeeded, BOOL unicode)
7137 DWORD size, left = cbBuf;
7138 BOOL space = (cbBuf > 0);
7145 ji1->JobId = job->job_id;
7148 string_to_buf(job->document_title, ptr, left, &size, unicode);
7149 if(space && size <= left)
7151 ji1->pDocument = (LPWSTR)ptr;
7159 if (job->printer_name)
7161 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7162 if(space && size <= left)
7164 ji1->pPrinterName = (LPWSTR)ptr;
7176 /*****************************************************************************
7179 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7180 LPDWORD pcbNeeded, BOOL unicode)
7182 DWORD size, left = cbBuf;
7184 BOOL space = (cbBuf > 0);
7193 ji2->JobId = job->job_id;
7196 string_to_buf(job->document_title, ptr, left, &size, unicode);
7197 if(space && size <= left)
7199 ji2->pDocument = (LPWSTR)ptr;
7207 if (job->printer_name)
7209 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7210 if(space && size <= left)
7212 ji2->pPrinterName = (LPWSTR)ptr;
7225 dmA = DEVMODEdupWtoA(job->devmode);
7226 devmode = (LPDEVMODEW) dmA;
7227 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7231 devmode = job->devmode;
7232 size = devmode->dmSize + devmode->dmDriverExtra;
7236 FIXME("Can't convert DEVMODE W to A\n");
7239 /* align DEVMODE to a DWORD boundary */
7240 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7246 memcpy(ptr, devmode, size-shift);
7247 ji2->pDevMode = (LPDEVMODEW)ptr;
7248 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7261 /*****************************************************************************
7264 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7265 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7268 DWORD needed = 0, size;
7272 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7274 EnterCriticalSection(&printer_handles_cs);
7275 job = get_job(hPrinter, JobId);
7282 size = sizeof(JOB_INFO_1W);
7287 memset(pJob, 0, size);
7291 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7296 size = sizeof(JOB_INFO_2W);
7301 memset(pJob, 0, size);
7305 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7310 size = sizeof(JOB_INFO_3);
7314 memset(pJob, 0, size);
7323 SetLastError(ERROR_INVALID_LEVEL);
7327 *pcbNeeded = needed;
7329 LeaveCriticalSection(&printer_handles_cs);
7333 /*****************************************************************************
7334 * GetJobA [WINSPOOL.@]
7337 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7338 DWORD cbBuf, LPDWORD pcbNeeded)
7340 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7343 /*****************************************************************************
7344 * GetJobW [WINSPOOL.@]
7347 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7348 DWORD cbBuf, LPDWORD pcbNeeded)
7350 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7353 /*****************************************************************************
7356 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7358 char *unixname, *queue, *cmd;
7359 char fmt[] = "lpr -P'%s' '%s'";
7363 if(!(unixname = wine_get_unix_file_name(filename)))
7366 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7367 queue = HeapAlloc(GetProcessHeap(), 0, len);
7368 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7370 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7371 sprintf(cmd, fmt, queue, unixname);
7373 TRACE("printing with: %s\n", cmd);
7376 HeapFree(GetProcessHeap(), 0, cmd);
7377 HeapFree(GetProcessHeap(), 0, queue);
7378 HeapFree(GetProcessHeap(), 0, unixname);
7382 /*****************************************************************************
7385 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7387 #ifdef SONAME_LIBCUPS
7390 char *unixname, *queue, *unix_doc_title;
7394 if(!(unixname = wine_get_unix_file_name(filename)))
7397 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7398 queue = HeapAlloc(GetProcessHeap(), 0, len);
7399 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7401 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7402 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7403 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7405 TRACE("printing via cups\n");
7406 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7407 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7408 HeapFree(GetProcessHeap(), 0, queue);
7409 HeapFree(GetProcessHeap(), 0, unixname);
7415 return schedule_lpr(printer_name, filename);
7419 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7426 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7430 if(HIWORD(wparam) == BN_CLICKED)
7432 if(LOWORD(wparam) == IDOK)
7435 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7438 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7439 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7441 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7443 WCHAR caption[200], message[200];
7446 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7447 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7448 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7449 if(mb_ret == IDCANCEL)
7451 HeapFree(GetProcessHeap(), 0, filename);
7455 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7456 if(hf == INVALID_HANDLE_VALUE)
7458 WCHAR caption[200], message[200];
7460 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7461 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7462 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7463 HeapFree(GetProcessHeap(), 0, filename);
7467 DeleteFileW(filename);
7468 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7470 EndDialog(hwnd, IDOK);
7473 if(LOWORD(wparam) == IDCANCEL)
7475 EndDialog(hwnd, IDCANCEL);
7484 /*****************************************************************************
7487 static BOOL get_filename(LPWSTR *filename)
7489 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7490 file_dlg_proc, (LPARAM)filename) == IDOK;
7493 /*****************************************************************************
7496 static BOOL schedule_file(LPCWSTR filename)
7498 LPWSTR output = NULL;
7500 if(get_filename(&output))
7503 TRACE("copy to %s\n", debugstr_w(output));
7504 r = CopyFileW(filename, output, FALSE);
7505 HeapFree(GetProcessHeap(), 0, output);
7511 /*****************************************************************************
7514 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7517 char *unixname, *cmdA;
7519 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7523 if(!(unixname = wine_get_unix_file_name(filename)))
7526 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7527 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7528 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7530 TRACE("printing with: %s\n", cmdA);
7532 if((file_fd = open(unixname, O_RDONLY)) == -1)
7537 ERR("pipe() failed!\n");
7547 /* reset signals that we previously set to SIG_IGN */
7548 signal(SIGPIPE, SIG_DFL);
7549 signal(SIGCHLD, SIG_DFL);
7551 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7555 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7556 write(fds[1], buf, no_read);
7561 if(file_fd != -1) close(file_fd);
7562 if(fds[0] != -1) close(fds[0]);
7563 if(fds[1] != -1) close(fds[1]);
7565 HeapFree(GetProcessHeap(), 0, cmdA);
7566 HeapFree(GetProcessHeap(), 0, unixname);
7573 /*****************************************************************************
7576 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7578 int in_fd, out_fd, no_read;
7581 char *unixname, *outputA;
7584 if(!(unixname = wine_get_unix_file_name(filename)))
7587 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7588 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7589 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7591 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7592 in_fd = open(unixname, O_RDONLY);
7593 if(out_fd == -1 || in_fd == -1)
7596 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7597 write(out_fd, buf, no_read);
7601 if(in_fd != -1) close(in_fd);
7602 if(out_fd != -1) close(out_fd);
7603 HeapFree(GetProcessHeap(), 0, outputA);
7604 HeapFree(GetProcessHeap(), 0, unixname);
7608 /*****************************************************************************
7609 * ScheduleJob [WINSPOOL.@]
7612 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7614 opened_printer_t *printer;
7616 struct list *cursor, *cursor2;
7618 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7619 EnterCriticalSection(&printer_handles_cs);
7620 printer = get_opened_printer(hPrinter);
7624 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7626 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7629 if(job->job_id != dwJobID) continue;
7631 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7632 if(hf != INVALID_HANDLE_VALUE)
7634 PRINTER_INFO_5W *pi5 = NULL;
7635 LPWSTR portname = job->portname;
7639 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7640 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7644 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7645 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7646 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7647 portname = pi5->pPortName;
7649 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7650 debugstr_w(portname));
7654 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7655 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7657 DWORD type, count = sizeof(output);
7658 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7661 if(output[0] == '|')
7663 ret = schedule_pipe(output + 1, job->filename);
7667 ret = schedule_unixfile(output, job->filename);
7669 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7671 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7673 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7675 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7677 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7679 ret = schedule_file(job->filename);
7683 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7685 HeapFree(GetProcessHeap(), 0, pi5);
7687 DeleteFileW(job->filename);
7689 list_remove(cursor);
7690 HeapFree(GetProcessHeap(), 0, job->document_title);
7691 HeapFree(GetProcessHeap(), 0, job->printer_name);
7692 HeapFree(GetProcessHeap(), 0, job->portname);
7693 HeapFree(GetProcessHeap(), 0, job->filename);
7694 HeapFree(GetProcessHeap(), 0, job->devmode);
7695 HeapFree(GetProcessHeap(), 0, job);
7699 LeaveCriticalSection(&printer_handles_cs);
7703 /*****************************************************************************
7704 * StartDocDlgA [WINSPOOL.@]
7706 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7708 UNICODE_STRING usBuffer;
7711 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7714 docW.cbSize = sizeof(docW);
7715 if (doc->lpszDocName)
7717 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7718 if (!(docW.lpszDocName = docnameW)) return NULL;
7720 if (doc->lpszOutput)
7722 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7723 if (!(docW.lpszOutput = outputW)) return NULL;
7725 if (doc->lpszDatatype)
7727 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7728 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7730 docW.fwType = doc->fwType;
7732 retW = StartDocDlgW(hPrinter, &docW);
7736 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7737 ret = HeapAlloc(GetProcessHeap(), 0, len);
7738 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7739 HeapFree(GetProcessHeap(), 0, retW);
7742 HeapFree(GetProcessHeap(), 0, datatypeW);
7743 HeapFree(GetProcessHeap(), 0, outputW);
7744 HeapFree(GetProcessHeap(), 0, docnameW);
7749 /*****************************************************************************
7750 * StartDocDlgW [WINSPOOL.@]
7752 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7753 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7754 * port is "FILE:". Also returns the full path if passed a relative path.
7756 * The caller should free the returned string from the process heap.
7758 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7763 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7765 PRINTER_INFO_5W *pi5;
7766 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7767 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7769 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7770 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7771 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7773 HeapFree(GetProcessHeap(), 0, pi5);
7776 HeapFree(GetProcessHeap(), 0, pi5);
7779 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7783 if (get_filename(&name))
7785 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7787 HeapFree(GetProcessHeap(), 0, name);
7790 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7791 GetFullPathNameW(name, len, ret, NULL);
7792 HeapFree(GetProcessHeap(), 0, name);
7797 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7800 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7801 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7803 attr = GetFileAttributesW(ret);
7804 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7806 HeapFree(GetProcessHeap(), 0, ret);