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, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
64 #include "ddk/winsplp.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
69 /* ############################### */
71 static CRITICAL_SECTION monitor_handles_cs;
72 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
74 0, 0, &monitor_handles_cs,
75 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
76 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
78 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
81 static CRITICAL_SECTION printer_handles_cs;
82 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
84 0, 0, &printer_handles_cs,
85 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
88 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
90 /* ############################### */
123 WCHAR *document_title;
131 LPCWSTR versionregpath;
132 LPCWSTR versionsubdir;
135 /* ############################### */
137 static struct list monitor_handles = LIST_INIT( monitor_handles );
139 static opened_printer_t **printer_handles;
140 static int nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
185 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
186 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
187 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
188 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
189 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
190 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
192 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
193 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
195 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
196 'i','o','n',' ','F','i','l','e',0};
197 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
198 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
199 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
201 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
203 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
204 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
205 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
206 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
207 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
208 static const WCHAR NameW[] = {'N','a','m','e',0};
209 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
210 static const WCHAR PortW[] = {'P','o','r','t',0};
211 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
213 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
215 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
216 'v','e','r','D','a','t','a',0};
217 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
219 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
220 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
221 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
222 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
223 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
224 static const WCHAR emptyStringW[] = {0};
226 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
228 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
229 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
230 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
232 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
233 'D','o','c','u','m','e','n','t',0};
235 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
236 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
237 DWORD Level, LPBYTE pDriverInfo,
238 DWORD cbBuf, LPDWORD pcbNeeded,
240 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
241 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
243 /******************************************************************
244 * validate the user-supplied printing-environment [internal]
247 * env [I] PTR to Environment-String or NULL
251 * Success: PTR to printenv_t
254 * An empty string is handled the same way as NULL.
255 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
259 static const printenv_t * validate_envW(LPCWSTR env)
261 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
262 3, Version3_RegPathW, Version3_SubdirW};
263 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
264 0, emptyStringW, emptyStringW};
265 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
267 const printenv_t *result = NULL;
270 TRACE("testing %s\n", debugstr_w(env));
273 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
275 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
277 result = all_printenv[i];
282 if (result == NULL) {
283 FIXME("unsupported Environment: %s\n", debugstr_w(env));
284 SetLastError(ERROR_INVALID_ENVIRONMENT);
286 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
290 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
292 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
298 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
299 if passed a NULL string. This returns NULLs to the result.
301 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
305 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
306 return usBufferPtr->Buffer;
308 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
312 static LPWSTR strdupW(LPCWSTR p)
318 len = (strlenW(p) + 1) * sizeof(WCHAR);
319 ret = HeapAlloc(GetProcessHeap(), 0, len);
325 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
328 /* If forcing, or no profile string entry for device yet, set the entry
330 * The always change entry if not WINEPS yet is discussable.
333 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
335 !strstr(qbuf,"WINEPS.DRV")
337 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
340 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
341 WriteProfileStringA("windows","device",buf);
342 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
343 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
346 HeapFree(GetProcessHeap(),0,buf);
350 #ifdef HAVE_CUPS_CUPS_H
351 static typeof(cupsGetDests) *pcupsGetDests;
352 static typeof(cupsGetPPD) *pcupsGetPPD;
353 static typeof(cupsPrintFile) *pcupsPrintFile;
354 static void *cupshandle;
356 static BOOL CUPS_LoadPrinters(void)
359 BOOL hadprinter = FALSE;
361 PRINTER_INFO_2A pinfo2a;
363 HKEY hkeyPrinter, hkeyPrinters, hkey;
365 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
368 TRACE("loaded %s\n", SONAME_LIBCUPS);
371 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
372 if (!p##x) return FALSE;
375 DYNCUPS(cupsGetDests);
376 DYNCUPS(cupsPrintFile);
379 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
381 ERR("Can't create Printers key\n");
385 nrofdests = pcupsGetDests(&dests);
386 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
387 for (i=0;i<nrofdests;i++) {
388 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
389 sprintf(port,"LPR:%s",dests[i].name);
390 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
391 sprintf(devline,"WINEPS.DRV,%s",port);
392 WriteProfileStringA("devices",dests[i].name,devline);
393 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
394 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
397 HeapFree(GetProcessHeap(),0,devline);
399 TRACE("Printer %d: %s\n", i, dests[i].name);
400 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
401 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
403 TRACE("Printer already exists\n");
404 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
405 RegCloseKey(hkeyPrinter);
407 static CHAR data_type[] = "RAW",
408 print_proc[] = "WinPrint",
409 driver_name[] = "PS Driver",
410 comment[] = "WINEPS Printer using CUPS",
411 location[] = "<physical location of printer>",
412 params[] = "<parameters?>",
413 share_name[] = "<share name?>",
414 sep_file[] = "<sep file?>";
416 memset(&pinfo2a,0,sizeof(pinfo2a));
417 pinfo2a.pPrinterName = dests[i].name;
418 pinfo2a.pDatatype = data_type;
419 pinfo2a.pPrintProcessor = print_proc;
420 pinfo2a.pDriverName = driver_name;
421 pinfo2a.pComment = comment;
422 pinfo2a.pLocation = location;
423 pinfo2a.pPortName = port;
424 pinfo2a.pParameters = params;
425 pinfo2a.pShareName = share_name;
426 pinfo2a.pSepFile = sep_file;
428 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
429 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
430 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
433 HeapFree(GetProcessHeap(),0,port);
436 if (dests[i].is_default)
437 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
439 RegCloseKey(hkeyPrinters);
445 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
446 PRINTER_INFO_2A pinfo2a;
447 char *e,*s,*name,*prettyname,*devname;
448 BOOL ret = FALSE, set_default = FALSE;
449 char *port,*devline,*env_default;
450 HKEY hkeyPrinter, hkeyPrinters, hkey;
452 while (isspace(*pent)) pent++;
453 s = strchr(pent,':');
455 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
463 TRACE("name=%s entry=%s\n",name, pent);
465 if(ispunct(*name)) { /* a tc entry, not a real printer */
466 TRACE("skipping tc entry\n");
470 if(strstr(pent,":server")) { /* server only version so skip */
471 TRACE("skipping server entry\n");
475 /* Determine whether this is a postscript printer. */
478 env_default = getenv("PRINTER");
480 /* Get longest name, usually the one at the right for later display. */
481 while((s=strchr(prettyname,'|'))) {
484 while(isspace(*--e)) *e = '\0';
485 TRACE("\t%s\n", debugstr_a(prettyname));
486 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
487 for(prettyname = s+1; isspace(*prettyname); prettyname++)
490 e = prettyname + strlen(prettyname);
491 while(isspace(*--e)) *e = '\0';
492 TRACE("\t%s\n", debugstr_a(prettyname));
493 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
495 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
496 * if it is too long, we use it as comment below. */
497 devname = prettyname;
498 if (strlen(devname)>=CCHDEVICENAME-1)
500 if (strlen(devname)>=CCHDEVICENAME-1) {
505 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
506 sprintf(port,"LPR:%s",name);
508 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
509 sprintf(devline,"WINEPS.DRV,%s",port);
510 WriteProfileStringA("devices",devname,devline);
511 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
512 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
515 HeapFree(GetProcessHeap(),0,devline);
517 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
519 ERR("Can't create Printers key\n");
523 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
524 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
526 TRACE("Printer already exists\n");
527 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
528 RegCloseKey(hkeyPrinter);
530 static CHAR data_type[] = "RAW",
531 print_proc[] = "WinPrint",
532 driver_name[] = "PS Driver",
533 comment[] = "WINEPS Printer using LPR",
534 params[] = "<parameters?>",
535 share_name[] = "<share name?>",
536 sep_file[] = "<sep file?>";
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = devname;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = driver_name;
543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = prettyname;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
555 RegCloseKey(hkeyPrinters);
557 if (isfirst || set_default)
558 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
560 HeapFree(GetProcessHeap(), 0, port);
562 HeapFree(GetProcessHeap(), 0, name);
567 PRINTCAP_LoadPrinters(void) {
568 BOOL hadprinter = FALSE;
572 BOOL had_bash = FALSE;
574 f = fopen("/etc/printcap","r");
578 while(fgets(buf,sizeof(buf),f)) {
581 end=strchr(buf,'\n');
585 while(isspace(*start)) start++;
586 if(*start == '#' || *start == '\0')
589 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
590 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
591 HeapFree(GetProcessHeap(),0,pent);
595 if (end && *--end == '\\') {
602 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
605 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
611 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
612 HeapFree(GetProcessHeap(),0,pent);
618 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
621 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
622 lstrlenW(value) * sizeof(WCHAR));
624 return ERROR_FILE_NOT_FOUND;
627 void WINSPOOL_LoadSystemPrinters(void)
629 HKEY hkey, hkeyPrinters;
632 DWORD needed, num, i;
633 WCHAR PrinterName[256];
635 static CHAR name[] = "PS Driver",
636 driver_path[] = "wineps16",
637 data_file[] = "<datafile?>",
638 config_file[] = "wineps16",
639 help_file[] = "<helpfile?>",
640 dep_file[] = "<dependend files?>",
641 monitor_name[] = "<monitor name?>",
642 default_data_type[] = "RAW";
644 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
646 di3a.pEnvironment = NULL; /* NULL means auto */
647 di3a.pDriverPath = driver_path;
648 di3a.pDataFile = data_file;
649 di3a.pConfigFile = config_file;
650 di3a.pHelpFile = help_file;
651 di3a.pDependentFiles = dep_file;
652 di3a.pMonitorName = monitor_name;
653 di3a.pDefaultDataType = default_data_type;
655 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
656 ERR("Failed adding PS Driver (%d)\n",GetLastError());
660 /* This ensures that all printer entries have a valid Name value. If causes
661 problems later if they don't. If one is found to be missed we create one
662 and set it equal to the name of the key */
663 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
664 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
665 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
666 for(i = 0; i < num; i++) {
667 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
668 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
669 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
670 set_reg_szW(hkey, NameW, PrinterName);
677 RegCloseKey(hkeyPrinters);
680 /* We want to avoid calling AddPrinter on printers as much as
681 possible, because on cups printers this will (eventually) lead
682 to a call to cupsGetPPD which takes forever, even with non-cups
683 printers AddPrinter takes a while. So we'll tag all printers that
684 were automatically added last time around, if they still exist
685 we'll leave them be otherwise we'll delete them. */
686 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
688 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
689 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
690 for(i = 0; i < num; i++) {
691 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
692 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
693 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
695 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
703 HeapFree(GetProcessHeap(), 0, pi);
707 #ifdef HAVE_CUPS_CUPS_H
708 done = CUPS_LoadPrinters();
711 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
712 /* Check for [ppd] section in config file before parsing /etc/printcap */
713 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
714 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
715 &hkey) == ERROR_SUCCESS) {
717 PRINTCAP_LoadPrinters();
721 /* Now enumerate the list again and delete any printers that a still tagged */
722 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
724 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
725 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
726 for(i = 0; i < num; i++) {
727 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
728 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
729 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
730 DWORD dw, type, size = sizeof(dw);
731 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
732 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
742 HeapFree(GetProcessHeap(), 0, pi);
749 /*****************************************************************************
750 * enumerate the local monitors (INTERNAL)
752 * returns the needed size (in bytes) for pMonitors
753 * and *lpreturned is set to number of entries returned in pMonitors
756 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
761 LPMONITOR_INFO_2W mi;
762 WCHAR buffer[MAX_PATH];
763 WCHAR dllname[MAX_PATH];
771 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
773 numentries = *lpreturned; /* this is 0, when we scan the registry */
774 len = entrysize * numentries;
775 ptr = (LPWSTR) &pMonitors[len];
778 len = sizeof(buffer);
781 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
782 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
783 /* Scan all Monitor-Registry-Keys */
784 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
785 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
786 dllsize = sizeof(dllname);
789 /* The Monitor must have a Driver-DLL */
790 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
791 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
792 /* We found a valid DLL for this Monitor. */
793 TRACE("using Driver: %s\n", debugstr_w(dllname));
798 /* Windows returns only Port-Monitors here, but to simplify our code,
799 we do no filtering for Language-Monitors */
803 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
805 /* we install and return only monitors for "Windows NT x86" */
806 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
810 /* required size is calculated. Now fill the user-buffer */
811 if (pMonitors && (cbBuf >= needed)){
812 mi = (LPMONITOR_INFO_2W) pMonitors;
813 pMonitors += entrysize;
815 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
817 lstrcpyW(ptr, buffer); /* Name of the Monitor */
818 ptr += (len+1); /* len is lstrlenW(monitorname) */
820 mi->pEnvironment = ptr;
821 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
822 ptr += (lstrlenW(envname_x86W)+1);
825 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
826 ptr += (dllsize / sizeof(WCHAR));
831 len = sizeof(buffer);
836 *lpreturned = numentries;
837 TRACE("need %d byte for %d entries\n", needed, numentries);
841 /******************************************************************
842 * monitor_unload [internal]
844 * release a printmonitor and unload it from memory, when needed
847 static void monitor_unload(monitor_t * pm)
849 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
851 EnterCriticalSection(&monitor_handles_cs);
853 if (pm->refcount) pm->refcount--;
855 if (pm->refcount == 0) {
856 list_remove(&pm->entry);
857 FreeLibrary(pm->hdll);
858 HeapFree(GetProcessHeap(), 0, pm->name);
859 HeapFree(GetProcessHeap(), 0, pm->dllname);
860 HeapFree(GetProcessHeap(), 0, pm);
862 LeaveCriticalSection(&monitor_handles_cs);
865 /******************************************************************
866 * monitor_load [internal]
868 * load a printmonitor, get the dllname from the registry, when needed
869 * initialize the monitor and dump found function-pointers
871 * On failure, SetLastError() is called and NULL is returned
874 static monitor_t * monitor_load(LPWSTR name, LPWSTR dllname)
876 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
877 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
878 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
879 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
880 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
882 monitor_t * pm = NULL;
884 LPWSTR regroot = NULL;
885 LPWSTR driver = dllname;
887 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
888 /* Is the Monitor already loaded? */
889 EnterCriticalSection(&monitor_handles_cs);
891 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
893 if (lstrcmpW(name, cursor->name) == 0) {
900 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
901 if (pm == NULL) goto cleanup;
902 list_add_tail(&monitor_handles, &pm->entry);
906 if (pm->name == NULL) {
907 /* Load the monitor */
908 LPMONITOREX pmonitorEx;
911 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
912 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
915 lstrcpyW(regroot, MonitorsW);
916 lstrcatW(regroot, name);
917 /* Get the Driver from the Registry */
920 pm->name = strdupW(name);
921 pm->dllname = strdupW(driver);
923 if (!regroot || !pm->name || !pm->dllname) {
925 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
930 pm->hdll = LoadLibraryW(driver);
931 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
933 if (pm->hdll == NULL) {
935 SetLastError(ERROR_MOD_NOT_FOUND);
940 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
941 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
942 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
943 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
944 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
947 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
948 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
949 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
950 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
951 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
953 if (pInitializePrintMonitorUI != NULL) {
954 pm->monitorUI = pInitializePrintMonitorUI();
955 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
957 TRACE( "0x%08x: dwMonitorSize (%d)\n",
958 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
963 if (pInitializePrintMonitor != NULL) {
964 pmonitorEx = pInitializePrintMonitor(regroot);
965 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
966 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
969 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
970 pm->monitor = &(pmonitorEx->Monitor);
975 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
980 if (pInitializePrintMonitor2 != NULL) {
981 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
983 if (pInitializeMonitorEx != NULL) {
984 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
986 if (pInitializeMonitor != NULL) {
987 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
990 if (!pm->monitor && !pm->monitorUI) {
992 SetLastError(ERROR_PROC_NOT_FOUND);
997 LeaveCriticalSection(&monitor_handles_cs);
998 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
999 HeapFree(GetProcessHeap(), 0, regroot);
1000 TRACE("=> %p\n", pm);
1004 /******************************************************************
1005 * get_opened_printer_entry
1006 * Get the first place empty in the opened printer table
1009 * - pDefault is ignored
1011 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1013 UINT_PTR handle = nb_printer_handles, i;
1014 jobqueue_t *queue = NULL;
1015 opened_printer_t *printer = NULL;
1017 EnterCriticalSection(&printer_handles_cs);
1019 for (i = 0; i < nb_printer_handles; i++)
1021 if (!printer_handles[i])
1023 if(handle == nb_printer_handles)
1028 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1029 queue = printer_handles[i]->queue;
1033 if (handle >= nb_printer_handles)
1035 opened_printer_t **new_array;
1036 if (printer_handles)
1037 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1038 (nb_printer_handles + 16) * sizeof(*new_array) );
1040 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1041 (nb_printer_handles + 16) * sizeof(*new_array) );
1048 printer_handles = new_array;
1049 nb_printer_handles += 16;
1052 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1059 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
1060 if (!printer->name) {
1064 strcpyW(printer->name, name);
1068 printer->queue = queue;
1071 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1072 if (!printer->queue) {
1076 list_init(&printer->queue->jobs);
1077 printer->queue->ref = 0;
1079 InterlockedIncrement(&printer->queue->ref);
1081 printer_handles[handle] = printer;
1084 LeaveCriticalSection(&printer_handles_cs);
1085 if (!handle && printer) {
1086 /* Something Failed: Free the Buffers */
1087 HeapFree(GetProcessHeap(), 0, printer->name);
1088 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1089 HeapFree(GetProcessHeap(), 0, printer);
1092 return (HANDLE)handle;
1095 /******************************************************************
1096 * get_opened_printer
1097 * Get the pointer to the opened printer referred by the handle
1099 static opened_printer_t *get_opened_printer(HANDLE hprn)
1101 UINT_PTR idx = (UINT_PTR)hprn;
1102 opened_printer_t *ret = NULL;
1104 EnterCriticalSection(&printer_handles_cs);
1106 if ((idx <= 0) || (idx > nb_printer_handles))
1109 ret = printer_handles[idx - 1];
1111 LeaveCriticalSection(&printer_handles_cs);
1115 /******************************************************************
1116 * get_opened_printer_name
1117 * Get the pointer to the opened printer name referred by the handle
1119 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1121 opened_printer_t *printer = get_opened_printer(hprn);
1122 if(!printer) return NULL;
1123 return printer->name;
1126 /******************************************************************
1127 * WINSPOOL_GetOpenedPrinterRegKey
1130 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1132 LPCWSTR name = get_opened_printer_name(hPrinter);
1136 if(!name) return ERROR_INVALID_HANDLE;
1138 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1142 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1144 ERR("Can't find opened printer %s in registry\n",
1146 RegCloseKey(hkeyPrinters);
1147 return ERROR_INVALID_PRINTER_NAME; /* ? */
1149 RegCloseKey(hkeyPrinters);
1150 return ERROR_SUCCESS;
1153 /******************************************************************
1156 * Get the pointer to the specified job.
1157 * Should hold the printer_handles_cs before calling.
1159 static job_t *get_job(HANDLE hprn, DWORD JobId)
1161 opened_printer_t *printer = get_opened_printer(hprn);
1164 if(!printer) return NULL;
1165 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1167 if(job->job_id == JobId)
1173 /***********************************************************
1176 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1179 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1182 Formname = (dmA->dmSize > off_formname);
1183 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1184 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1185 dmW->dmDeviceName, CCHDEVICENAME);
1187 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1188 dmA->dmSize - CCHDEVICENAME);
1190 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1191 off_formname - CCHDEVICENAME);
1192 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1193 dmW->dmFormName, CCHFORMNAME);
1194 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1195 (off_formname + CCHFORMNAME));
1198 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1199 dmA->dmDriverExtra);
1203 /***********************************************************
1205 * Creates an ascii copy of supplied devmode on heap
1207 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1212 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1214 if(!dmW) return NULL;
1215 Formname = (dmW->dmSize > off_formname);
1216 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1217 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1218 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1219 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1221 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1222 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1224 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1225 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1226 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1227 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1228 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1229 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1232 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1233 dmW->dmDriverExtra);
1237 /***********************************************************
1238 * PRINTER_INFO_2AtoW
1239 * Creates a unicode copy of PRINTER_INFO_2A on heap
1241 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1243 LPPRINTER_INFO_2W piW;
1244 UNICODE_STRING usBuffer;
1246 if(!piA) return NULL;
1247 piW = HeapAlloc(heap, 0, sizeof(*piW));
1248 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1250 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1251 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1252 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1253 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1254 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1255 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1256 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1257 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1258 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1259 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1260 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1261 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1265 /***********************************************************
1266 * FREE_PRINTER_INFO_2W
1267 * Free PRINTER_INFO_2W and all strings
1269 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1273 HeapFree(heap,0,piW->pServerName);
1274 HeapFree(heap,0,piW->pPrinterName);
1275 HeapFree(heap,0,piW->pShareName);
1276 HeapFree(heap,0,piW->pPortName);
1277 HeapFree(heap,0,piW->pDriverName);
1278 HeapFree(heap,0,piW->pComment);
1279 HeapFree(heap,0,piW->pLocation);
1280 HeapFree(heap,0,piW->pDevMode);
1281 HeapFree(heap,0,piW->pSepFile);
1282 HeapFree(heap,0,piW->pPrintProcessor);
1283 HeapFree(heap,0,piW->pDatatype);
1284 HeapFree(heap,0,piW->pParameters);
1285 HeapFree(heap,0,piW);
1289 /******************************************************************
1290 * DeviceCapabilities [WINSPOOL.@]
1291 * DeviceCapabilitiesA [WINSPOOL.@]
1294 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1295 LPSTR pOutput, LPDEVMODEA lpdm)
1299 if (!GDI_CallDeviceCapabilities16)
1301 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1303 if (!GDI_CallDeviceCapabilities16) return -1;
1305 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1307 /* If DC_PAPERSIZE map POINT16s to POINTs */
1308 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1309 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1310 POINT *pt = (POINT *)pOutput;
1312 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1313 for(i = 0; i < ret; i++, pt++)
1318 HeapFree( GetProcessHeap(), 0, tmp );
1324 /*****************************************************************************
1325 * DeviceCapabilitiesW [WINSPOOL.@]
1327 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1330 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1331 WORD fwCapability, LPWSTR pOutput,
1332 const DEVMODEW *pDevMode)
1334 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1335 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1336 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1339 if(pOutput && (fwCapability == DC_BINNAMES ||
1340 fwCapability == DC_FILEDEPENDENCIES ||
1341 fwCapability == DC_PAPERNAMES)) {
1342 /* These need A -> W translation */
1345 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1349 switch(fwCapability) {
1354 case DC_FILEDEPENDENCIES:
1358 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1359 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1361 for(i = 0; i < ret; i++)
1362 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1363 pOutput + (i * size), size);
1364 HeapFree(GetProcessHeap(), 0, pOutputA);
1366 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1367 (LPSTR)pOutput, dmA);
1369 HeapFree(GetProcessHeap(),0,pPortA);
1370 HeapFree(GetProcessHeap(),0,pDeviceA);
1371 HeapFree(GetProcessHeap(),0,dmA);
1375 /******************************************************************
1376 * DocumentPropertiesA [WINSPOOL.@]
1378 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1380 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1381 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1382 LPDEVMODEA pDevModeInput,DWORD fMode )
1384 LPSTR lpName = pDeviceName;
1385 static CHAR port[] = "LPT1:";
1388 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1389 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1393 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1395 ERR("no name from hPrinter?\n");
1396 SetLastError(ERROR_INVALID_HANDLE);
1399 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1402 if (!GDI_CallExtDeviceMode16)
1404 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1406 if (!GDI_CallExtDeviceMode16) {
1407 ERR("No CallExtDeviceMode16?\n");
1411 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1412 pDevModeInput, NULL, fMode);
1415 HeapFree(GetProcessHeap(),0,lpName);
1420 /*****************************************************************************
1421 * DocumentPropertiesW (WINSPOOL.@)
1423 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1425 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1427 LPDEVMODEW pDevModeOutput,
1428 LPDEVMODEW pDevModeInput, DWORD fMode)
1431 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1432 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1433 LPDEVMODEA pDevModeOutputA = NULL;
1436 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1437 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1439 if(pDevModeOutput) {
1440 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1441 if(ret < 0) return ret;
1442 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1444 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1445 pDevModeInputA, fMode);
1446 if(pDevModeOutput) {
1447 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1448 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1450 if(fMode == 0 && ret > 0)
1451 ret += (CCHDEVICENAME + CCHFORMNAME);
1452 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1453 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1457 /******************************************************************
1458 * OpenPrinterA [WINSPOOL.@]
1463 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1464 LPPRINTER_DEFAULTSA pDefault)
1466 UNICODE_STRING lpPrinterNameW;
1467 UNICODE_STRING usBuffer;
1468 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1469 PWSTR pwstrPrinterNameW;
1472 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1475 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1476 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1477 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1478 pDefaultW = &DefaultW;
1480 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1482 RtlFreeUnicodeString(&usBuffer);
1483 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1485 RtlFreeUnicodeString(&lpPrinterNameW);
1489 /******************************************************************
1490 * OpenPrinterW [WINSPOOL.@]
1492 * Open a Printer / Printserver or a Printer-Object
1495 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1496 * phPrinter [O] The resulting Handle is stored here
1497 * pDefault [I] PTR to Default Printer Settings or NULL
1504 * lpPrinterName is one of:
1505 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1506 *| Printer: "PrinterName"
1507 *| Printer-Object: "PrinterName,Job xxx"
1508 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1509 *| XcvPort: "Servername,XcvPort PortName"
1512 *| Printer-Object not supported
1513 *| XcvMonitor not supported
1514 *| XcvPort not supported
1515 *| pDefaults is ignored
1518 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1520 HKEY hkeyPrinters = NULL;
1521 HKEY hkeyPrinter = NULL;
1523 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1525 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1526 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1529 if(lpPrinterName != NULL)
1531 /* Check any Printer exists */
1532 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1533 ERR("Can't create Printers key\n");
1534 SetLastError(ERROR_FILE_NOT_FOUND);
1537 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1538 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1540 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1541 RegCloseKey(hkeyPrinters);
1542 SetLastError(ERROR_INVALID_PRINTER_NAME);
1545 RegCloseKey(hkeyPrinter);
1546 RegCloseKey(hkeyPrinters);
1549 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1550 SetLastError(ERROR_INVALID_PARAMETER);
1554 /* Get the unique handle of the printer or Printserver */
1555 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1556 return (*phPrinter != 0);
1559 /******************************************************************
1560 * AddMonitorA [WINSPOOL.@]
1565 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1567 LPWSTR nameW = NULL;
1570 LPMONITOR_INFO_2A mi2a;
1571 MONITOR_INFO_2W mi2w;
1573 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1574 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1575 mi2a ? debugstr_a(mi2a->pName) : NULL,
1576 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1577 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1580 SetLastError(ERROR_INVALID_LEVEL);
1584 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1590 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1591 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1592 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1595 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1597 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1598 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1599 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1601 if (mi2a->pEnvironment) {
1602 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1603 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1604 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1606 if (mi2a->pDLLName) {
1607 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1608 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1609 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1612 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1614 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1615 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1616 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1618 HeapFree(GetProcessHeap(), 0, nameW);
1622 /******************************************************************************
1623 * AddMonitorW [WINSPOOL.@]
1625 * Install a Printmonitor
1628 * pName [I] Servername or NULL (local Computer)
1629 * Level [I] Structure-Level (Must be 2)
1630 * pMonitors [I] PTR to MONITOR_INFO_2
1637 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1640 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1642 monitor_t * pm = NULL;
1643 LPMONITOR_INFO_2W mi2w;
1649 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1650 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1651 mi2w ? debugstr_w(mi2w->pName) : NULL,
1652 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1653 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1656 SetLastError(ERROR_INVALID_LEVEL);
1660 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1665 if (pName && (pName[0])) {
1666 FIXME("for server %s not implemented\n", debugstr_w(pName));
1667 SetLastError(ERROR_ACCESS_DENIED);
1672 if (!mi2w->pName || (! mi2w->pName[0])) {
1673 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1674 SetLastError(ERROR_INVALID_PARAMETER);
1677 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1678 WARN("Environment %s requested (we support only %s)\n",
1679 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1680 SetLastError(ERROR_INVALID_ENVIRONMENT);
1684 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1685 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1686 SetLastError(ERROR_INVALID_PARAMETER);
1690 /* Load and initialize the monitor. SetLastError() is called on failure */
1691 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1696 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1697 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1701 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1702 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1703 &disposition) == ERROR_SUCCESS) {
1705 /* Some installers set options for the port before calling AddMonitor.
1706 We query the "Driver" entry to verify that the monitor is installed,
1707 before we return an error.
1708 When a user installs two print monitors at the same time with the
1709 same name but with a different driver DLL and a task switch comes
1710 between RegQueryValueExW and RegSetValueExW, a race condition
1711 is possible but silently ignored. */
1715 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1716 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1717 &namesize) == ERROR_SUCCESS)) {
1718 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1719 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1720 9x: ERROR_ALREADY_EXISTS (183) */
1721 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1726 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1727 res = (RegSetValueExW(hentry, DriverW, 0,
1728 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1730 RegCloseKey(hentry);
1737 /******************************************************************
1738 * DeletePrinterDriverA [WINSPOOL.@]
1742 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1744 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1745 debugstr_a(pDriverName));
1746 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1750 /******************************************************************
1751 * DeletePrinterDriverW [WINSPOOL.@]
1755 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1757 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1758 debugstr_w(pDriverName));
1759 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1763 /******************************************************************
1764 * DeleteMonitorA [WINSPOOL.@]
1766 * See DeleteMonitorW.
1769 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1771 LPWSTR nameW = NULL;
1772 LPWSTR EnvironmentW = NULL;
1773 LPWSTR MonitorNameW = NULL;
1778 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1779 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1780 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1784 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1785 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1786 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1789 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1790 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1791 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1794 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1796 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1797 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1798 HeapFree(GetProcessHeap(), 0, nameW);
1802 /******************************************************************
1803 * DeleteMonitorW [WINSPOOL.@]
1805 * Delete a specific Printmonitor from a Printing-Environment
1808 * pName [I] Servername or NULL (local Computer)
1809 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1810 * pMonitorName [I] Name of the Monitor, that should be deleted
1817 * pEnvironment is ignored in Windows for the local Computer.
1821 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1825 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1826 debugstr_w(pMonitorName));
1828 if (pName && (pName[0])) {
1829 FIXME("for server %s not implemented\n", debugstr_w(pName));
1830 SetLastError(ERROR_ACCESS_DENIED);
1834 /* pEnvironment is ignored in Windows for the local Computer */
1836 if (!pMonitorName || !pMonitorName[0]) {
1837 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1838 SetLastError(ERROR_INVALID_PARAMETER);
1842 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1843 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1847 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1848 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1849 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1854 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1857 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1858 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1862 /******************************************************************
1863 * DeletePortA [WINSPOOL.@]
1869 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1871 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1872 debugstr_a(pPortName));
1873 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1877 /******************************************************************
1878 * DeletePortW [WINSPOOL.@]
1880 * Delete a specific Port
1883 * pName [I] Servername or NULL (local Computer)
1884 * hWnd [I] Handle to parent Window for the Dialog-Box
1885 * pPortName [I] Name of the Port, that should be deleted
1896 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1898 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1899 debugstr_w(pPortName));
1900 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1904 /******************************************************************************
1905 * SetPrinterW [WINSPOOL.@]
1907 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1909 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
1910 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1914 /******************************************************************************
1915 * WritePrinter [WINSPOOL.@]
1917 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1919 opened_printer_t *printer;
1922 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1924 EnterCriticalSection(&printer_handles_cs);
1925 printer = get_opened_printer(hPrinter);
1928 SetLastError(ERROR_INVALID_HANDLE);
1934 SetLastError(ERROR_SPL_NO_STARTDOC);
1938 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1940 LeaveCriticalSection(&printer_handles_cs);
1944 /*****************************************************************************
1945 * AddFormA [WINSPOOL.@]
1947 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1949 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1953 /*****************************************************************************
1954 * AddFormW [WINSPOOL.@]
1956 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1958 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1962 /*****************************************************************************
1963 * AddJobA [WINSPOOL.@]
1965 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1968 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1972 SetLastError(ERROR_INVALID_LEVEL);
1976 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1979 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1980 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1981 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1982 if(*pcbNeeded > cbBuf) {
1983 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1986 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1987 addjobA->JobId = addjobW->JobId;
1988 addjobA->Path = (char *)(addjobA + 1);
1989 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1995 /*****************************************************************************
1996 * AddJobW [WINSPOOL.@]
1998 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2000 opened_printer_t *printer;
2003 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2004 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2005 WCHAR path[MAX_PATH], filename[MAX_PATH];
2007 ADDJOB_INFO_1W *addjob;
2009 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2011 EnterCriticalSection(&printer_handles_cs);
2013 printer = get_opened_printer(hPrinter);
2016 SetLastError(ERROR_INVALID_HANDLE);
2021 SetLastError(ERROR_INVALID_LEVEL);
2025 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2029 job->job_id = InterlockedIncrement(&next_job_id);
2031 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2032 if(path[len - 1] != '\\')
2034 memcpy(path + len, spool_path, sizeof(spool_path));
2035 sprintfW(filename, fmtW, path, job->job_id);
2037 len = strlenW(filename);
2038 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2039 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2040 job->document_title = strdupW(default_doc_title);
2041 list_add_tail(&printer->queue->jobs, &job->entry);
2043 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2044 if(*pcbNeeded <= cbBuf) {
2045 addjob = (ADDJOB_INFO_1W*)pData;
2046 addjob->JobId = job->job_id;
2047 addjob->Path = (WCHAR *)(addjob + 1);
2048 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2051 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2054 LeaveCriticalSection(&printer_handles_cs);
2058 /*****************************************************************************
2059 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2061 * Return the PATH for the Print-Processors
2063 * See GetPrintProcessorDirectoryW.
2067 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2068 DWORD level, LPBYTE Info,
2069 DWORD cbBuf, LPDWORD pcbNeeded)
2071 LPWSTR serverW = NULL;
2076 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2077 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2081 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2082 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2083 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2087 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2088 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2089 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2092 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2093 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2095 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2098 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2099 cbBuf, NULL, NULL) > 0;
2102 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2103 HeapFree(GetProcessHeap(), 0, envW);
2104 HeapFree(GetProcessHeap(), 0, serverW);
2108 /*****************************************************************************
2109 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2111 * Return the PATH for the Print-Processors
2114 * server [I] Servername (NT only) or NULL (local Computer)
2115 * env [I] Printing-Environment (see below) or NULL (Default)
2116 * level [I] Structure-Level (must be 1)
2117 * Info [O] PTR to Buffer that receives the Result
2118 * cbBuf [I] Size of Buffer at "Info"
2119 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2120 * required for the Buffer at "Info"
2123 * Success: TRUE and in pcbNeeded the Bytes used in Info
2124 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2125 * if cbBuf is too small
2127 * Native Values returned in Info on Success:
2128 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2129 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2130 *| win9x(Windows 4.0): "%winsysdir%"
2132 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2135 * Only NULL or "" is supported for server
2138 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2139 DWORD level, LPBYTE Info,
2140 DWORD cbBuf, LPDWORD pcbNeeded)
2143 const printenv_t * env_t;
2145 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2146 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2148 if(server != NULL && server[0]) {
2149 FIXME("server not supported: %s\n", debugstr_w(server));
2150 SetLastError(ERROR_INVALID_PARAMETER);
2154 env_t = validate_envW(env);
2155 if(!env_t) return FALSE; /* environment invalid or unsupported */
2158 WARN("(Level: %d) is ignored in win9x\n", level);
2159 SetLastError(ERROR_INVALID_LEVEL);
2163 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2164 needed = GetSystemDirectoryW(NULL, 0);
2165 /* add the Size for the Subdirectories */
2166 needed += lstrlenW(spoolprtprocsW);
2167 needed += lstrlenW(env_t->subdir);
2168 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2170 if(pcbNeeded) *pcbNeeded = needed;
2171 TRACE ("required: 0x%x/%d\n", needed, needed);
2172 if (needed > cbBuf) {
2173 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2176 if(pcbNeeded == NULL) {
2177 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2178 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2179 SetLastError(RPC_X_NULL_REF_POINTER);
2183 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2184 SetLastError(RPC_X_NULL_REF_POINTER);
2188 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2189 /* add the Subdirectories */
2190 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2191 lstrcatW((LPWSTR) Info, env_t->subdir);
2192 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2196 /*****************************************************************************
2197 * WINSPOOL_OpenDriverReg [internal]
2199 * opens the registry for the printer drivers depending on the given input
2200 * variable pEnvironment
2203 * the opened hkey on success
2206 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2210 const printenv_t * env;
2213 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2215 if (!pEnvironment || unicode) {
2216 /* pEnvironment was NULL or an Unicode-String: use it direct */
2217 env = validate_envW(pEnvironment);
2221 /* pEnvironment was an ANSI-String: convert to unicode first */
2223 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2224 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2225 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2226 env = validate_envW(buffer);
2227 HeapFree(GetProcessHeap(), 0, buffer);
2229 if (!env) return NULL;
2231 buffer = HeapAlloc( GetProcessHeap(), 0,
2232 (strlenW(DriversW) + strlenW(env->envname) +
2233 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2235 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2236 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2237 HeapFree(GetProcessHeap(), 0, buffer);
2242 /*****************************************************************************
2243 * AddPrinterW [WINSPOOL.@]
2245 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2247 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2251 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2254 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2257 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2258 SetLastError(ERROR_INVALID_PARAMETER);
2262 ERR("Level = %d, unsupported!\n", Level);
2263 SetLastError(ERROR_INVALID_LEVEL);
2267 SetLastError(ERROR_INVALID_PARAMETER);
2270 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2272 ERR("Can't create Printers key\n");
2275 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2276 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2277 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2278 RegCloseKey(hkeyPrinter);
2279 RegCloseKey(hkeyPrinters);
2282 RegCloseKey(hkeyPrinter);
2284 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2286 ERR("Can't create Drivers key\n");
2287 RegCloseKey(hkeyPrinters);
2290 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2292 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2293 RegCloseKey(hkeyPrinters);
2294 RegCloseKey(hkeyDrivers);
2295 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2298 RegCloseKey(hkeyDriver);
2299 RegCloseKey(hkeyDrivers);
2301 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2302 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2303 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2304 RegCloseKey(hkeyPrinters);
2308 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2310 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2311 SetLastError(ERROR_INVALID_PRINTER_NAME);
2312 RegCloseKey(hkeyPrinters);
2315 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2316 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2317 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2319 /* See if we can load the driver. We may need the devmode structure anyway
2322 * Note that DocumentPropertiesW will briefly try to open the printer we
2323 * just create to find a DEVMODEA struct (it will use the WINEPS default
2324 * one in case it is not there, so we are ok).
2326 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2329 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2330 size = sizeof(DEVMODEW);
2336 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2337 ZeroMemory(dmW,size);
2339 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2341 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2342 HeapFree(GetProcessHeap(),0,dmW);
2347 /* set devmode to printer name */
2348 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2352 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2353 and we support these drivers. NT writes DEVMODEW so somehow
2354 we'll need to distinguish between these when we support NT
2358 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2359 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2360 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2361 HeapFree(GetProcessHeap(), 0, dmA);
2363 HeapFree(GetProcessHeap(), 0, dmW);
2365 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2366 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2367 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2368 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2370 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2371 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2372 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2373 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2374 (LPBYTE)&pi->Priority, sizeof(DWORD));
2375 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2376 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2377 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2378 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2379 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2380 (LPBYTE)&pi->Status, sizeof(DWORD));
2381 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2382 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2384 RegCloseKey(hkeyPrinter);
2385 RegCloseKey(hkeyPrinters);
2386 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2387 ERR("OpenPrinter failing\n");
2393 /*****************************************************************************
2394 * AddPrinterA [WINSPOOL.@]
2396 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2398 UNICODE_STRING pNameW;
2400 PRINTER_INFO_2W *piW;
2401 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2404 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2406 ERR("Level = %d, unsupported!\n", Level);
2407 SetLastError(ERROR_INVALID_LEVEL);
2410 pwstrNameW = asciitounicode(&pNameW,pName);
2411 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2413 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2415 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2416 RtlFreeUnicodeString(&pNameW);
2421 /*****************************************************************************
2422 * ClosePrinter [WINSPOOL.@]
2424 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2426 UINT_PTR i = (UINT_PTR)hPrinter;
2427 opened_printer_t *printer = NULL;
2430 TRACE("Handle %p\n", hPrinter);
2432 EnterCriticalSection(&printer_handles_cs);
2434 if ((i > 0) && (i <= nb_printer_handles))
2435 printer = printer_handles[i - 1];
2439 struct list *cursor, *cursor2;
2442 EndDocPrinter(hPrinter);
2444 if(InterlockedDecrement(&printer->queue->ref) == 0)
2446 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2448 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2449 ScheduleJob(hPrinter, job->job_id);
2451 HeapFree(GetProcessHeap(), 0, printer->queue);
2453 HeapFree(GetProcessHeap(), 0, printer->name);
2454 HeapFree(GetProcessHeap(), 0, printer);
2455 printer_handles[i - 1] = NULL;
2458 LeaveCriticalSection(&printer_handles_cs);
2462 /*****************************************************************************
2463 * DeleteFormA [WINSPOOL.@]
2465 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2467 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2471 /*****************************************************************************
2472 * DeleteFormW [WINSPOOL.@]
2474 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2476 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2480 /*****************************************************************************
2481 * WINSPOOL_SHRegDeleteKey
2483 * Recursively delete subkeys.
2484 * Cut & paste from shlwapi.
2487 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2489 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2490 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2493 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2496 /* Find how many subkeys there are */
2497 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2498 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2502 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2503 /* Name too big: alloc a buffer for it */
2504 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2507 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2510 /* Recursively delete all the subkeys */
2511 for(i = 0; i < dwKeyCount && !dwRet; i++)
2513 dwSize = dwMaxSubkeyLen;
2514 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2516 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2519 if (lpszName != szNameBuf)
2520 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2524 RegCloseKey(hSubKey);
2526 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2531 /*****************************************************************************
2532 * DeletePrinter [WINSPOOL.@]
2534 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2536 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2537 HKEY hkeyPrinters, hkey;
2540 SetLastError(ERROR_INVALID_HANDLE);
2543 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2544 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2545 RegCloseKey(hkeyPrinters);
2547 WriteProfileStringW(devicesW, lpNameW, NULL);
2548 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2549 RegDeleteValueW(hkey, lpNameW);
2555 /*****************************************************************************
2556 * SetPrinterA [WINSPOOL.@]
2558 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2561 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2565 /*****************************************************************************
2566 * SetJobA [WINSPOOL.@]
2568 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2569 LPBYTE pJob, DWORD Command)
2573 UNICODE_STRING usBuffer;
2575 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2577 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2578 are all ignored by SetJob, so we don't bother copying them */
2586 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2587 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2589 JobW = (LPBYTE)info1W;
2590 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2591 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2592 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2593 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2594 info1W->Status = info1A->Status;
2595 info1W->Priority = info1A->Priority;
2596 info1W->Position = info1A->Position;
2597 info1W->PagesPrinted = info1A->PagesPrinted;
2602 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2603 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2605 JobW = (LPBYTE)info2W;
2606 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2607 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2608 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2609 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2610 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2611 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2612 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2613 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2614 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2615 info2W->Status = info2A->Status;
2616 info2W->Priority = info2A->Priority;
2617 info2W->Position = info2A->Position;
2618 info2W->StartTime = info2A->StartTime;
2619 info2W->UntilTime = info2A->UntilTime;
2620 info2W->PagesPrinted = info2A->PagesPrinted;
2624 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2625 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2628 SetLastError(ERROR_INVALID_LEVEL);
2632 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2638 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2639 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2640 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2641 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2642 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2647 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2648 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2649 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2650 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2651 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2652 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2653 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2654 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2655 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2659 HeapFree(GetProcessHeap(), 0, JobW);
2664 /*****************************************************************************
2665 * SetJobW [WINSPOOL.@]
2667 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2668 LPBYTE pJob, DWORD Command)
2673 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2674 FIXME("Ignoring everything other than document title\n");
2676 EnterCriticalSection(&printer_handles_cs);
2677 job = get_job(hPrinter, JobId);
2687 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2688 HeapFree(GetProcessHeap(), 0, job->document_title);
2689 job->document_title = strdupW(info1->pDocument);
2694 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2695 HeapFree(GetProcessHeap(), 0, job->document_title);
2696 job->document_title = strdupW(info2->pDocument);
2702 SetLastError(ERROR_INVALID_LEVEL);
2707 LeaveCriticalSection(&printer_handles_cs);
2711 /*****************************************************************************
2712 * EndDocPrinter [WINSPOOL.@]
2714 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2716 opened_printer_t *printer;
2718 TRACE("(%p)\n", hPrinter);
2720 EnterCriticalSection(&printer_handles_cs);
2722 printer = get_opened_printer(hPrinter);
2725 SetLastError(ERROR_INVALID_HANDLE);
2731 SetLastError(ERROR_SPL_NO_STARTDOC);
2735 CloseHandle(printer->doc->hf);
2736 ScheduleJob(hPrinter, printer->doc->job_id);
2737 HeapFree(GetProcessHeap(), 0, printer->doc);
2738 printer->doc = NULL;
2741 LeaveCriticalSection(&printer_handles_cs);
2745 /*****************************************************************************
2746 * EndPagePrinter [WINSPOOL.@]
2748 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2750 FIXME("(%p): stub\n", hPrinter);
2754 /*****************************************************************************
2755 * StartDocPrinterA [WINSPOOL.@]
2757 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2759 UNICODE_STRING usBuffer;
2761 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2764 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2765 or one (DOC_INFO_3) extra DWORDs */
2769 doc2W.JobId = doc2->JobId;
2772 doc2W.dwMode = doc2->dwMode;
2775 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2776 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2777 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2781 SetLastError(ERROR_INVALID_LEVEL);
2785 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2787 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2788 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2789 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2794 /*****************************************************************************
2795 * StartDocPrinterW [WINSPOOL.@]
2797 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2799 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2800 opened_printer_t *printer;
2801 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2802 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2803 JOB_INFO_1W job_info;
2804 DWORD needed, ret = 0;
2808 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2809 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2810 debugstr_w(doc->pDatatype));
2812 if(Level < 1 || Level > 3)
2814 SetLastError(ERROR_INVALID_LEVEL);
2818 EnterCriticalSection(&printer_handles_cs);
2819 printer = get_opened_printer(hPrinter);
2822 SetLastError(ERROR_INVALID_HANDLE);
2828 SetLastError(ERROR_INVALID_PRINTER_STATE);
2832 /* Even if we're printing to a file we still add a print job, we'll
2833 just ignore the spool file name */
2835 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2837 ERR("AddJob failed gle %08x\n", GetLastError());
2841 if(doc->pOutputFile)
2842 filename = doc->pOutputFile;
2844 filename = addjob->Path;
2846 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2847 if(hf == INVALID_HANDLE_VALUE)
2850 memset(&job_info, 0, sizeof(job_info));
2851 job_info.pDocument = doc->pDocName;
2852 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2854 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2855 printer->doc->hf = hf;
2856 ret = printer->doc->job_id = addjob->JobId;
2858 LeaveCriticalSection(&printer_handles_cs);
2863 /*****************************************************************************
2864 * StartPagePrinter [WINSPOOL.@]
2866 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2868 FIXME("(%p): stub\n", hPrinter);
2872 /*****************************************************************************
2873 * GetFormA [WINSPOOL.@]
2875 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2876 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2878 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
2879 Level,pForm,cbBuf,pcbNeeded);
2883 /*****************************************************************************
2884 * GetFormW [WINSPOOL.@]
2886 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2887 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2889 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
2890 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2894 /*****************************************************************************
2895 * SetFormA [WINSPOOL.@]
2897 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2900 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2904 /*****************************************************************************
2905 * SetFormW [WINSPOOL.@]
2907 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2910 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2914 /*****************************************************************************
2915 * ReadPrinter [WINSPOOL.@]
2917 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2918 LPDWORD pNoBytesRead)
2920 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2924 /*****************************************************************************
2925 * ResetPrinterA [WINSPOOL.@]
2927 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2929 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2933 /*****************************************************************************
2934 * ResetPrinterW [WINSPOOL.@]
2936 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2938 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2942 /*****************************************************************************
2943 * WINSPOOL_GetDWORDFromReg
2945 * Return DWORD associated with ValueName from hkey.
2947 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2949 DWORD sz = sizeof(DWORD), type, value = 0;
2952 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2954 if(ret != ERROR_SUCCESS) {
2955 WARN("Got ret = %d on name %s\n", ret, ValueName);
2958 if(type != REG_DWORD) {
2959 ERR("Got type %d\n", type);
2965 /*****************************************************************************
2966 * WINSPOOL_GetStringFromReg
2968 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2969 * String is stored either as unicode or ascii.
2970 * Bit of a hack here to get the ValueName if we want ascii.
2972 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2973 DWORD buflen, DWORD *needed,
2976 DWORD sz = buflen, type;
2980 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2982 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2983 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2984 HeapFree(GetProcessHeap(),0,ValueNameA);
2986 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2987 WARN("Got ret = %d\n", ret);
2991 /* add space for terminating '\0' */
2992 sz += unicode ? sizeof(WCHAR) : 1;
2996 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3001 /*****************************************************************************
3002 * WINSPOOL_GetDefaultDevMode
3004 * Get a default DevMode values for wineps.
3008 static void WINSPOOL_GetDefaultDevMode(
3010 DWORD buflen, DWORD *needed,
3014 static const char szwps[] = "wineps.drv";
3016 /* fill default DEVMODE - should be read from ppd... */
3017 ZeroMemory( &dm, sizeof(dm) );
3018 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3019 dm.dmSpecVersion = DM_SPECVERSION;
3020 dm.dmDriverVersion = 1;
3021 dm.dmSize = sizeof(DEVMODEA);
3022 dm.dmDriverExtra = 0;
3024 DM_ORIENTATION | DM_PAPERSIZE |
3025 DM_PAPERLENGTH | DM_PAPERWIDTH |
3028 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3029 DM_YRESOLUTION | DM_TTOPTION;
3031 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3032 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3033 dm.u1.s1.dmPaperLength = 2970;
3034 dm.u1.s1.dmPaperWidth = 2100;
3038 dm.dmDefaultSource = DMBIN_AUTO;
3039 dm.dmPrintQuality = DMRES_MEDIUM;
3042 dm.dmYResolution = 300; /* 300dpi */
3043 dm.dmTTOption = DMTT_BITMAP;
3046 /* dm.dmLogPixels */
3047 /* dm.dmBitsPerPel */
3048 /* dm.dmPelsWidth */
3049 /* dm.dmPelsHeight */
3050 /* dm.dmDisplayFlags */
3051 /* dm.dmDisplayFrequency */
3052 /* dm.dmICMMethod */
3053 /* dm.dmICMIntent */
3054 /* dm.dmMediaType */
3055 /* dm.dmDitherType */
3056 /* dm.dmReserved1 */
3057 /* dm.dmReserved2 */
3058 /* dm.dmPanningWidth */
3059 /* dm.dmPanningHeight */
3062 if(buflen >= sizeof(DEVMODEW)) {
3063 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3064 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3065 HeapFree(GetProcessHeap(),0,pdmW);
3067 *needed = sizeof(DEVMODEW);
3071 if(buflen >= sizeof(DEVMODEA)) {
3072 memcpy(ptr, &dm, sizeof(DEVMODEA));
3074 *needed = sizeof(DEVMODEA);
3078 /*****************************************************************************
3079 * WINSPOOL_GetDevModeFromReg
3081 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3082 * DevMode is stored either as unicode or ascii.
3084 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3086 DWORD buflen, DWORD *needed,
3089 DWORD sz = buflen, type;
3092 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3093 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3094 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3095 if (sz < sizeof(DEVMODEA))
3097 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3100 /* ensures that dmSize is not erratically bogus if registry is invalid */
3101 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3102 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3104 sz += (CCHDEVICENAME + CCHFORMNAME);
3106 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3107 memcpy(ptr, dmW, sz);
3108 HeapFree(GetProcessHeap(),0,dmW);
3115 /*********************************************************************
3116 * WINSPOOL_GetPrinter_2
3118 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3119 * The strings are either stored as unicode or ascii.
3121 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3122 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3125 DWORD size, left = cbBuf;
3126 BOOL space = (cbBuf > 0);
3131 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3133 if(space && size <= left) {
3134 pi2->pPrinterName = (LPWSTR)ptr;
3141 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3143 if(space && size <= left) {
3144 pi2->pShareName = (LPWSTR)ptr;
3151 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3153 if(space && size <= left) {
3154 pi2->pPortName = (LPWSTR)ptr;
3161 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3163 if(space && size <= left) {
3164 pi2->pDriverName = (LPWSTR)ptr;
3171 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3173 if(space && size <= left) {
3174 pi2->pComment = (LPWSTR)ptr;
3181 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3183 if(space && size <= left) {
3184 pi2->pLocation = (LPWSTR)ptr;
3191 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3193 if(space && size <= left) {
3194 pi2->pDevMode = (LPDEVMODEW)ptr;
3203 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3204 if(space && size <= left) {
3205 pi2->pDevMode = (LPDEVMODEW)ptr;
3212 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3214 if(space && size <= left) {
3215 pi2->pSepFile = (LPWSTR)ptr;
3222 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3224 if(space && size <= left) {
3225 pi2->pPrintProcessor = (LPWSTR)ptr;
3232 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3234 if(space && size <= left) {
3235 pi2->pDatatype = (LPWSTR)ptr;
3242 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3244 if(space && size <= left) {
3245 pi2->pParameters = (LPWSTR)ptr;
3253 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3254 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3255 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3256 "Default Priority");
3257 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3258 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3261 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3262 memset(pi2, 0, sizeof(*pi2));
3267 /*********************************************************************
3268 * WINSPOOL_GetPrinter_4
3270 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3272 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3273 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3276 DWORD size, left = cbBuf;
3277 BOOL space = (cbBuf > 0);
3282 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3284 if(space && size <= left) {
3285 pi4->pPrinterName = (LPWSTR)ptr;
3293 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3296 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3297 memset(pi4, 0, sizeof(*pi4));
3302 /*********************************************************************
3303 * WINSPOOL_GetPrinter_5
3305 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3307 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3308 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3311 DWORD size, left = cbBuf;
3312 BOOL space = (cbBuf > 0);
3317 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3319 if(space && size <= left) {
3320 pi5->pPrinterName = (LPWSTR)ptr;
3327 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3329 if(space && size <= left) {
3330 pi5->pPortName = (LPWSTR)ptr;
3338 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3339 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3341 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3345 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3346 memset(pi5, 0, sizeof(*pi5));
3351 /*****************************************************************************
3352 * WINSPOOL_GetPrinter
3354 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3355 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3356 * just a collection of pointers to strings.
3358 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3359 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3362 DWORD size, needed = 0;
3364 HKEY hkeyPrinter, hkeyPrinters;
3367 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3369 if (!(name = get_opened_printer_name(hPrinter))) {
3370 SetLastError(ERROR_INVALID_HANDLE);
3374 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3376 ERR("Can't create Printers key\n");
3379 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3381 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3382 RegCloseKey(hkeyPrinters);
3383 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3390 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3392 size = sizeof(PRINTER_INFO_2W);
3394 ptr = pPrinter + size;
3396 memset(pPrinter, 0, size);
3401 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3409 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3411 size = sizeof(PRINTER_INFO_4W);
3413 ptr = pPrinter + size;
3415 memset(pPrinter, 0, size);
3420 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3429 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3431 size = sizeof(PRINTER_INFO_5W);
3433 ptr = pPrinter + size;
3435 memset(pPrinter, 0, size);
3441 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3448 FIXME("Unimplemented level %d\n", Level);
3449 SetLastError(ERROR_INVALID_LEVEL);
3450 RegCloseKey(hkeyPrinters);
3451 RegCloseKey(hkeyPrinter);
3455 RegCloseKey(hkeyPrinter);
3456 RegCloseKey(hkeyPrinters);
3458 TRACE("returning %d needed = %d\n", ret, needed);
3459 if(pcbNeeded) *pcbNeeded = needed;
3461 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3465 /*****************************************************************************
3466 * GetPrinterW [WINSPOOL.@]
3468 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3469 DWORD cbBuf, LPDWORD pcbNeeded)
3471 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3475 /*****************************************************************************
3476 * GetPrinterA [WINSPOOL.@]
3478 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3479 DWORD cbBuf, LPDWORD pcbNeeded)
3481 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3485 /*****************************************************************************
3486 * WINSPOOL_EnumPrinters
3488 * Implementation of EnumPrintersA|W
3490 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3491 DWORD dwLevel, LPBYTE lpbPrinters,
3492 DWORD cbBuf, LPDWORD lpdwNeeded,
3493 LPDWORD lpdwReturned, BOOL unicode)
3496 HKEY hkeyPrinters, hkeyPrinter;
3497 WCHAR PrinterName[255];
3498 DWORD needed = 0, number = 0;
3499 DWORD used, i, left;
3503 memset(lpbPrinters, 0, cbBuf);
3509 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3510 if(dwType == PRINTER_ENUM_DEFAULT)
3513 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3514 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3515 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3516 if(!dwType) return TRUE;
3519 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3520 FIXME("dwType = %08x\n", dwType);
3521 SetLastError(ERROR_INVALID_FLAGS);
3525 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3527 ERR("Can't create Printers key\n");
3531 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3532 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3533 RegCloseKey(hkeyPrinters);
3534 ERR("Can't query Printers key\n");
3537 TRACE("Found %d printers\n", number);
3541 RegCloseKey(hkeyPrinters);
3543 *lpdwReturned = number;
3547 used = number * sizeof(PRINTER_INFO_2W);
3550 used = number * sizeof(PRINTER_INFO_4W);
3553 used = number * sizeof(PRINTER_INFO_5W);
3557 SetLastError(ERROR_INVALID_LEVEL);
3558 RegCloseKey(hkeyPrinters);
3561 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3563 for(i = 0; i < number; i++) {
3564 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3566 ERR("Can't enum key number %d\n", i);
3567 RegCloseKey(hkeyPrinters);
3570 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3571 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3573 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3574 RegCloseKey(hkeyPrinters);
3579 buf = lpbPrinters + used;
3580 left = cbBuf - used;
3588 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3589 left, &needed, unicode);
3591 if(pi) pi += sizeof(PRINTER_INFO_2W);
3594 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3595 left, &needed, unicode);
3597 if(pi) pi += sizeof(PRINTER_INFO_4W);
3600 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3601 left, &needed, unicode);
3603 if(pi) pi += sizeof(PRINTER_INFO_5W);
3606 ERR("Shouldn't be here!\n");
3607 RegCloseKey(hkeyPrinter);
3608 RegCloseKey(hkeyPrinters);
3611 RegCloseKey(hkeyPrinter);
3613 RegCloseKey(hkeyPrinters);
3620 memset(lpbPrinters, 0, cbBuf);
3621 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3625 *lpdwReturned = number;
3626 SetLastError(ERROR_SUCCESS);
3631 /******************************************************************
3632 * EnumPrintersW [WINSPOOL.@]
3634 * Enumerates the available printers, print servers and print
3635 * providers, depending on the specified flags, name and level.
3639 * If level is set to 1:
3640 * Not implemented yet!
3641 * Returns TRUE with an empty list.
3643 * If level is set to 2:
3644 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3645 * Returns an array of PRINTER_INFO_2 data structures in the
3646 * lpbPrinters buffer. Note that according to MSDN also an
3647 * OpenPrinter should be performed on every remote printer.
3649 * If level is set to 4 (officially WinNT only):
3650 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3651 * Fast: Only the registry is queried to retrieve printer names,
3652 * no connection to the driver is made.
3653 * Returns an array of PRINTER_INFO_4 data structures in the
3654 * lpbPrinters buffer.
3656 * If level is set to 5 (officially WinNT4/Win9x only):
3657 * Fast: Only the registry is queried to retrieve printer names,
3658 * no connection to the driver is made.
3659 * Returns an array of PRINTER_INFO_5 data structures in the
3660 * lpbPrinters buffer.
3662 * If level set to 3 or 6+:
3663 * returns zero (failure!)
3665 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3669 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3670 * - Only levels 2, 4 and 5 are implemented at the moment.
3671 * - 16-bit printer drivers are not enumerated.
3672 * - Returned amount of bytes used/needed does not match the real Windoze
3673 * implementation (as in this implementation, all strings are part
3674 * of the buffer, whereas Win32 keeps them somewhere else)
3675 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3678 * - In a regular Wine installation, no registry settings for printers
3679 * exist, which makes this function return an empty list.
3681 BOOL WINAPI EnumPrintersW(
3682 DWORD dwType, /* [in] Types of print objects to enumerate */
3683 LPWSTR lpszName, /* [in] name of objects to enumerate */
3684 DWORD dwLevel, /* [in] type of printer info structure */
3685 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3686 DWORD cbBuf, /* [in] max size of buffer in bytes */
3687 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3688 LPDWORD lpdwReturned /* [out] number of entries returned */
3691 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3692 lpdwNeeded, lpdwReturned, TRUE);
3695 /******************************************************************
3696 * EnumPrintersA [WINSPOOL.@]
3699 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3700 DWORD dwLevel, LPBYTE lpbPrinters,
3701 DWORD cbBuf, LPDWORD lpdwNeeded,
3702 LPDWORD lpdwReturned)
3705 UNICODE_STRING lpszNameW;
3708 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3709 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3710 lpdwNeeded, lpdwReturned, FALSE);
3711 RtlFreeUnicodeString(&lpszNameW);
3715 /*****************************************************************************
3716 * WINSPOOL_GetDriverInfoFromReg [internal]
3718 * Enters the information from the registry into the DRIVER_INFO struct
3721 * zero if the printer driver does not exist in the registry
3722 * (only if Level > 1) otherwise nonzero
3724 static BOOL WINSPOOL_GetDriverInfoFromReg(
3727 LPCWSTR pEnvironment,
3729 LPBYTE ptr, /* DRIVER_INFO */
3730 LPBYTE pDriverStrings, /* strings buffer */
3731 DWORD cbBuf, /* size of string buffer */
3732 LPDWORD pcbNeeded, /* space needed for str. */
3733 BOOL unicode) /* type of strings */
3737 LPBYTE strPtr = pDriverStrings;
3739 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
3740 debugstr_w(DriverName), debugstr_w(pEnvironment),
3741 Level, ptr, pDriverStrings, cbBuf, unicode);
3744 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3745 if (*pcbNeeded <= cbBuf)
3746 strcpyW((LPWSTR)strPtr, DriverName);
3748 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3750 if(*pcbNeeded <= cbBuf)
3751 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3752 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3756 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3760 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3761 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3764 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3765 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3766 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3771 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3774 pEnvironment = DefaultEnvironmentW;
3776 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3778 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3781 if(*pcbNeeded <= cbBuf) {
3783 strcpyW((LPWSTR)strPtr, pEnvironment);
3785 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3786 (LPSTR)strPtr, size, NULL, NULL);
3788 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3789 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3792 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3795 if(*pcbNeeded <= cbBuf)
3796 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3799 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3800 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3803 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3806 if(*pcbNeeded <= cbBuf)
3807 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3810 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3811 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3814 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3815 0, &size, unicode)) {
3817 if(*pcbNeeded <= cbBuf)
3818 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3819 size, &tmp, unicode);
3821 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3822 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3826 RegCloseKey(hkeyDriver);
3827 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
3831 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3834 if(*pcbNeeded <= cbBuf)
3835 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3836 size, &tmp, unicode);
3838 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3839 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3842 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3845 if(*pcbNeeded <= cbBuf)
3846 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3847 size, &tmp, unicode);
3849 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3850 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3853 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3856 if(*pcbNeeded <= cbBuf)
3857 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3858 size, &tmp, unicode);
3860 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3861 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3864 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3867 if(*pcbNeeded <= cbBuf)
3868 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3869 size, &tmp, unicode);
3871 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3872 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3875 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
3876 RegCloseKey(hkeyDriver);
3880 /*****************************************************************************
3881 * WINSPOOL_GetPrinterDriver
3883 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3884 DWORD Level, LPBYTE pDriverInfo,
3885 DWORD cbBuf, LPDWORD pcbNeeded,
3889 WCHAR DriverName[100];
3890 DWORD ret, type, size, needed = 0;
3892 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3894 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
3895 Level,pDriverInfo,cbBuf, pcbNeeded);
3897 ZeroMemory(pDriverInfo, cbBuf);
3899 if (!(name = get_opened_printer_name(hPrinter))) {
3900 SetLastError(ERROR_INVALID_HANDLE);
3903 if(Level < 1 || Level > 6) {
3904 SetLastError(ERROR_INVALID_LEVEL);
3907 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3909 ERR("Can't create Printers key\n");
3912 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3914 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3915 RegCloseKey(hkeyPrinters);
3916 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3919 size = sizeof(DriverName);
3921 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3922 (LPBYTE)DriverName, &size);
3923 RegCloseKey(hkeyPrinter);
3924 RegCloseKey(hkeyPrinters);
3925 if(ret != ERROR_SUCCESS) {
3926 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3930 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3932 ERR("Can't create Drivers key\n");
3938 size = sizeof(DRIVER_INFO_1W);
3941 size = sizeof(DRIVER_INFO_2W);
3944 size = sizeof(DRIVER_INFO_3W);
3947 size = sizeof(DRIVER_INFO_4W);
3950 size = sizeof(DRIVER_INFO_5W);
3953 size = sizeof(DRIVER_INFO_6W);
3956 ERR("Invalid level\n");
3961 ptr = pDriverInfo + size;
3963 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3964 pEnvironment, Level, pDriverInfo,
3965 (cbBuf < size) ? NULL : ptr,
3966 (cbBuf < size) ? 0 : cbBuf - size,
3967 &needed, unicode)) {
3968 RegCloseKey(hkeyDrivers);
3972 RegCloseKey(hkeyDrivers);
3974 if(pcbNeeded) *pcbNeeded = size + needed;
3975 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
3976 if(cbBuf >= needed) return TRUE;
3977 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3981 /*****************************************************************************
3982 * GetPrinterDriverA [WINSPOOL.@]
3984 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3985 DWORD Level, LPBYTE pDriverInfo,
3986 DWORD cbBuf, LPDWORD pcbNeeded)
3989 UNICODE_STRING pEnvW;
3992 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3993 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3994 cbBuf, pcbNeeded, FALSE);
3995 RtlFreeUnicodeString(&pEnvW);
3998 /*****************************************************************************
3999 * GetPrinterDriverW [WINSPOOL.@]
4001 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4002 DWORD Level, LPBYTE pDriverInfo,
4003 DWORD cbBuf, LPDWORD pcbNeeded)
4005 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4006 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4009 /*****************************************************************************
4010 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4012 * Return the PATH for the Printer-Drivers (UNICODE)
4015 * pName [I] Servername (NT only) or NULL (local Computer)
4016 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4017 * Level [I] Structure-Level (must be 1)
4018 * pDriverDirectory [O] PTR to Buffer that receives the Result
4019 * cbBuf [I] Size of Buffer at pDriverDirectory
4020 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4021 * required for pDriverDirectory
4024 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4025 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4026 * if cbBuf is too small
4028 * Native Values returned in pDriverDirectory on Success:
4029 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4030 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4031 *| win9x(Windows 4.0): "%winsysdir%"
4033 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4036 *- Only NULL or "" is supported for pName
4039 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4040 DWORD Level, LPBYTE pDriverDirectory,
4041 DWORD cbBuf, LPDWORD pcbNeeded)
4044 const printenv_t * env;
4046 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4047 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4048 if(pName != NULL && pName[0]) {
4049 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4050 SetLastError(ERROR_INVALID_PARAMETER);
4054 env = validate_envW(pEnvironment);
4055 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4058 WARN("(Level: %d) is ignored in win9x\n", Level);
4059 SetLastError(ERROR_INVALID_LEVEL);
4063 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4064 needed = GetSystemDirectoryW(NULL, 0);
4065 /* add the Size for the Subdirectories */
4066 needed += lstrlenW(spooldriversW);
4067 needed += lstrlenW(env->subdir);
4068 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4071 *pcbNeeded = needed;
4072 TRACE("required: 0x%x/%d\n", needed, needed);
4073 if(needed > cbBuf) {
4074 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4077 if(pcbNeeded == NULL) {
4078 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4079 SetLastError(RPC_X_NULL_REF_POINTER);
4082 if(pDriverDirectory == NULL) {
4083 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4084 SetLastError(ERROR_INVALID_USER_BUFFER);
4088 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4089 /* add the Subdirectories */
4090 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4091 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4092 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4097 /*****************************************************************************
4098 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4100 * Return the PATH for the Printer-Drivers (ANSI)
4102 * See GetPrinterDriverDirectoryW.
4105 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4108 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4109 DWORD Level, LPBYTE pDriverDirectory,
4110 DWORD cbBuf, LPDWORD pcbNeeded)
4112 UNICODE_STRING nameW, environmentW;
4115 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4116 WCHAR *driverDirectoryW = NULL;
4118 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4119 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4121 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4123 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4124 else nameW.Buffer = NULL;
4125 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4126 else environmentW.Buffer = NULL;
4128 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4129 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4132 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4133 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4135 *pcbNeeded = needed;
4136 ret = (needed <= cbBuf) ? TRUE : FALSE;
4138 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4140 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4142 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4143 RtlFreeUnicodeString(&environmentW);
4144 RtlFreeUnicodeString(&nameW);
4149 /*****************************************************************************
4150 * AddPrinterDriverA [WINSPOOL.@]
4152 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4155 HKEY hkeyDrivers, hkeyName;
4156 static CHAR empty[] = "",
4159 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4161 if(level != 2 && level != 3) {
4162 SetLastError(ERROR_INVALID_LEVEL);
4165 if ((pName) && (pName[0])) {
4166 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4167 SetLastError(ERROR_INVALID_PARAMETER);
4171 WARN("pDriverInfo == NULL\n");
4172 SetLastError(ERROR_INVALID_PARAMETER);
4177 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4179 memset(&di3, 0, sizeof(di3));
4180 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4183 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4185 SetLastError(ERROR_INVALID_PARAMETER);
4189 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4190 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4191 if(!di3.pHelpFile) di3.pHelpFile = empty;
4192 if(!di3.pMonitorName) di3.pMonitorName = empty;
4194 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4197 ERR("Can't create Drivers key\n");
4201 if(level == 2) { /* apparently can't overwrite with level2 */
4202 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4203 RegCloseKey(hkeyName);
4204 RegCloseKey(hkeyDrivers);
4205 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4206 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4210 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4211 RegCloseKey(hkeyDrivers);
4212 ERR("Can't create Name key\n");
4215 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4217 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
4218 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
4219 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4221 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
4222 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4223 (LPBYTE) di3.pDependentFiles, 0);
4224 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
4225 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
4226 RegCloseKey(hkeyName);
4227 RegCloseKey(hkeyDrivers);
4232 /*****************************************************************************
4233 * AddPrinterDriverW [WINSPOOL.@]
4235 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4238 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4243 /*****************************************************************************
4244 * AddPrintProcessorA [WINSPOOL.@]
4246 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4247 LPSTR pPrintProcessorName)
4249 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4250 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4254 /*****************************************************************************
4255 * AddPrintProcessorW [WINSPOOL.@]
4257 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4258 LPWSTR pPrintProcessorName)
4260 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4261 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4265 /*****************************************************************************
4266 * AddPrintProvidorA [WINSPOOL.@]
4268 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4270 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4274 /*****************************************************************************
4275 * AddPrintProvidorW [WINSPOOL.@]
4277 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4279 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4283 /*****************************************************************************
4284 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4286 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4287 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4289 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4290 pDevModeOutput, pDevModeInput);
4294 /*****************************************************************************
4295 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4297 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4298 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4300 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4301 pDevModeOutput, pDevModeInput);
4305 /*****************************************************************************
4306 * PrinterProperties [WINSPOOL.@]
4308 * Displays a dialog to set the properties of the printer.
4311 * nonzero on success or zero on failure
4314 * implemented as stub only
4316 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4317 HANDLE hPrinter /* [in] handle to printer object */
4319 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4320 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4324 /*****************************************************************************
4325 * EnumJobsA [WINSPOOL.@]
4328 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4329 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4332 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4333 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4335 if(pcbNeeded) *pcbNeeded = 0;
4336 if(pcReturned) *pcReturned = 0;
4341 /*****************************************************************************
4342 * EnumJobsW [WINSPOOL.@]
4345 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4346 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4349 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4350 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4352 if(pcbNeeded) *pcbNeeded = 0;
4353 if(pcReturned) *pcReturned = 0;
4357 /*****************************************************************************
4358 * WINSPOOL_EnumPrinterDrivers [internal]
4360 * Delivers information about all printer drivers installed on the
4361 * localhost or a given server
4364 * nonzero on success or zero on failure. If the buffer for the returned
4365 * information is too small the function will return an error
4368 * - only implemented for localhost, foreign hosts will return an error
4370 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4371 DWORD Level, LPBYTE pDriverInfo,
4372 DWORD cbBuf, LPDWORD pcbNeeded,
4373 LPDWORD pcReturned, BOOL unicode)
4376 DWORD i, needed, number = 0, size = 0;
4377 WCHAR DriverNameW[255];
4380 TRACE("%s,%s,%d,%p,%d,%d\n",
4381 debugstr_w(pName), debugstr_w(pEnvironment),
4382 Level, pDriverInfo, cbBuf, unicode);
4384 /* check for local drivers */
4385 if((pName) && (pName[0])) {
4386 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4387 SetLastError(ERROR_ACCESS_DENIED);
4391 /* check input parameter */
4392 if((Level < 1) || (Level > 3)) {
4393 ERR("unsupported level %d\n", Level);
4394 SetLastError(ERROR_INVALID_LEVEL);
4398 /* initialize return values */
4400 memset( pDriverInfo, 0, cbBuf);
4404 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4406 ERR("Can't open Drivers key\n");
4410 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4411 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4412 RegCloseKey(hkeyDrivers);
4413 ERR("Can't query Drivers key\n");
4416 TRACE("Found %d Drivers\n", number);
4418 /* get size of single struct
4419 * unicode and ascii structure have the same size
4423 size = sizeof(DRIVER_INFO_1A);
4426 size = sizeof(DRIVER_INFO_2A);
4429 size = sizeof(DRIVER_INFO_3A);
4433 /* calculate required buffer size */
4434 *pcbNeeded = size * number;
4436 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4438 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4439 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4441 ERR("Can't enum key number %d\n", i);
4442 RegCloseKey(hkeyDrivers);
4445 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4446 pEnvironment, Level, ptr,
4447 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4448 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4449 &needed, unicode)) {
4450 RegCloseKey(hkeyDrivers);
4453 (*pcbNeeded) += needed;
4456 RegCloseKey(hkeyDrivers);
4458 if(cbBuf < *pcbNeeded){
4459 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4463 *pcReturned = number;
4467 /*****************************************************************************
4468 * EnumPrinterDriversW [WINSPOOL.@]
4470 * see function EnumPrinterDrivers for RETURNS, BUGS
4472 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4473 LPBYTE pDriverInfo, DWORD cbBuf,
4474 LPDWORD pcbNeeded, LPDWORD pcReturned)
4476 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4477 cbBuf, pcbNeeded, pcReturned, TRUE);
4480 /*****************************************************************************
4481 * EnumPrinterDriversA [WINSPOOL.@]
4483 * see function EnumPrinterDrivers for RETURNS, BUGS
4485 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4486 LPBYTE pDriverInfo, DWORD cbBuf,
4487 LPDWORD pcbNeeded, LPDWORD pcReturned)
4489 UNICODE_STRING pNameW, pEnvironmentW;
4490 PWSTR pwstrNameW, pwstrEnvironmentW;
4492 pwstrNameW = asciitounicode(&pNameW, pName);
4493 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4495 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4496 Level, pDriverInfo, cbBuf, pcbNeeded,
4498 RtlFreeUnicodeString(&pNameW);
4499 RtlFreeUnicodeString(&pEnvironmentW);
4504 static CHAR PortMonitor[] = "Wine Port Monitor";
4505 static CHAR PortDescription[] = "Wine Port";
4507 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4511 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4512 NULL, OPEN_EXISTING, 0, NULL );
4513 if (handle == INVALID_HANDLE_VALUE)
4515 TRACE("Checking %s exists\n", name );
4516 CloseHandle( handle );
4520 static DWORD WINSPOOL_CountSerialPorts(void)
4527 strcpy( name, "COMx:" );
4529 if (WINSPOOL_ComPortExists( name ))
4536 /******************************************************************************
4537 * EnumPortsA (WINSPOOL.@)
4542 * ANSI-Version did not call the UNICODE-Version
4545 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4546 LPDWORD bufneeded,LPDWORD bufreturned)
4549 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4550 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4554 TRACE("(%s,%d,%p,%d,%p,%p)\n",
4555 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4560 info_size = sizeof (PORT_INFO_1A);
4563 info_size = sizeof (PORT_INFO_2A);
4566 SetLastError(ERROR_INVALID_LEVEL);
4570 /* see how many exist */
4573 serial_count = WINSPOOL_CountSerialPorts();
4576 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4577 if ( r == ERROR_SUCCESS )
4579 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4580 &printer_count, NULL, NULL, NULL, NULL);
4582 count = serial_count + printer_count;
4584 /* then fill in the structure info structure once
4585 we know the offset to the first string */
4587 memset( buffer, 0, bufsize );
4589 ofs = info_size*count;
4590 for ( i=0; i<count; i++)
4592 DWORD vallen = sizeof(portname) - 1;
4594 /* get the serial port values, then the printer values */
4595 if ( i < serial_count )
4597 strcpy( portname, "COMx:" );
4598 portname[3] = '1' + i;
4599 if (!WINSPOOL_ComPortExists( portname ))
4602 TRACE("Found %s\n", portname );
4603 vallen = strlen( portname );
4607 r = RegEnumValueA( hkey_printer, i-serial_count,
4608 portname, &vallen, NULL, NULL, NULL, 0 );
4613 /* add a colon if necessary, and make it upper case */
4614 CharUpperBuffA(portname,vallen);
4615 if (strcasecmp(portname,"nul")!=0)
4616 if (vallen && (portname[vallen-1] != ':') )
4617 lstrcatA(portname,":");
4619 /* add the port info structure if we can fit it */
4620 if ( info_size*(n+1) < bufsize )
4624 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4625 info->pName = (LPSTR) &buffer[ofs];
4627 else if ( level == 2)
4629 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4630 info->pPortName = (LPSTR) &buffer[ofs];
4631 /* FIXME: fill in more stuff here */
4632 info->pMonitorName = PortMonitor;
4633 info->pDescription = PortDescription;
4634 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4637 /* add the name of the port if we can fit it */
4638 if ( ofs < bufsize )
4639 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4645 ofs += lstrlenA(portname)+1;
4648 RegCloseKey(hkey_printer);
4659 /******************************************************************************
4660 * EnumPortsW (WINSPOOL.@)
4662 * Enumerate available Ports
4665 * name [I] Servername or NULL (local Computer)
4666 * level [I] Structure-Level (1 or 2)
4667 * buffer [O] PTR to Buffer that receives the Result
4668 * bufsize [I] Size of Buffer at buffer
4669 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4670 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4674 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4677 * UNICODE-Version is a stub
4680 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4681 LPDWORD bufneeded,LPDWORD bufreturned)
4683 FIXME("(%s,%d,%p,%d,%p,%p) - stub\n",
4684 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4688 /******************************************************************************
4689 * GetDefaultPrinterW (WINSPOOL.@)
4692 * This function must read the value from data 'device' of key
4693 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4695 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4699 WCHAR *buffer, *ptr;
4703 SetLastError(ERROR_INVALID_PARAMETER);
4707 /* make the buffer big enough for the stuff from the profile/registry,
4708 * the content must fit into the local buffer to compute the correct
4709 * size even if the extern buffer is too small or not given.
4710 * (20 for ,driver,port) */
4712 len = max(100, (insize + 20));
4713 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4715 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4717 SetLastError (ERROR_FILE_NOT_FOUND);
4721 TRACE("%s\n", debugstr_w(buffer));
4723 if ((ptr = strchrW(buffer, ',')) == NULL)
4725 SetLastError(ERROR_INVALID_NAME);
4731 *namesize = strlenW(buffer) + 1;
4732 if(!name || (*namesize > insize))
4734 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4738 strcpyW(name, buffer);
4741 HeapFree( GetProcessHeap(), 0, buffer);
4746 /******************************************************************************
4747 * GetDefaultPrinterA (WINSPOOL.@)
4749 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4753 WCHAR *bufferW = NULL;
4757 SetLastError(ERROR_INVALID_PARAMETER);
4761 if(name && *namesize) {
4763 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4766 if(!GetDefaultPrinterW( bufferW, namesize)) {
4771 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4775 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4778 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
4781 HeapFree( GetProcessHeap(), 0, bufferW);
4786 /******************************************************************************
4787 * SetDefaultPrinterW (WINSPOOL.204)
4789 * Set the Name of the Default Printer
4792 * pszPrinter [I] Name of the Printer or NULL
4799 * When the Parameter is NULL or points to an Empty String and
4800 * a Default Printer was already present, then this Function changes nothing.
4801 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4802 * the First enumerated local Printer is used.
4805 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4808 TRACE("(%s)\n", debugstr_w(pszPrinter));
4810 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4814 /******************************************************************************
4815 * SetDefaultPrinterA (WINSPOOL.202)
4817 * See SetDefaultPrinterW.
4820 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4823 TRACE("(%s)\n", debugstr_a(pszPrinter));
4825 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4830 /******************************************************************************
4831 * SetPrinterDataExA (WINSPOOL.@)
4833 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4834 LPCSTR pValueName, DWORD Type,
4835 LPBYTE pData, DWORD cbData)
4837 HKEY hkeyPrinter, hkeySubkey;
4840 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
4841 debugstr_a(pValueName), Type, pData, cbData);
4843 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4847 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4849 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4850 RegCloseKey(hkeyPrinter);
4853 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4854 RegCloseKey(hkeySubkey);
4855 RegCloseKey(hkeyPrinter);
4859 /******************************************************************************
4860 * SetPrinterDataExW (WINSPOOL.@)
4862 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4863 LPCWSTR pValueName, DWORD Type,
4864 LPBYTE pData, DWORD cbData)
4866 HKEY hkeyPrinter, hkeySubkey;
4869 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
4870 debugstr_w(pValueName), Type, pData, cbData);
4872 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4876 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4878 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4879 RegCloseKey(hkeyPrinter);
4882 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4883 RegCloseKey(hkeySubkey);
4884 RegCloseKey(hkeyPrinter);
4888 /******************************************************************************
4889 * SetPrinterDataA (WINSPOOL.@)
4891 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4892 LPBYTE pData, DWORD cbData)
4894 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4898 /******************************************************************************
4899 * SetPrinterDataW (WINSPOOL.@)
4901 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4902 LPBYTE pData, DWORD cbData)
4904 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4908 /******************************************************************************
4909 * GetPrinterDataExA (WINSPOOL.@)
4911 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4912 LPCSTR pValueName, LPDWORD pType,
4913 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4915 HKEY hkeyPrinter, hkeySubkey;
4918 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
4919 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4922 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4926 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4928 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4929 RegCloseKey(hkeyPrinter);
4933 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4934 RegCloseKey(hkeySubkey);
4935 RegCloseKey(hkeyPrinter);
4939 /******************************************************************************
4940 * GetPrinterDataExW (WINSPOOL.@)
4942 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4943 LPCWSTR pValueName, LPDWORD pType,
4944 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4946 HKEY hkeyPrinter, hkeySubkey;
4949 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
4950 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4953 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4957 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4959 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4960 RegCloseKey(hkeyPrinter);
4964 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4965 RegCloseKey(hkeySubkey);
4966 RegCloseKey(hkeyPrinter);
4970 /******************************************************************************
4971 * GetPrinterDataA (WINSPOOL.@)
4973 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4974 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4976 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4977 pData, nSize, pcbNeeded);
4980 /******************************************************************************
4981 * GetPrinterDataW (WINSPOOL.@)
4983 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4984 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4986 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4987 pData, nSize, pcbNeeded);
4990 /*******************************************************************************
4991 * EnumPrinterDataExW [WINSPOOL.@]
4993 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4994 LPBYTE pEnumValues, DWORD cbEnumValues,
4995 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4997 HKEY hkPrinter, hkSubKey;
4998 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4999 cbValueNameLen, cbMaxValueLen, cbValueLen,
5004 PPRINTER_ENUM_VALUESW ppev;
5006 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5008 if (pKeyName == NULL || *pKeyName == 0)
5009 return ERROR_INVALID_PARAMETER;
5011 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5012 if (ret != ERROR_SUCCESS)
5014 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5019 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5020 if (ret != ERROR_SUCCESS)
5022 r = RegCloseKey (hkPrinter);
5023 if (r != ERROR_SUCCESS)
5024 WARN ("RegCloseKey returned %i\n", r);
5025 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5026 debugstr_w (pKeyName), ret);
5030 ret = RegCloseKey (hkPrinter);
5031 if (ret != ERROR_SUCCESS)
5033 ERR ("RegCloseKey returned %i\n", ret);
5034 r = RegCloseKey (hkSubKey);
5035 if (r != ERROR_SUCCESS)
5036 WARN ("RegCloseKey returned %i\n", r);
5040 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5041 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5042 if (ret != ERROR_SUCCESS)
5044 r = RegCloseKey (hkSubKey);
5045 if (r != ERROR_SUCCESS)
5046 WARN ("RegCloseKey returned %i\n", r);
5047 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5051 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5052 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5054 if (cValues == 0) /* empty key */
5056 r = RegCloseKey (hkSubKey);
5057 if (r != ERROR_SUCCESS)
5058 WARN ("RegCloseKey returned %i\n", r);
5059 *pcbEnumValues = *pnEnumValues = 0;
5060 return ERROR_SUCCESS;
5063 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5065 hHeap = GetProcessHeap ();
5068 ERR ("GetProcessHeap failed\n");
5069 r = RegCloseKey (hkSubKey);
5070 if (r != ERROR_SUCCESS)
5071 WARN ("RegCloseKey returned %i\n", r);
5072 return ERROR_OUTOFMEMORY;
5075 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5076 if (lpValueName == NULL)
5078 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5079 r = RegCloseKey (hkSubKey);
5080 if (r != ERROR_SUCCESS)
5081 WARN ("RegCloseKey returned %i\n", r);
5082 return ERROR_OUTOFMEMORY;
5085 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5086 if (lpValue == NULL)
5088 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5089 if (HeapFree (hHeap, 0, lpValueName) == 0)
5090 WARN ("HeapFree failed with code %i\n", GetLastError ());
5091 r = RegCloseKey (hkSubKey);
5092 if (r != ERROR_SUCCESS)
5093 WARN ("RegCloseKey returned %i\n", r);
5094 return ERROR_OUTOFMEMORY;
5097 TRACE ("pass 1: calculating buffer required for all names and values\n");
5099 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5101 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5103 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5105 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5106 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5107 NULL, NULL, lpValue, &cbValueLen);
5108 if (ret != ERROR_SUCCESS)
5110 if (HeapFree (hHeap, 0, lpValue) == 0)
5111 WARN ("HeapFree failed with code %i\n", GetLastError ());
5112 if (HeapFree (hHeap, 0, lpValueName) == 0)
5113 WARN ("HeapFree failed with code %i\n", GetLastError ());
5114 r = RegCloseKey (hkSubKey);
5115 if (r != ERROR_SUCCESS)
5116 WARN ("RegCloseKey returned %i\n", r);
5117 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5121 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5122 debugstr_w (lpValueName), dwIndex,
5123 cbValueNameLen + 1, cbValueLen);
5125 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5126 cbBufSize += cbValueLen;
5129 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5131 *pcbEnumValues = cbBufSize;
5132 *pnEnumValues = cValues;
5134 if (cbEnumValues < cbBufSize) /* buffer too small */
5136 if (HeapFree (hHeap, 0, lpValue) == 0)
5137 WARN ("HeapFree failed with code %i\n", GetLastError ());
5138 if (HeapFree (hHeap, 0, lpValueName) == 0)
5139 WARN ("HeapFree failed with code %i\n", GetLastError ());
5140 r = RegCloseKey (hkSubKey);
5141 if (r != ERROR_SUCCESS)
5142 WARN ("RegCloseKey returned %i\n", r);
5143 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5144 return ERROR_MORE_DATA;
5147 TRACE ("pass 2: copying all names and values to buffer\n");
5149 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5150 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5152 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5154 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5155 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5156 NULL, &dwType, lpValue, &cbValueLen);
5157 if (ret != ERROR_SUCCESS)
5159 if (HeapFree (hHeap, 0, lpValue) == 0)
5160 WARN ("HeapFree failed with code %i\n", GetLastError ());
5161 if (HeapFree (hHeap, 0, lpValueName) == 0)
5162 WARN ("HeapFree failed with code %i\n", GetLastError ());
5163 r = RegCloseKey (hkSubKey);
5164 if (r != ERROR_SUCCESS)
5165 WARN ("RegCloseKey returned %i\n", r);
5166 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5170 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5171 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5172 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5173 pEnumValues += cbValueNameLen;
5175 /* return # of *bytes* (including trailing \0), not # of chars */
5176 ppev[dwIndex].cbValueName = cbValueNameLen;
5178 ppev[dwIndex].dwType = dwType;
5180 memcpy (pEnumValues, lpValue, cbValueLen);
5181 ppev[dwIndex].pData = pEnumValues;
5182 pEnumValues += cbValueLen;
5184 ppev[dwIndex].cbData = cbValueLen;
5186 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5187 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5190 if (HeapFree (hHeap, 0, lpValue) == 0)
5192 ret = GetLastError ();
5193 ERR ("HeapFree failed with code %i\n", ret);
5194 if (HeapFree (hHeap, 0, lpValueName) == 0)
5195 WARN ("HeapFree failed with code %i\n", GetLastError ());
5196 r = RegCloseKey (hkSubKey);
5197 if (r != ERROR_SUCCESS)
5198 WARN ("RegCloseKey returned %i\n", r);
5202 if (HeapFree (hHeap, 0, lpValueName) == 0)
5204 ret = GetLastError ();
5205 ERR ("HeapFree failed with code %i\n", ret);
5206 r = RegCloseKey (hkSubKey);
5207 if (r != ERROR_SUCCESS)
5208 WARN ("RegCloseKey returned %i\n", r);
5212 ret = RegCloseKey (hkSubKey);
5213 if (ret != ERROR_SUCCESS)
5215 ERR ("RegCloseKey returned %i\n", ret);
5219 return ERROR_SUCCESS;
5222 /*******************************************************************************
5223 * EnumPrinterDataExA [WINSPOOL.@]
5225 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5226 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5227 * what Windows 2000 SP1 does.
5230 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5231 LPBYTE pEnumValues, DWORD cbEnumValues,
5232 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5236 DWORD ret, dwIndex, dwBufSize;
5240 TRACE ("%p %s\n", hPrinter, pKeyName);
5242 if (pKeyName == NULL || *pKeyName == 0)
5243 return ERROR_INVALID_PARAMETER;
5245 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5248 ret = GetLastError ();
5249 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5253 hHeap = GetProcessHeap ();
5256 ERR ("GetProcessHeap failed\n");
5257 return ERROR_OUTOFMEMORY;
5260 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5261 if (pKeyNameW == NULL)
5263 ERR ("Failed to allocate %i bytes from process heap\n",
5264 (LONG)(len * sizeof (WCHAR)));
5265 return ERROR_OUTOFMEMORY;
5268 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5270 ret = GetLastError ();
5271 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5272 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5273 WARN ("HeapFree failed with code %i\n", GetLastError ());
5277 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5278 pcbEnumValues, pnEnumValues);
5279 if (ret != ERROR_SUCCESS)
5281 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5282 WARN ("HeapFree failed with code %i\n", GetLastError ());
5283 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5287 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5289 ret = GetLastError ();
5290 ERR ("HeapFree failed with code %i\n", ret);
5294 if (*pnEnumValues == 0) /* empty key */
5295 return ERROR_SUCCESS;
5298 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5300 PPRINTER_ENUM_VALUESW ppev =
5301 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5303 if (dwBufSize < ppev->cbValueName)
5304 dwBufSize = ppev->cbValueName;
5306 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5307 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5308 dwBufSize = ppev->cbData;
5311 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5313 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5314 if (pBuffer == NULL)
5316 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5317 return ERROR_OUTOFMEMORY;
5320 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5322 PPRINTER_ENUM_VALUESW ppev =
5323 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5325 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5326 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5330 ret = GetLastError ();
5331 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5332 if (HeapFree (hHeap, 0, pBuffer) == 0)
5333 WARN ("HeapFree failed with code %i\n", GetLastError ());
5337 memcpy (ppev->pValueName, pBuffer, len);
5339 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5341 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5342 ppev->dwType != REG_MULTI_SZ)
5345 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5346 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5349 ret = GetLastError ();
5350 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5351 if (HeapFree (hHeap, 0, pBuffer) == 0)
5352 WARN ("HeapFree failed with code %i\n", GetLastError ());
5356 memcpy (ppev->pData, pBuffer, len);
5358 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5359 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5362 if (HeapFree (hHeap, 0, pBuffer) == 0)
5364 ret = GetLastError ();
5365 ERR ("HeapFree failed with code %i\n", ret);
5369 return ERROR_SUCCESS;
5372 /******************************************************************************
5373 * AbortPrinter (WINSPOOL.@)
5375 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5377 FIXME("(%p), stub!\n", hPrinter);
5381 /******************************************************************************
5382 * AddPortA (WINSPOOL.@)
5387 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5389 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5393 /******************************************************************************
5394 * AddPortW (WINSPOOL.@)
5396 * Add a Port for a specific Monitor
5399 * pName [I] Servername or NULL (local Computer)
5400 * hWnd [I] Handle to parent Window for the Dialog-Box
5401 * pMonitorName [I] Name of the Monitor that manage the Port
5411 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5413 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5417 /******************************************************************************
5418 * AddPortExA (WINSPOOL.@)
5423 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5425 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5426 lpBuffer, debugstr_a(lpMonitorName));
5430 /******************************************************************************
5431 * AddPortExW (WINSPOOL.@)
5433 * Add a Port for a specific Monitor, without presenting a user interface
5436 * hMonitor [I] Handle from InitializePrintMonitor2()
5437 * pName [I] Servername or NULL (local Computer)
5438 * Level [I] Structure-Level (1 or 2) for lpBuffer
5439 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5440 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5450 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5452 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5453 lpBuffer, debugstr_w(lpMonitorName));
5457 /******************************************************************************
5458 * AddPrinterConnectionA (WINSPOOL.@)
5460 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5462 FIXME("%s\n", debugstr_a(pName));
5466 /******************************************************************************
5467 * AddPrinterConnectionW (WINSPOOL.@)
5469 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5471 FIXME("%s\n", debugstr_w(pName));
5475 /******************************************************************************
5476 * AddPrinterDriverExW (WINSPOOL.@)
5478 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5479 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5481 FIXME("%s %d %p %d\n", debugstr_w(pName),
5482 Level, pDriverInfo, dwFileCopyFlags);
5483 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5487 /******************************************************************************
5488 * AddPrinterDriverExA (WINSPOOL.@)
5490 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5491 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5493 FIXME("%s %d %p %d\n", debugstr_a(pName),
5494 Level, pDriverInfo, dwFileCopyFlags);
5495 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5499 /******************************************************************************
5500 * ConfigurePortA (WINSPOOL.@)
5502 * See ConfigurePortW.
5505 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5507 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5511 /******************************************************************************
5512 * ConfigurePortW (WINSPOOL.@)
5514 * Display the Configuration-Dialog for a specific Port
5517 * pName [I] Servername or NULL (local Computer)
5518 * hWnd [I] Handle to parent Window for the Dialog-Box
5519 * pPortName [I] Name of the Port, that should be configured
5529 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5531 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5535 /******************************************************************************
5536 * ConnectToPrinterDlg (WINSPOOL.@)
5538 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5540 FIXME("%p %x\n", hWnd, Flags);
5544 /******************************************************************************
5545 * DeletePrinterConnectionA (WINSPOOL.@)
5547 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5549 FIXME("%s\n", debugstr_a(pName));
5553 /******************************************************************************
5554 * DeletePrinterConnectionW (WINSPOOL.@)
5556 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5558 FIXME("%s\n", debugstr_w(pName));
5562 /******************************************************************************
5563 * DeletePrinterDriverExW (WINSPOOL.@)
5565 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5566 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5568 FIXME("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
5569 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5573 /******************************************************************************
5574 * DeletePrinterDriverExA (WINSPOOL.@)
5576 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5577 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5579 FIXME("%s %s %s %x %x\n", debugstr_a(pName), debugstr_a(pEnvironment),
5580 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5584 /******************************************************************************
5585 * DeletePrinterDataExW (WINSPOOL.@)
5587 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5590 FIXME("%p %s %s\n", hPrinter,
5591 debugstr_w(pKeyName), debugstr_w(pValueName));
5592 return ERROR_INVALID_PARAMETER;
5595 /******************************************************************************
5596 * DeletePrinterDataExA (WINSPOOL.@)
5598 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5601 FIXME("%p %s %s\n", hPrinter,
5602 debugstr_a(pKeyName), debugstr_a(pValueName));
5603 return ERROR_INVALID_PARAMETER;
5606 /******************************************************************************
5607 * DeletePrintProcessorA (WINSPOOL.@)
5609 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5611 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5612 debugstr_a(pPrintProcessorName));
5616 /******************************************************************************
5617 * DeletePrintProcessorW (WINSPOOL.@)
5619 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5621 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5622 debugstr_w(pPrintProcessorName));
5626 /******************************************************************************
5627 * DeletePrintProvidorA (WINSPOOL.@)
5629 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5631 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5632 debugstr_a(pPrintProviderName));
5636 /******************************************************************************
5637 * DeletePrintProvidorW (WINSPOOL.@)
5639 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5641 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5642 debugstr_w(pPrintProviderName));
5646 /******************************************************************************
5647 * EnumFormsA (WINSPOOL.@)
5649 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5650 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5652 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5653 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5657 /******************************************************************************
5658 * EnumFormsW (WINSPOOL.@)
5660 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5661 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5663 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5664 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5668 /*****************************************************************************
5669 * EnumMonitorsA [WINSPOOL.@]
5671 * See EnumMonitorsW.
5674 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5675 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5678 LPBYTE bufferW = NULL;
5679 LPWSTR nameW = NULL;
5681 DWORD numentries = 0;
5684 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5685 cbBuf, pcbNeeded, pcReturned);
5687 /* convert servername to unicode */
5689 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5690 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5691 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5693 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5694 needed = cbBuf * sizeof(WCHAR);
5695 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5696 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5698 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5699 if (pcbNeeded) needed = *pcbNeeded;
5700 /* HeapReAlloc return NULL, when bufferW was NULL */
5701 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5702 HeapAlloc(GetProcessHeap(), 0, needed);
5704 /* Try again with the large Buffer */
5705 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5707 numentries = pcReturned ? *pcReturned : 0;
5710 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5711 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5714 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5715 DWORD entrysize = 0;
5718 LPMONITOR_INFO_2W mi2w;
5719 LPMONITOR_INFO_2A mi2a;
5721 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5722 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5724 /* First pass: calculate the size for all Entries */
5725 mi2w = (LPMONITOR_INFO_2W) bufferW;
5726 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5728 while (index < numentries) {
5730 needed += entrysize; /* MONITOR_INFO_?A */
5731 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5733 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5734 NULL, 0, NULL, NULL);
5736 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5737 NULL, 0, NULL, NULL);
5738 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5739 NULL, 0, NULL, NULL);
5741 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5742 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5743 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5746 /* check for errors and quit on failure */
5747 if (cbBuf < needed) {
5748 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5752 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5753 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5754 cbBuf -= len ; /* free Bytes in the user-Buffer */
5755 mi2w = (LPMONITOR_INFO_2W) bufferW;
5756 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5758 /* Second Pass: Fill the User Buffer (if we have one) */
5759 while ((index < numentries) && pMonitors) {
5761 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
5763 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5764 ptr, cbBuf , NULL, NULL);
5768 mi2a->pEnvironment = ptr;
5769 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5770 ptr, cbBuf, NULL, NULL);
5774 mi2a->pDLLName = ptr;
5775 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5776 ptr, cbBuf, NULL, NULL);
5780 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5781 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5782 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5786 if (pcbNeeded) *pcbNeeded = needed;
5787 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5789 HeapFree(GetProcessHeap(), 0, nameW);
5790 HeapFree(GetProcessHeap(), 0, bufferW);
5792 TRACE("returning %d with %d (%d byte for %d entries)\n",
5793 (res), GetLastError(), needed, numentries);
5799 /*****************************************************************************
5800 * EnumMonitorsW [WINSPOOL.@]
5802 * Enumerate available Port-Monitors
5805 * pName [I] Servername or NULL (local Computer)
5806 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5807 * pMonitors [O] PTR to Buffer that receives the Result
5808 * cbBuf [I] Size of Buffer at pMonitors
5809 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5810 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5814 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5817 * Windows reads the Registry once and cache the Results.
5819 *| Language-Monitors are also installed in the same Registry-Location but
5820 *| they are filtered in Windows (not returned by EnumMonitors).
5821 *| We do no filtering to simplify our Code.
5824 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5825 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5828 DWORD numentries = 0;
5831 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5832 cbBuf, pcbNeeded, pcReturned);
5834 if (pName && (lstrlenW(pName))) {
5835 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5836 SetLastError(ERROR_ACCESS_DENIED);
5840 /* Level is not checked in win9x */
5841 if (!Level || (Level > 2)) {
5842 WARN("level (%d) is ignored in win9x\n", Level);
5843 SetLastError(ERROR_INVALID_LEVEL);
5847 SetLastError(RPC_X_NULL_REF_POINTER);
5851 /* Scan all Monitor-Keys */
5853 needed = get_local_monitors(Level, NULL, 0, &numentries);
5855 /* we calculated the needed buffersize. now do the error-checks */
5856 if (cbBuf < needed) {
5857 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5860 else if (!pMonitors || !pcReturned) {
5861 SetLastError(RPC_X_NULL_REF_POINTER);
5865 /* fill the Buffer with the Monitor-Keys */
5866 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5870 if (pcbNeeded) *pcbNeeded = needed;
5871 if (pcReturned) *pcReturned = numentries;
5873 TRACE("returning %d with %d (%d byte for %d entries)\n",
5874 res, GetLastError(), needed, numentries);
5879 /******************************************************************************
5880 * XcvDataW (WINSPOOL.@)
5883 * There doesn't seem to be an A version...
5885 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5886 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5887 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5889 FIXME("%p %s %p %d %p %d %p %p\n", hXcv, debugstr_w(pszDataName),
5890 pInputData, cbInputData, pOutputData,
5891 cbOutputData, pcbOutputNeeded, pdwStatus);
5895 /*****************************************************************************
5896 * EnumPrinterDataA [WINSPOOL.@]
5899 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5900 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5901 DWORD cbData, LPDWORD pcbData )
5903 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
5904 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5905 return ERROR_NO_MORE_ITEMS;
5908 /*****************************************************************************
5909 * EnumPrinterDataW [WINSPOOL.@]
5912 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5913 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5914 DWORD cbData, LPDWORD pcbData )
5916 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
5917 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5918 return ERROR_NO_MORE_ITEMS;
5921 /*****************************************************************************
5922 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5925 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5926 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5927 LPDWORD pcbNeeded, LPDWORD pcReturned)
5929 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
5930 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5931 pcbNeeded, pcReturned);
5935 /*****************************************************************************
5936 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5939 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5940 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5941 LPDWORD pcbNeeded, LPDWORD pcReturned)
5943 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
5944 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5945 pcbNeeded, pcReturned);
5949 /*****************************************************************************
5950 * EnumPrintProcessorsA [WINSPOOL.@]
5953 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5954 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5956 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
5957 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5961 /*****************************************************************************
5962 * EnumPrintProcessorsW [WINSPOOL.@]
5965 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5966 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5968 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
5969 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5970 cbBuf, pcbNeeded, pcbReturned);
5974 /*****************************************************************************
5975 * ExtDeviceMode [WINSPOOL.@]
5978 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5979 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5982 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
5983 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5984 debugstr_a(pProfile), fMode);
5988 /*****************************************************************************
5989 * FindClosePrinterChangeNotification [WINSPOOL.@]
5992 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5994 FIXME("Stub: %p\n", hChange);
5998 /*****************************************************************************
5999 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6002 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6003 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6005 FIXME("Stub: %p %x %x %p\n",
6006 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6007 return INVALID_HANDLE_VALUE;
6010 /*****************************************************************************
6011 * FindNextPrinterChangeNotification [WINSPOOL.@]
6014 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6015 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6017 FIXME("Stub: %p %p %p %p\n",
6018 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6022 /*****************************************************************************
6023 * FreePrinterNotifyInfo [WINSPOOL.@]
6026 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6028 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6032 /*****************************************************************************
6035 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6036 * ansi depending on the unicode parameter.
6038 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6048 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6051 memcpy(ptr, str, *size);
6058 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6061 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6068 /*****************************************************************************
6071 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6072 LPDWORD pcbNeeded, BOOL unicode)
6074 DWORD size, left = cbBuf;
6075 BOOL space = (cbBuf > 0);
6082 ji1->JobId = job->job_id;
6085 string_to_buf(job->document_title, ptr, left, &size, unicode);
6086 if(space && size <= left)
6088 ji1->pDocument = (LPWSTR)ptr;
6099 /*****************************************************************************
6102 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6103 LPDWORD pcbNeeded, BOOL unicode)
6105 DWORD size, left = cbBuf;
6106 BOOL space = (cbBuf > 0);
6113 ji2->JobId = job->job_id;
6116 string_to_buf(job->document_title, ptr, left, &size, unicode);
6117 if(space && size <= left)
6119 ji2->pDocument = (LPWSTR)ptr;
6130 /*****************************************************************************
6133 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6134 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6137 DWORD needed = 0, size;
6141 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6143 EnterCriticalSection(&printer_handles_cs);
6144 job = get_job(hPrinter, JobId);
6151 size = sizeof(JOB_INFO_1W);
6156 memset(pJob, 0, size);
6160 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6165 size = sizeof(JOB_INFO_2W);
6170 memset(pJob, 0, size);
6174 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6179 size = sizeof(JOB_INFO_3);
6183 memset(pJob, 0, size);
6192 SetLastError(ERROR_INVALID_LEVEL);
6196 *pcbNeeded = needed;
6198 LeaveCriticalSection(&printer_handles_cs);
6202 /*****************************************************************************
6203 * GetJobA [WINSPOOL.@]
6206 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6207 DWORD cbBuf, LPDWORD pcbNeeded)
6209 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6212 /*****************************************************************************
6213 * GetJobW [WINSPOOL.@]
6216 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6217 DWORD cbBuf, LPDWORD pcbNeeded)
6219 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6222 /*****************************************************************************
6225 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6227 char *unixname, *queue, *cmd;
6228 char fmt[] = "lpr -P%s %s";
6231 if(!(unixname = wine_get_unix_file_name(filename)))
6234 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6235 queue = HeapAlloc(GetProcessHeap(), 0, len);
6236 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6238 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6239 sprintf(cmd, fmt, queue, unixname);
6241 TRACE("printing with: %s\n", cmd);
6244 HeapFree(GetProcessHeap(), 0, cmd);
6245 HeapFree(GetProcessHeap(), 0, queue);
6246 HeapFree(GetProcessHeap(), 0, unixname);
6250 /*****************************************************************************
6253 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6255 #if HAVE_CUPS_CUPS_H
6258 char *unixname, *queue, *doc_titleA;
6262 if(!(unixname = wine_get_unix_file_name(filename)))
6265 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6266 queue = HeapAlloc(GetProcessHeap(), 0, len);
6267 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6269 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6270 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6271 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6273 TRACE("printing via cups\n");
6274 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6275 HeapFree(GetProcessHeap(), 0, doc_titleA);
6276 HeapFree(GetProcessHeap(), 0, queue);
6277 HeapFree(GetProcessHeap(), 0, unixname);
6283 return schedule_lpr(printer_name, filename);
6287 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6294 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6298 if(HIWORD(wparam) == BN_CLICKED)
6300 if(LOWORD(wparam) == IDOK)
6303 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6306 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6307 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6309 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6311 WCHAR caption[200], message[200];
6314 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6315 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6316 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6317 if(mb_ret == IDCANCEL)
6319 HeapFree(GetProcessHeap(), 0, filename);
6323 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6324 if(hf == INVALID_HANDLE_VALUE)
6326 WCHAR caption[200], message[200];
6328 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6329 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6330 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6331 HeapFree(GetProcessHeap(), 0, filename);
6335 DeleteFileW(filename);
6336 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6338 EndDialog(hwnd, IDOK);
6341 if(LOWORD(wparam) == IDCANCEL)
6343 EndDialog(hwnd, IDCANCEL);
6352 /*****************************************************************************
6355 static BOOL get_filename(LPWSTR *filename)
6357 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6358 file_dlg_proc, (LPARAM)filename) == IDOK;
6361 /*****************************************************************************
6364 static BOOL schedule_file(LPCWSTR filename)
6366 LPWSTR output = NULL;
6368 if(get_filename(&output))
6370 TRACE("copy to %s\n", debugstr_w(output));
6371 CopyFileW(filename, output, FALSE);
6372 HeapFree(GetProcessHeap(), 0, output);
6378 /*****************************************************************************
6381 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6384 char *unixname, *cmdA;
6386 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6390 if(!(unixname = wine_get_unix_file_name(filename)))
6393 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6394 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6395 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6397 TRACE("printing with: %s\n", cmdA);
6399 if((file_fd = open(unixname, O_RDONLY)) == -1)
6404 ERR("pipe() failed!\n");
6414 /* reset signals that we previously set to SIG_IGN */
6415 signal(SIGPIPE, SIG_DFL);
6416 signal(SIGCHLD, SIG_DFL);
6422 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6423 write(fds[1], buf, no_read);
6428 if(file_fd != -1) close(file_fd);
6429 if(fds[0] != -1) close(fds[0]);
6430 if(fds[1] != -1) close(fds[1]);
6432 HeapFree(GetProcessHeap(), 0, cmdA);
6433 HeapFree(GetProcessHeap(), 0, unixname);
6440 /*****************************************************************************
6443 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6445 int in_fd, out_fd, no_read;
6448 char *unixname, *outputA;
6451 if(!(unixname = wine_get_unix_file_name(filename)))
6454 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6455 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6456 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6458 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6459 in_fd = open(unixname, O_RDONLY);
6460 if(out_fd == -1 || in_fd == -1)
6463 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6464 write(out_fd, buf, no_read);
6468 if(in_fd != -1) close(in_fd);
6469 if(out_fd != -1) close(out_fd);
6470 HeapFree(GetProcessHeap(), 0, outputA);
6471 HeapFree(GetProcessHeap(), 0, unixname);
6475 /*****************************************************************************
6476 * ScheduleJob [WINSPOOL.@]
6479 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6481 opened_printer_t *printer;
6483 struct list *cursor, *cursor2;
6485 TRACE("(%p, %x)\n", hPrinter, dwJobID);
6486 EnterCriticalSection(&printer_handles_cs);
6487 printer = get_opened_printer(hPrinter);
6491 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6493 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6496 if(job->job_id != dwJobID) continue;
6498 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6499 if(hf != INVALID_HANDLE_VALUE)
6501 PRINTER_INFO_5W *pi5;
6505 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6506 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6508 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6509 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6510 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6511 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6512 debugstr_w(pi5->pPortName));
6516 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6517 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6519 DWORD type, count = sizeof(output);
6520 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6523 if(output[0] == '|')
6525 schedule_pipe(output + 1, job->filename);
6529 schedule_unixfile(output, job->filename);
6531 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6533 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6535 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6537 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6539 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6541 schedule_file(job->filename);
6545 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6547 HeapFree(GetProcessHeap(), 0, pi5);
6549 DeleteFileW(job->filename);
6551 list_remove(cursor);
6552 HeapFree(GetProcessHeap(), 0, job->document_title);
6553 HeapFree(GetProcessHeap(), 0, job->filename);
6554 HeapFree(GetProcessHeap(), 0, job);
6559 LeaveCriticalSection(&printer_handles_cs);
6563 /*****************************************************************************
6564 * StartDocDlgA [WINSPOOL.@]
6566 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6568 UNICODE_STRING usBuffer;
6571 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
6574 docW.cbSize = sizeof(docW);
6575 if (doc->lpszDocName)
6577 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
6578 if (!(docW.lpszDocName = docnameW)) return NULL;
6580 if (doc->lpszOutput)
6582 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
6583 if (!(docW.lpszOutput = outputW)) return NULL;
6585 if (doc->lpszDatatype)
6587 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
6588 if (!(docW.lpszDatatype = datatypeW)) return NULL;
6590 docW.fwType = doc->fwType;
6592 retW = StartDocDlgW(hPrinter, &docW);
6596 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6597 ret = HeapAlloc(GetProcessHeap(), 0, len);
6598 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6599 HeapFree(GetProcessHeap(), 0, retW);
6602 HeapFree(GetProcessHeap(), 0, datatypeW);
6603 HeapFree(GetProcessHeap(), 0, outputW);
6604 HeapFree(GetProcessHeap(), 0, docnameW);
6609 /*****************************************************************************
6610 * StartDocDlgW [WINSPOOL.@]
6612 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6613 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6614 * port is "FILE:". Also returns the full path if passed a relative path.
6616 * The caller should free the returned string from the process heap.
6618 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6623 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6625 PRINTER_INFO_5W *pi5;
6626 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6627 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6629 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6630 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6631 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6633 HeapFree(GetProcessHeap(), 0, pi5);
6636 HeapFree(GetProcessHeap(), 0, pi5);
6639 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6642 get_filename(&name);
6645 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6647 HeapFree(GetProcessHeap(), 0, name);
6650 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6651 GetFullPathNameW(name, len, ret, NULL);
6652 HeapFree(GetProcessHeap(), 0, name);
6657 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6660 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6661 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6663 attr = GetFileAttributesW(ret);
6664 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6666 HeapFree(GetProcessHeap(), 0, ret);