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 %ld)\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 (%ld)\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 (%ld)\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_%ld: %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_%ldW #%ld\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 %ld byte for %ld 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: %ld) %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) => %ld\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%08lx: dwMonitorSize (%ld) => %ld Functions\n",
958 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize,
959 (pm->monitorUI->dwMonitorUISize - sizeof(DWORD) ) / sizeof(VOID *));
964 if (pInitializePrintMonitor != NULL) {
965 pmonitorEx = pInitializePrintMonitor(regroot);
966 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
967 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
970 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
971 pm->monitor = &(pmonitorEx->Monitor);
976 TRACE( "0x%08lx: dwMonitorSize (%ld) => %ld Functions\n",
977 pm->dwMonitorSize, pm->dwMonitorSize,
978 (pm->dwMonitorSize) / sizeof(VOID *) );
983 if (pInitializePrintMonitor2 != NULL) {
984 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
986 if (pInitializeMonitorEx != NULL) {
987 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
989 if (pInitializeMonitor != NULL) {
990 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
993 if (!pm->monitor && !pm->monitorUI) {
995 SetLastError(ERROR_PROC_NOT_FOUND);
1000 LeaveCriticalSection(&monitor_handles_cs);
1001 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1002 HeapFree(GetProcessHeap(), 0, regroot);
1003 TRACE("=> %p\n", pm);
1007 /******************************************************************
1008 * get_opened_printer_entry
1009 * Get the first place empty in the opened printer table
1012 * - pDefault is ignored
1014 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1016 UINT_PTR handle = nb_printer_handles, i;
1017 jobqueue_t *queue = NULL;
1018 opened_printer_t *printer = NULL;
1020 EnterCriticalSection(&printer_handles_cs);
1022 for (i = 0; i < nb_printer_handles; i++)
1024 if (!printer_handles[i])
1026 if(handle == nb_printer_handles)
1031 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1032 queue = printer_handles[i]->queue;
1036 if (handle >= nb_printer_handles)
1038 opened_printer_t **new_array;
1039 if (printer_handles)
1040 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1041 (nb_printer_handles + 16) * sizeof(*new_array) );
1043 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1044 (nb_printer_handles + 16) * sizeof(*new_array) );
1051 printer_handles = new_array;
1052 nb_printer_handles += 16;
1055 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1062 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
1063 if (!printer->name) {
1067 strcpyW(printer->name, name);
1071 printer->queue = queue;
1074 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1075 if (!printer->queue) {
1079 list_init(&printer->queue->jobs);
1080 printer->queue->ref = 0;
1082 InterlockedIncrement(&printer->queue->ref);
1084 printer_handles[handle] = printer;
1087 LeaveCriticalSection(&printer_handles_cs);
1088 if (!handle && printer) {
1089 /* Something Failed: Free the Buffers */
1090 HeapFree(GetProcessHeap(), 0, printer->name);
1091 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1092 HeapFree(GetProcessHeap(), 0, printer);
1095 return (HANDLE)handle;
1098 /******************************************************************
1099 * get_opened_printer
1100 * Get the pointer to the opened printer referred by the handle
1102 static opened_printer_t *get_opened_printer(HANDLE hprn)
1104 UINT_PTR idx = (UINT_PTR)hprn;
1105 opened_printer_t *ret = NULL;
1107 EnterCriticalSection(&printer_handles_cs);
1109 if ((idx <= 0) || (idx > nb_printer_handles))
1112 ret = printer_handles[idx - 1];
1114 LeaveCriticalSection(&printer_handles_cs);
1118 /******************************************************************
1119 * get_opened_printer_name
1120 * Get the pointer to the opened printer name referred by the handle
1122 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1124 opened_printer_t *printer = get_opened_printer(hprn);
1125 if(!printer) return NULL;
1126 return printer->name;
1129 /******************************************************************
1130 * WINSPOOL_GetOpenedPrinterRegKey
1133 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1135 LPCWSTR name = get_opened_printer_name(hPrinter);
1139 if(!name) return ERROR_INVALID_HANDLE;
1141 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1145 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1147 ERR("Can't find opened printer %s in registry\n",
1149 RegCloseKey(hkeyPrinters);
1150 return ERROR_INVALID_PRINTER_NAME; /* ? */
1152 RegCloseKey(hkeyPrinters);
1153 return ERROR_SUCCESS;
1156 /******************************************************************
1159 * Get the pointer to the specified job.
1160 * Should hold the printer_handles_cs before calling.
1162 static job_t *get_job(HANDLE hprn, DWORD JobId)
1164 opened_printer_t *printer = get_opened_printer(hprn);
1167 if(!printer) return NULL;
1168 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1170 if(job->job_id == JobId)
1176 /***********************************************************
1179 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1182 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1185 Formname = (dmA->dmSize > off_formname);
1186 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1187 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1188 dmW->dmDeviceName, CCHDEVICENAME);
1190 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1191 dmA->dmSize - CCHDEVICENAME);
1193 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1194 off_formname - CCHDEVICENAME);
1195 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1196 dmW->dmFormName, CCHFORMNAME);
1197 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1198 (off_formname + CCHFORMNAME));
1201 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1202 dmA->dmDriverExtra);
1206 /***********************************************************
1208 * Creates an ascii copy of supplied devmode on heap
1210 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1215 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1217 if(!dmW) return NULL;
1218 Formname = (dmW->dmSize > off_formname);
1219 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1220 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1221 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1222 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1224 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1225 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1227 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1228 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1229 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1230 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1231 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1232 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1235 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1236 dmW->dmDriverExtra);
1240 /***********************************************************
1241 * PRINTER_INFO_2AtoW
1242 * Creates a unicode copy of PRINTER_INFO_2A on heap
1244 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1246 LPPRINTER_INFO_2W piW;
1247 UNICODE_STRING usBuffer;
1249 if(!piA) return NULL;
1250 piW = HeapAlloc(heap, 0, sizeof(*piW));
1251 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1253 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1254 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1255 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1256 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1257 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1258 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1259 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1260 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1261 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1262 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1263 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1264 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1268 /***********************************************************
1269 * FREE_PRINTER_INFO_2W
1270 * Free PRINTER_INFO_2W and all strings
1272 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1276 HeapFree(heap,0,piW->pServerName);
1277 HeapFree(heap,0,piW->pPrinterName);
1278 HeapFree(heap,0,piW->pShareName);
1279 HeapFree(heap,0,piW->pPortName);
1280 HeapFree(heap,0,piW->pDriverName);
1281 HeapFree(heap,0,piW->pComment);
1282 HeapFree(heap,0,piW->pLocation);
1283 HeapFree(heap,0,piW->pDevMode);
1284 HeapFree(heap,0,piW->pSepFile);
1285 HeapFree(heap,0,piW->pPrintProcessor);
1286 HeapFree(heap,0,piW->pDatatype);
1287 HeapFree(heap,0,piW->pParameters);
1288 HeapFree(heap,0,piW);
1292 /******************************************************************
1293 * DeviceCapabilities [WINSPOOL.@]
1294 * DeviceCapabilitiesA [WINSPOOL.@]
1297 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1298 LPSTR pOutput, LPDEVMODEA lpdm)
1302 if (!GDI_CallDeviceCapabilities16)
1304 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1306 if (!GDI_CallDeviceCapabilities16) return -1;
1308 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1310 /* If DC_PAPERSIZE map POINT16s to POINTs */
1311 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1312 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1313 POINT *pt = (POINT *)pOutput;
1315 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1316 for(i = 0; i < ret; i++, pt++)
1321 HeapFree( GetProcessHeap(), 0, tmp );
1327 /*****************************************************************************
1328 * DeviceCapabilitiesW [WINSPOOL.@]
1330 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1333 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1334 WORD fwCapability, LPWSTR pOutput,
1335 const DEVMODEW *pDevMode)
1337 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1338 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1339 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1342 if(pOutput && (fwCapability == DC_BINNAMES ||
1343 fwCapability == DC_FILEDEPENDENCIES ||
1344 fwCapability == DC_PAPERNAMES)) {
1345 /* These need A -> W translation */
1348 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1352 switch(fwCapability) {
1357 case DC_FILEDEPENDENCIES:
1361 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1362 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1364 for(i = 0; i < ret; i++)
1365 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1366 pOutput + (i * size), size);
1367 HeapFree(GetProcessHeap(), 0, pOutputA);
1369 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1370 (LPSTR)pOutput, dmA);
1372 HeapFree(GetProcessHeap(),0,pPortA);
1373 HeapFree(GetProcessHeap(),0,pDeviceA);
1374 HeapFree(GetProcessHeap(),0,dmA);
1378 /******************************************************************
1379 * DocumentPropertiesA [WINSPOOL.@]
1381 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1383 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1384 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1385 LPDEVMODEA pDevModeInput,DWORD fMode )
1387 LPSTR lpName = pDeviceName;
1388 static CHAR port[] = "LPT1:";
1391 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1392 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1396 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1398 ERR("no name from hPrinter?\n");
1399 SetLastError(ERROR_INVALID_HANDLE);
1402 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1405 if (!GDI_CallExtDeviceMode16)
1407 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1409 if (!GDI_CallExtDeviceMode16) {
1410 ERR("No CallExtDeviceMode16?\n");
1414 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1415 pDevModeInput, NULL, fMode);
1418 HeapFree(GetProcessHeap(),0,lpName);
1423 /*****************************************************************************
1424 * DocumentPropertiesW (WINSPOOL.@)
1426 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1428 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1430 LPDEVMODEW pDevModeOutput,
1431 LPDEVMODEW pDevModeInput, DWORD fMode)
1434 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1435 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1436 LPDEVMODEA pDevModeOutputA = NULL;
1439 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1440 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1442 if(pDevModeOutput) {
1443 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1444 if(ret < 0) return ret;
1445 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1447 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1448 pDevModeInputA, fMode);
1449 if(pDevModeOutput) {
1450 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1451 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1453 if(fMode == 0 && ret > 0)
1454 ret += (CCHDEVICENAME + CCHFORMNAME);
1455 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1456 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1460 /******************************************************************
1461 * OpenPrinterA [WINSPOOL.@]
1466 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1467 LPPRINTER_DEFAULTSA pDefault)
1469 UNICODE_STRING lpPrinterNameW;
1470 UNICODE_STRING usBuffer;
1471 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1472 PWSTR pwstrPrinterNameW;
1475 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1478 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1479 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1480 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1481 pDefaultW = &DefaultW;
1483 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1485 RtlFreeUnicodeString(&usBuffer);
1486 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1488 RtlFreeUnicodeString(&lpPrinterNameW);
1492 /******************************************************************
1493 * OpenPrinterW [WINSPOOL.@]
1495 * Open a Printer / Printserver or a Printer-Object
1498 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1499 * phPrinter [O] The resulting Handle is stored here
1500 * pDefault [I] PTR to Default Printer Settings or NULL
1507 * lpPrinterName is one of:
1508 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1509 *| Printer: "PrinterName"
1510 *| Printer-Object: "PrinterName,Job xxx"
1511 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1512 *| XcvPort: "Servername,XcvPort PortName"
1515 *| Printer-Object not supported
1516 *| XcvMonitor not supported
1517 *| XcvPort not supported
1518 *| pDefaults is ignored
1521 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1523 HKEY hkeyPrinters = NULL;
1524 HKEY hkeyPrinter = NULL;
1526 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1528 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08lx\n",
1529 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1532 if(lpPrinterName != NULL)
1534 /* Check any Printer exists */
1535 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1536 ERR("Can't create Printers key\n");
1537 SetLastError(ERROR_FILE_NOT_FOUND);
1540 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1541 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1543 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1544 RegCloseKey(hkeyPrinters);
1545 SetLastError(ERROR_INVALID_PRINTER_NAME);
1548 RegCloseKey(hkeyPrinter);
1549 RegCloseKey(hkeyPrinters);
1552 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1553 SetLastError(ERROR_INVALID_PARAMETER);
1557 /* Get the unique handle of the printer or Printserver */
1558 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1559 return (*phPrinter != 0);
1562 /******************************************************************
1563 * AddMonitorA [WINSPOOL.@]
1568 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1570 LPWSTR nameW = NULL;
1573 LPMONITOR_INFO_2A mi2a;
1574 MONITOR_INFO_2W mi2w;
1576 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1577 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1578 mi2a ? debugstr_a(mi2a->pName) : NULL,
1579 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1580 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1583 SetLastError(ERROR_INVALID_LEVEL);
1587 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1593 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1594 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1595 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1598 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1600 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1601 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1602 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1604 if (mi2a->pEnvironment) {
1605 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1606 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1607 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1609 if (mi2a->pDLLName) {
1610 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1611 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1612 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1615 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1617 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1618 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1619 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1621 HeapFree(GetProcessHeap(), 0, nameW);
1625 /******************************************************************************
1626 * AddMonitorW [WINSPOOL.@]
1628 * Install a Printmonitor
1631 * pName [I] Servername or NULL (local Computer)
1632 * Level [I] Structure-Level (Must be 2)
1633 * pMonitors [I] PTR to MONITOR_INFO_2
1640 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1643 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1645 monitor_t * pm = NULL;
1646 LPMONITOR_INFO_2W mi2w;
1652 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1653 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1654 mi2w ? debugstr_w(mi2w->pName) : NULL,
1655 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1656 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1659 SetLastError(ERROR_INVALID_LEVEL);
1663 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1668 if (pName && (pName[0])) {
1669 FIXME("for server %s not implemented\n", debugstr_w(pName));
1670 SetLastError(ERROR_ACCESS_DENIED);
1675 if (!mi2w->pName || (! mi2w->pName[0])) {
1676 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1677 SetLastError(ERROR_INVALID_PARAMETER);
1680 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1681 WARN("Environment %s requested (we support only %s)\n",
1682 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1683 SetLastError(ERROR_INVALID_ENVIRONMENT);
1687 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1688 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1689 SetLastError(ERROR_INVALID_PARAMETER);
1693 /* Load and initialize the monitor. SetLastError() is called on failure */
1694 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1699 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1700 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1704 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1705 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1706 &disposition) == ERROR_SUCCESS) {
1708 /* Some installers set options for the port before calling AddMonitor.
1709 We query the "Driver" entry to verify that the monitor is installed,
1710 before we return an error.
1711 When a user installs two print monitors at the same time with the
1712 same name but with a different driver DLL and a task switch comes
1713 between RegQueryValueExW and RegSetValueExW, a race condition
1714 is possible but silently ignored. */
1718 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1719 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1720 &namesize) == ERROR_SUCCESS)) {
1721 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1722 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1723 9x: ERROR_ALREADY_EXISTS (183) */
1724 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1729 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1730 res = (RegSetValueExW(hentry, DriverW, 0,
1731 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1733 RegCloseKey(hentry);
1740 /******************************************************************
1741 * DeletePrinterDriverA [WINSPOOL.@]
1745 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1747 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1748 debugstr_a(pDriverName));
1749 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1753 /******************************************************************
1754 * DeletePrinterDriverW [WINSPOOL.@]
1758 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1760 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1761 debugstr_w(pDriverName));
1762 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1766 /******************************************************************
1767 * DeleteMonitorA [WINSPOOL.@]
1769 * See DeleteMonitorW.
1772 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1774 LPWSTR nameW = NULL;
1775 LPWSTR EnvironmentW = NULL;
1776 LPWSTR MonitorNameW = NULL;
1781 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1782 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1783 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1787 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1788 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1789 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1792 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1793 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1794 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1797 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1799 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1800 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1801 HeapFree(GetProcessHeap(), 0, nameW);
1805 /******************************************************************
1806 * DeleteMonitorW [WINSPOOL.@]
1808 * Delete a specific Printmonitor from a Printing-Environment
1811 * pName [I] Servername or NULL (local Computer)
1812 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1813 * pMonitorName [I] Name of the Monitor, that should be deleted
1820 * pEnvironment is ignored in Windows for the local Computer.
1824 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1828 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1829 debugstr_w(pMonitorName));
1831 if (pName && (pName[0])) {
1832 FIXME("for server %s not implemented\n", debugstr_w(pName));
1833 SetLastError(ERROR_ACCESS_DENIED);
1837 /* pEnvironment is ignored in Windows for the local Computer */
1839 if (!pMonitorName || !pMonitorName[0]) {
1840 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1841 SetLastError(ERROR_INVALID_PARAMETER);
1845 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1846 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1850 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1851 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1852 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1857 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1860 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1861 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1865 /******************************************************************
1866 * DeletePortA [WINSPOOL.@]
1872 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1874 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1875 debugstr_a(pPortName));
1876 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1880 /******************************************************************
1881 * DeletePortW [WINSPOOL.@]
1883 * Delete a specific Port
1886 * pName [I] Servername or NULL (local Computer)
1887 * hWnd [I] Handle to parent Window for the Dialog-Box
1888 * pPortName [I] Name of the Port, that should be deleted
1899 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1901 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1902 debugstr_w(pPortName));
1903 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1907 /******************************************************************************
1908 * SetPrinterW [WINSPOOL.@]
1910 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1912 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1913 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1917 /******************************************************************************
1918 * WritePrinter [WINSPOOL.@]
1920 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1922 opened_printer_t *printer;
1925 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1927 EnterCriticalSection(&printer_handles_cs);
1928 printer = get_opened_printer(hPrinter);
1931 SetLastError(ERROR_INVALID_HANDLE);
1937 SetLastError(ERROR_SPL_NO_STARTDOC);
1941 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1943 LeaveCriticalSection(&printer_handles_cs);
1947 /*****************************************************************************
1948 * AddFormA [WINSPOOL.@]
1950 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1952 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1956 /*****************************************************************************
1957 * AddFormW [WINSPOOL.@]
1959 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1961 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1965 /*****************************************************************************
1966 * AddJobA [WINSPOOL.@]
1968 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1971 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1975 SetLastError(ERROR_INVALID_LEVEL);
1979 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1982 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1983 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1984 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1985 if(*pcbNeeded > cbBuf) {
1986 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1989 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1990 addjobA->JobId = addjobW->JobId;
1991 addjobA->Path = (char *)(addjobA + 1);
1992 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1998 /*****************************************************************************
1999 * AddJobW [WINSPOOL.@]
2001 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2003 opened_printer_t *printer;
2006 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2007 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2008 WCHAR path[MAX_PATH], filename[MAX_PATH];
2010 ADDJOB_INFO_1W *addjob;
2012 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2014 EnterCriticalSection(&printer_handles_cs);
2016 printer = get_opened_printer(hPrinter);
2019 SetLastError(ERROR_INVALID_HANDLE);
2024 SetLastError(ERROR_INVALID_LEVEL);
2028 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2032 job->job_id = InterlockedIncrement(&next_job_id);
2034 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2035 if(path[len - 1] != '\\')
2037 memcpy(path + len, spool_path, sizeof(spool_path));
2038 sprintfW(filename, fmtW, path, job->job_id);
2040 len = strlenW(filename);
2041 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2042 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2043 job->document_title = strdupW(default_doc_title);
2044 list_add_tail(&printer->queue->jobs, &job->entry);
2046 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2047 if(*pcbNeeded <= cbBuf) {
2048 addjob = (ADDJOB_INFO_1W*)pData;
2049 addjob->JobId = job->job_id;
2050 addjob->Path = (WCHAR *)(addjob + 1);
2051 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2054 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2057 LeaveCriticalSection(&printer_handles_cs);
2061 /*****************************************************************************
2062 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2064 * Return the PATH for the Print-Processors
2066 * See GetPrintProcessorDirectoryW.
2070 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2071 DWORD level, LPBYTE Info,
2072 DWORD cbBuf, LPDWORD pcbNeeded)
2074 LPWSTR serverW = NULL;
2079 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
2080 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2084 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2085 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2086 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2090 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2091 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2092 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2095 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2096 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2098 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2101 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2102 cbBuf, NULL, NULL) > 0;
2105 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2106 HeapFree(GetProcessHeap(), 0, envW);
2107 HeapFree(GetProcessHeap(), 0, serverW);
2111 /*****************************************************************************
2112 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2114 * Return the PATH for the Print-Processors
2117 * server [I] Servername (NT only) or NULL (local Computer)
2118 * env [I] Printing-Environment (see below) or NULL (Default)
2119 * level [I] Structure-Level (must be 1)
2120 * Info [O] PTR to Buffer that receives the Result
2121 * cbBuf [I] Size of Buffer at "Info"
2122 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2123 * required for the Buffer at "Info"
2126 * Success: TRUE and in pcbNeeded the Bytes used in Info
2127 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2128 * if cbBuf is too small
2130 * Native Values returned in Info on Success:
2131 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2132 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2133 *| win9x(Windows 4.0): "%winsysdir%"
2135 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2138 * Only NULL or "" is supported for server
2141 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2142 DWORD level, LPBYTE Info,
2143 DWORD cbBuf, LPDWORD pcbNeeded)
2146 const printenv_t * env_t;
2148 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server),
2149 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2151 if(server != NULL && server[0]) {
2152 FIXME("server not supported: %s\n", debugstr_w(server));
2153 SetLastError(ERROR_INVALID_PARAMETER);
2157 env_t = validate_envW(env);
2158 if(!env_t) return FALSE; /* environment invalid or unsupported */
2161 WARN("(Level: %ld) is ignored in win9x\n", level);
2162 SetLastError(ERROR_INVALID_LEVEL);
2166 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2167 needed = GetSystemDirectoryW(NULL, 0);
2168 /* add the Size for the Subdirectories */
2169 needed += lstrlenW(spoolprtprocsW);
2170 needed += lstrlenW(env_t->subdir);
2171 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2173 if(pcbNeeded) *pcbNeeded = needed;
2174 TRACE ("required: 0x%lx/%ld\n", needed, needed);
2175 if (needed > cbBuf) {
2176 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2179 if(pcbNeeded == NULL) {
2180 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2181 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2182 SetLastError(RPC_X_NULL_REF_POINTER);
2186 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2187 SetLastError(RPC_X_NULL_REF_POINTER);
2191 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2192 /* add the Subdirectories */
2193 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2194 lstrcatW((LPWSTR) Info, env_t->subdir);
2195 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2199 /*****************************************************************************
2200 * WINSPOOL_OpenDriverReg [internal]
2202 * opens the registry for the printer drivers depending on the given input
2203 * variable pEnvironment
2206 * the opened hkey on success
2209 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2213 const printenv_t * env;
2216 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2218 if (!pEnvironment || unicode) {
2219 /* pEnvironment was NULL or an Unicode-String: use it direct */
2220 env = validate_envW(pEnvironment);
2224 /* pEnvironment was an ANSI-String: convert to unicode first */
2226 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2227 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2228 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2229 env = validate_envW(buffer);
2230 HeapFree(GetProcessHeap(), 0, buffer);
2232 if (!env) return NULL;
2234 buffer = HeapAlloc( GetProcessHeap(), 0,
2235 (strlenW(DriversW) + strlenW(env->envname) +
2236 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2238 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2239 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2240 HeapFree(GetProcessHeap(), 0, buffer);
2245 /*****************************************************************************
2246 * AddPrinterW [WINSPOOL.@]
2248 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2250 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2254 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2257 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2260 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2261 SetLastError(ERROR_INVALID_PARAMETER);
2265 ERR("Level = %ld, unsupported!\n", Level);
2266 SetLastError(ERROR_INVALID_LEVEL);
2270 SetLastError(ERROR_INVALID_PARAMETER);
2273 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2275 ERR("Can't create Printers key\n");
2278 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2279 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2280 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2281 RegCloseKey(hkeyPrinter);
2282 RegCloseKey(hkeyPrinters);
2285 RegCloseKey(hkeyPrinter);
2287 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2289 ERR("Can't create Drivers key\n");
2290 RegCloseKey(hkeyPrinters);
2293 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2295 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2296 RegCloseKey(hkeyPrinters);
2297 RegCloseKey(hkeyDrivers);
2298 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2301 RegCloseKey(hkeyDriver);
2302 RegCloseKey(hkeyDrivers);
2304 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2305 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2306 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2307 RegCloseKey(hkeyPrinters);
2311 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2313 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2314 SetLastError(ERROR_INVALID_PRINTER_NAME);
2315 RegCloseKey(hkeyPrinters);
2318 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2319 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2320 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2322 /* See if we can load the driver. We may need the devmode structure anyway
2325 * Note that DocumentPropertiesW will briefly try to open the printer we
2326 * just create to find a DEVMODEA struct (it will use the WINEPS default
2327 * one in case it is not there, so we are ok).
2329 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2332 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2333 size = sizeof(DEVMODEW);
2339 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2340 ZeroMemory(dmW,size);
2342 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2344 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2345 HeapFree(GetProcessHeap(),0,dmW);
2350 /* set devmode to printer name */
2351 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2355 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2356 and we support these drivers. NT writes DEVMODEW so somehow
2357 we'll need to distinguish between these when we support NT
2361 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2362 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2363 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2364 HeapFree(GetProcessHeap(), 0, dmA);
2366 HeapFree(GetProcessHeap(), 0, dmW);
2368 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2369 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2370 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2371 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2373 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2374 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2375 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2376 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2377 (LPBYTE)&pi->Priority, sizeof(DWORD));
2378 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2379 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2380 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2381 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2382 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2383 (LPBYTE)&pi->Status, sizeof(DWORD));
2384 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2385 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2387 RegCloseKey(hkeyPrinter);
2388 RegCloseKey(hkeyPrinters);
2389 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2390 ERR("OpenPrinter failing\n");
2396 /*****************************************************************************
2397 * AddPrinterA [WINSPOOL.@]
2399 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2401 UNICODE_STRING pNameW;
2403 PRINTER_INFO_2W *piW;
2404 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2407 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2409 ERR("Level = %ld, unsupported!\n", Level);
2410 SetLastError(ERROR_INVALID_LEVEL);
2413 pwstrNameW = asciitounicode(&pNameW,pName);
2414 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2416 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2418 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2419 RtlFreeUnicodeString(&pNameW);
2424 /*****************************************************************************
2425 * ClosePrinter [WINSPOOL.@]
2427 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2429 UINT_PTR i = (UINT_PTR)hPrinter;
2430 opened_printer_t *printer = NULL;
2433 TRACE("Handle %p\n", hPrinter);
2435 EnterCriticalSection(&printer_handles_cs);
2437 if ((i > 0) && (i <= nb_printer_handles))
2438 printer = printer_handles[i - 1];
2442 struct list *cursor, *cursor2;
2445 EndDocPrinter(hPrinter);
2447 if(InterlockedDecrement(&printer->queue->ref) == 0)
2449 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2451 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2452 ScheduleJob(hPrinter, job->job_id);
2454 HeapFree(GetProcessHeap(), 0, printer->queue);
2456 HeapFree(GetProcessHeap(), 0, printer->name);
2457 HeapFree(GetProcessHeap(), 0, printer);
2458 printer_handles[i - 1] = NULL;
2461 LeaveCriticalSection(&printer_handles_cs);
2465 /*****************************************************************************
2466 * DeleteFormA [WINSPOOL.@]
2468 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2470 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2474 /*****************************************************************************
2475 * DeleteFormW [WINSPOOL.@]
2477 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2479 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2483 /*****************************************************************************
2484 * WINSPOOL_SHRegDeleteKey
2486 * Recursively delete subkeys.
2487 * Cut & paste from shlwapi.
2490 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2492 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2493 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2496 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2499 /* Find how many subkeys there are */
2500 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2501 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2505 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2506 /* Name too big: alloc a buffer for it */
2507 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2510 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2513 /* Recursively delete all the subkeys */
2514 for(i = 0; i < dwKeyCount && !dwRet; i++)
2516 dwSize = dwMaxSubkeyLen;
2517 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2519 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2522 if (lpszName != szNameBuf)
2523 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2527 RegCloseKey(hSubKey);
2529 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2534 /*****************************************************************************
2535 * DeletePrinter [WINSPOOL.@]
2537 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2539 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2540 HKEY hkeyPrinters, hkey;
2543 SetLastError(ERROR_INVALID_HANDLE);
2546 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2547 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2548 RegCloseKey(hkeyPrinters);
2550 WriteProfileStringW(devicesW, lpNameW, NULL);
2551 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2552 RegDeleteValueW(hkey, lpNameW);
2558 /*****************************************************************************
2559 * SetPrinterA [WINSPOOL.@]
2561 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2564 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2568 /*****************************************************************************
2569 * SetJobA [WINSPOOL.@]
2571 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2572 LPBYTE pJob, DWORD Command)
2576 UNICODE_STRING usBuffer;
2578 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2580 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2581 are all ignored by SetJob, so we don't bother copying them */
2589 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2590 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2592 JobW = (LPBYTE)info1W;
2593 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2594 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2595 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2596 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2597 info1W->Status = info1A->Status;
2598 info1W->Priority = info1A->Priority;
2599 info1W->Position = info1A->Position;
2600 info1W->PagesPrinted = info1A->PagesPrinted;
2605 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2606 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2608 JobW = (LPBYTE)info2W;
2609 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2610 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2611 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2612 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2613 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2614 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2615 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2616 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2617 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2618 info2W->Status = info2A->Status;
2619 info2W->Priority = info2A->Priority;
2620 info2W->Position = info2A->Position;
2621 info2W->StartTime = info2A->StartTime;
2622 info2W->UntilTime = info2A->UntilTime;
2623 info2W->PagesPrinted = info2A->PagesPrinted;
2627 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2628 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2631 SetLastError(ERROR_INVALID_LEVEL);
2635 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2641 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2642 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2643 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2644 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2645 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2650 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2651 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2652 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2653 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2654 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2655 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2656 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2657 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2658 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2662 HeapFree(GetProcessHeap(), 0, JobW);
2667 /*****************************************************************************
2668 * SetJobW [WINSPOOL.@]
2670 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2671 LPBYTE pJob, DWORD Command)
2676 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2677 FIXME("Ignoring everything other than document title\n");
2679 EnterCriticalSection(&printer_handles_cs);
2680 job = get_job(hPrinter, JobId);
2690 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2691 HeapFree(GetProcessHeap(), 0, job->document_title);
2692 job->document_title = strdupW(info1->pDocument);
2697 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2698 HeapFree(GetProcessHeap(), 0, job->document_title);
2699 job->document_title = strdupW(info2->pDocument);
2705 SetLastError(ERROR_INVALID_LEVEL);
2710 LeaveCriticalSection(&printer_handles_cs);
2714 /*****************************************************************************
2715 * EndDocPrinter [WINSPOOL.@]
2717 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2719 opened_printer_t *printer;
2721 TRACE("(%p)\n", hPrinter);
2723 EnterCriticalSection(&printer_handles_cs);
2725 printer = get_opened_printer(hPrinter);
2728 SetLastError(ERROR_INVALID_HANDLE);
2734 SetLastError(ERROR_SPL_NO_STARTDOC);
2738 CloseHandle(printer->doc->hf);
2739 ScheduleJob(hPrinter, printer->doc->job_id);
2740 HeapFree(GetProcessHeap(), 0, printer->doc);
2741 printer->doc = NULL;
2744 LeaveCriticalSection(&printer_handles_cs);
2748 /*****************************************************************************
2749 * EndPagePrinter [WINSPOOL.@]
2751 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2753 FIXME("(%p): stub\n", hPrinter);
2757 /*****************************************************************************
2758 * StartDocPrinterA [WINSPOOL.@]
2760 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2762 UNICODE_STRING usBuffer;
2764 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2767 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2768 or one (DOC_INFO_3) extra DWORDs */
2772 doc2W.JobId = doc2->JobId;
2775 doc2W.dwMode = doc2->dwMode;
2778 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2779 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2780 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2784 SetLastError(ERROR_INVALID_LEVEL);
2788 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2790 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2791 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2792 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2797 /*****************************************************************************
2798 * StartDocPrinterW [WINSPOOL.@]
2800 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2802 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2803 opened_printer_t *printer;
2804 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2805 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2806 JOB_INFO_1W job_info;
2807 DWORD needed, ret = 0;
2811 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2812 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2813 debugstr_w(doc->pDatatype));
2815 if(Level < 1 || Level > 3)
2817 SetLastError(ERROR_INVALID_LEVEL);
2821 EnterCriticalSection(&printer_handles_cs);
2822 printer = get_opened_printer(hPrinter);
2825 SetLastError(ERROR_INVALID_HANDLE);
2831 SetLastError(ERROR_INVALID_PRINTER_STATE);
2835 /* Even if we're printing to a file we still add a print job, we'll
2836 just ignore the spool file name */
2838 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2840 ERR("AddJob failed gle %08lx\n", GetLastError());
2844 if(doc->pOutputFile)
2845 filename = doc->pOutputFile;
2847 filename = addjob->Path;
2849 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2850 if(hf == INVALID_HANDLE_VALUE)
2853 memset(&job_info, 0, sizeof(job_info));
2854 job_info.pDocument = doc->pDocName;
2855 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2857 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2858 printer->doc->hf = hf;
2859 ret = printer->doc->job_id = addjob->JobId;
2861 LeaveCriticalSection(&printer_handles_cs);
2866 /*****************************************************************************
2867 * StartPagePrinter [WINSPOOL.@]
2869 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2871 FIXME("(%p): stub\n", hPrinter);
2875 /*****************************************************************************
2876 * GetFormA [WINSPOOL.@]
2878 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2879 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2881 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2882 Level,pForm,cbBuf,pcbNeeded);
2886 /*****************************************************************************
2887 * GetFormW [WINSPOOL.@]
2889 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2890 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2892 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2893 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2897 /*****************************************************************************
2898 * SetFormA [WINSPOOL.@]
2900 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2903 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2907 /*****************************************************************************
2908 * SetFormW [WINSPOOL.@]
2910 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2913 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2917 /*****************************************************************************
2918 * ReadPrinter [WINSPOOL.@]
2920 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2921 LPDWORD pNoBytesRead)
2923 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2927 /*****************************************************************************
2928 * ResetPrinterA [WINSPOOL.@]
2930 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2932 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2936 /*****************************************************************************
2937 * ResetPrinterW [WINSPOOL.@]
2939 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2941 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2945 /*****************************************************************************
2946 * WINSPOOL_GetDWORDFromReg
2948 * Return DWORD associated with ValueName from hkey.
2950 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2952 DWORD sz = sizeof(DWORD), type, value = 0;
2955 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2957 if(ret != ERROR_SUCCESS) {
2958 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2961 if(type != REG_DWORD) {
2962 ERR("Got type %ld\n", type);
2968 /*****************************************************************************
2969 * WINSPOOL_GetStringFromReg
2971 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2972 * String is stored either as unicode or ascii.
2973 * Bit of a hack here to get the ValueName if we want ascii.
2975 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2976 DWORD buflen, DWORD *needed,
2979 DWORD sz = buflen, type;
2983 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2985 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2986 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2987 HeapFree(GetProcessHeap(),0,ValueNameA);
2989 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2990 WARN("Got ret = %ld\n", ret);
2994 /* add space for terminating '\0' */
2995 sz += unicode ? sizeof(WCHAR) : 1;
2999 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3004 /*****************************************************************************
3005 * WINSPOOL_GetDefaultDevMode
3007 * Get a default DevMode values for wineps.
3011 static void WINSPOOL_GetDefaultDevMode(
3013 DWORD buflen, DWORD *needed,
3017 static const char szwps[] = "wineps.drv";
3019 /* fill default DEVMODE - should be read from ppd... */
3020 ZeroMemory( &dm, sizeof(dm) );
3021 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3022 dm.dmSpecVersion = DM_SPECVERSION;
3023 dm.dmDriverVersion = 1;
3024 dm.dmSize = sizeof(DEVMODEA);
3025 dm.dmDriverExtra = 0;
3027 DM_ORIENTATION | DM_PAPERSIZE |
3028 DM_PAPERLENGTH | DM_PAPERWIDTH |
3031 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3032 DM_YRESOLUTION | DM_TTOPTION;
3034 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3035 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3036 dm.u1.s1.dmPaperLength = 2970;
3037 dm.u1.s1.dmPaperWidth = 2100;
3041 dm.dmDefaultSource = DMBIN_AUTO;
3042 dm.dmPrintQuality = DMRES_MEDIUM;
3045 dm.dmYResolution = 300; /* 300dpi */
3046 dm.dmTTOption = DMTT_BITMAP;
3049 /* dm.dmLogPixels */
3050 /* dm.dmBitsPerPel */
3051 /* dm.dmPelsWidth */
3052 /* dm.dmPelsHeight */
3053 /* dm.dmDisplayFlags */
3054 /* dm.dmDisplayFrequency */
3055 /* dm.dmICMMethod */
3056 /* dm.dmICMIntent */
3057 /* dm.dmMediaType */
3058 /* dm.dmDitherType */
3059 /* dm.dmReserved1 */
3060 /* dm.dmReserved2 */
3061 /* dm.dmPanningWidth */
3062 /* dm.dmPanningHeight */
3065 if(buflen >= sizeof(DEVMODEW)) {
3066 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3067 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3068 HeapFree(GetProcessHeap(),0,pdmW);
3070 *needed = sizeof(DEVMODEW);
3074 if(buflen >= sizeof(DEVMODEA)) {
3075 memcpy(ptr, &dm, sizeof(DEVMODEA));
3077 *needed = sizeof(DEVMODEA);
3081 /*****************************************************************************
3082 * WINSPOOL_GetDevModeFromReg
3084 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3085 * DevMode is stored either as unicode or ascii.
3087 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3089 DWORD buflen, DWORD *needed,
3092 DWORD sz = buflen, type;
3095 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3096 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3097 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3098 if (sz < sizeof(DEVMODEA))
3100 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
3103 /* ensures that dmSize is not erratically bogus if registry is invalid */
3104 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3105 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3107 sz += (CCHDEVICENAME + CCHFORMNAME);
3109 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3110 memcpy(ptr, dmW, sz);
3111 HeapFree(GetProcessHeap(),0,dmW);
3118 /*********************************************************************
3119 * WINSPOOL_GetPrinter_2
3121 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3122 * The strings are either stored as unicode or ascii.
3124 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3125 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3128 DWORD size, left = cbBuf;
3129 BOOL space = (cbBuf > 0);
3134 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3136 if(space && size <= left) {
3137 pi2->pPrinterName = (LPWSTR)ptr;
3144 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3146 if(space && size <= left) {
3147 pi2->pShareName = (LPWSTR)ptr;
3154 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3156 if(space && size <= left) {
3157 pi2->pPortName = (LPWSTR)ptr;
3164 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3166 if(space && size <= left) {
3167 pi2->pDriverName = (LPWSTR)ptr;
3174 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3176 if(space && size <= left) {
3177 pi2->pComment = (LPWSTR)ptr;
3184 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3186 if(space && size <= left) {
3187 pi2->pLocation = (LPWSTR)ptr;
3194 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3196 if(space && size <= left) {
3197 pi2->pDevMode = (LPDEVMODEW)ptr;
3206 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3207 if(space && size <= left) {
3208 pi2->pDevMode = (LPDEVMODEW)ptr;
3215 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3217 if(space && size <= left) {
3218 pi2->pSepFile = (LPWSTR)ptr;
3225 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3227 if(space && size <= left) {
3228 pi2->pPrintProcessor = (LPWSTR)ptr;
3235 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3237 if(space && size <= left) {
3238 pi2->pDatatype = (LPWSTR)ptr;
3245 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3247 if(space && size <= left) {
3248 pi2->pParameters = (LPWSTR)ptr;
3256 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3257 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3258 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3259 "Default Priority");
3260 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3261 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3264 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3265 memset(pi2, 0, sizeof(*pi2));
3270 /*********************************************************************
3271 * WINSPOOL_GetPrinter_4
3273 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3275 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3276 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3279 DWORD size, left = cbBuf;
3280 BOOL space = (cbBuf > 0);
3285 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3287 if(space && size <= left) {
3288 pi4->pPrinterName = (LPWSTR)ptr;
3296 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3299 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3300 memset(pi4, 0, sizeof(*pi4));
3305 /*********************************************************************
3306 * WINSPOOL_GetPrinter_5
3308 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3310 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3311 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3314 DWORD size, left = cbBuf;
3315 BOOL space = (cbBuf > 0);
3320 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3322 if(space && size <= left) {
3323 pi5->pPrinterName = (LPWSTR)ptr;
3330 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3332 if(space && size <= left) {
3333 pi5->pPortName = (LPWSTR)ptr;
3341 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3342 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3344 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3348 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3349 memset(pi5, 0, sizeof(*pi5));
3354 /*****************************************************************************
3355 * WINSPOOL_GetPrinter
3357 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3358 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3359 * just a collection of pointers to strings.
3361 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3362 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3365 DWORD size, needed = 0;
3367 HKEY hkeyPrinter, hkeyPrinters;
3370 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3372 if (!(name = get_opened_printer_name(hPrinter))) {
3373 SetLastError(ERROR_INVALID_HANDLE);
3377 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3379 ERR("Can't create Printers key\n");
3382 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3384 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3385 RegCloseKey(hkeyPrinters);
3386 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3393 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3395 size = sizeof(PRINTER_INFO_2W);
3397 ptr = pPrinter + size;
3399 memset(pPrinter, 0, size);
3404 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3412 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3414 size = sizeof(PRINTER_INFO_4W);
3416 ptr = pPrinter + size;
3418 memset(pPrinter, 0, size);
3423 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3432 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3434 size = sizeof(PRINTER_INFO_5W);
3436 ptr = pPrinter + size;
3438 memset(pPrinter, 0, size);
3444 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3451 FIXME("Unimplemented level %ld\n", Level);
3452 SetLastError(ERROR_INVALID_LEVEL);
3453 RegCloseKey(hkeyPrinters);
3454 RegCloseKey(hkeyPrinter);
3458 RegCloseKey(hkeyPrinter);
3459 RegCloseKey(hkeyPrinters);
3461 TRACE("returning %d needed = %ld\n", ret, needed);
3462 if(pcbNeeded) *pcbNeeded = needed;
3464 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3468 /*****************************************************************************
3469 * GetPrinterW [WINSPOOL.@]
3471 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3472 DWORD cbBuf, LPDWORD pcbNeeded)
3474 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3478 /*****************************************************************************
3479 * GetPrinterA [WINSPOOL.@]
3481 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3482 DWORD cbBuf, LPDWORD pcbNeeded)
3484 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3488 /*****************************************************************************
3489 * WINSPOOL_EnumPrinters
3491 * Implementation of EnumPrintersA|W
3493 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3494 DWORD dwLevel, LPBYTE lpbPrinters,
3495 DWORD cbBuf, LPDWORD lpdwNeeded,
3496 LPDWORD lpdwReturned, BOOL unicode)
3499 HKEY hkeyPrinters, hkeyPrinter;
3500 WCHAR PrinterName[255];
3501 DWORD needed = 0, number = 0;
3502 DWORD used, i, left;
3506 memset(lpbPrinters, 0, cbBuf);
3512 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3513 if(dwType == PRINTER_ENUM_DEFAULT)
3516 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3517 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3518 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3519 if(!dwType) return TRUE;
3522 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3523 FIXME("dwType = %08lx\n", dwType);
3524 SetLastError(ERROR_INVALID_FLAGS);
3528 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3530 ERR("Can't create Printers key\n");
3534 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3535 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3536 RegCloseKey(hkeyPrinters);
3537 ERR("Can't query Printers key\n");
3540 TRACE("Found %ld printers\n", number);
3544 RegCloseKey(hkeyPrinters);
3546 *lpdwReturned = number;
3550 used = number * sizeof(PRINTER_INFO_2W);
3553 used = number * sizeof(PRINTER_INFO_4W);
3556 used = number * sizeof(PRINTER_INFO_5W);
3560 SetLastError(ERROR_INVALID_LEVEL);
3561 RegCloseKey(hkeyPrinters);
3564 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3566 for(i = 0; i < number; i++) {
3567 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3569 ERR("Can't enum key number %ld\n", i);
3570 RegCloseKey(hkeyPrinters);
3573 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3574 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3576 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3577 RegCloseKey(hkeyPrinters);
3582 buf = lpbPrinters + used;
3583 left = cbBuf - used;
3591 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3592 left, &needed, unicode);
3594 if(pi) pi += sizeof(PRINTER_INFO_2W);
3597 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3598 left, &needed, unicode);
3600 if(pi) pi += sizeof(PRINTER_INFO_4W);
3603 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3604 left, &needed, unicode);
3606 if(pi) pi += sizeof(PRINTER_INFO_5W);
3609 ERR("Shouldn't be here!\n");
3610 RegCloseKey(hkeyPrinter);
3611 RegCloseKey(hkeyPrinters);
3614 RegCloseKey(hkeyPrinter);
3616 RegCloseKey(hkeyPrinters);
3623 memset(lpbPrinters, 0, cbBuf);
3624 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3628 *lpdwReturned = number;
3629 SetLastError(ERROR_SUCCESS);
3634 /******************************************************************
3635 * EnumPrintersW [WINSPOOL.@]
3637 * Enumerates the available printers, print servers and print
3638 * providers, depending on the specified flags, name and level.
3642 * If level is set to 1:
3643 * Not implemented yet!
3644 * Returns TRUE with an empty list.
3646 * If level is set to 2:
3647 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3648 * Returns an array of PRINTER_INFO_2 data structures in the
3649 * lpbPrinters buffer. Note that according to MSDN also an
3650 * OpenPrinter should be performed on every remote printer.
3652 * If level is set to 4 (officially WinNT only):
3653 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3654 * Fast: Only the registry is queried to retrieve printer names,
3655 * no connection to the driver is made.
3656 * Returns an array of PRINTER_INFO_4 data structures in the
3657 * lpbPrinters buffer.
3659 * If level is set to 5 (officially WinNT4/Win9x only):
3660 * Fast: Only the registry is queried to retrieve printer names,
3661 * no connection to the driver is made.
3662 * Returns an array of PRINTER_INFO_5 data structures in the
3663 * lpbPrinters buffer.
3665 * If level set to 3 or 6+:
3666 * returns zero (failure!)
3668 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3672 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3673 * - Only levels 2, 4 and 5 are implemented at the moment.
3674 * - 16-bit printer drivers are not enumerated.
3675 * - Returned amount of bytes used/needed does not match the real Windoze
3676 * implementation (as in this implementation, all strings are part
3677 * of the buffer, whereas Win32 keeps them somewhere else)
3678 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3681 * - In a regular Wine installation, no registry settings for printers
3682 * exist, which makes this function return an empty list.
3684 BOOL WINAPI EnumPrintersW(
3685 DWORD dwType, /* [in] Types of print objects to enumerate */
3686 LPWSTR lpszName, /* [in] name of objects to enumerate */
3687 DWORD dwLevel, /* [in] type of printer info structure */
3688 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3689 DWORD cbBuf, /* [in] max size of buffer in bytes */
3690 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3691 LPDWORD lpdwReturned /* [out] number of entries returned */
3694 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3695 lpdwNeeded, lpdwReturned, TRUE);
3698 /******************************************************************
3699 * EnumPrintersA [WINSPOOL.@]
3702 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3703 DWORD dwLevel, LPBYTE lpbPrinters,
3704 DWORD cbBuf, LPDWORD lpdwNeeded,
3705 LPDWORD lpdwReturned)
3708 UNICODE_STRING lpszNameW;
3711 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3712 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3713 lpdwNeeded, lpdwReturned, FALSE);
3714 RtlFreeUnicodeString(&lpszNameW);
3718 /*****************************************************************************
3719 * WINSPOOL_GetDriverInfoFromReg [internal]
3721 * Enters the information from the registry into the DRIVER_INFO struct
3724 * zero if the printer driver does not exist in the registry
3725 * (only if Level > 1) otherwise nonzero
3727 static BOOL WINSPOOL_GetDriverInfoFromReg(
3730 LPWSTR pEnvironment,
3732 LPBYTE ptr, /* DRIVER_INFO */
3733 LPBYTE pDriverStrings, /* strings buffer */
3734 DWORD cbBuf, /* size of string buffer */
3735 LPDWORD pcbNeeded, /* space needed for str. */
3736 BOOL unicode) /* type of strings */
3740 LPBYTE strPtr = pDriverStrings;
3742 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3743 debugstr_w(DriverName), debugstr_w(pEnvironment),
3744 Level, ptr, pDriverStrings, cbBuf, unicode);
3747 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3748 if (*pcbNeeded <= cbBuf)
3749 strcpyW((LPWSTR)strPtr, DriverName);
3751 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3753 if(*pcbNeeded <= cbBuf)
3754 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3755 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3759 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3763 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3764 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3767 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3768 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3769 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3774 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3777 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3779 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3781 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3784 if(*pcbNeeded <= cbBuf) {
3786 strcpyW((LPWSTR)strPtr, pEnvironment);
3788 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3789 (LPSTR)strPtr, size, NULL, NULL);
3791 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3792 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3795 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3798 if(*pcbNeeded <= cbBuf)
3799 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3802 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3803 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3806 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3809 if(*pcbNeeded <= cbBuf)
3810 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3813 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3814 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3817 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3818 0, &size, unicode)) {
3820 if(*pcbNeeded <= cbBuf)
3821 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3822 size, &tmp, unicode);
3824 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3825 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3829 RegCloseKey(hkeyDriver);
3830 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3834 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3837 if(*pcbNeeded <= cbBuf)
3838 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3839 size, &tmp, unicode);
3841 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3842 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3845 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3848 if(*pcbNeeded <= cbBuf)
3849 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3850 size, &tmp, unicode);
3852 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3853 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3856 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3859 if(*pcbNeeded <= cbBuf)
3860 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3861 size, &tmp, unicode);
3863 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3864 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3867 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3870 if(*pcbNeeded <= cbBuf)
3871 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3872 size, &tmp, unicode);
3874 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3875 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3878 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3879 RegCloseKey(hkeyDriver);
3883 /*****************************************************************************
3884 * WINSPOOL_GetPrinterDriver
3886 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3887 DWORD Level, LPBYTE pDriverInfo,
3888 DWORD cbBuf, LPDWORD pcbNeeded,
3892 WCHAR DriverName[100];
3893 DWORD ret, type, size, needed = 0;
3895 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3897 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3898 Level,pDriverInfo,cbBuf, pcbNeeded);
3900 ZeroMemory(pDriverInfo, cbBuf);
3902 if (!(name = get_opened_printer_name(hPrinter))) {
3903 SetLastError(ERROR_INVALID_HANDLE);
3906 if(Level < 1 || Level > 6) {
3907 SetLastError(ERROR_INVALID_LEVEL);
3910 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3912 ERR("Can't create Printers key\n");
3915 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3917 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3918 RegCloseKey(hkeyPrinters);
3919 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3922 size = sizeof(DriverName);
3924 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3925 (LPBYTE)DriverName, &size);
3926 RegCloseKey(hkeyPrinter);
3927 RegCloseKey(hkeyPrinters);
3928 if(ret != ERROR_SUCCESS) {
3929 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3933 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3935 ERR("Can't create Drivers key\n");
3941 size = sizeof(DRIVER_INFO_1W);
3944 size = sizeof(DRIVER_INFO_2W);
3947 size = sizeof(DRIVER_INFO_3W);
3950 size = sizeof(DRIVER_INFO_4W);
3953 size = sizeof(DRIVER_INFO_5W);
3956 size = sizeof(DRIVER_INFO_6W);
3959 ERR("Invalid level\n");
3964 ptr = pDriverInfo + size;
3966 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3967 pEnvironment, Level, pDriverInfo,
3968 (cbBuf < size) ? NULL : ptr,
3969 (cbBuf < size) ? 0 : cbBuf - size,
3970 &needed, unicode)) {
3971 RegCloseKey(hkeyDrivers);
3975 RegCloseKey(hkeyDrivers);
3977 if(pcbNeeded) *pcbNeeded = size + needed;
3978 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3979 if(cbBuf >= needed) return TRUE;
3980 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3984 /*****************************************************************************
3985 * GetPrinterDriverA [WINSPOOL.@]
3987 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3988 DWORD Level, LPBYTE pDriverInfo,
3989 DWORD cbBuf, LPDWORD pcbNeeded)
3992 UNICODE_STRING pEnvW;
3995 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3996 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3997 cbBuf, pcbNeeded, FALSE);
3998 RtlFreeUnicodeString(&pEnvW);
4001 /*****************************************************************************
4002 * GetPrinterDriverW [WINSPOOL.@]
4004 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4005 DWORD Level, LPBYTE pDriverInfo,
4006 DWORD cbBuf, LPDWORD pcbNeeded)
4008 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4009 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4012 /*****************************************************************************
4013 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4015 * Return the PATH for the Printer-Drivers (UNICODE)
4018 * pName [I] Servername (NT only) or NULL (local Computer)
4019 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4020 * Level [I] Structure-Level (must be 1)
4021 * pDriverDirectory [O] PTR to Buffer that receives the Result
4022 * cbBuf [I] Size of Buffer at pDriverDirectory
4023 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4024 * required for pDriverDirectory
4027 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4028 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4029 * if cbBuf is too small
4031 * Native Values returned in pDriverDirectory on Success:
4032 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4033 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4034 *| win9x(Windows 4.0): "%winsysdir%"
4036 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4039 *- Only NULL or "" is supported for pName
4042 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4043 DWORD Level, LPBYTE pDriverDirectory,
4044 DWORD cbBuf, LPDWORD pcbNeeded)
4047 const printenv_t * env;
4049 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
4050 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4051 if(pName != NULL && pName[0]) {
4052 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4053 SetLastError(ERROR_INVALID_PARAMETER);
4057 env = validate_envW(pEnvironment);
4058 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4061 WARN("(Level: %ld) is ignored in win9x\n", Level);
4062 SetLastError(ERROR_INVALID_LEVEL);
4066 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4067 needed = GetSystemDirectoryW(NULL, 0);
4068 /* add the Size for the Subdirectories */
4069 needed += lstrlenW(spooldriversW);
4070 needed += lstrlenW(env->subdir);
4071 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4074 *pcbNeeded = needed;
4075 TRACE("required: 0x%lx/%ld\n", needed, needed);
4076 if(needed > cbBuf) {
4077 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4080 if(pcbNeeded == NULL) {
4081 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4082 SetLastError(RPC_X_NULL_REF_POINTER);
4085 if(pDriverDirectory == NULL) {
4086 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4087 SetLastError(ERROR_INVALID_USER_BUFFER);
4091 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4092 /* add the Subdirectories */
4093 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4094 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4095 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4100 /*****************************************************************************
4101 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4103 * Return the PATH for the Printer-Drivers (ANSI)
4105 * See GetPrinterDriverDirectoryW.
4108 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4111 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4112 DWORD Level, LPBYTE pDriverDirectory,
4113 DWORD cbBuf, LPDWORD pcbNeeded)
4115 UNICODE_STRING nameW, environmentW;
4118 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4119 WCHAR *driverDirectoryW = NULL;
4121 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
4122 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4124 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4126 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4127 else nameW.Buffer = NULL;
4128 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4129 else environmentW.Buffer = NULL;
4131 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4132 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4135 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4136 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4138 *pcbNeeded = needed;
4139 ret = (needed <= cbBuf) ? TRUE : FALSE;
4141 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4143 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4145 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4146 RtlFreeUnicodeString(&environmentW);
4147 RtlFreeUnicodeString(&nameW);
4152 /*****************************************************************************
4153 * AddPrinterDriverA [WINSPOOL.@]
4155 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4158 HKEY hkeyDrivers, hkeyName;
4159 static CHAR empty[] = "",
4162 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
4164 if(level != 2 && level != 3) {
4165 SetLastError(ERROR_INVALID_LEVEL);
4168 if ((pName) && (pName[0])) {
4169 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4170 SetLastError(ERROR_INVALID_PARAMETER);
4174 WARN("pDriverInfo == NULL\n");
4175 SetLastError(ERROR_INVALID_PARAMETER);
4180 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4182 memset(&di3, 0, sizeof(di3));
4183 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4186 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4188 SetLastError(ERROR_INVALID_PARAMETER);
4192 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4193 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4194 if(!di3.pHelpFile) di3.pHelpFile = empty;
4195 if(!di3.pMonitorName) di3.pMonitorName = empty;
4197 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4200 ERR("Can't create Drivers key\n");
4204 if(level == 2) { /* apparently can't overwrite with level2 */
4205 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4206 RegCloseKey(hkeyName);
4207 RegCloseKey(hkeyDrivers);
4208 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4209 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4213 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4214 RegCloseKey(hkeyDrivers);
4215 ERR("Can't create Name key\n");
4218 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4220 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
4221 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
4222 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4224 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
4225 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4226 (LPBYTE) di3.pDependentFiles, 0);
4227 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
4228 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
4229 RegCloseKey(hkeyName);
4230 RegCloseKey(hkeyDrivers);
4235 /*****************************************************************************
4236 * AddPrinterDriverW [WINSPOOL.@]
4238 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4241 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
4246 /*****************************************************************************
4247 * AddPrintProcessorA [WINSPOOL.@]
4249 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4250 LPSTR pPrintProcessorName)
4252 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4253 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4257 /*****************************************************************************
4258 * AddPrintProcessorW [WINSPOOL.@]
4260 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4261 LPWSTR pPrintProcessorName)
4263 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4264 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4268 /*****************************************************************************
4269 * AddPrintProvidorA [WINSPOOL.@]
4271 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4273 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4277 /*****************************************************************************
4278 * AddPrintProvidorW [WINSPOOL.@]
4280 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4282 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4286 /*****************************************************************************
4287 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4289 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4290 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4292 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4293 pDevModeOutput, pDevModeInput);
4297 /*****************************************************************************
4298 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4300 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4301 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4303 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4304 pDevModeOutput, pDevModeInput);
4308 /*****************************************************************************
4309 * PrinterProperties [WINSPOOL.@]
4311 * Displays a dialog to set the properties of the printer.
4314 * nonzero on success or zero on failure
4317 * implemented as stub only
4319 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4320 HANDLE hPrinter /* [in] handle to printer object */
4322 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4323 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4327 /*****************************************************************************
4328 * EnumJobsA [WINSPOOL.@]
4331 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4332 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4335 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4336 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4338 if(pcbNeeded) *pcbNeeded = 0;
4339 if(pcReturned) *pcReturned = 0;
4344 /*****************************************************************************
4345 * EnumJobsW [WINSPOOL.@]
4348 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4349 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4352 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4353 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4355 if(pcbNeeded) *pcbNeeded = 0;
4356 if(pcReturned) *pcReturned = 0;
4360 /*****************************************************************************
4361 * WINSPOOL_EnumPrinterDrivers [internal]
4363 * Delivers information about all printer drivers installed on the
4364 * localhost or a given server
4367 * nonzero on success or zero on failure. If the buffer for the returned
4368 * information is too small the function will return an error
4371 * - only implemented for localhost, foreign hosts will return an error
4373 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4374 DWORD Level, LPBYTE pDriverInfo,
4375 DWORD cbBuf, LPDWORD pcbNeeded,
4376 LPDWORD pcReturned, BOOL unicode)
4379 DWORD i, needed, number = 0, size = 0;
4380 WCHAR DriverNameW[255];
4383 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4384 debugstr_w(pName), debugstr_w(pEnvironment),
4385 Level, pDriverInfo, cbBuf, unicode);
4387 /* check for local drivers */
4388 if((pName) && (pName[0])) {
4389 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4390 SetLastError(ERROR_ACCESS_DENIED);
4394 /* check input parameter */
4395 if((Level < 1) || (Level > 3)) {
4396 ERR("unsupported level %ld\n", Level);
4397 SetLastError(ERROR_INVALID_LEVEL);
4401 /* initialize return values */
4403 memset( pDriverInfo, 0, cbBuf);
4407 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4409 ERR("Can't open Drivers key\n");
4413 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4414 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4415 RegCloseKey(hkeyDrivers);
4416 ERR("Can't query Drivers key\n");
4419 TRACE("Found %ld Drivers\n", number);
4421 /* get size of single struct
4422 * unicode and ascii structure have the same size
4426 size = sizeof(DRIVER_INFO_1A);
4429 size = sizeof(DRIVER_INFO_2A);
4432 size = sizeof(DRIVER_INFO_3A);
4436 /* calculate required buffer size */
4437 *pcbNeeded = size * number;
4439 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4441 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4442 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4444 ERR("Can't enum key number %ld\n", i);
4445 RegCloseKey(hkeyDrivers);
4448 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4449 pEnvironment, Level, ptr,
4450 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4451 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4452 &needed, unicode)) {
4453 RegCloseKey(hkeyDrivers);
4456 (*pcbNeeded) += needed;
4459 RegCloseKey(hkeyDrivers);
4461 if(cbBuf < *pcbNeeded){
4462 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4466 *pcReturned = number;
4470 /*****************************************************************************
4471 * EnumPrinterDriversW [WINSPOOL.@]
4473 * see function EnumPrinterDrivers for RETURNS, BUGS
4475 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4476 LPBYTE pDriverInfo, DWORD cbBuf,
4477 LPDWORD pcbNeeded, LPDWORD pcReturned)
4479 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4480 cbBuf, pcbNeeded, pcReturned, TRUE);
4483 /*****************************************************************************
4484 * EnumPrinterDriversA [WINSPOOL.@]
4486 * see function EnumPrinterDrivers for RETURNS, BUGS
4488 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4489 LPBYTE pDriverInfo, DWORD cbBuf,
4490 LPDWORD pcbNeeded, LPDWORD pcReturned)
4492 UNICODE_STRING pNameW, pEnvironmentW;
4493 PWSTR pwstrNameW, pwstrEnvironmentW;
4495 pwstrNameW = asciitounicode(&pNameW, pName);
4496 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4498 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4499 Level, pDriverInfo, cbBuf, pcbNeeded,
4501 RtlFreeUnicodeString(&pNameW);
4502 RtlFreeUnicodeString(&pEnvironmentW);
4507 static CHAR PortMonitor[] = "Wine Port Monitor";
4508 static CHAR PortDescription[] = "Wine Port";
4510 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4514 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4515 NULL, OPEN_EXISTING, 0, NULL );
4516 if (handle == INVALID_HANDLE_VALUE)
4518 TRACE("Checking %s exists\n", name );
4519 CloseHandle( handle );
4523 static DWORD WINSPOOL_CountSerialPorts(void)
4530 strcpy( name, "COMx:" );
4532 if (WINSPOOL_ComPortExists( name ))
4539 /******************************************************************************
4540 * EnumPortsA (WINSPOOL.@)
4545 * ANSI-Version did not call the UNICODE-Version
4548 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4549 LPDWORD bufneeded,LPDWORD bufreturned)
4552 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4553 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4557 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4558 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4563 info_size = sizeof (PORT_INFO_1A);
4566 info_size = sizeof (PORT_INFO_2A);
4569 SetLastError(ERROR_INVALID_LEVEL);
4573 /* see how many exist */
4576 serial_count = WINSPOOL_CountSerialPorts();
4579 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4580 if ( r == ERROR_SUCCESS )
4582 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4583 &printer_count, NULL, NULL, NULL, NULL);
4585 count = serial_count + printer_count;
4587 /* then fill in the structure info structure once
4588 we know the offset to the first string */
4590 memset( buffer, 0, bufsize );
4592 ofs = info_size*count;
4593 for ( i=0; i<count; i++)
4595 DWORD vallen = sizeof(portname) - 1;
4597 /* get the serial port values, then the printer values */
4598 if ( i < serial_count )
4600 strcpy( portname, "COMx:" );
4601 portname[3] = '1' + i;
4602 if (!WINSPOOL_ComPortExists( portname ))
4605 TRACE("Found %s\n", portname );
4606 vallen = strlen( portname );
4610 r = RegEnumValueA( hkey_printer, i-serial_count,
4611 portname, &vallen, NULL, NULL, NULL, 0 );
4616 /* add a colon if necessary, and make it upper case */
4617 CharUpperBuffA(portname,vallen);
4618 if (strcasecmp(portname,"nul")!=0)
4619 if (vallen && (portname[vallen-1] != ':') )
4620 lstrcatA(portname,":");
4622 /* add the port info structure if we can fit it */
4623 if ( info_size*(n+1) < bufsize )
4627 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4628 info->pName = (LPSTR) &buffer[ofs];
4630 else if ( level == 2)
4632 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4633 info->pPortName = (LPSTR) &buffer[ofs];
4634 /* FIXME: fill in more stuff here */
4635 info->pMonitorName = PortMonitor;
4636 info->pDescription = PortDescription;
4637 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4640 /* add the name of the port if we can fit it */
4641 if ( ofs < bufsize )
4642 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4648 ofs += lstrlenA(portname)+1;
4651 RegCloseKey(hkey_printer);
4662 /******************************************************************************
4663 * EnumPortsW (WINSPOOL.@)
4665 * Enumerate available Ports
4668 * name [I] Servername or NULL (local Computer)
4669 * level [I] Structure-Level (1 or 2)
4670 * buffer [O] PTR to Buffer that receives the Result
4671 * bufsize [I] Size of Buffer at buffer
4672 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4673 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4677 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4680 * UNICODE-Version is a stub
4683 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4684 LPDWORD bufneeded,LPDWORD bufreturned)
4686 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4687 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4691 /******************************************************************************
4692 * GetDefaultPrinterW (WINSPOOL.@)
4695 * This function must read the value from data 'device' of key
4696 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4698 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4702 WCHAR *buffer, *ptr;
4706 SetLastError(ERROR_INVALID_PARAMETER);
4710 /* make the buffer big enough for the stuff from the profile/registry,
4711 * the content must fit into the local buffer to compute the correct
4712 * size even if the extern buffer is too small or not given.
4713 * (20 for ,driver,port) */
4715 len = max(100, (insize + 20));
4716 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4718 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4720 SetLastError (ERROR_FILE_NOT_FOUND);
4724 TRACE("%s\n", debugstr_w(buffer));
4726 if ((ptr = strchrW(buffer, ',')) == NULL)
4728 SetLastError(ERROR_INVALID_NAME);
4734 *namesize = strlenW(buffer) + 1;
4735 if(!name || (*namesize > insize))
4737 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4741 strcpyW(name, buffer);
4744 HeapFree( GetProcessHeap(), 0, buffer);
4749 /******************************************************************************
4750 * GetDefaultPrinterA (WINSPOOL.@)
4752 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4756 WCHAR *bufferW = NULL;
4760 SetLastError(ERROR_INVALID_PARAMETER);
4764 if(name && *namesize) {
4766 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4769 if(!GetDefaultPrinterW( bufferW, namesize)) {
4774 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4778 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4781 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4784 HeapFree( GetProcessHeap(), 0, bufferW);
4789 /******************************************************************************
4790 * SetDefaultPrinterW (WINSPOOL.204)
4792 * Set the Name of the Default Printer
4795 * pszPrinter [I] Name of the Printer or NULL
4802 * When the Parameter is NULL or points to an Empty String and
4803 * a Default Printer was already present, then this Function changes nothing.
4804 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4805 * the First enumerated local Printer is used.
4808 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4811 TRACE("(%s)\n", debugstr_w(pszPrinter));
4813 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4817 /******************************************************************************
4818 * SetDefaultPrinterA (WINSPOOL.202)
4820 * See SetDefaultPrinterW.
4823 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4826 TRACE("(%s)\n", debugstr_a(pszPrinter));
4828 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4833 /******************************************************************************
4834 * SetPrinterDataExA (WINSPOOL.@)
4836 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4837 LPCSTR pValueName, DWORD Type,
4838 LPBYTE pData, DWORD cbData)
4840 HKEY hkeyPrinter, hkeySubkey;
4843 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4844 debugstr_a(pValueName), Type, pData, cbData);
4846 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4850 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4852 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4853 RegCloseKey(hkeyPrinter);
4856 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4857 RegCloseKey(hkeySubkey);
4858 RegCloseKey(hkeyPrinter);
4862 /******************************************************************************
4863 * SetPrinterDataExW (WINSPOOL.@)
4865 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4866 LPCWSTR pValueName, DWORD Type,
4867 LPBYTE pData, DWORD cbData)
4869 HKEY hkeyPrinter, hkeySubkey;
4872 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4873 debugstr_w(pValueName), Type, pData, cbData);
4875 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4879 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4881 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4882 RegCloseKey(hkeyPrinter);
4885 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4886 RegCloseKey(hkeySubkey);
4887 RegCloseKey(hkeyPrinter);
4891 /******************************************************************************
4892 * SetPrinterDataA (WINSPOOL.@)
4894 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4895 LPBYTE pData, DWORD cbData)
4897 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4901 /******************************************************************************
4902 * SetPrinterDataW (WINSPOOL.@)
4904 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4905 LPBYTE pData, DWORD cbData)
4907 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4911 /******************************************************************************
4912 * GetPrinterDataExA (WINSPOOL.@)
4914 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4915 LPCSTR pValueName, LPDWORD pType,
4916 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4918 HKEY hkeyPrinter, hkeySubkey;
4921 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4922 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4925 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4929 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4931 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4932 RegCloseKey(hkeyPrinter);
4936 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4937 RegCloseKey(hkeySubkey);
4938 RegCloseKey(hkeyPrinter);
4942 /******************************************************************************
4943 * GetPrinterDataExW (WINSPOOL.@)
4945 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4946 LPCWSTR pValueName, LPDWORD pType,
4947 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4949 HKEY hkeyPrinter, hkeySubkey;
4952 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4953 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4956 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4960 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4962 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4963 RegCloseKey(hkeyPrinter);
4967 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4968 RegCloseKey(hkeySubkey);
4969 RegCloseKey(hkeyPrinter);
4973 /******************************************************************************
4974 * GetPrinterDataA (WINSPOOL.@)
4976 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4977 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4979 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4980 pData, nSize, pcbNeeded);
4983 /******************************************************************************
4984 * GetPrinterDataW (WINSPOOL.@)
4986 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4987 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4989 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4990 pData, nSize, pcbNeeded);
4993 /*******************************************************************************
4994 * EnumPrinterDataExW [WINSPOOL.@]
4996 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4997 LPBYTE pEnumValues, DWORD cbEnumValues,
4998 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5000 HKEY hkPrinter, hkSubKey;
5001 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5002 cbValueNameLen, cbMaxValueLen, cbValueLen,
5007 PPRINTER_ENUM_VALUESW ppev;
5009 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5011 if (pKeyName == NULL || *pKeyName == 0)
5012 return ERROR_INVALID_PARAMETER;
5014 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5015 if (ret != ERROR_SUCCESS)
5017 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
5022 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5023 if (ret != ERROR_SUCCESS)
5025 r = RegCloseKey (hkPrinter);
5026 if (r != ERROR_SUCCESS)
5027 WARN ("RegCloseKey returned %li\n", r);
5028 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
5029 debugstr_w (pKeyName), ret);
5033 ret = RegCloseKey (hkPrinter);
5034 if (ret != ERROR_SUCCESS)
5036 ERR ("RegCloseKey returned %li\n", ret);
5037 r = RegCloseKey (hkSubKey);
5038 if (r != ERROR_SUCCESS)
5039 WARN ("RegCloseKey returned %li\n", r);
5043 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5044 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5045 if (ret != ERROR_SUCCESS)
5047 r = RegCloseKey (hkSubKey);
5048 if (r != ERROR_SUCCESS)
5049 WARN ("RegCloseKey returned %li\n", r);
5050 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
5054 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
5055 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5057 if (cValues == 0) /* empty key */
5059 r = RegCloseKey (hkSubKey);
5060 if (r != ERROR_SUCCESS)
5061 WARN ("RegCloseKey returned %li\n", r);
5062 *pcbEnumValues = *pnEnumValues = 0;
5063 return ERROR_SUCCESS;
5066 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5068 hHeap = GetProcessHeap ();
5071 ERR ("GetProcessHeap failed\n");
5072 r = RegCloseKey (hkSubKey);
5073 if (r != ERROR_SUCCESS)
5074 WARN ("RegCloseKey returned %li\n", r);
5075 return ERROR_OUTOFMEMORY;
5078 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5079 if (lpValueName == NULL)
5081 ERR ("Failed to allocate %li bytes from process heap\n",
5082 cbMaxValueNameLen * sizeof (WCHAR));
5083 r = RegCloseKey (hkSubKey);
5084 if (r != ERROR_SUCCESS)
5085 WARN ("RegCloseKey returned %li\n", r);
5086 return ERROR_OUTOFMEMORY;
5089 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5090 if (lpValue == NULL)
5092 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
5093 if (HeapFree (hHeap, 0, lpValueName) == 0)
5094 WARN ("HeapFree failed with code %li\n", GetLastError ());
5095 r = RegCloseKey (hkSubKey);
5096 if (r != ERROR_SUCCESS)
5097 WARN ("RegCloseKey returned %li\n", r);
5098 return ERROR_OUTOFMEMORY;
5101 TRACE ("pass 1: calculating buffer required for all names and values\n");
5103 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5105 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
5107 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5109 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5110 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5111 NULL, NULL, lpValue, &cbValueLen);
5112 if (ret != ERROR_SUCCESS)
5114 if (HeapFree (hHeap, 0, lpValue) == 0)
5115 WARN ("HeapFree failed with code %li\n", GetLastError ());
5116 if (HeapFree (hHeap, 0, lpValueName) == 0)
5117 WARN ("HeapFree failed with code %li\n", GetLastError ());
5118 r = RegCloseKey (hkSubKey);
5119 if (r != ERROR_SUCCESS)
5120 WARN ("RegCloseKey returned %li\n", r);
5121 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5125 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
5126 debugstr_w (lpValueName), dwIndex,
5127 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
5129 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5130 cbBufSize += cbValueLen;
5133 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
5135 *pcbEnumValues = cbBufSize;
5136 *pnEnumValues = cValues;
5138 if (cbEnumValues < cbBufSize) /* buffer too small */
5140 if (HeapFree (hHeap, 0, lpValue) == 0)
5141 WARN ("HeapFree failed with code %li\n", GetLastError ());
5142 if (HeapFree (hHeap, 0, lpValueName) == 0)
5143 WARN ("HeapFree failed with code %li\n", GetLastError ());
5144 r = RegCloseKey (hkSubKey);
5145 if (r != ERROR_SUCCESS)
5146 WARN ("RegCloseKey returned %li\n", r);
5147 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
5148 return ERROR_MORE_DATA;
5151 TRACE ("pass 2: copying all names and values to buffer\n");
5153 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5154 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5156 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5158 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5159 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5160 NULL, &dwType, lpValue, &cbValueLen);
5161 if (ret != ERROR_SUCCESS)
5163 if (HeapFree (hHeap, 0, lpValue) == 0)
5164 WARN ("HeapFree failed with code %li\n", GetLastError ());
5165 if (HeapFree (hHeap, 0, lpValueName) == 0)
5166 WARN ("HeapFree failed with code %li\n", GetLastError ());
5167 r = RegCloseKey (hkSubKey);
5168 if (r != ERROR_SUCCESS)
5169 WARN ("RegCloseKey returned %li\n", r);
5170 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
5174 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5175 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5176 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5177 pEnumValues += cbValueNameLen;
5179 /* return # of *bytes* (including trailing \0), not # of chars */
5180 ppev[dwIndex].cbValueName = cbValueNameLen;
5182 ppev[dwIndex].dwType = dwType;
5184 memcpy (pEnumValues, lpValue, cbValueLen);
5185 ppev[dwIndex].pData = pEnumValues;
5186 pEnumValues += cbValueLen;
5188 ppev[dwIndex].cbData = cbValueLen;
5190 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
5191 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5194 if (HeapFree (hHeap, 0, lpValue) == 0)
5196 ret = GetLastError ();
5197 ERR ("HeapFree failed with code %li\n", ret);
5198 if (HeapFree (hHeap, 0, lpValueName) == 0)
5199 WARN ("HeapFree failed with code %li\n", GetLastError ());
5200 r = RegCloseKey (hkSubKey);
5201 if (r != ERROR_SUCCESS)
5202 WARN ("RegCloseKey returned %li\n", r);
5206 if (HeapFree (hHeap, 0, lpValueName) == 0)
5208 ret = GetLastError ();
5209 ERR ("HeapFree failed with code %li\n", ret);
5210 r = RegCloseKey (hkSubKey);
5211 if (r != ERROR_SUCCESS)
5212 WARN ("RegCloseKey returned %li\n", r);
5216 ret = RegCloseKey (hkSubKey);
5217 if (ret != ERROR_SUCCESS)
5219 ERR ("RegCloseKey returned %li\n", ret);
5223 return ERROR_SUCCESS;
5226 /*******************************************************************************
5227 * EnumPrinterDataExA [WINSPOOL.@]
5229 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5230 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5231 * what Windows 2000 SP1 does.
5234 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5235 LPBYTE pEnumValues, DWORD cbEnumValues,
5236 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5240 DWORD ret, dwIndex, dwBufSize;
5244 TRACE ("%p %s\n", hPrinter, pKeyName);
5246 if (pKeyName == NULL || *pKeyName == 0)
5247 return ERROR_INVALID_PARAMETER;
5249 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5252 ret = GetLastError ();
5253 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5257 hHeap = GetProcessHeap ();
5260 ERR ("GetProcessHeap failed\n");
5261 return ERROR_OUTOFMEMORY;
5264 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5265 if (pKeyNameW == NULL)
5267 ERR ("Failed to allocate %li bytes from process heap\n",
5268 (LONG) len * sizeof (WCHAR));
5269 return ERROR_OUTOFMEMORY;
5272 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5274 ret = GetLastError ();
5275 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5276 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5277 WARN ("HeapFree failed with code %li\n", GetLastError ());
5281 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5282 pcbEnumValues, pnEnumValues);
5283 if (ret != ERROR_SUCCESS)
5285 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5286 WARN ("HeapFree failed with code %li\n", GetLastError ());
5287 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5291 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5293 ret = GetLastError ();
5294 ERR ("HeapFree failed with code %li\n", ret);
5298 if (*pnEnumValues == 0) /* empty key */
5299 return ERROR_SUCCESS;
5302 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5304 PPRINTER_ENUM_VALUESW ppev =
5305 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5307 if (dwBufSize < ppev->cbValueName)
5308 dwBufSize = ppev->cbValueName;
5310 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5311 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5312 dwBufSize = ppev->cbData;
5315 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5317 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5318 if (pBuffer == NULL)
5320 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5321 return ERROR_OUTOFMEMORY;
5324 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5326 PPRINTER_ENUM_VALUESW ppev =
5327 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5329 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5330 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5334 ret = GetLastError ();
5335 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5336 if (HeapFree (hHeap, 0, pBuffer) == 0)
5337 WARN ("HeapFree failed with code %li\n", GetLastError ());
5341 memcpy (ppev->pValueName, pBuffer, len);
5343 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5345 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5346 ppev->dwType != REG_MULTI_SZ)
5349 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5350 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5353 ret = GetLastError ();
5354 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5355 if (HeapFree (hHeap, 0, pBuffer) == 0)
5356 WARN ("HeapFree failed with code %li\n", GetLastError ());
5360 memcpy (ppev->pData, pBuffer, len);
5362 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5363 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5366 if (HeapFree (hHeap, 0, pBuffer) == 0)
5368 ret = GetLastError ();
5369 ERR ("HeapFree failed with code %li\n", ret);
5373 return ERROR_SUCCESS;
5376 /******************************************************************************
5377 * AbortPrinter (WINSPOOL.@)
5379 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5381 FIXME("(%p), stub!\n", hPrinter);
5385 /******************************************************************************
5386 * AddPortA (WINSPOOL.@)
5391 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5393 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5397 /******************************************************************************
5398 * AddPortW (WINSPOOL.@)
5400 * Add a Port for a specific Monitor
5403 * pName [I] Servername or NULL (local Computer)
5404 * hWnd [I] Handle to parent Window for the Dialog-Box
5405 * pMonitorName [I] Name of the Monitor that manage the Port
5415 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5417 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5421 /******************************************************************************
5422 * AddPortExA (WINSPOOL.@)
5427 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5429 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5430 lpBuffer, debugstr_a(lpMonitorName));
5434 /******************************************************************************
5435 * AddPortExW (WINSPOOL.@)
5437 * Add a Port for a specific Monitor, without presenting a user interface
5440 * hMonitor [I] Handle from InitializePrintMonitor2()
5441 * pName [I] Servername or NULL (local Computer)
5442 * Level [I] Structure-Level (1 or 2) for lpBuffer
5443 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5444 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5454 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5456 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5457 lpBuffer, debugstr_w(lpMonitorName));
5461 /******************************************************************************
5462 * AddPrinterConnectionA (WINSPOOL.@)
5464 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5466 FIXME("%s\n", debugstr_a(pName));
5470 /******************************************************************************
5471 * AddPrinterConnectionW (WINSPOOL.@)
5473 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5475 FIXME("%s\n", debugstr_w(pName));
5479 /******************************************************************************
5480 * AddPrinterDriverExW (WINSPOOL.@)
5482 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5483 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5485 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5486 Level, pDriverInfo, dwFileCopyFlags);
5487 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5491 /******************************************************************************
5492 * AddPrinterDriverExA (WINSPOOL.@)
5494 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5495 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5497 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5498 Level, pDriverInfo, dwFileCopyFlags);
5499 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5503 /******************************************************************************
5504 * ConfigurePortA (WINSPOOL.@)
5506 * See ConfigurePortW.
5509 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5511 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5515 /******************************************************************************
5516 * ConfigurePortW (WINSPOOL.@)
5518 * Display the Configuration-Dialog for a specific Port
5521 * pName [I] Servername or NULL (local Computer)
5522 * hWnd [I] Handle to parent Window for the Dialog-Box
5523 * pPortName [I] Name of the Port, that should be configured
5533 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5535 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5539 /******************************************************************************
5540 * ConnectToPrinterDlg (WINSPOOL.@)
5542 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5544 FIXME("%p %lx\n", hWnd, Flags);
5548 /******************************************************************************
5549 * DeletePrinterConnectionA (WINSPOOL.@)
5551 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5553 FIXME("%s\n", debugstr_a(pName));
5557 /******************************************************************************
5558 * DeletePrinterConnectionW (WINSPOOL.@)
5560 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5562 FIXME("%s\n", debugstr_w(pName));
5566 /******************************************************************************
5567 * DeletePrinterDriverExW (WINSPOOL.@)
5569 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5570 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5572 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5573 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5577 /******************************************************************************
5578 * DeletePrinterDriverExA (WINSPOOL.@)
5580 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5581 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5583 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5584 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5588 /******************************************************************************
5589 * DeletePrinterDataExW (WINSPOOL.@)
5591 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5594 FIXME("%p %s %s\n", hPrinter,
5595 debugstr_w(pKeyName), debugstr_w(pValueName));
5596 return ERROR_INVALID_PARAMETER;
5599 /******************************************************************************
5600 * DeletePrinterDataExA (WINSPOOL.@)
5602 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5605 FIXME("%p %s %s\n", hPrinter,
5606 debugstr_a(pKeyName), debugstr_a(pValueName));
5607 return ERROR_INVALID_PARAMETER;
5610 /******************************************************************************
5611 * DeletePrintProcessorA (WINSPOOL.@)
5613 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5615 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5616 debugstr_a(pPrintProcessorName));
5620 /******************************************************************************
5621 * DeletePrintProcessorW (WINSPOOL.@)
5623 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5625 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5626 debugstr_w(pPrintProcessorName));
5630 /******************************************************************************
5631 * DeletePrintProvidorA (WINSPOOL.@)
5633 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5635 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5636 debugstr_a(pPrintProviderName));
5640 /******************************************************************************
5641 * DeletePrintProvidorW (WINSPOOL.@)
5643 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5645 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5646 debugstr_w(pPrintProviderName));
5650 /******************************************************************************
5651 * EnumFormsA (WINSPOOL.@)
5653 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5654 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5656 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5657 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5661 /******************************************************************************
5662 * EnumFormsW (WINSPOOL.@)
5664 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5665 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5667 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5668 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5672 /*****************************************************************************
5673 * EnumMonitorsA [WINSPOOL.@]
5675 * See EnumMonitorsW.
5678 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5679 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5682 LPBYTE bufferW = NULL;
5683 LPWSTR nameW = NULL;
5685 DWORD numentries = 0;
5688 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5689 cbBuf, pcbNeeded, pcReturned);
5691 /* convert servername to unicode */
5693 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5694 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5695 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5697 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5698 needed = cbBuf * sizeof(WCHAR);
5699 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5700 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5702 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5703 if (pcbNeeded) needed = *pcbNeeded;
5704 /* HeapReAlloc return NULL, when bufferW was NULL */
5705 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5706 HeapAlloc(GetProcessHeap(), 0, needed);
5708 /* Try again with the large Buffer */
5709 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5711 numentries = pcReturned ? *pcReturned : 0;
5714 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5715 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5718 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5719 DWORD entrysize = 0;
5722 LPMONITOR_INFO_2W mi2w;
5723 LPMONITOR_INFO_2A mi2a;
5725 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5726 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5728 /* First pass: calculate the size for all Entries */
5729 mi2w = (LPMONITOR_INFO_2W) bufferW;
5730 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5732 while (index < numentries) {
5734 needed += entrysize; /* MONITOR_INFO_?A */
5735 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5737 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5738 NULL, 0, NULL, NULL);
5740 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5741 NULL, 0, NULL, NULL);
5742 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5743 NULL, 0, NULL, NULL);
5745 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5746 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5747 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5750 /* check for errors and quit on failure */
5751 if (cbBuf < needed) {
5752 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5756 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5757 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5758 cbBuf -= len ; /* free Bytes in the user-Buffer */
5759 mi2w = (LPMONITOR_INFO_2W) bufferW;
5760 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5762 /* Second Pass: Fill the User Buffer (if we have one) */
5763 while ((index < numentries) && pMonitors) {
5765 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5767 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5768 ptr, cbBuf , NULL, NULL);
5772 mi2a->pEnvironment = ptr;
5773 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5774 ptr, cbBuf, NULL, NULL);
5778 mi2a->pDLLName = ptr;
5779 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5780 ptr, cbBuf, NULL, NULL);
5784 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5785 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5786 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5790 if (pcbNeeded) *pcbNeeded = needed;
5791 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5793 HeapFree(GetProcessHeap(), 0, nameW);
5794 HeapFree(GetProcessHeap(), 0, bufferW);
5796 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5797 (res), GetLastError(), needed, numentries);
5803 /*****************************************************************************
5804 * EnumMonitorsW [WINSPOOL.@]
5806 * Enumerate available Port-Monitors
5809 * pName [I] Servername or NULL (local Computer)
5810 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5811 * pMonitors [O] PTR to Buffer that receives the Result
5812 * cbBuf [I] Size of Buffer at pMonitors
5813 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5814 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5818 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5821 * Windows reads the Registry once and cache the Results.
5823 *| Language-Monitors are also installed in the same Registry-Location but
5824 *| they are filtered in Windows (not returned by EnumMonitors).
5825 *| We do no filtering to simplify our Code.
5828 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5829 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5832 DWORD numentries = 0;
5835 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5836 cbBuf, pcbNeeded, pcReturned);
5838 if (pName && (lstrlenW(pName))) {
5839 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5840 SetLastError(ERROR_ACCESS_DENIED);
5844 /* Level is not checked in win9x */
5845 if (!Level || (Level > 2)) {
5846 WARN("level (%ld) is ignored in win9x\n", Level);
5847 SetLastError(ERROR_INVALID_LEVEL);
5851 SetLastError(RPC_X_NULL_REF_POINTER);
5855 /* Scan all Monitor-Keys */
5857 needed = get_local_monitors(Level, NULL, 0, &numentries);
5859 /* we calculated the needed buffersize. now do the error-checks */
5860 if (cbBuf < needed) {
5861 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5864 else if (!pMonitors || !pcReturned) {
5865 SetLastError(RPC_X_NULL_REF_POINTER);
5869 /* fill the Buffer with the Monitor-Keys */
5870 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5874 if (pcbNeeded) *pcbNeeded = needed;
5875 if (pcReturned) *pcReturned = numentries;
5877 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5878 res, GetLastError(), needed, numentries);
5883 /******************************************************************************
5884 * XcvDataW (WINSPOOL.@)
5887 * There doesn't seem to be an A version...
5889 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5890 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5891 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5893 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5894 pInputData, cbInputData, pOutputData,
5895 cbOutputData, pcbOutputNeeded, pdwStatus);
5899 /*****************************************************************************
5900 * EnumPrinterDataA [WINSPOOL.@]
5903 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5904 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5905 DWORD cbData, LPDWORD pcbData )
5907 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5908 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5909 return ERROR_NO_MORE_ITEMS;
5912 /*****************************************************************************
5913 * EnumPrinterDataW [WINSPOOL.@]
5916 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5917 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5918 DWORD cbData, LPDWORD pcbData )
5920 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5921 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5922 return ERROR_NO_MORE_ITEMS;
5925 /*****************************************************************************
5926 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5929 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5930 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5931 LPDWORD pcbNeeded, LPDWORD pcReturned)
5933 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5934 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5935 pcbNeeded, pcReturned);
5939 /*****************************************************************************
5940 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5943 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5944 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5945 LPDWORD pcbNeeded, LPDWORD pcReturned)
5947 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5948 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5949 pcbNeeded, pcReturned);
5953 /*****************************************************************************
5954 * EnumPrintProcessorsA [WINSPOOL.@]
5957 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5958 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5960 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5961 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5965 /*****************************************************************************
5966 * EnumPrintProcessorsW [WINSPOOL.@]
5969 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5970 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5972 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5973 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5974 cbBuf, pcbNeeded, pcbReturned);
5978 /*****************************************************************************
5979 * ExtDeviceMode [WINSPOOL.@]
5982 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5983 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5986 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5987 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5988 debugstr_a(pProfile), fMode);
5992 /*****************************************************************************
5993 * FindClosePrinterChangeNotification [WINSPOOL.@]
5996 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5998 FIXME("Stub: %p\n", hChange);
6002 /*****************************************************************************
6003 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6006 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6007 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6009 FIXME("Stub: %p %lx %lx %p\n",
6010 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6011 return INVALID_HANDLE_VALUE;
6014 /*****************************************************************************
6015 * FindNextPrinterChangeNotification [WINSPOOL.@]
6018 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6019 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6021 FIXME("Stub: %p %p %p %p\n",
6022 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6026 /*****************************************************************************
6027 * FreePrinterNotifyInfo [WINSPOOL.@]
6030 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6032 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6036 /*****************************************************************************
6039 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6040 * ansi depending on the unicode parameter.
6042 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6052 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6055 memcpy(ptr, str, *size);
6062 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6065 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6072 /*****************************************************************************
6075 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6076 LPDWORD pcbNeeded, BOOL unicode)
6078 DWORD size, left = cbBuf;
6079 BOOL space = (cbBuf > 0);
6086 ji1->JobId = job->job_id;
6089 string_to_buf(job->document_title, ptr, left, &size, unicode);
6090 if(space && size <= left)
6092 ji1->pDocument = (LPWSTR)ptr;
6103 /*****************************************************************************
6106 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6107 LPDWORD pcbNeeded, BOOL unicode)
6109 DWORD size, left = cbBuf;
6110 BOOL space = (cbBuf > 0);
6117 ji2->JobId = job->job_id;
6120 string_to_buf(job->document_title, ptr, left, &size, unicode);
6121 if(space && size <= left)
6123 ji2->pDocument = (LPWSTR)ptr;
6134 /*****************************************************************************
6137 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6138 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6141 DWORD needed = 0, size;
6145 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6147 EnterCriticalSection(&printer_handles_cs);
6148 job = get_job(hPrinter, JobId);
6155 size = sizeof(JOB_INFO_1W);
6160 memset(pJob, 0, size);
6164 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6169 size = sizeof(JOB_INFO_2W);
6174 memset(pJob, 0, size);
6178 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6183 size = sizeof(JOB_INFO_3);
6187 memset(pJob, 0, size);
6196 SetLastError(ERROR_INVALID_LEVEL);
6200 *pcbNeeded = needed;
6202 LeaveCriticalSection(&printer_handles_cs);
6206 /*****************************************************************************
6207 * GetJobA [WINSPOOL.@]
6210 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6211 DWORD cbBuf, LPDWORD pcbNeeded)
6213 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6216 /*****************************************************************************
6217 * GetJobW [WINSPOOL.@]
6220 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6221 DWORD cbBuf, LPDWORD pcbNeeded)
6223 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6226 /*****************************************************************************
6229 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6231 char *unixname, *queue, *cmd;
6232 char fmt[] = "lpr -P%s %s";
6235 if(!(unixname = wine_get_unix_file_name(filename)))
6238 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6239 queue = HeapAlloc(GetProcessHeap(), 0, len);
6240 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6242 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6243 sprintf(cmd, fmt, queue, unixname);
6245 TRACE("printing with: %s\n", cmd);
6248 HeapFree(GetProcessHeap(), 0, cmd);
6249 HeapFree(GetProcessHeap(), 0, queue);
6250 HeapFree(GetProcessHeap(), 0, unixname);
6254 /*****************************************************************************
6257 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6259 #if HAVE_CUPS_CUPS_H
6262 char *unixname, *queue, *doc_titleA;
6266 if(!(unixname = wine_get_unix_file_name(filename)))
6269 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6270 queue = HeapAlloc(GetProcessHeap(), 0, len);
6271 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6273 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6274 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6275 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6277 TRACE("printing via cups\n");
6278 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6279 HeapFree(GetProcessHeap(), 0, doc_titleA);
6280 HeapFree(GetProcessHeap(), 0, queue);
6281 HeapFree(GetProcessHeap(), 0, unixname);
6287 return schedule_lpr(printer_name, filename);
6291 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6298 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6302 if(HIWORD(wparam) == BN_CLICKED)
6304 if(LOWORD(wparam) == IDOK)
6307 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6310 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6311 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6313 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6315 WCHAR caption[200], message[200];
6318 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6319 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6320 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6321 if(mb_ret == IDCANCEL)
6323 HeapFree(GetProcessHeap(), 0, filename);
6327 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6328 if(hf == INVALID_HANDLE_VALUE)
6330 WCHAR caption[200], message[200];
6332 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6333 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6334 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6335 HeapFree(GetProcessHeap(), 0, filename);
6339 DeleteFileW(filename);
6340 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6342 EndDialog(hwnd, IDOK);
6345 if(LOWORD(wparam) == IDCANCEL)
6347 EndDialog(hwnd, IDCANCEL);
6356 /*****************************************************************************
6359 static BOOL get_filename(LPWSTR *filename)
6361 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6362 file_dlg_proc, (LPARAM)filename) == IDOK;
6365 /*****************************************************************************
6368 static BOOL schedule_file(LPCWSTR filename)
6370 LPWSTR output = NULL;
6372 if(get_filename(&output))
6374 TRACE("copy to %s\n", debugstr_w(output));
6375 CopyFileW(filename, output, FALSE);
6376 HeapFree(GetProcessHeap(), 0, output);
6382 /*****************************************************************************
6385 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6388 char *unixname, *cmdA;
6390 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6394 if(!(unixname = wine_get_unix_file_name(filename)))
6397 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6398 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6399 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6401 TRACE("printing with: %s\n", cmdA);
6403 if((file_fd = open(unixname, O_RDONLY)) == -1)
6408 ERR("pipe() failed!\n");
6418 /* reset signals that we previously set to SIG_IGN */
6419 signal(SIGPIPE, SIG_DFL);
6420 signal(SIGCHLD, SIG_DFL);
6426 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6427 write(fds[1], buf, no_read);
6432 if(file_fd != -1) close(file_fd);
6433 if(fds[0] != -1) close(fds[0]);
6434 if(fds[1] != -1) close(fds[1]);
6436 HeapFree(GetProcessHeap(), 0, cmdA);
6437 HeapFree(GetProcessHeap(), 0, unixname);
6444 /*****************************************************************************
6447 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6449 int in_fd, out_fd, no_read;
6452 char *unixname, *outputA;
6455 if(!(unixname = wine_get_unix_file_name(filename)))
6458 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6459 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6460 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6462 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6463 in_fd = open(unixname, O_RDONLY);
6464 if(out_fd == -1 || in_fd == -1)
6467 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6468 write(out_fd, buf, no_read);
6472 if(in_fd != -1) close(in_fd);
6473 if(out_fd != -1) close(out_fd);
6474 HeapFree(GetProcessHeap(), 0, outputA);
6475 HeapFree(GetProcessHeap(), 0, unixname);
6479 /*****************************************************************************
6480 * ScheduleJob [WINSPOOL.@]
6483 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6485 opened_printer_t *printer;
6487 struct list *cursor, *cursor2;
6489 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6490 EnterCriticalSection(&printer_handles_cs);
6491 printer = get_opened_printer(hPrinter);
6495 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6497 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6500 if(job->job_id != dwJobID) continue;
6502 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6503 if(hf != INVALID_HANDLE_VALUE)
6505 PRINTER_INFO_5W *pi5;
6509 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6510 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6512 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6513 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6514 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6515 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6516 debugstr_w(pi5->pPortName));
6520 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6521 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6523 DWORD type, count = sizeof(output);
6524 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6527 if(output[0] == '|')
6529 schedule_pipe(output + 1, job->filename);
6533 schedule_unixfile(output, job->filename);
6535 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6537 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6539 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6541 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6543 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6545 schedule_file(job->filename);
6549 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6551 HeapFree(GetProcessHeap(), 0, pi5);
6553 DeleteFileW(job->filename);
6555 list_remove(cursor);
6556 HeapFree(GetProcessHeap(), 0, job->document_title);
6557 HeapFree(GetProcessHeap(), 0, job->filename);
6558 HeapFree(GetProcessHeap(), 0, job);
6563 LeaveCriticalSection(&printer_handles_cs);
6567 /*****************************************************************************
6568 * StartDocDlgA [WINSPOOL.@]
6570 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6572 UNICODE_STRING usBuffer;
6577 docW.cbSize = sizeof(docW);
6578 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6579 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6580 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6581 docW.fwType = doc->fwType;
6583 retW = StartDocDlgW(hPrinter, &docW);
6587 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6588 ret = HeapAlloc(GetProcessHeap(), 0, len);
6589 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6590 HeapFree(GetProcessHeap(), 0, retW);
6593 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6594 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6595 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6600 /*****************************************************************************
6601 * StartDocDlgW [WINSPOOL.@]
6603 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6604 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6605 * port is "FILE:". Also returns the full path if passed a relative path.
6607 * The caller should free the returned string from the process heap.
6609 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6614 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6616 PRINTER_INFO_5W *pi5;
6617 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6618 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6620 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6621 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6622 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6624 HeapFree(GetProcessHeap(), 0, pi5);
6627 HeapFree(GetProcessHeap(), 0, pi5);
6630 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6633 get_filename(&name);
6636 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6638 HeapFree(GetProcessHeap(), 0, name);
6641 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6642 GetFullPathNameW(name, len, ret, NULL);
6643 HeapFree(GetProcessHeap(), 0, name);
6648 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6651 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6652 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6654 attr = GetFileAttributesW(ret);
6655 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6657 HeapFree(GetProcessHeap(), 0, ret);