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 /* ############################### */
101 LPPORT_INFO_2W cache; /* cached PORT_INFO_2W data */
102 DWORD pi1_needed; /* size for PORT_INFO_1W */
103 DWORD pi2_needed; /* size for PORT_INFO_2W */
104 DWORD returned; /* number of cached PORT_INFO_2W - entries */
127 WCHAR *document_title;
135 LPCWSTR versionregpath;
136 LPCWSTR versionsubdir;
139 /* ############################### */
141 static struct list monitor_handles = LIST_INIT( monitor_handles );
143 static opened_printer_t **printer_handles;
144 static int nb_printer_handles;
145 static LONG next_job_id = 1;
147 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
148 WORD fwCapability, LPSTR lpszOutput,
150 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
151 LPSTR lpszDevice, LPSTR lpszPort,
152 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
155 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
156 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
157 'c','o','n','t','r','o','l','\\',
158 'P','r','i','n','t','\\',
159 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
160 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
162 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
163 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
164 'C','o','n','t','r','o','l','\\',
165 'P','r','i','n','t','\\',
166 'M','o','n','i','t','o','r','s','\\',0};
168 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
169 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
170 'C','o','n','t','r','o','l','\\',
171 'P','r','i','n','t','\\',
172 'P','r','i','n','t','e','r','s',0};
174 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
176 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
177 'M','i','c','r','o','s','o','f','t','\\',
178 'W','i','n','d','o','w','s',' ','N','T','\\',
179 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
180 'W','i','n','d','o','w','s',0};
182 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
183 'M','i','c','r','o','s','o','f','t','\\',
184 'W','i','n','d','o','w','s',' ','N','T','\\',
185 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
186 'D','e','v','i','c','e','s',0};
188 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
189 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
190 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
191 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
192 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
193 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
194 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
196 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
197 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
199 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
200 'i','o','n',' ','F','i','l','e',0};
201 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
202 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
203 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
205 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
207 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
208 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
209 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
210 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
211 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
212 static const WCHAR NameW[] = {'N','a','m','e',0};
213 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
214 static const WCHAR PortW[] = {'P','o','r','t',0};
215 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
217 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
219 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
220 'v','e','r','D','a','t','a',0};
221 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
223 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
224 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
225 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
226 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
227 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
228 static const WCHAR emptyStringW[] = {0};
230 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
232 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
233 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
234 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
236 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
237 'D','o','c','u','m','e','n','t',0};
239 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
240 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
241 DWORD Level, LPBYTE pDriverInfo,
242 DWORD cbBuf, LPDWORD pcbNeeded,
244 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
245 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
247 /******************************************************************
248 * validate the user-supplied printing-environment [internal]
251 * env [I] PTR to Environment-String or NULL
255 * Success: PTR to printenv_t
258 * An empty string is handled the same way as NULL.
259 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
263 static const printenv_t * validate_envW(LPCWSTR env)
265 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
266 3, Version3_RegPathW, Version3_SubdirW};
267 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
268 0, emptyStringW, emptyStringW};
269 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
271 const printenv_t *result = NULL;
274 TRACE("testing %s\n", debugstr_w(env));
277 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
279 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
281 result = all_printenv[i];
286 if (result == NULL) {
287 FIXME("unsupported Environment: %s\n", debugstr_w(env));
288 SetLastError(ERROR_INVALID_ENVIRONMENT);
290 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
294 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
296 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
302 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
303 if passed a NULL string. This returns NULLs to the result.
305 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
309 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
310 return usBufferPtr->Buffer;
312 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
316 static LPWSTR strdupW(LPCWSTR p)
322 len = (strlenW(p) + 1) * sizeof(WCHAR);
323 ret = HeapAlloc(GetProcessHeap(), 0, len);
328 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
329 The result includes all \0s (specifically the last two). */
330 static int multi_sz_lenA(const char *str)
332 const char *ptr = str;
336 ptr += lstrlenA(ptr) + 1;
339 return ptr - str + 1;
343 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
346 /* If forcing, or no profile string entry for device yet, set the entry
348 * The always change entry if not WINEPS yet is discussable.
351 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
353 !strstr(qbuf,"WINEPS.DRV")
355 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
358 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
359 WriteProfileStringA("windows","device",buf);
360 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
361 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
364 HeapFree(GetProcessHeap(),0,buf);
368 BOOL add_printer_driver(const char *name)
372 static char driver_path[] = "wineps16",
373 data_file[] = "<datafile?>",
374 config_file[] = "wineps16",
375 help_file[] = "<helpfile?>",
376 dep_file[] = "<dependent files?>\0",
377 monitor_name[] = "<monitor name?>",
378 default_data_type[] = "RAW";
380 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
381 di3a.pName = (char *)name;
382 di3a.pEnvironment = NULL; /* NULL means auto */
383 di3a.pDriverPath = driver_path;
384 di3a.pDataFile = data_file;
385 di3a.pConfigFile = config_file;
386 di3a.pHelpFile = help_file;
387 di3a.pDependentFiles = dep_file;
388 di3a.pMonitorName = monitor_name;
389 di3a.pDefaultDataType = default_data_type;
391 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
393 ERR("Failed adding driver (%d)\n", GetLastError());
399 #ifdef HAVE_CUPS_CUPS_H
400 static typeof(cupsGetDests) *pcupsGetDests;
401 static typeof(cupsGetPPD) *pcupsGetPPD;
402 static typeof(cupsPrintFile) *pcupsPrintFile;
403 static void *cupshandle;
405 static BOOL CUPS_LoadPrinters(void)
408 BOOL hadprinter = FALSE;
410 PRINTER_INFO_2A pinfo2a;
412 HKEY hkeyPrinter, hkeyPrinters, hkey;
414 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
417 TRACE("loaded %s\n", SONAME_LIBCUPS);
420 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
421 if (!p##x) return FALSE;
424 DYNCUPS(cupsGetDests);
425 DYNCUPS(cupsPrintFile);
428 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
430 ERR("Can't create Printers key\n");
434 nrofdests = pcupsGetDests(&dests);
435 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
436 for (i=0;i<nrofdests;i++) {
437 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
438 sprintf(port,"LPR:%s",dests[i].name);
439 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
440 sprintf(devline,"WINEPS.DRV,%s",port);
441 WriteProfileStringA("devices",dests[i].name,devline);
442 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
443 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
446 HeapFree(GetProcessHeap(),0,devline);
448 TRACE("Printer %d: %s\n", i, dests[i].name);
449 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
450 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
452 TRACE("Printer already exists\n");
453 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
454 RegCloseKey(hkeyPrinter);
456 static CHAR data_type[] = "RAW",
457 print_proc[] = "WinPrint",
458 comment[] = "WINEPS Printer using CUPS",
459 location[] = "<physical location of printer>",
460 params[] = "<parameters?>",
461 share_name[] = "<share name?>",
462 sep_file[] = "<sep file?>";
464 add_printer_driver(dests[i].name);
466 memset(&pinfo2a,0,sizeof(pinfo2a));
467 pinfo2a.pPrinterName = dests[i].name;
468 pinfo2a.pDatatype = data_type;
469 pinfo2a.pPrintProcessor = print_proc;
470 pinfo2a.pDriverName = dests[i].name;
471 pinfo2a.pComment = comment;
472 pinfo2a.pLocation = location;
473 pinfo2a.pPortName = port;
474 pinfo2a.pParameters = params;
475 pinfo2a.pShareName = share_name;
476 pinfo2a.pSepFile = sep_file;
478 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
479 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
480 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
483 HeapFree(GetProcessHeap(),0,port);
486 if (dests[i].is_default)
487 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
489 RegCloseKey(hkeyPrinters);
495 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
496 PRINTER_INFO_2A pinfo2a;
497 char *e,*s,*name,*prettyname,*devname;
498 BOOL ret = FALSE, set_default = FALSE;
499 char *port,*devline,*env_default;
500 HKEY hkeyPrinter, hkeyPrinters, hkey;
502 while (isspace(*pent)) pent++;
503 s = strchr(pent,':');
505 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
513 TRACE("name=%s entry=%s\n",name, pent);
515 if(ispunct(*name)) { /* a tc entry, not a real printer */
516 TRACE("skipping tc entry\n");
520 if(strstr(pent,":server")) { /* server only version so skip */
521 TRACE("skipping server entry\n");
525 /* Determine whether this is a postscript printer. */
528 env_default = getenv("PRINTER");
530 /* Get longest name, usually the one at the right for later display. */
531 while((s=strchr(prettyname,'|'))) {
534 while(isspace(*--e)) *e = '\0';
535 TRACE("\t%s\n", debugstr_a(prettyname));
536 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
537 for(prettyname = s+1; isspace(*prettyname); prettyname++)
540 e = prettyname + strlen(prettyname);
541 while(isspace(*--e)) *e = '\0';
542 TRACE("\t%s\n", debugstr_a(prettyname));
543 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
545 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
546 * if it is too long, we use it as comment below. */
547 devname = prettyname;
548 if (strlen(devname)>=CCHDEVICENAME-1)
550 if (strlen(devname)>=CCHDEVICENAME-1) {
555 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
556 sprintf(port,"LPR:%s",name);
558 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
559 sprintf(devline,"WINEPS.DRV,%s",port);
560 WriteProfileStringA("devices",devname,devline);
561 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
562 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
565 HeapFree(GetProcessHeap(),0,devline);
567 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
569 ERR("Can't create Printers key\n");
573 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
574 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
576 TRACE("Printer already exists\n");
577 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
578 RegCloseKey(hkeyPrinter);
580 static CHAR data_type[] = "RAW",
581 print_proc[] = "WinPrint",
582 comment[] = "WINEPS Printer using LPR",
583 params[] = "<parameters?>",
584 share_name[] = "<share name?>",
585 sep_file[] = "<sep file?>";
587 add_printer_driver(devname);
589 memset(&pinfo2a,0,sizeof(pinfo2a));
590 pinfo2a.pPrinterName = devname;
591 pinfo2a.pDatatype = data_type;
592 pinfo2a.pPrintProcessor = print_proc;
593 pinfo2a.pDriverName = devname;
594 pinfo2a.pComment = comment;
595 pinfo2a.pLocation = prettyname;
596 pinfo2a.pPortName = port;
597 pinfo2a.pParameters = params;
598 pinfo2a.pShareName = share_name;
599 pinfo2a.pSepFile = sep_file;
601 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
602 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
603 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
606 RegCloseKey(hkeyPrinters);
608 if (isfirst || set_default)
609 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
611 HeapFree(GetProcessHeap(), 0, port);
613 HeapFree(GetProcessHeap(), 0, name);
618 PRINTCAP_LoadPrinters(void) {
619 BOOL hadprinter = FALSE;
623 BOOL had_bash = FALSE;
625 f = fopen("/etc/printcap","r");
629 while(fgets(buf,sizeof(buf),f)) {
632 end=strchr(buf,'\n');
636 while(isspace(*start)) start++;
637 if(*start == '#' || *start == '\0')
640 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
641 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
642 HeapFree(GetProcessHeap(),0,pent);
646 if (end && *--end == '\\') {
653 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
656 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
662 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
663 HeapFree(GetProcessHeap(),0,pent);
669 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
672 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
673 (lstrlenW(value) + 1) * sizeof(WCHAR));
675 return ERROR_FILE_NOT_FOUND;
678 void WINSPOOL_LoadSystemPrinters(void)
680 HKEY hkey, hkeyPrinters;
682 DWORD needed, num, i;
683 WCHAR PrinterName[256];
686 /* This ensures that all printer entries have a valid Name value. If causes
687 problems later if they don't. If one is found to be missed we create one
688 and set it equal to the name of the key */
689 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
690 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
691 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
692 for(i = 0; i < num; i++) {
693 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
694 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
695 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
696 set_reg_szW(hkey, NameW, PrinterName);
703 RegCloseKey(hkeyPrinters);
706 /* We want to avoid calling AddPrinter on printers as much as
707 possible, because on cups printers this will (eventually) lead
708 to a call to cupsGetPPD which takes forever, even with non-cups
709 printers AddPrinter takes a while. So we'll tag all printers that
710 were automatically added last time around, if they still exist
711 we'll leave them be otherwise we'll delete them. */
712 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
714 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
715 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
716 for(i = 0; i < num; i++) {
717 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
718 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
719 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
721 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
729 HeapFree(GetProcessHeap(), 0, pi);
733 #ifdef HAVE_CUPS_CUPS_H
734 done = CUPS_LoadPrinters();
737 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
738 /* Check for [ppd] section in config file before parsing /etc/printcap */
739 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
740 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
741 &hkey) == ERROR_SUCCESS) {
743 PRINTCAP_LoadPrinters();
747 /* Now enumerate the list again and delete any printers that a still tagged */
748 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
750 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
751 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
752 for(i = 0; i < num; i++) {
753 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
754 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
755 BOOL delete_driver = FALSE;
756 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
757 DWORD dw, type, size = sizeof(dw);
758 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
759 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
761 delete_driver = TRUE;
767 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
772 HeapFree(GetProcessHeap(), 0, pi);
779 /*****************************************************************************
780 * enumerate the local monitors (INTERNAL)
782 * returns the needed size (in bytes) for pMonitors
783 * and *lpreturned is set to number of entries returned in pMonitors
786 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
791 LPMONITOR_INFO_2W mi;
792 WCHAR buffer[MAX_PATH];
793 WCHAR dllname[MAX_PATH];
801 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
803 numentries = *lpreturned; /* this is 0, when we scan the registry */
804 len = entrysize * numentries;
805 ptr = (LPWSTR) &pMonitors[len];
808 len = sizeof(buffer);
811 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
812 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
813 /* Scan all Monitor-Registry-Keys */
814 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
815 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
816 dllsize = sizeof(dllname);
819 /* The Monitor must have a Driver-DLL */
820 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
821 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
822 /* We found a valid DLL for this Monitor. */
823 TRACE("using Driver: %s\n", debugstr_w(dllname));
828 /* Windows returns only Port-Monitors here, but to simplify our code,
829 we do no filtering for Language-Monitors */
833 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
835 /* we install and return only monitors for "Windows NT x86" */
836 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
840 /* required size is calculated. Now fill the user-buffer */
841 if (pMonitors && (cbBuf >= needed)){
842 mi = (LPMONITOR_INFO_2W) pMonitors;
843 pMonitors += entrysize;
845 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
847 lstrcpyW(ptr, buffer); /* Name of the Monitor */
848 ptr += (len+1); /* len is lstrlenW(monitorname) */
850 mi->pEnvironment = ptr;
851 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
852 ptr += (lstrlenW(envname_x86W)+1);
855 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
856 ptr += (dllsize / sizeof(WCHAR));
861 len = sizeof(buffer);
866 *lpreturned = numentries;
867 TRACE("need %d byte for %d entries\n", needed, numentries);
871 /******************************************************************
872 * monitor_unload [internal]
874 * release a printmonitor and unload it from memory, when needed
877 static void monitor_unload(monitor_t * pm)
879 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
881 EnterCriticalSection(&monitor_handles_cs);
883 if (pm->refcount) pm->refcount--;
885 if (pm->refcount == 0) {
886 list_remove(&pm->entry);
887 FreeLibrary(pm->hdll);
888 HeapFree(GetProcessHeap(), 0, pm->name);
889 HeapFree(GetProcessHeap(), 0, pm->dllname);
890 HeapFree(GetProcessHeap(), 0, pm);
892 LeaveCriticalSection(&monitor_handles_cs);
895 /******************************************************************
896 * monitor_unloadall [internal]
898 * release all printmonitors and unload them from memory, when needed
901 static void monitor_unloadall(void)
906 EnterCriticalSection(&monitor_handles_cs);
907 /* iterate through the list, with safety against removal */
908 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
912 LeaveCriticalSection(&monitor_handles_cs);
915 /******************************************************************
916 * monitor_load [internal]
918 * load a printmonitor, get the dllname from the registry, when needed
919 * initialize the monitor and dump found function-pointers
921 * On failure, SetLastError() is called and NULL is returned
924 static monitor_t * monitor_load(LPWSTR name, LPWSTR dllname)
926 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
927 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
928 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
929 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
930 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
932 monitor_t * pm = NULL;
934 LPWSTR regroot = NULL;
935 LPWSTR driver = dllname;
937 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
938 /* Is the Monitor already loaded? */
939 EnterCriticalSection(&monitor_handles_cs);
941 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
943 if (lstrcmpW(name, cursor->name) == 0) {
950 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
951 if (pm == NULL) goto cleanup;
952 list_add_tail(&monitor_handles, &pm->entry);
956 if (pm->name == NULL) {
957 /* Load the monitor */
958 LPMONITOREX pmonitorEx;
961 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
962 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
965 lstrcpyW(regroot, MonitorsW);
966 lstrcatW(regroot, name);
967 /* Get the Driver from the Registry */
968 if (driver == NULL) {
971 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
972 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
973 &namesize) == ERROR_SUCCESS) {
974 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
975 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
982 pm->name = strdupW(name);
983 pm->dllname = strdupW(driver);
985 if (!regroot || !pm->name || !pm->dllname) {
987 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
992 pm->hdll = LoadLibraryW(driver);
993 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
995 if (pm->hdll == NULL) {
997 SetLastError(ERROR_MOD_NOT_FOUND);
1002 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
1003 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1004 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1005 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1006 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1009 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1010 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1011 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1012 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1013 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1015 if (pInitializePrintMonitorUI != NULL) {
1016 pm->monitorUI = pInitializePrintMonitorUI();
1017 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1018 if (pm->monitorUI) {
1019 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1020 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1025 if (pInitializePrintMonitor != NULL) {
1026 pmonitorEx = pInitializePrintMonitor(regroot);
1027 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1028 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1031 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1032 pm->monitor = &(pmonitorEx->Monitor);
1037 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1042 if (pInitializePrintMonitor2 != NULL) {
1043 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1045 if (pInitializeMonitorEx != NULL) {
1046 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1048 if (pInitializeMonitor != NULL) {
1049 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1052 if (!pm->monitor && !pm->monitorUI) {
1054 SetLastError(ERROR_PROC_NOT_FOUND);
1059 LeaveCriticalSection(&monitor_handles_cs);
1060 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1061 HeapFree(GetProcessHeap(), 0, regroot);
1062 TRACE("=> %p\n", pm);
1066 /******************************************************************
1067 * monitor_loadall [internal]
1069 * Load all registered monitors
1072 static DWORD monitor_loadall(void)
1075 DWORD registered = 0;
1078 WCHAR buffer[MAX_PATH];
1081 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1082 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1083 NULL, NULL, NULL, NULL, NULL);
1085 TRACE("%d monitors registered\n", registered);
1087 EnterCriticalSection(&monitor_handles_cs);
1088 while (id < registered) {
1090 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1091 pm = monitor_load(buffer, NULL);
1095 LeaveCriticalSection(&monitor_handles_cs);
1096 RegCloseKey(hmonitors);
1098 TRACE("%d monitors loaded\n", loaded);
1102 /******************************************************************
1103 * enumerate the local Ports from all loaded monitors (internal)
1105 * returns the needed size (in bytes) for pPorts
1106 * and *lpreturned is set to number of entries returned in pPorts
1109 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1113 LPPORT_INFO_2W cache;
1123 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1124 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1126 numentries = *lpreturned; /* this is 0, when we scan the registry */
1127 needed = entrysize * numentries;
1128 ptr = (LPWSTR) &pPorts[needed];
1133 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1135 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1136 if (pm->cache == NULL) {
1137 res = pm->monitor->pfnEnumPorts(NULL, 2, NULL, 0, &(pm->pi2_needed), &(pm->returned));
1138 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1139 pm->cache = HeapAlloc(GetProcessHeap(), 0, (pm->pi2_needed));
1140 res = pm->monitor->pfnEnumPorts(NULL, 2, (LPBYTE) pm->cache, pm->pi2_needed, &(pm->pi2_needed), &(pm->returned));
1142 TRACE("(%s) got %d with %d (cache need %d byte for %d entries)\n",
1143 debugstr_w(pm->name), res, GetLastError(), pm->pi2_needed, pm->returned);
1146 if (pm->cache && (level == 1) && (pm->pi1_needed == 0) && (pm->returned > 0)) {
1149 while (cacheindex < (pm->returned)) {
1150 pm->pi1_needed += sizeof(PORT_INFO_1W);
1151 pm->pi1_needed += (lstrlenW(cache->pPortName) + 1) * sizeof(WCHAR);
1155 TRACE("%d byte for %d cached PORT_INFO_1W entries (%s)\n",
1156 pm->pi1_needed, cacheindex, debugstr_w(pm->name));
1158 numentries += pm->returned;
1159 needed += (level == 1) ? pm->pi1_needed : pm->pi2_needed;
1161 /* fill the buffer, if we have one */
1162 if (pPorts && (cbBuf >= needed )) {
1165 while (cacheindex < pm->returned) {
1166 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1167 out->pPortName = ptr;
1168 lstrcpyW(ptr, cache->pPortName);
1169 ptr += (lstrlenW(ptr)+1);
1171 out->pMonitorName = ptr;
1172 lstrcpyW(ptr, cache->pMonitorName);
1173 ptr += (lstrlenW(ptr)+1);
1175 out->pDescription = ptr;
1176 lstrcpyW(ptr, cache->pDescription);
1177 ptr += (lstrlenW(ptr)+1);
1178 out->fPortType = cache->fPortType;
1179 out->Reserved = cache->Reserved;
1189 *lpreturned = numentries;
1190 TRACE("need %d byte for %d entries\n", needed, numentries);
1194 /******************************************************************
1195 * get_opened_printer_entry
1196 * Get the first place empty in the opened printer table
1199 * - pDefault is ignored
1201 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1203 UINT_PTR handle = nb_printer_handles, i;
1204 jobqueue_t *queue = NULL;
1205 opened_printer_t *printer = NULL;
1207 EnterCriticalSection(&printer_handles_cs);
1209 for (i = 0; i < nb_printer_handles; i++)
1211 if (!printer_handles[i])
1213 if(handle == nb_printer_handles)
1218 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1219 queue = printer_handles[i]->queue;
1223 if (handle >= nb_printer_handles)
1225 opened_printer_t **new_array;
1226 if (printer_handles)
1227 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1228 (nb_printer_handles + 16) * sizeof(*new_array) );
1230 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1231 (nb_printer_handles + 16) * sizeof(*new_array) );
1238 printer_handles = new_array;
1239 nb_printer_handles += 16;
1242 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1249 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
1250 if (!printer->name) {
1254 strcpyW(printer->name, name);
1258 printer->queue = queue;
1261 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1262 if (!printer->queue) {
1266 list_init(&printer->queue->jobs);
1267 printer->queue->ref = 0;
1269 InterlockedIncrement(&printer->queue->ref);
1271 printer_handles[handle] = printer;
1274 LeaveCriticalSection(&printer_handles_cs);
1275 if (!handle && printer) {
1276 /* Something Failed: Free the Buffers */
1277 HeapFree(GetProcessHeap(), 0, printer->name);
1278 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1279 HeapFree(GetProcessHeap(), 0, printer);
1282 return (HANDLE)handle;
1285 /******************************************************************
1286 * get_opened_printer
1287 * Get the pointer to the opened printer referred by the handle
1289 static opened_printer_t *get_opened_printer(HANDLE hprn)
1291 UINT_PTR idx = (UINT_PTR)hprn;
1292 opened_printer_t *ret = NULL;
1294 EnterCriticalSection(&printer_handles_cs);
1296 if ((idx <= 0) || (idx > nb_printer_handles))
1299 ret = printer_handles[idx - 1];
1301 LeaveCriticalSection(&printer_handles_cs);
1305 /******************************************************************
1306 * get_opened_printer_name
1307 * Get the pointer to the opened printer name referred by the handle
1309 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1311 opened_printer_t *printer = get_opened_printer(hprn);
1312 if(!printer) return NULL;
1313 return printer->name;
1316 /******************************************************************
1317 * WINSPOOL_GetOpenedPrinterRegKey
1320 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1322 LPCWSTR name = get_opened_printer_name(hPrinter);
1326 if(!name) return ERROR_INVALID_HANDLE;
1328 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1332 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1334 ERR("Can't find opened printer %s in registry\n",
1336 RegCloseKey(hkeyPrinters);
1337 return ERROR_INVALID_PRINTER_NAME; /* ? */
1339 RegCloseKey(hkeyPrinters);
1340 return ERROR_SUCCESS;
1343 /******************************************************************
1346 * Get the pointer to the specified job.
1347 * Should hold the printer_handles_cs before calling.
1349 static job_t *get_job(HANDLE hprn, DWORD JobId)
1351 opened_printer_t *printer = get_opened_printer(hprn);
1354 if(!printer) return NULL;
1355 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1357 if(job->job_id == JobId)
1363 /***********************************************************
1366 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1369 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1372 Formname = (dmA->dmSize > off_formname);
1373 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1374 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1375 dmW->dmDeviceName, CCHDEVICENAME);
1377 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1378 dmA->dmSize - CCHDEVICENAME);
1380 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1381 off_formname - CCHDEVICENAME);
1382 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1383 dmW->dmFormName, CCHFORMNAME);
1384 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1385 (off_formname + CCHFORMNAME));
1388 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1389 dmA->dmDriverExtra);
1393 /***********************************************************
1395 * Creates an ascii copy of supplied devmode on heap
1397 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1402 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1404 if(!dmW) return NULL;
1405 Formname = (dmW->dmSize > off_formname);
1406 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1407 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1408 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1409 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1411 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1412 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1414 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1415 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1416 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1417 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1418 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1419 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1422 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1423 dmW->dmDriverExtra);
1427 /***********************************************************
1428 * PRINTER_INFO_2AtoW
1429 * Creates a unicode copy of PRINTER_INFO_2A on heap
1431 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1433 LPPRINTER_INFO_2W piW;
1434 UNICODE_STRING usBuffer;
1436 if(!piA) return NULL;
1437 piW = HeapAlloc(heap, 0, sizeof(*piW));
1438 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1440 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1441 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1442 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1443 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1444 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1445 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1446 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1447 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1448 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1449 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1450 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1451 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1455 /***********************************************************
1456 * FREE_PRINTER_INFO_2W
1457 * Free PRINTER_INFO_2W and all strings
1459 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1463 HeapFree(heap,0,piW->pServerName);
1464 HeapFree(heap,0,piW->pPrinterName);
1465 HeapFree(heap,0,piW->pShareName);
1466 HeapFree(heap,0,piW->pPortName);
1467 HeapFree(heap,0,piW->pDriverName);
1468 HeapFree(heap,0,piW->pComment);
1469 HeapFree(heap,0,piW->pLocation);
1470 HeapFree(heap,0,piW->pDevMode);
1471 HeapFree(heap,0,piW->pSepFile);
1472 HeapFree(heap,0,piW->pPrintProcessor);
1473 HeapFree(heap,0,piW->pDatatype);
1474 HeapFree(heap,0,piW->pParameters);
1475 HeapFree(heap,0,piW);
1479 /******************************************************************
1480 * DeviceCapabilities [WINSPOOL.@]
1481 * DeviceCapabilitiesA [WINSPOOL.@]
1484 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1485 LPSTR pOutput, LPDEVMODEA lpdm)
1489 if (!GDI_CallDeviceCapabilities16)
1491 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1493 if (!GDI_CallDeviceCapabilities16) return -1;
1495 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1497 /* If DC_PAPERSIZE map POINT16s to POINTs */
1498 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1499 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1500 POINT *pt = (POINT *)pOutput;
1502 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1503 for(i = 0; i < ret; i++, pt++)
1508 HeapFree( GetProcessHeap(), 0, tmp );
1514 /*****************************************************************************
1515 * DeviceCapabilitiesW [WINSPOOL.@]
1517 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1520 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1521 WORD fwCapability, LPWSTR pOutput,
1522 const DEVMODEW *pDevMode)
1524 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1525 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1526 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1529 if(pOutput && (fwCapability == DC_BINNAMES ||
1530 fwCapability == DC_FILEDEPENDENCIES ||
1531 fwCapability == DC_PAPERNAMES)) {
1532 /* These need A -> W translation */
1535 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1539 switch(fwCapability) {
1544 case DC_FILEDEPENDENCIES:
1548 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1549 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1551 for(i = 0; i < ret; i++)
1552 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1553 pOutput + (i * size), size);
1554 HeapFree(GetProcessHeap(), 0, pOutputA);
1556 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1557 (LPSTR)pOutput, dmA);
1559 HeapFree(GetProcessHeap(),0,pPortA);
1560 HeapFree(GetProcessHeap(),0,pDeviceA);
1561 HeapFree(GetProcessHeap(),0,dmA);
1565 /******************************************************************
1566 * DocumentPropertiesA [WINSPOOL.@]
1568 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1570 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1571 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1572 LPDEVMODEA pDevModeInput,DWORD fMode )
1574 LPSTR lpName = pDeviceName;
1575 static CHAR port[] = "LPT1:";
1578 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1579 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1583 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1585 ERR("no name from hPrinter?\n");
1586 SetLastError(ERROR_INVALID_HANDLE);
1589 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1592 if (!GDI_CallExtDeviceMode16)
1594 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1596 if (!GDI_CallExtDeviceMode16) {
1597 ERR("No CallExtDeviceMode16?\n");
1601 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1602 pDevModeInput, NULL, fMode);
1605 HeapFree(GetProcessHeap(),0,lpName);
1610 /*****************************************************************************
1611 * DocumentPropertiesW (WINSPOOL.@)
1613 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1615 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1617 LPDEVMODEW pDevModeOutput,
1618 LPDEVMODEW pDevModeInput, DWORD fMode)
1621 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1622 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1623 LPDEVMODEA pDevModeOutputA = NULL;
1626 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1627 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1629 if(pDevModeOutput) {
1630 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1631 if(ret < 0) return ret;
1632 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1634 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1635 pDevModeInputA, fMode);
1636 if(pDevModeOutput) {
1637 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1638 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1640 if(fMode == 0 && ret > 0)
1641 ret += (CCHDEVICENAME + CCHFORMNAME);
1642 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1643 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1647 /******************************************************************
1648 * OpenPrinterA [WINSPOOL.@]
1653 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1654 LPPRINTER_DEFAULTSA pDefault)
1656 UNICODE_STRING lpPrinterNameW;
1657 UNICODE_STRING usBuffer;
1658 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1659 PWSTR pwstrPrinterNameW;
1662 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1665 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1666 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1667 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1668 pDefaultW = &DefaultW;
1670 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1672 RtlFreeUnicodeString(&usBuffer);
1673 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1675 RtlFreeUnicodeString(&lpPrinterNameW);
1679 /******************************************************************
1680 * OpenPrinterW [WINSPOOL.@]
1682 * Open a Printer / Printserver or a Printer-Object
1685 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1686 * phPrinter [O] The resulting Handle is stored here
1687 * pDefault [I] PTR to Default Printer Settings or NULL
1694 * lpPrinterName is one of:
1695 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1696 *| Printer: "PrinterName"
1697 *| Printer-Object: "PrinterName,Job xxx"
1698 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1699 *| XcvPort: "Servername,XcvPort PortName"
1702 *| Printer-Object not supported
1703 *| XcvMonitor not supported
1704 *| XcvPort not supported
1705 *| pDefaults is ignored
1708 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1710 HKEY hkeyPrinters = NULL;
1711 HKEY hkeyPrinter = NULL;
1713 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1715 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1716 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1719 if(lpPrinterName != NULL)
1721 /* Check any Printer exists */
1722 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1723 ERR("Can't create Printers key\n");
1724 SetLastError(ERROR_FILE_NOT_FOUND);
1727 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1728 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1730 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1731 RegCloseKey(hkeyPrinters);
1732 SetLastError(ERROR_INVALID_PRINTER_NAME);
1735 RegCloseKey(hkeyPrinter);
1736 RegCloseKey(hkeyPrinters);
1739 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1740 SetLastError(ERROR_INVALID_PARAMETER);
1744 /* Get the unique handle of the printer or Printserver */
1745 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1746 return (*phPrinter != 0);
1749 /******************************************************************
1750 * AddMonitorA [WINSPOOL.@]
1755 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1757 LPWSTR nameW = NULL;
1760 LPMONITOR_INFO_2A mi2a;
1761 MONITOR_INFO_2W mi2w;
1763 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1764 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1765 mi2a ? debugstr_a(mi2a->pName) : NULL,
1766 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1767 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1770 SetLastError(ERROR_INVALID_LEVEL);
1774 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1780 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1781 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1782 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1785 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1787 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1788 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1789 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1791 if (mi2a->pEnvironment) {
1792 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1793 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1794 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1796 if (mi2a->pDLLName) {
1797 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1798 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1799 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1802 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1804 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1805 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1806 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1808 HeapFree(GetProcessHeap(), 0, nameW);
1812 /******************************************************************************
1813 * AddMonitorW [WINSPOOL.@]
1815 * Install a Printmonitor
1818 * pName [I] Servername or NULL (local Computer)
1819 * Level [I] Structure-Level (Must be 2)
1820 * pMonitors [I] PTR to MONITOR_INFO_2
1827 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1830 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1832 monitor_t * pm = NULL;
1833 LPMONITOR_INFO_2W mi2w;
1839 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1840 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1841 mi2w ? debugstr_w(mi2w->pName) : NULL,
1842 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1843 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1846 SetLastError(ERROR_INVALID_LEVEL);
1850 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1855 if (pName && (pName[0])) {
1856 FIXME("for server %s not implemented\n", debugstr_w(pName));
1857 SetLastError(ERROR_ACCESS_DENIED);
1862 if (!mi2w->pName || (! mi2w->pName[0])) {
1863 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1864 SetLastError(ERROR_INVALID_PARAMETER);
1867 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1868 WARN("Environment %s requested (we support only %s)\n",
1869 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1870 SetLastError(ERROR_INVALID_ENVIRONMENT);
1874 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1875 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1876 SetLastError(ERROR_INVALID_PARAMETER);
1880 /* Load and initialize the monitor. SetLastError() is called on failure */
1881 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1886 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1887 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1891 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1892 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1893 &disposition) == ERROR_SUCCESS) {
1895 /* Some installers set options for the port before calling AddMonitor.
1896 We query the "Driver" entry to verify that the monitor is installed,
1897 before we return an error.
1898 When a user installs two print monitors at the same time with the
1899 same name but with a different driver DLL and a task switch comes
1900 between RegQueryValueExW and RegSetValueExW, a race condition
1901 is possible but silently ignored. */
1905 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1906 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1907 &namesize) == ERROR_SUCCESS)) {
1908 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1909 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1910 9x: ERROR_ALREADY_EXISTS (183) */
1911 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1916 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1917 res = (RegSetValueExW(hentry, DriverW, 0,
1918 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1920 RegCloseKey(hentry);
1927 /******************************************************************
1928 * DeletePrinterDriverA [WINSPOOL.@]
1931 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1933 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
1936 /******************************************************************
1937 * DeletePrinterDriverW [WINSPOOL.@]
1940 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1942 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
1945 /******************************************************************
1946 * DeleteMonitorA [WINSPOOL.@]
1948 * See DeleteMonitorW.
1951 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1953 LPWSTR nameW = NULL;
1954 LPWSTR EnvironmentW = NULL;
1955 LPWSTR MonitorNameW = NULL;
1960 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1961 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1962 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1966 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1967 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1968 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1971 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1972 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1973 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1976 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1978 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1979 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1980 HeapFree(GetProcessHeap(), 0, nameW);
1984 /******************************************************************
1985 * DeleteMonitorW [WINSPOOL.@]
1987 * Delete a specific Printmonitor from a Printing-Environment
1990 * pName [I] Servername or NULL (local Computer)
1991 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1992 * pMonitorName [I] Name of the Monitor, that should be deleted
1999 * pEnvironment is ignored in Windows for the local Computer.
2003 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2007 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2008 debugstr_w(pMonitorName));
2010 if (pName && (pName[0])) {
2011 FIXME("for server %s not implemented\n", debugstr_w(pName));
2012 SetLastError(ERROR_ACCESS_DENIED);
2016 /* pEnvironment is ignored in Windows for the local Computer */
2018 if (!pMonitorName || !pMonitorName[0]) {
2019 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2020 SetLastError(ERROR_INVALID_PARAMETER);
2024 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2025 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2029 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2030 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2031 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2036 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
2039 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2040 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2044 /******************************************************************
2045 * DeletePortA [WINSPOOL.@]
2051 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2053 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
2054 debugstr_a(pPortName));
2055 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2059 /******************************************************************
2060 * DeletePortW [WINSPOOL.@]
2062 * Delete a specific Port
2065 * pName [I] Servername or NULL (local Computer)
2066 * hWnd [I] Handle to parent Window for the Dialog-Box
2067 * pPortName [I] Name of the Port, that should be deleted
2078 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2080 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
2081 debugstr_w(pPortName));
2082 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2086 /******************************************************************************
2087 * SetPrinterW [WINSPOOL.@]
2089 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2091 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2092 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2096 /******************************************************************************
2097 * WritePrinter [WINSPOOL.@]
2099 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2101 opened_printer_t *printer;
2104 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2106 EnterCriticalSection(&printer_handles_cs);
2107 printer = get_opened_printer(hPrinter);
2110 SetLastError(ERROR_INVALID_HANDLE);
2116 SetLastError(ERROR_SPL_NO_STARTDOC);
2120 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2122 LeaveCriticalSection(&printer_handles_cs);
2126 /*****************************************************************************
2127 * AddFormA [WINSPOOL.@]
2129 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2131 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2135 /*****************************************************************************
2136 * AddFormW [WINSPOOL.@]
2138 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2140 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2144 /*****************************************************************************
2145 * AddJobA [WINSPOOL.@]
2147 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2150 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2154 SetLastError(ERROR_INVALID_LEVEL);
2158 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2161 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2162 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2163 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2164 if(*pcbNeeded > cbBuf) {
2165 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2168 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2169 addjobA->JobId = addjobW->JobId;
2170 addjobA->Path = (char *)(addjobA + 1);
2171 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2177 /*****************************************************************************
2178 * AddJobW [WINSPOOL.@]
2180 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2182 opened_printer_t *printer;
2185 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2186 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2187 WCHAR path[MAX_PATH], filename[MAX_PATH];
2189 ADDJOB_INFO_1W *addjob;
2191 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2193 EnterCriticalSection(&printer_handles_cs);
2195 printer = get_opened_printer(hPrinter);
2198 SetLastError(ERROR_INVALID_HANDLE);
2203 SetLastError(ERROR_INVALID_LEVEL);
2207 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2211 job->job_id = InterlockedIncrement(&next_job_id);
2213 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2214 if(path[len - 1] != '\\')
2216 memcpy(path + len, spool_path, sizeof(spool_path));
2217 sprintfW(filename, fmtW, path, job->job_id);
2219 len = strlenW(filename);
2220 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2221 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2222 job->document_title = strdupW(default_doc_title);
2223 list_add_tail(&printer->queue->jobs, &job->entry);
2225 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2226 if(*pcbNeeded <= cbBuf) {
2227 addjob = (ADDJOB_INFO_1W*)pData;
2228 addjob->JobId = job->job_id;
2229 addjob->Path = (WCHAR *)(addjob + 1);
2230 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2233 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2236 LeaveCriticalSection(&printer_handles_cs);
2240 /*****************************************************************************
2241 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2243 * Return the PATH for the Print-Processors
2245 * See GetPrintProcessorDirectoryW.
2249 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2250 DWORD level, LPBYTE Info,
2251 DWORD cbBuf, LPDWORD pcbNeeded)
2253 LPWSTR serverW = NULL;
2258 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2259 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2263 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2264 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2265 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2269 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2270 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2271 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2274 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2275 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2277 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2280 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2281 cbBuf, NULL, NULL) > 0;
2284 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2285 HeapFree(GetProcessHeap(), 0, envW);
2286 HeapFree(GetProcessHeap(), 0, serverW);
2290 /*****************************************************************************
2291 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2293 * Return the PATH for the Print-Processors
2296 * server [I] Servername (NT only) or NULL (local Computer)
2297 * env [I] Printing-Environment (see below) or NULL (Default)
2298 * level [I] Structure-Level (must be 1)
2299 * Info [O] PTR to Buffer that receives the Result
2300 * cbBuf [I] Size of Buffer at "Info"
2301 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2302 * required for the Buffer at "Info"
2305 * Success: TRUE and in pcbNeeded the Bytes used in Info
2306 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2307 * if cbBuf is too small
2309 * Native Values returned in Info on Success:
2310 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2311 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2312 *| win9x(Windows 4.0): "%winsysdir%"
2314 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2317 * Only NULL or "" is supported for server
2320 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2321 DWORD level, LPBYTE Info,
2322 DWORD cbBuf, LPDWORD pcbNeeded)
2325 const printenv_t * env_t;
2327 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2328 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2330 if(server != NULL && server[0]) {
2331 FIXME("server not supported: %s\n", debugstr_w(server));
2332 SetLastError(ERROR_INVALID_PARAMETER);
2336 env_t = validate_envW(env);
2337 if(!env_t) return FALSE; /* environment invalid or unsupported */
2340 WARN("(Level: %d) is ignored in win9x\n", level);
2341 SetLastError(ERROR_INVALID_LEVEL);
2345 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2346 needed = GetSystemDirectoryW(NULL, 0);
2347 /* add the Size for the Subdirectories */
2348 needed += lstrlenW(spoolprtprocsW);
2349 needed += lstrlenW(env_t->subdir);
2350 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2352 if(pcbNeeded) *pcbNeeded = needed;
2353 TRACE ("required: 0x%x/%d\n", needed, needed);
2354 if (needed > cbBuf) {
2355 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2358 if(pcbNeeded == NULL) {
2359 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2360 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2361 SetLastError(RPC_X_NULL_REF_POINTER);
2365 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2366 SetLastError(RPC_X_NULL_REF_POINTER);
2370 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2371 /* add the Subdirectories */
2372 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2373 lstrcatW((LPWSTR) Info, env_t->subdir);
2374 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2378 /*****************************************************************************
2379 * WINSPOOL_OpenDriverReg [internal]
2381 * opens the registry for the printer drivers depending on the given input
2382 * variable pEnvironment
2385 * the opened hkey on success
2388 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2392 const printenv_t * env;
2395 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2397 if (!pEnvironment || unicode) {
2398 /* pEnvironment was NULL or an Unicode-String: use it direct */
2399 env = validate_envW(pEnvironment);
2403 /* pEnvironment was an ANSI-String: convert to unicode first */
2405 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2406 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2407 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2408 env = validate_envW(buffer);
2409 HeapFree(GetProcessHeap(), 0, buffer);
2411 if (!env) return NULL;
2413 buffer = HeapAlloc( GetProcessHeap(), 0,
2414 (strlenW(DriversW) + strlenW(env->envname) +
2415 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2417 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2418 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2419 HeapFree(GetProcessHeap(), 0, buffer);
2424 /*****************************************************************************
2425 * AddPrinterW [WINSPOOL.@]
2427 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2429 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2433 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2436 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2439 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2440 SetLastError(ERROR_INVALID_PARAMETER);
2444 ERR("Level = %d, unsupported!\n", Level);
2445 SetLastError(ERROR_INVALID_LEVEL);
2449 SetLastError(ERROR_INVALID_PARAMETER);
2452 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2454 ERR("Can't create Printers key\n");
2457 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2458 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2459 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2460 RegCloseKey(hkeyPrinter);
2461 RegCloseKey(hkeyPrinters);
2464 RegCloseKey(hkeyPrinter);
2466 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2468 ERR("Can't create Drivers key\n");
2469 RegCloseKey(hkeyPrinters);
2472 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2474 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2475 RegCloseKey(hkeyPrinters);
2476 RegCloseKey(hkeyDrivers);
2477 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2480 RegCloseKey(hkeyDriver);
2481 RegCloseKey(hkeyDrivers);
2483 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2484 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2485 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2486 RegCloseKey(hkeyPrinters);
2490 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2492 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2493 SetLastError(ERROR_INVALID_PRINTER_NAME);
2494 RegCloseKey(hkeyPrinters);
2497 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2498 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2499 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2501 /* See if we can load the driver. We may need the devmode structure anyway
2504 * Note that DocumentPropertiesW will briefly try to open the printer we
2505 * just create to find a DEVMODEA struct (it will use the WINEPS default
2506 * one in case it is not there, so we are ok).
2508 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2511 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2512 size = sizeof(DEVMODEW);
2518 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2519 ZeroMemory(dmW,size);
2521 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2523 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2524 HeapFree(GetProcessHeap(),0,dmW);
2529 /* set devmode to printer name */
2530 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2534 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2535 and we support these drivers. NT writes DEVMODEW so somehow
2536 we'll need to distinguish between these when we support NT
2540 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2541 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2542 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2543 HeapFree(GetProcessHeap(), 0, dmA);
2545 HeapFree(GetProcessHeap(), 0, dmW);
2547 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2548 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2549 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2550 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2552 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2553 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2554 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2555 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2556 (LPBYTE)&pi->Priority, sizeof(DWORD));
2557 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2558 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2559 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2560 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2561 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2562 (LPBYTE)&pi->Status, sizeof(DWORD));
2563 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2564 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2566 RegCloseKey(hkeyPrinter);
2567 RegCloseKey(hkeyPrinters);
2568 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2569 ERR("OpenPrinter failing\n");
2575 /*****************************************************************************
2576 * AddPrinterA [WINSPOOL.@]
2578 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2580 UNICODE_STRING pNameW;
2582 PRINTER_INFO_2W *piW;
2583 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2586 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2588 ERR("Level = %d, unsupported!\n", Level);
2589 SetLastError(ERROR_INVALID_LEVEL);
2592 pwstrNameW = asciitounicode(&pNameW,pName);
2593 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2595 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2597 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2598 RtlFreeUnicodeString(&pNameW);
2603 /*****************************************************************************
2604 * ClosePrinter [WINSPOOL.@]
2606 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2608 UINT_PTR i = (UINT_PTR)hPrinter;
2609 opened_printer_t *printer = NULL;
2612 TRACE("Handle %p\n", hPrinter);
2614 EnterCriticalSection(&printer_handles_cs);
2616 if ((i > 0) && (i <= nb_printer_handles))
2617 printer = printer_handles[i - 1];
2621 struct list *cursor, *cursor2;
2624 EndDocPrinter(hPrinter);
2626 if(InterlockedDecrement(&printer->queue->ref) == 0)
2628 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2630 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2631 ScheduleJob(hPrinter, job->job_id);
2633 HeapFree(GetProcessHeap(), 0, printer->queue);
2635 HeapFree(GetProcessHeap(), 0, printer->name);
2636 HeapFree(GetProcessHeap(), 0, printer);
2637 printer_handles[i - 1] = NULL;
2640 LeaveCriticalSection(&printer_handles_cs);
2644 /*****************************************************************************
2645 * DeleteFormA [WINSPOOL.@]
2647 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2649 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2653 /*****************************************************************************
2654 * DeleteFormW [WINSPOOL.@]
2656 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2658 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2662 /*****************************************************************************
2663 * WINSPOOL_SHRegDeleteKey
2665 * Recursively delete subkeys.
2666 * Cut & paste from shlwapi.
2669 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2671 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2672 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2675 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2678 /* Find how many subkeys there are */
2679 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2680 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2684 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2685 /* Name too big: alloc a buffer for it */
2686 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2689 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2692 /* Recursively delete all the subkeys */
2693 for(i = 0; i < dwKeyCount && !dwRet; i++)
2695 dwSize = dwMaxSubkeyLen;
2696 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2698 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2701 if (lpszName != szNameBuf)
2702 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2706 RegCloseKey(hSubKey);
2708 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2713 /*****************************************************************************
2714 * DeletePrinter [WINSPOOL.@]
2716 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2718 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2719 HKEY hkeyPrinters, hkey;
2722 SetLastError(ERROR_INVALID_HANDLE);
2725 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2726 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2727 RegCloseKey(hkeyPrinters);
2729 WriteProfileStringW(devicesW, lpNameW, NULL);
2730 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2731 RegDeleteValueW(hkey, lpNameW);
2737 /*****************************************************************************
2738 * SetPrinterA [WINSPOOL.@]
2740 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2743 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2747 /*****************************************************************************
2748 * SetJobA [WINSPOOL.@]
2750 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2751 LPBYTE pJob, DWORD Command)
2755 UNICODE_STRING usBuffer;
2757 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2759 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2760 are all ignored by SetJob, so we don't bother copying them */
2768 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2769 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2771 JobW = (LPBYTE)info1W;
2772 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2773 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2774 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2775 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2776 info1W->Status = info1A->Status;
2777 info1W->Priority = info1A->Priority;
2778 info1W->Position = info1A->Position;
2779 info1W->PagesPrinted = info1A->PagesPrinted;
2784 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2785 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2787 JobW = (LPBYTE)info2W;
2788 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2789 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2790 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2791 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2792 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2793 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2794 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2795 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2796 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2797 info2W->Status = info2A->Status;
2798 info2W->Priority = info2A->Priority;
2799 info2W->Position = info2A->Position;
2800 info2W->StartTime = info2A->StartTime;
2801 info2W->UntilTime = info2A->UntilTime;
2802 info2W->PagesPrinted = info2A->PagesPrinted;
2806 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2807 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2810 SetLastError(ERROR_INVALID_LEVEL);
2814 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2820 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2821 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2822 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2823 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2824 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2829 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2830 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2831 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2832 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2833 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2834 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2835 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2836 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2837 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2841 HeapFree(GetProcessHeap(), 0, JobW);
2846 /*****************************************************************************
2847 * SetJobW [WINSPOOL.@]
2849 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2850 LPBYTE pJob, DWORD Command)
2855 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2856 FIXME("Ignoring everything other than document title\n");
2858 EnterCriticalSection(&printer_handles_cs);
2859 job = get_job(hPrinter, JobId);
2869 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2870 HeapFree(GetProcessHeap(), 0, job->document_title);
2871 job->document_title = strdupW(info1->pDocument);
2876 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2877 HeapFree(GetProcessHeap(), 0, job->document_title);
2878 job->document_title = strdupW(info2->pDocument);
2884 SetLastError(ERROR_INVALID_LEVEL);
2889 LeaveCriticalSection(&printer_handles_cs);
2893 /*****************************************************************************
2894 * EndDocPrinter [WINSPOOL.@]
2896 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2898 opened_printer_t *printer;
2900 TRACE("(%p)\n", hPrinter);
2902 EnterCriticalSection(&printer_handles_cs);
2904 printer = get_opened_printer(hPrinter);
2907 SetLastError(ERROR_INVALID_HANDLE);
2913 SetLastError(ERROR_SPL_NO_STARTDOC);
2917 CloseHandle(printer->doc->hf);
2918 ScheduleJob(hPrinter, printer->doc->job_id);
2919 HeapFree(GetProcessHeap(), 0, printer->doc);
2920 printer->doc = NULL;
2923 LeaveCriticalSection(&printer_handles_cs);
2927 /*****************************************************************************
2928 * EndPagePrinter [WINSPOOL.@]
2930 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2932 FIXME("(%p): stub\n", hPrinter);
2936 /*****************************************************************************
2937 * StartDocPrinterA [WINSPOOL.@]
2939 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2941 UNICODE_STRING usBuffer;
2943 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2946 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2947 or one (DOC_INFO_3) extra DWORDs */
2951 doc2W.JobId = doc2->JobId;
2954 doc2W.dwMode = doc2->dwMode;
2957 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2958 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2959 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2963 SetLastError(ERROR_INVALID_LEVEL);
2967 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2969 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2970 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2971 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2976 /*****************************************************************************
2977 * StartDocPrinterW [WINSPOOL.@]
2979 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2981 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2982 opened_printer_t *printer;
2983 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2984 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2985 JOB_INFO_1W job_info;
2986 DWORD needed, ret = 0;
2990 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2991 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2992 debugstr_w(doc->pDatatype));
2994 if(Level < 1 || Level > 3)
2996 SetLastError(ERROR_INVALID_LEVEL);
3000 EnterCriticalSection(&printer_handles_cs);
3001 printer = get_opened_printer(hPrinter);
3004 SetLastError(ERROR_INVALID_HANDLE);
3010 SetLastError(ERROR_INVALID_PRINTER_STATE);
3014 /* Even if we're printing to a file we still add a print job, we'll
3015 just ignore the spool file name */
3017 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3019 ERR("AddJob failed gle %08x\n", GetLastError());
3023 if(doc->pOutputFile)
3024 filename = doc->pOutputFile;
3026 filename = addjob->Path;
3028 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3029 if(hf == INVALID_HANDLE_VALUE)
3032 memset(&job_info, 0, sizeof(job_info));
3033 job_info.pDocument = doc->pDocName;
3034 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3036 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3037 printer->doc->hf = hf;
3038 ret = printer->doc->job_id = addjob->JobId;
3040 LeaveCriticalSection(&printer_handles_cs);
3045 /*****************************************************************************
3046 * StartPagePrinter [WINSPOOL.@]
3048 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3050 FIXME("(%p): stub\n", hPrinter);
3054 /*****************************************************************************
3055 * GetFormA [WINSPOOL.@]
3057 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3058 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3060 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3061 Level,pForm,cbBuf,pcbNeeded);
3065 /*****************************************************************************
3066 * GetFormW [WINSPOOL.@]
3068 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3069 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3071 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3072 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3076 /*****************************************************************************
3077 * SetFormA [WINSPOOL.@]
3079 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3082 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3086 /*****************************************************************************
3087 * SetFormW [WINSPOOL.@]
3089 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3092 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3096 /*****************************************************************************
3097 * ReadPrinter [WINSPOOL.@]
3099 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3100 LPDWORD pNoBytesRead)
3102 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3106 /*****************************************************************************
3107 * ResetPrinterA [WINSPOOL.@]
3109 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3111 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3115 /*****************************************************************************
3116 * ResetPrinterW [WINSPOOL.@]
3118 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3120 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3124 /*****************************************************************************
3125 * WINSPOOL_GetDWORDFromReg
3127 * Return DWORD associated with ValueName from hkey.
3129 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3131 DWORD sz = sizeof(DWORD), type, value = 0;
3134 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3136 if(ret != ERROR_SUCCESS) {
3137 WARN("Got ret = %d on name %s\n", ret, ValueName);
3140 if(type != REG_DWORD) {
3141 ERR("Got type %d\n", type);
3147 /*****************************************************************************
3148 * WINSPOOL_GetStringFromReg
3150 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3151 * String is stored either as unicode or ascii.
3152 * Bit of a hack here to get the ValueName if we want ascii.
3154 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3155 DWORD buflen, DWORD *needed,
3158 DWORD sz = buflen, type;
3162 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3164 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
3165 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3166 HeapFree(GetProcessHeap(),0,ValueNameA);
3168 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3169 WARN("Got ret = %d\n", ret);
3173 /* add space for terminating '\0' */
3174 sz += unicode ? sizeof(WCHAR) : 1;
3178 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3183 /*****************************************************************************
3184 * WINSPOOL_GetDefaultDevMode
3186 * Get a default DevMode values for wineps.
3190 static void WINSPOOL_GetDefaultDevMode(
3192 DWORD buflen, DWORD *needed,
3196 static const char szwps[] = "wineps.drv";
3198 /* fill default DEVMODE - should be read from ppd... */
3199 ZeroMemory( &dm, sizeof(dm) );
3200 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3201 dm.dmSpecVersion = DM_SPECVERSION;
3202 dm.dmDriverVersion = 1;
3203 dm.dmSize = sizeof(DEVMODEA);
3204 dm.dmDriverExtra = 0;
3206 DM_ORIENTATION | DM_PAPERSIZE |
3207 DM_PAPERLENGTH | DM_PAPERWIDTH |
3210 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3211 DM_YRESOLUTION | DM_TTOPTION;
3213 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3214 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3215 dm.u1.s1.dmPaperLength = 2970;
3216 dm.u1.s1.dmPaperWidth = 2100;
3220 dm.dmDefaultSource = DMBIN_AUTO;
3221 dm.dmPrintQuality = DMRES_MEDIUM;
3224 dm.dmYResolution = 300; /* 300dpi */
3225 dm.dmTTOption = DMTT_BITMAP;
3228 /* dm.dmLogPixels */
3229 /* dm.dmBitsPerPel */
3230 /* dm.dmPelsWidth */
3231 /* dm.dmPelsHeight */
3232 /* dm.dmDisplayFlags */
3233 /* dm.dmDisplayFrequency */
3234 /* dm.dmICMMethod */
3235 /* dm.dmICMIntent */
3236 /* dm.dmMediaType */
3237 /* dm.dmDitherType */
3238 /* dm.dmReserved1 */
3239 /* dm.dmReserved2 */
3240 /* dm.dmPanningWidth */
3241 /* dm.dmPanningHeight */
3244 if(buflen >= sizeof(DEVMODEW)) {
3245 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3246 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3247 HeapFree(GetProcessHeap(),0,pdmW);
3249 *needed = sizeof(DEVMODEW);
3253 if(buflen >= sizeof(DEVMODEA)) {
3254 memcpy(ptr, &dm, sizeof(DEVMODEA));
3256 *needed = sizeof(DEVMODEA);
3260 /*****************************************************************************
3261 * WINSPOOL_GetDevModeFromReg
3263 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3264 * DevMode is stored either as unicode or ascii.
3266 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3268 DWORD buflen, DWORD *needed,
3271 DWORD sz = buflen, type;
3274 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3275 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3276 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3277 if (sz < sizeof(DEVMODEA))
3279 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3282 /* ensures that dmSize is not erratically bogus if registry is invalid */
3283 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3284 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3286 sz += (CCHDEVICENAME + CCHFORMNAME);
3288 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3289 memcpy(ptr, dmW, sz);
3290 HeapFree(GetProcessHeap(),0,dmW);
3297 /*********************************************************************
3298 * WINSPOOL_GetPrinter_2
3300 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3301 * The strings are either stored as unicode or ascii.
3303 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3304 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3307 DWORD size, left = cbBuf;
3308 BOOL space = (cbBuf > 0);
3313 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3315 if(space && size <= left) {
3316 pi2->pPrinterName = (LPWSTR)ptr;
3323 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3325 if(space && size <= left) {
3326 pi2->pShareName = (LPWSTR)ptr;
3333 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3335 if(space && size <= left) {
3336 pi2->pPortName = (LPWSTR)ptr;
3343 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3345 if(space && size <= left) {
3346 pi2->pDriverName = (LPWSTR)ptr;
3353 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3355 if(space && size <= left) {
3356 pi2->pComment = (LPWSTR)ptr;
3363 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3365 if(space && size <= left) {
3366 pi2->pLocation = (LPWSTR)ptr;
3373 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3375 if(space && size <= left) {
3376 pi2->pDevMode = (LPDEVMODEW)ptr;
3385 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3386 if(space && size <= left) {
3387 pi2->pDevMode = (LPDEVMODEW)ptr;
3394 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3396 if(space && size <= left) {
3397 pi2->pSepFile = (LPWSTR)ptr;
3404 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3406 if(space && size <= left) {
3407 pi2->pPrintProcessor = (LPWSTR)ptr;
3414 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3416 if(space && size <= left) {
3417 pi2->pDatatype = (LPWSTR)ptr;
3424 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3426 if(space && size <= left) {
3427 pi2->pParameters = (LPWSTR)ptr;
3435 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3436 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3437 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3438 "Default Priority");
3439 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3440 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3443 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3444 memset(pi2, 0, sizeof(*pi2));
3449 /*********************************************************************
3450 * WINSPOOL_GetPrinter_4
3452 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3454 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3455 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3458 DWORD size, left = cbBuf;
3459 BOOL space = (cbBuf > 0);
3464 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3466 if(space && size <= left) {
3467 pi4->pPrinterName = (LPWSTR)ptr;
3475 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3478 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3479 memset(pi4, 0, sizeof(*pi4));
3484 /*********************************************************************
3485 * WINSPOOL_GetPrinter_5
3487 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3489 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3490 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3493 DWORD size, left = cbBuf;
3494 BOOL space = (cbBuf > 0);
3499 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3501 if(space && size <= left) {
3502 pi5->pPrinterName = (LPWSTR)ptr;
3509 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3511 if(space && size <= left) {
3512 pi5->pPortName = (LPWSTR)ptr;
3520 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3521 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3523 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3527 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3528 memset(pi5, 0, sizeof(*pi5));
3533 /*****************************************************************************
3534 * WINSPOOL_GetPrinter
3536 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3537 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3538 * just a collection of pointers to strings.
3540 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3541 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3544 DWORD size, needed = 0;
3546 HKEY hkeyPrinter, hkeyPrinters;
3549 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3551 if (!(name = get_opened_printer_name(hPrinter))) {
3552 SetLastError(ERROR_INVALID_HANDLE);
3556 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3558 ERR("Can't create Printers key\n");
3561 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3563 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3564 RegCloseKey(hkeyPrinters);
3565 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3572 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3574 size = sizeof(PRINTER_INFO_2W);
3576 ptr = pPrinter + size;
3578 memset(pPrinter, 0, size);
3583 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3591 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3593 size = sizeof(PRINTER_INFO_4W);
3595 ptr = pPrinter + size;
3597 memset(pPrinter, 0, size);
3602 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3611 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3613 size = sizeof(PRINTER_INFO_5W);
3615 ptr = pPrinter + size;
3617 memset(pPrinter, 0, size);
3623 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3630 FIXME("Unimplemented level %d\n", Level);
3631 SetLastError(ERROR_INVALID_LEVEL);
3632 RegCloseKey(hkeyPrinters);
3633 RegCloseKey(hkeyPrinter);
3637 RegCloseKey(hkeyPrinter);
3638 RegCloseKey(hkeyPrinters);
3640 TRACE("returning %d needed = %d\n", ret, needed);
3641 if(pcbNeeded) *pcbNeeded = needed;
3643 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3647 /*****************************************************************************
3648 * GetPrinterW [WINSPOOL.@]
3650 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3651 DWORD cbBuf, LPDWORD pcbNeeded)
3653 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3657 /*****************************************************************************
3658 * GetPrinterA [WINSPOOL.@]
3660 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3661 DWORD cbBuf, LPDWORD pcbNeeded)
3663 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3667 /*****************************************************************************
3668 * WINSPOOL_EnumPrinters
3670 * Implementation of EnumPrintersA|W
3672 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3673 DWORD dwLevel, LPBYTE lpbPrinters,
3674 DWORD cbBuf, LPDWORD lpdwNeeded,
3675 LPDWORD lpdwReturned, BOOL unicode)
3678 HKEY hkeyPrinters, hkeyPrinter;
3679 WCHAR PrinterName[255];
3680 DWORD needed = 0, number = 0;
3681 DWORD used, i, left;
3685 memset(lpbPrinters, 0, cbBuf);
3691 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3692 if(dwType == PRINTER_ENUM_DEFAULT)
3695 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3696 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3697 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3698 if(!dwType) return TRUE;
3701 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3702 FIXME("dwType = %08x\n", dwType);
3703 SetLastError(ERROR_INVALID_FLAGS);
3707 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3709 ERR("Can't create Printers key\n");
3713 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3714 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3715 RegCloseKey(hkeyPrinters);
3716 ERR("Can't query Printers key\n");
3719 TRACE("Found %d printers\n", number);
3723 RegCloseKey(hkeyPrinters);
3725 *lpdwReturned = number;
3729 used = number * sizeof(PRINTER_INFO_2W);
3732 used = number * sizeof(PRINTER_INFO_4W);
3735 used = number * sizeof(PRINTER_INFO_5W);
3739 SetLastError(ERROR_INVALID_LEVEL);
3740 RegCloseKey(hkeyPrinters);
3743 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3745 for(i = 0; i < number; i++) {
3746 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3748 ERR("Can't enum key number %d\n", i);
3749 RegCloseKey(hkeyPrinters);
3752 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3753 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3755 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3756 RegCloseKey(hkeyPrinters);
3761 buf = lpbPrinters + used;
3762 left = cbBuf - used;
3770 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3771 left, &needed, unicode);
3773 if(pi) pi += sizeof(PRINTER_INFO_2W);
3776 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3777 left, &needed, unicode);
3779 if(pi) pi += sizeof(PRINTER_INFO_4W);
3782 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3783 left, &needed, unicode);
3785 if(pi) pi += sizeof(PRINTER_INFO_5W);
3788 ERR("Shouldn't be here!\n");
3789 RegCloseKey(hkeyPrinter);
3790 RegCloseKey(hkeyPrinters);
3793 RegCloseKey(hkeyPrinter);
3795 RegCloseKey(hkeyPrinters);
3802 memset(lpbPrinters, 0, cbBuf);
3803 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3807 *lpdwReturned = number;
3808 SetLastError(ERROR_SUCCESS);
3813 /******************************************************************
3814 * EnumPrintersW [WINSPOOL.@]
3816 * Enumerates the available printers, print servers and print
3817 * providers, depending on the specified flags, name and level.
3821 * If level is set to 1:
3822 * Not implemented yet!
3823 * Returns TRUE with an empty list.
3825 * If level is set to 2:
3826 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3827 * Returns an array of PRINTER_INFO_2 data structures in the
3828 * lpbPrinters buffer. Note that according to MSDN also an
3829 * OpenPrinter should be performed on every remote printer.
3831 * If level is set to 4 (officially WinNT only):
3832 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3833 * Fast: Only the registry is queried to retrieve printer names,
3834 * no connection to the driver is made.
3835 * Returns an array of PRINTER_INFO_4 data structures in the
3836 * lpbPrinters buffer.
3838 * If level is set to 5 (officially WinNT4/Win9x only):
3839 * Fast: Only the registry is queried to retrieve printer names,
3840 * no connection to the driver is made.
3841 * Returns an array of PRINTER_INFO_5 data structures in the
3842 * lpbPrinters buffer.
3844 * If level set to 3 or 6+:
3845 * returns zero (failure!)
3847 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3851 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3852 * - Only levels 2, 4 and 5 are implemented at the moment.
3853 * - 16-bit printer drivers are not enumerated.
3854 * - Returned amount of bytes used/needed does not match the real Windoze
3855 * implementation (as in this implementation, all strings are part
3856 * of the buffer, whereas Win32 keeps them somewhere else)
3857 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3860 * - In a regular Wine installation, no registry settings for printers
3861 * exist, which makes this function return an empty list.
3863 BOOL WINAPI EnumPrintersW(
3864 DWORD dwType, /* [in] Types of print objects to enumerate */
3865 LPWSTR lpszName, /* [in] name of objects to enumerate */
3866 DWORD dwLevel, /* [in] type of printer info structure */
3867 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3868 DWORD cbBuf, /* [in] max size of buffer in bytes */
3869 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3870 LPDWORD lpdwReturned /* [out] number of entries returned */
3873 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3874 lpdwNeeded, lpdwReturned, TRUE);
3877 /******************************************************************
3878 * EnumPrintersA [WINSPOOL.@]
3881 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3882 DWORD dwLevel, LPBYTE lpbPrinters,
3883 DWORD cbBuf, LPDWORD lpdwNeeded,
3884 LPDWORD lpdwReturned)
3887 UNICODE_STRING lpszNameW;
3890 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3891 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3892 lpdwNeeded, lpdwReturned, FALSE);
3893 RtlFreeUnicodeString(&lpszNameW);
3897 /*****************************************************************************
3898 * WINSPOOL_GetDriverInfoFromReg [internal]
3900 * Enters the information from the registry into the DRIVER_INFO struct
3903 * zero if the printer driver does not exist in the registry
3904 * (only if Level > 1) otherwise nonzero
3906 static BOOL WINSPOOL_GetDriverInfoFromReg(
3909 LPCWSTR pEnvironment,
3911 LPBYTE ptr, /* DRIVER_INFO */
3912 LPBYTE pDriverStrings, /* strings buffer */
3913 DWORD cbBuf, /* size of string buffer */
3914 LPDWORD pcbNeeded, /* space needed for str. */
3915 BOOL unicode) /* type of strings */
3919 LPBYTE strPtr = pDriverStrings;
3921 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
3922 debugstr_w(DriverName), debugstr_w(pEnvironment),
3923 Level, ptr, pDriverStrings, cbBuf, unicode);
3926 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3927 if (*pcbNeeded <= cbBuf)
3928 strcpyW((LPWSTR)strPtr, DriverName);
3930 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3932 if(*pcbNeeded <= cbBuf)
3933 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3934 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3938 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3942 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3943 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3946 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3947 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3948 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3953 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3956 pEnvironment = DefaultEnvironmentW;
3958 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3960 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3963 if(*pcbNeeded <= cbBuf) {
3965 strcpyW((LPWSTR)strPtr, pEnvironment);
3967 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3968 (LPSTR)strPtr, size, NULL, NULL);
3970 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3971 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3974 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3977 if(*pcbNeeded <= cbBuf)
3978 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3981 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3982 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3985 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3988 if(*pcbNeeded <= cbBuf)
3989 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3992 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3993 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3996 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3997 0, &size, unicode)) {
3999 if(*pcbNeeded <= cbBuf)
4000 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4001 size, &tmp, unicode);
4003 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4004 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4008 RegCloseKey(hkeyDriver);
4009 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4013 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4016 if(*pcbNeeded <= cbBuf)
4017 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4018 size, &tmp, unicode);
4020 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4021 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4024 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4027 if(*pcbNeeded <= cbBuf)
4028 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4029 size, &tmp, unicode);
4031 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4032 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4035 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4038 if(*pcbNeeded <= cbBuf)
4039 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4040 size, &tmp, unicode);
4042 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4043 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4046 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4049 if(*pcbNeeded <= cbBuf)
4050 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4051 size, &tmp, unicode);
4053 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4054 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4057 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4058 RegCloseKey(hkeyDriver);
4062 /*****************************************************************************
4063 * WINSPOOL_GetPrinterDriver
4065 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
4066 DWORD Level, LPBYTE pDriverInfo,
4067 DWORD cbBuf, LPDWORD pcbNeeded,
4071 WCHAR DriverName[100];
4072 DWORD ret, type, size, needed = 0;
4074 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4076 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4077 Level,pDriverInfo,cbBuf, pcbNeeded);
4079 ZeroMemory(pDriverInfo, cbBuf);
4081 if (!(name = get_opened_printer_name(hPrinter))) {
4082 SetLastError(ERROR_INVALID_HANDLE);
4085 if(Level < 1 || Level > 6) {
4086 SetLastError(ERROR_INVALID_LEVEL);
4089 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4091 ERR("Can't create Printers key\n");
4094 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4096 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4097 RegCloseKey(hkeyPrinters);
4098 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4101 size = sizeof(DriverName);
4103 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4104 (LPBYTE)DriverName, &size);
4105 RegCloseKey(hkeyPrinter);
4106 RegCloseKey(hkeyPrinters);
4107 if(ret != ERROR_SUCCESS) {
4108 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4112 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4114 ERR("Can't create Drivers key\n");
4120 size = sizeof(DRIVER_INFO_1W);
4123 size = sizeof(DRIVER_INFO_2W);
4126 size = sizeof(DRIVER_INFO_3W);
4129 size = sizeof(DRIVER_INFO_4W);
4132 size = sizeof(DRIVER_INFO_5W);
4135 size = sizeof(DRIVER_INFO_6W);
4138 ERR("Invalid level\n");
4143 ptr = pDriverInfo + size;
4145 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4146 pEnvironment, Level, pDriverInfo,
4147 (cbBuf < size) ? NULL : ptr,
4148 (cbBuf < size) ? 0 : cbBuf - size,
4149 &needed, unicode)) {
4150 RegCloseKey(hkeyDrivers);
4154 RegCloseKey(hkeyDrivers);
4156 if(pcbNeeded) *pcbNeeded = size + needed;
4157 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4158 if(cbBuf >= needed) return TRUE;
4159 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4163 /*****************************************************************************
4164 * GetPrinterDriverA [WINSPOOL.@]
4166 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4167 DWORD Level, LPBYTE pDriverInfo,
4168 DWORD cbBuf, LPDWORD pcbNeeded)
4171 UNICODE_STRING pEnvW;
4174 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4175 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4176 cbBuf, pcbNeeded, FALSE);
4177 RtlFreeUnicodeString(&pEnvW);
4180 /*****************************************************************************
4181 * GetPrinterDriverW [WINSPOOL.@]
4183 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4184 DWORD Level, LPBYTE pDriverInfo,
4185 DWORD cbBuf, LPDWORD pcbNeeded)
4187 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4188 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4191 /*****************************************************************************
4192 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4194 * Return the PATH for the Printer-Drivers (UNICODE)
4197 * pName [I] Servername (NT only) or NULL (local Computer)
4198 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4199 * Level [I] Structure-Level (must be 1)
4200 * pDriverDirectory [O] PTR to Buffer that receives the Result
4201 * cbBuf [I] Size of Buffer at pDriverDirectory
4202 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4203 * required for pDriverDirectory
4206 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4207 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4208 * if cbBuf is too small
4210 * Native Values returned in pDriverDirectory on Success:
4211 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4212 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4213 *| win9x(Windows 4.0): "%winsysdir%"
4215 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4218 *- Only NULL or "" is supported for pName
4221 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4222 DWORD Level, LPBYTE pDriverDirectory,
4223 DWORD cbBuf, LPDWORD pcbNeeded)
4226 const printenv_t * env;
4228 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4229 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4230 if(pName != NULL && pName[0]) {
4231 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4232 SetLastError(ERROR_INVALID_PARAMETER);
4236 env = validate_envW(pEnvironment);
4237 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4240 WARN("(Level: %d) is ignored in win9x\n", Level);
4241 SetLastError(ERROR_INVALID_LEVEL);
4245 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4246 needed = GetSystemDirectoryW(NULL, 0);
4247 /* add the Size for the Subdirectories */
4248 needed += lstrlenW(spooldriversW);
4249 needed += lstrlenW(env->subdir);
4250 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4253 *pcbNeeded = needed;
4254 TRACE("required: 0x%x/%d\n", needed, needed);
4255 if(needed > cbBuf) {
4256 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4259 if(pcbNeeded == NULL) {
4260 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4261 SetLastError(RPC_X_NULL_REF_POINTER);
4264 if(pDriverDirectory == NULL) {
4265 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4266 SetLastError(ERROR_INVALID_USER_BUFFER);
4270 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4271 /* add the Subdirectories */
4272 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4273 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4274 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4279 /*****************************************************************************
4280 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4282 * Return the PATH for the Printer-Drivers (ANSI)
4284 * See GetPrinterDriverDirectoryW.
4287 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4290 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4291 DWORD Level, LPBYTE pDriverDirectory,
4292 DWORD cbBuf, LPDWORD pcbNeeded)
4294 UNICODE_STRING nameW, environmentW;
4297 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4298 WCHAR *driverDirectoryW = NULL;
4300 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4301 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4303 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4305 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4306 else nameW.Buffer = NULL;
4307 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4308 else environmentW.Buffer = NULL;
4310 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4311 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4314 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4315 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4317 *pcbNeeded = needed;
4318 ret = (needed <= cbBuf) ? TRUE : FALSE;
4320 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4322 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4324 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4325 RtlFreeUnicodeString(&environmentW);
4326 RtlFreeUnicodeString(&nameW);
4331 /*****************************************************************************
4332 * AddPrinterDriverA [WINSPOOL.@]
4334 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4337 HKEY hkeyDrivers, hkeyName;
4338 static CHAR empty[] = "",
4341 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4343 if(level != 2 && level != 3) {
4344 SetLastError(ERROR_INVALID_LEVEL);
4347 if ((pName) && (pName[0])) {
4348 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4349 SetLastError(ERROR_INVALID_PARAMETER);
4353 WARN("pDriverInfo == NULL\n");
4354 SetLastError(ERROR_INVALID_PARAMETER);
4359 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4361 memset(&di3, 0, sizeof(di3));
4362 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4365 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4367 SetLastError(ERROR_INVALID_PARAMETER);
4371 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4372 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4373 if(!di3.pHelpFile) di3.pHelpFile = empty;
4374 if(!di3.pMonitorName) di3.pMonitorName = empty;
4376 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4379 ERR("Can't create Drivers key\n");
4383 if(level == 2) { /* apparently can't overwrite with level2 */
4384 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4385 RegCloseKey(hkeyName);
4386 RegCloseKey(hkeyDrivers);
4387 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4388 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4392 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4393 RegCloseKey(hkeyDrivers);
4394 ERR("Can't create Name key\n");
4397 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4398 lstrlenA(di3.pConfigFile) + 1);
4399 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4400 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4401 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4403 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4404 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4405 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4406 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4407 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4408 RegCloseKey(hkeyName);
4409 RegCloseKey(hkeyDrivers);
4414 /*****************************************************************************
4415 * AddPrinterDriverW [WINSPOOL.@]
4417 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4420 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4425 /*****************************************************************************
4426 * AddPrintProcessorA [WINSPOOL.@]
4428 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4429 LPSTR pPrintProcessorName)
4431 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4432 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4436 /*****************************************************************************
4437 * AddPrintProcessorW [WINSPOOL.@]
4439 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4440 LPWSTR pPrintProcessorName)
4442 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4443 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4447 /*****************************************************************************
4448 * AddPrintProvidorA [WINSPOOL.@]
4450 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4452 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4456 /*****************************************************************************
4457 * AddPrintProvidorW [WINSPOOL.@]
4459 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4461 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4465 /*****************************************************************************
4466 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4468 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4469 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4471 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4472 pDevModeOutput, pDevModeInput);
4476 /*****************************************************************************
4477 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4479 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4480 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4482 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4483 pDevModeOutput, pDevModeInput);
4487 /*****************************************************************************
4488 * PrinterProperties [WINSPOOL.@]
4490 * Displays a dialog to set the properties of the printer.
4493 * nonzero on success or zero on failure
4496 * implemented as stub only
4498 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4499 HANDLE hPrinter /* [in] handle to printer object */
4501 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4502 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4506 /*****************************************************************************
4507 * EnumJobsA [WINSPOOL.@]
4510 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4511 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4514 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4515 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4517 if(pcbNeeded) *pcbNeeded = 0;
4518 if(pcReturned) *pcReturned = 0;
4523 /*****************************************************************************
4524 * EnumJobsW [WINSPOOL.@]
4527 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4528 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4531 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4532 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4534 if(pcbNeeded) *pcbNeeded = 0;
4535 if(pcReturned) *pcReturned = 0;
4539 /*****************************************************************************
4540 * WINSPOOL_EnumPrinterDrivers [internal]
4542 * Delivers information about all printer drivers installed on the
4543 * localhost or a given server
4546 * nonzero on success or zero on failure. If the buffer for the returned
4547 * information is too small the function will return an error
4550 * - only implemented for localhost, foreign hosts will return an error
4552 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4553 DWORD Level, LPBYTE pDriverInfo,
4554 DWORD cbBuf, LPDWORD pcbNeeded,
4555 LPDWORD pcReturned, BOOL unicode)
4558 DWORD i, needed, number = 0, size = 0;
4559 WCHAR DriverNameW[255];
4562 TRACE("%s,%s,%d,%p,%d,%d\n",
4563 debugstr_w(pName), debugstr_w(pEnvironment),
4564 Level, pDriverInfo, cbBuf, unicode);
4566 /* check for local drivers */
4567 if((pName) && (pName[0])) {
4568 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4569 SetLastError(ERROR_ACCESS_DENIED);
4573 /* check input parameter */
4574 if((Level < 1) || (Level > 3)) {
4575 ERR("unsupported level %d\n", Level);
4576 SetLastError(ERROR_INVALID_LEVEL);
4580 /* initialize return values */
4582 memset( pDriverInfo, 0, cbBuf);
4586 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4588 ERR("Can't open Drivers key\n");
4592 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4593 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4594 RegCloseKey(hkeyDrivers);
4595 ERR("Can't query Drivers key\n");
4598 TRACE("Found %d Drivers\n", number);
4600 /* get size of single struct
4601 * unicode and ascii structure have the same size
4605 size = sizeof(DRIVER_INFO_1A);
4608 size = sizeof(DRIVER_INFO_2A);
4611 size = sizeof(DRIVER_INFO_3A);
4615 /* calculate required buffer size */
4616 *pcbNeeded = size * number;
4618 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4620 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4621 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4623 ERR("Can't enum key number %d\n", i);
4624 RegCloseKey(hkeyDrivers);
4627 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4628 pEnvironment, Level, ptr,
4629 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4630 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4631 &needed, unicode)) {
4632 RegCloseKey(hkeyDrivers);
4635 (*pcbNeeded) += needed;
4638 RegCloseKey(hkeyDrivers);
4640 if(cbBuf < *pcbNeeded){
4641 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4645 *pcReturned = number;
4649 /*****************************************************************************
4650 * EnumPrinterDriversW [WINSPOOL.@]
4652 * see function EnumPrinterDrivers for RETURNS, BUGS
4654 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4655 LPBYTE pDriverInfo, DWORD cbBuf,
4656 LPDWORD pcbNeeded, LPDWORD pcReturned)
4658 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4659 cbBuf, pcbNeeded, pcReturned, TRUE);
4662 /*****************************************************************************
4663 * EnumPrinterDriversA [WINSPOOL.@]
4665 * see function EnumPrinterDrivers for RETURNS, BUGS
4667 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4668 LPBYTE pDriverInfo, DWORD cbBuf,
4669 LPDWORD pcbNeeded, LPDWORD pcReturned)
4671 UNICODE_STRING pNameW, pEnvironmentW;
4672 PWSTR pwstrNameW, pwstrEnvironmentW;
4674 pwstrNameW = asciitounicode(&pNameW, pName);
4675 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4677 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4678 Level, pDriverInfo, cbBuf, pcbNeeded,
4680 RtlFreeUnicodeString(&pNameW);
4681 RtlFreeUnicodeString(&pEnvironmentW);
4686 /******************************************************************************
4687 * EnumPortsA (WINSPOOL.@)
4692 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4693 LPDWORD pcbNeeded, LPDWORD pcReturned)
4696 LPBYTE bufferW = NULL;
4697 LPWSTR nameW = NULL;
4699 DWORD numentries = 0;
4702 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4703 cbBuf, pcbNeeded, pcReturned);
4705 /* convert servername to unicode */
4707 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4708 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4709 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4711 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4712 needed = cbBuf * sizeof(WCHAR);
4713 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4714 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4716 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4717 if (pcbNeeded) needed = *pcbNeeded;
4718 /* HeapReAlloc return NULL, when bufferW was NULL */
4719 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4720 HeapAlloc(GetProcessHeap(), 0, needed);
4722 /* Try again with the large Buffer */
4723 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4725 needed = pcbNeeded ? *pcbNeeded : 0;
4726 numentries = pcReturned ? *pcReturned : 0;
4729 W2k require the buffersize from EnumPortsW also for EnumPortsA.
4730 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4733 /* EnumPortsW collected all Data. Parse them to caclulate ANSI-Size */
4734 DWORD entrysize = 0;
4737 LPPORT_INFO_2W pi2w;
4738 LPPORT_INFO_2A pi2a;
4741 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
4743 /* First pass: calculate the size for all Entries */
4744 pi2w = (LPPORT_INFO_2W) bufferW;
4745 pi2a = (LPPORT_INFO_2A) pPorts;
4747 while (index < numentries) {
4749 needed += entrysize; /* PORT_INFO_?A */
4750 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
4752 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4753 NULL, 0, NULL, NULL);
4755 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4756 NULL, 0, NULL, NULL);
4757 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4758 NULL, 0, NULL, NULL);
4760 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4761 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4762 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4765 /* check for errors and quit on failure */
4766 if (cbBuf < needed) {
4767 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4771 len = entrysize * numentries; /* room for all PORT_INFO_?A */
4772 ptr = (LPSTR) &pPorts[len]; /* room for strings */
4773 cbBuf -= len ; /* free Bytes in the user-Buffer */
4774 pi2w = (LPPORT_INFO_2W) bufferW;
4775 pi2a = (LPPORT_INFO_2A) pPorts;
4777 /* Second Pass: Fill the User Buffer (if we have one) */
4778 while ((index < numentries) && pPorts) {
4780 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
4781 pi2a->pPortName = ptr;
4782 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4783 ptr, cbBuf , NULL, NULL);
4787 pi2a->pMonitorName = ptr;
4788 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4789 ptr, cbBuf, NULL, NULL);
4793 pi2a->pDescription = ptr;
4794 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4795 ptr, cbBuf, NULL, NULL);
4799 pi2a->fPortType = pi2w->fPortType;
4800 pi2a->Reserved = 0; /* documented: "must be zero" */
4803 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4804 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4805 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4810 if (pcbNeeded) *pcbNeeded = needed;
4811 if (pcReturned) *pcReturned = (res) ? numentries : 0;
4813 HeapFree(GetProcessHeap(), 0, nameW);
4814 HeapFree(GetProcessHeap(), 0, bufferW);
4816 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
4817 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
4823 /******************************************************************************
4824 * EnumPortsW (WINSPOOL.@)
4826 * Enumerate available Ports
4829 * name [I] Servername or NULL (local Computer)
4830 * level [I] Structure-Level (1 or 2)
4831 * buffer [O] PTR to Buffer that receives the Result
4832 * bufsize [I] Size of Buffer at buffer
4833 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4834 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4838 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4842 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4845 DWORD numentries = 0;
4848 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
4849 cbBuf, pcbNeeded, pcReturned);
4851 if (pName && (pName[0])) {
4852 FIXME("not implemented for Server %s\n", debugstr_w(pName));
4853 SetLastError(ERROR_ACCESS_DENIED);
4857 /* Level is not checked in win9x */
4858 if (!Level || (Level > 2)) {
4859 WARN("level (%d) is ignored in win9x\n", Level);
4860 SetLastError(ERROR_INVALID_LEVEL);
4864 SetLastError(RPC_X_NULL_REF_POINTER);
4868 EnterCriticalSection(&monitor_handles_cs);
4871 /* Scan all local Ports */
4873 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
4875 /* we calculated the needed buffersize. now do the error-checks */
4876 if (cbBuf < needed) {
4877 monitor_unloadall();
4878 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4879 goto emP_cleanup_cs;
4881 else if (!pPorts || !pcReturned) {
4882 monitor_unloadall();
4883 SetLastError(RPC_X_NULL_REF_POINTER);
4884 goto emP_cleanup_cs;
4887 /* Fill the Buffer */
4888 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
4890 monitor_unloadall();
4893 LeaveCriticalSection(&monitor_handles_cs);
4896 if (pcbNeeded) *pcbNeeded = needed;
4897 if (pcReturned) *pcReturned = (res) ? numentries : 0;
4899 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
4900 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
4905 /******************************************************************************
4906 * GetDefaultPrinterW (WINSPOOL.@)
4909 * This function must read the value from data 'device' of key
4910 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4912 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4916 WCHAR *buffer, *ptr;
4920 SetLastError(ERROR_INVALID_PARAMETER);
4924 /* make the buffer big enough for the stuff from the profile/registry,
4925 * the content must fit into the local buffer to compute the correct
4926 * size even if the extern buffer is too small or not given.
4927 * (20 for ,driver,port) */
4929 len = max(100, (insize + 20));
4930 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4932 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4934 SetLastError (ERROR_FILE_NOT_FOUND);
4938 TRACE("%s\n", debugstr_w(buffer));
4940 if ((ptr = strchrW(buffer, ',')) == NULL)
4942 SetLastError(ERROR_INVALID_NAME);
4948 *namesize = strlenW(buffer) + 1;
4949 if(!name || (*namesize > insize))
4951 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4955 strcpyW(name, buffer);
4958 HeapFree( GetProcessHeap(), 0, buffer);
4963 /******************************************************************************
4964 * GetDefaultPrinterA (WINSPOOL.@)
4966 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4970 WCHAR *bufferW = NULL;
4974 SetLastError(ERROR_INVALID_PARAMETER);
4978 if(name && *namesize) {
4980 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4983 if(!GetDefaultPrinterW( bufferW, namesize)) {
4988 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4992 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4995 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
4998 HeapFree( GetProcessHeap(), 0, bufferW);
5003 /******************************************************************************
5004 * SetDefaultPrinterW (WINSPOOL.204)
5006 * Set the Name of the Default Printer
5009 * pszPrinter [I] Name of the Printer or NULL
5016 * When the Parameter is NULL or points to an Empty String and
5017 * a Default Printer was already present, then this Function changes nothing.
5018 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5019 * the First enumerated local Printer is used.
5022 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5025 TRACE("(%s)\n", debugstr_w(pszPrinter));
5027 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5031 /******************************************************************************
5032 * SetDefaultPrinterA (WINSPOOL.202)
5034 * See SetDefaultPrinterW.
5037 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5040 TRACE("(%s)\n", debugstr_a(pszPrinter));
5042 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5047 /******************************************************************************
5048 * SetPrinterDataExA (WINSPOOL.@)
5050 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5051 LPCSTR pValueName, DWORD Type,
5052 LPBYTE pData, DWORD cbData)
5054 HKEY hkeyPrinter, hkeySubkey;
5057 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5058 debugstr_a(pValueName), Type, pData, cbData);
5060 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5064 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5066 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5067 RegCloseKey(hkeyPrinter);
5070 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5071 RegCloseKey(hkeySubkey);
5072 RegCloseKey(hkeyPrinter);
5076 /******************************************************************************
5077 * SetPrinterDataExW (WINSPOOL.@)
5079 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5080 LPCWSTR pValueName, DWORD Type,
5081 LPBYTE pData, DWORD cbData)
5083 HKEY hkeyPrinter, hkeySubkey;
5086 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5087 debugstr_w(pValueName), Type, pData, cbData);
5089 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5093 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5095 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5096 RegCloseKey(hkeyPrinter);
5099 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5100 RegCloseKey(hkeySubkey);
5101 RegCloseKey(hkeyPrinter);
5105 /******************************************************************************
5106 * SetPrinterDataA (WINSPOOL.@)
5108 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5109 LPBYTE pData, DWORD cbData)
5111 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5115 /******************************************************************************
5116 * SetPrinterDataW (WINSPOOL.@)
5118 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5119 LPBYTE pData, DWORD cbData)
5121 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5125 /******************************************************************************
5126 * GetPrinterDataExA (WINSPOOL.@)
5128 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5129 LPCSTR pValueName, LPDWORD pType,
5130 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5132 HKEY hkeyPrinter, hkeySubkey;
5135 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5136 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5139 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5143 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5145 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5146 RegCloseKey(hkeyPrinter);
5150 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5151 RegCloseKey(hkeySubkey);
5152 RegCloseKey(hkeyPrinter);
5156 /******************************************************************************
5157 * GetPrinterDataExW (WINSPOOL.@)
5159 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5160 LPCWSTR pValueName, LPDWORD pType,
5161 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5163 HKEY hkeyPrinter, hkeySubkey;
5166 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5167 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5170 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5174 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5176 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5177 RegCloseKey(hkeyPrinter);
5181 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5182 RegCloseKey(hkeySubkey);
5183 RegCloseKey(hkeyPrinter);
5187 /******************************************************************************
5188 * GetPrinterDataA (WINSPOOL.@)
5190 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5191 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5193 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5194 pData, nSize, pcbNeeded);
5197 /******************************************************************************
5198 * GetPrinterDataW (WINSPOOL.@)
5200 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5201 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5203 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5204 pData, nSize, pcbNeeded);
5207 /*******************************************************************************
5208 * EnumPrinterDataExW [WINSPOOL.@]
5210 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5211 LPBYTE pEnumValues, DWORD cbEnumValues,
5212 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5214 HKEY hkPrinter, hkSubKey;
5215 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5216 cbValueNameLen, cbMaxValueLen, cbValueLen,
5221 PPRINTER_ENUM_VALUESW ppev;
5223 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5225 if (pKeyName == NULL || *pKeyName == 0)
5226 return ERROR_INVALID_PARAMETER;
5228 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5229 if (ret != ERROR_SUCCESS)
5231 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5236 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5237 if (ret != ERROR_SUCCESS)
5239 r = RegCloseKey (hkPrinter);
5240 if (r != ERROR_SUCCESS)
5241 WARN ("RegCloseKey returned %i\n", r);
5242 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5243 debugstr_w (pKeyName), ret);
5247 ret = RegCloseKey (hkPrinter);
5248 if (ret != ERROR_SUCCESS)
5250 ERR ("RegCloseKey returned %i\n", ret);
5251 r = RegCloseKey (hkSubKey);
5252 if (r != ERROR_SUCCESS)
5253 WARN ("RegCloseKey returned %i\n", r);
5257 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5258 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5259 if (ret != ERROR_SUCCESS)
5261 r = RegCloseKey (hkSubKey);
5262 if (r != ERROR_SUCCESS)
5263 WARN ("RegCloseKey returned %i\n", r);
5264 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5268 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5269 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5271 if (cValues == 0) /* empty key */
5273 r = RegCloseKey (hkSubKey);
5274 if (r != ERROR_SUCCESS)
5275 WARN ("RegCloseKey returned %i\n", r);
5276 *pcbEnumValues = *pnEnumValues = 0;
5277 return ERROR_SUCCESS;
5280 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5282 hHeap = GetProcessHeap ();
5285 ERR ("GetProcessHeap failed\n");
5286 r = RegCloseKey (hkSubKey);
5287 if (r != ERROR_SUCCESS)
5288 WARN ("RegCloseKey returned %i\n", r);
5289 return ERROR_OUTOFMEMORY;
5292 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5293 if (lpValueName == NULL)
5295 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5296 r = RegCloseKey (hkSubKey);
5297 if (r != ERROR_SUCCESS)
5298 WARN ("RegCloseKey returned %i\n", r);
5299 return ERROR_OUTOFMEMORY;
5302 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5303 if (lpValue == NULL)
5305 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5306 if (HeapFree (hHeap, 0, lpValueName) == 0)
5307 WARN ("HeapFree failed with code %i\n", GetLastError ());
5308 r = RegCloseKey (hkSubKey);
5309 if (r != ERROR_SUCCESS)
5310 WARN ("RegCloseKey returned %i\n", r);
5311 return ERROR_OUTOFMEMORY;
5314 TRACE ("pass 1: calculating buffer required for all names and values\n");
5316 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5318 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5320 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5322 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5323 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5324 NULL, NULL, lpValue, &cbValueLen);
5325 if (ret != ERROR_SUCCESS)
5327 if (HeapFree (hHeap, 0, lpValue) == 0)
5328 WARN ("HeapFree failed with code %i\n", GetLastError ());
5329 if (HeapFree (hHeap, 0, lpValueName) == 0)
5330 WARN ("HeapFree failed with code %i\n", GetLastError ());
5331 r = RegCloseKey (hkSubKey);
5332 if (r != ERROR_SUCCESS)
5333 WARN ("RegCloseKey returned %i\n", r);
5334 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5338 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5339 debugstr_w (lpValueName), dwIndex,
5340 cbValueNameLen + 1, cbValueLen);
5342 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5343 cbBufSize += cbValueLen;
5346 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5348 *pcbEnumValues = cbBufSize;
5349 *pnEnumValues = cValues;
5351 if (cbEnumValues < cbBufSize) /* buffer too small */
5353 if (HeapFree (hHeap, 0, lpValue) == 0)
5354 WARN ("HeapFree failed with code %i\n", GetLastError ());
5355 if (HeapFree (hHeap, 0, lpValueName) == 0)
5356 WARN ("HeapFree failed with code %i\n", GetLastError ());
5357 r = RegCloseKey (hkSubKey);
5358 if (r != ERROR_SUCCESS)
5359 WARN ("RegCloseKey returned %i\n", r);
5360 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5361 return ERROR_MORE_DATA;
5364 TRACE ("pass 2: copying all names and values to buffer\n");
5366 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5367 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5369 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5371 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5372 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5373 NULL, &dwType, lpValue, &cbValueLen);
5374 if (ret != ERROR_SUCCESS)
5376 if (HeapFree (hHeap, 0, lpValue) == 0)
5377 WARN ("HeapFree failed with code %i\n", GetLastError ());
5378 if (HeapFree (hHeap, 0, lpValueName) == 0)
5379 WARN ("HeapFree failed with code %i\n", GetLastError ());
5380 r = RegCloseKey (hkSubKey);
5381 if (r != ERROR_SUCCESS)
5382 WARN ("RegCloseKey returned %i\n", r);
5383 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5387 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5388 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5389 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5390 pEnumValues += cbValueNameLen;
5392 /* return # of *bytes* (including trailing \0), not # of chars */
5393 ppev[dwIndex].cbValueName = cbValueNameLen;
5395 ppev[dwIndex].dwType = dwType;
5397 memcpy (pEnumValues, lpValue, cbValueLen);
5398 ppev[dwIndex].pData = pEnumValues;
5399 pEnumValues += cbValueLen;
5401 ppev[dwIndex].cbData = cbValueLen;
5403 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5404 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5407 if (HeapFree (hHeap, 0, lpValue) == 0)
5409 ret = GetLastError ();
5410 ERR ("HeapFree failed with code %i\n", ret);
5411 if (HeapFree (hHeap, 0, lpValueName) == 0)
5412 WARN ("HeapFree failed with code %i\n", GetLastError ());
5413 r = RegCloseKey (hkSubKey);
5414 if (r != ERROR_SUCCESS)
5415 WARN ("RegCloseKey returned %i\n", r);
5419 if (HeapFree (hHeap, 0, lpValueName) == 0)
5421 ret = GetLastError ();
5422 ERR ("HeapFree failed with code %i\n", ret);
5423 r = RegCloseKey (hkSubKey);
5424 if (r != ERROR_SUCCESS)
5425 WARN ("RegCloseKey returned %i\n", r);
5429 ret = RegCloseKey (hkSubKey);
5430 if (ret != ERROR_SUCCESS)
5432 ERR ("RegCloseKey returned %i\n", ret);
5436 return ERROR_SUCCESS;
5439 /*******************************************************************************
5440 * EnumPrinterDataExA [WINSPOOL.@]
5442 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5443 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5444 * what Windows 2000 SP1 does.
5447 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5448 LPBYTE pEnumValues, DWORD cbEnumValues,
5449 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5453 DWORD ret, dwIndex, dwBufSize;
5457 TRACE ("%p %s\n", hPrinter, pKeyName);
5459 if (pKeyName == NULL || *pKeyName == 0)
5460 return ERROR_INVALID_PARAMETER;
5462 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5465 ret = GetLastError ();
5466 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5470 hHeap = GetProcessHeap ();
5473 ERR ("GetProcessHeap failed\n");
5474 return ERROR_OUTOFMEMORY;
5477 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5478 if (pKeyNameW == NULL)
5480 ERR ("Failed to allocate %i bytes from process heap\n",
5481 (LONG)(len * sizeof (WCHAR)));
5482 return ERROR_OUTOFMEMORY;
5485 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5487 ret = GetLastError ();
5488 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5489 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5490 WARN ("HeapFree failed with code %i\n", GetLastError ());
5494 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5495 pcbEnumValues, pnEnumValues);
5496 if (ret != ERROR_SUCCESS)
5498 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5499 WARN ("HeapFree failed with code %i\n", GetLastError ());
5500 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5504 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5506 ret = GetLastError ();
5507 ERR ("HeapFree failed with code %i\n", ret);
5511 if (*pnEnumValues == 0) /* empty key */
5512 return ERROR_SUCCESS;
5515 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5517 PPRINTER_ENUM_VALUESW ppev =
5518 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5520 if (dwBufSize < ppev->cbValueName)
5521 dwBufSize = ppev->cbValueName;
5523 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5524 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5525 dwBufSize = ppev->cbData;
5528 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5530 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5531 if (pBuffer == NULL)
5533 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5534 return ERROR_OUTOFMEMORY;
5537 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5539 PPRINTER_ENUM_VALUESW ppev =
5540 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5542 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5543 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5547 ret = GetLastError ();
5548 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5549 if (HeapFree (hHeap, 0, pBuffer) == 0)
5550 WARN ("HeapFree failed with code %i\n", GetLastError ());
5554 memcpy (ppev->pValueName, pBuffer, len);
5556 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5558 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5559 ppev->dwType != REG_MULTI_SZ)
5562 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5563 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5566 ret = GetLastError ();
5567 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5568 if (HeapFree (hHeap, 0, pBuffer) == 0)
5569 WARN ("HeapFree failed with code %i\n", GetLastError ());
5573 memcpy (ppev->pData, pBuffer, len);
5575 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5576 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5579 if (HeapFree (hHeap, 0, pBuffer) == 0)
5581 ret = GetLastError ();
5582 ERR ("HeapFree failed with code %i\n", ret);
5586 return ERROR_SUCCESS;
5589 /******************************************************************************
5590 * AbortPrinter (WINSPOOL.@)
5592 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5594 FIXME("(%p), stub!\n", hPrinter);
5598 /******************************************************************************
5599 * AddPortA (WINSPOOL.@)
5604 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5606 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5610 /******************************************************************************
5611 * AddPortW (WINSPOOL.@)
5613 * Add a Port for a specific Monitor
5616 * pName [I] Servername or NULL (local Computer)
5617 * hWnd [I] Handle to parent Window for the Dialog-Box
5618 * pMonitorName [I] Name of the Monitor that manage the Port
5628 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5630 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5634 /******************************************************************************
5635 * AddPortExA (WINSPOOL.@)
5640 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5642 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5643 lpBuffer, debugstr_a(lpMonitorName));
5647 /******************************************************************************
5648 * AddPortExW (WINSPOOL.@)
5650 * Add a Port for a specific Monitor, without presenting a user interface
5653 * hMonitor [I] Handle from InitializePrintMonitor2()
5654 * pName [I] Servername or NULL (local Computer)
5655 * Level [I] Structure-Level (1 or 2) for lpBuffer
5656 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5657 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5667 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5669 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5670 lpBuffer, debugstr_w(lpMonitorName));
5674 /******************************************************************************
5675 * AddPrinterConnectionA (WINSPOOL.@)
5677 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5679 FIXME("%s\n", debugstr_a(pName));
5683 /******************************************************************************
5684 * AddPrinterConnectionW (WINSPOOL.@)
5686 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5688 FIXME("%s\n", debugstr_w(pName));
5692 /******************************************************************************
5693 * AddPrinterDriverExW (WINSPOOL.@)
5695 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5696 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5698 FIXME("%s %d %p %d\n", debugstr_w(pName),
5699 Level, pDriverInfo, dwFileCopyFlags);
5700 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5704 /******************************************************************************
5705 * AddPrinterDriverExA (WINSPOOL.@)
5707 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5708 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5710 FIXME("%s %d %p %d\n", debugstr_a(pName),
5711 Level, pDriverInfo, dwFileCopyFlags);
5712 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5716 /******************************************************************************
5717 * ConfigurePortA (WINSPOOL.@)
5719 * See ConfigurePortW.
5722 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5724 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5728 /******************************************************************************
5729 * ConfigurePortW (WINSPOOL.@)
5731 * Display the Configuration-Dialog for a specific Port
5734 * pName [I] Servername or NULL (local Computer)
5735 * hWnd [I] Handle to parent Window for the Dialog-Box
5736 * pPortName [I] Name of the Port, that should be configured
5746 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5748 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5752 /******************************************************************************
5753 * ConnectToPrinterDlg (WINSPOOL.@)
5755 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5757 FIXME("%p %x\n", hWnd, Flags);
5761 /******************************************************************************
5762 * DeletePrinterConnectionA (WINSPOOL.@)
5764 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5766 FIXME("%s\n", debugstr_a(pName));
5770 /******************************************************************************
5771 * DeletePrinterConnectionW (WINSPOOL.@)
5773 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5775 FIXME("%s\n", debugstr_w(pName));
5779 /******************************************************************************
5780 * DeletePrinterDriverExW (WINSPOOL.@)
5782 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5783 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5788 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
5789 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5791 if(pName && pName[0])
5793 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
5794 SetLastError(ERROR_INVALID_PARAMETER);
5800 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
5801 SetLastError(ERROR_INVALID_PARAMETER);
5805 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5809 ERR("Can't open drivers key\n");
5813 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
5816 RegCloseKey(hkey_drivers);
5821 /******************************************************************************
5822 * DeletePrinterDriverExA (WINSPOOL.@)
5824 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5825 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5827 UNICODE_STRING NameW, EnvW, DriverW;
5830 asciitounicode(&NameW, pName);
5831 asciitounicode(&EnvW, pEnvironment);
5832 asciitounicode(&DriverW, pDriverName);
5834 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
5836 RtlFreeUnicodeString(&DriverW);
5837 RtlFreeUnicodeString(&EnvW);
5838 RtlFreeUnicodeString(&NameW);
5843 /******************************************************************************
5844 * DeletePrinterDataExW (WINSPOOL.@)
5846 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5849 FIXME("%p %s %s\n", hPrinter,
5850 debugstr_w(pKeyName), debugstr_w(pValueName));
5851 return ERROR_INVALID_PARAMETER;
5854 /******************************************************************************
5855 * DeletePrinterDataExA (WINSPOOL.@)
5857 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5860 FIXME("%p %s %s\n", hPrinter,
5861 debugstr_a(pKeyName), debugstr_a(pValueName));
5862 return ERROR_INVALID_PARAMETER;
5865 /******************************************************************************
5866 * DeletePrintProcessorA (WINSPOOL.@)
5868 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5870 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5871 debugstr_a(pPrintProcessorName));
5875 /******************************************************************************
5876 * DeletePrintProcessorW (WINSPOOL.@)
5878 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5880 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5881 debugstr_w(pPrintProcessorName));
5885 /******************************************************************************
5886 * DeletePrintProvidorA (WINSPOOL.@)
5888 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5890 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5891 debugstr_a(pPrintProviderName));
5895 /******************************************************************************
5896 * DeletePrintProvidorW (WINSPOOL.@)
5898 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5900 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5901 debugstr_w(pPrintProviderName));
5905 /******************************************************************************
5906 * EnumFormsA (WINSPOOL.@)
5908 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5909 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5911 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5912 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5916 /******************************************************************************
5917 * EnumFormsW (WINSPOOL.@)
5919 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5920 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5922 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5923 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5927 /*****************************************************************************
5928 * EnumMonitorsA [WINSPOOL.@]
5930 * See EnumMonitorsW.
5933 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5934 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5937 LPBYTE bufferW = NULL;
5938 LPWSTR nameW = NULL;
5940 DWORD numentries = 0;
5943 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5944 cbBuf, pcbNeeded, pcReturned);
5946 /* convert servername to unicode */
5948 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5949 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5950 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5952 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5953 needed = cbBuf * sizeof(WCHAR);
5954 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5955 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5957 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5958 if (pcbNeeded) needed = *pcbNeeded;
5959 /* HeapReAlloc return NULL, when bufferW was NULL */
5960 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5961 HeapAlloc(GetProcessHeap(), 0, needed);
5963 /* Try again with the large Buffer */
5964 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5966 numentries = pcReturned ? *pcReturned : 0;
5969 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5970 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5973 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5974 DWORD entrysize = 0;
5977 LPMONITOR_INFO_2W mi2w;
5978 LPMONITOR_INFO_2A mi2a;
5980 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5981 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5983 /* First pass: calculate the size for all Entries */
5984 mi2w = (LPMONITOR_INFO_2W) bufferW;
5985 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5987 while (index < numentries) {
5989 needed += entrysize; /* MONITOR_INFO_?A */
5990 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5992 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5993 NULL, 0, NULL, NULL);
5995 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5996 NULL, 0, NULL, NULL);
5997 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5998 NULL, 0, NULL, NULL);
6000 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6001 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6002 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6005 /* check for errors and quit on failure */
6006 if (cbBuf < needed) {
6007 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6011 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6012 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6013 cbBuf -= len ; /* free Bytes in the user-Buffer */
6014 mi2w = (LPMONITOR_INFO_2W) bufferW;
6015 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6017 /* Second Pass: Fill the User Buffer (if we have one) */
6018 while ((index < numentries) && pMonitors) {
6020 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6022 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6023 ptr, cbBuf , NULL, NULL);
6027 mi2a->pEnvironment = ptr;
6028 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6029 ptr, cbBuf, NULL, NULL);
6033 mi2a->pDLLName = ptr;
6034 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6035 ptr, cbBuf, NULL, NULL);
6039 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6040 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6041 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6045 if (pcbNeeded) *pcbNeeded = needed;
6046 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6048 HeapFree(GetProcessHeap(), 0, nameW);
6049 HeapFree(GetProcessHeap(), 0, bufferW);
6051 TRACE("returning %d with %d (%d byte for %d entries)\n",
6052 (res), GetLastError(), needed, numentries);
6058 /*****************************************************************************
6059 * EnumMonitorsW [WINSPOOL.@]
6061 * Enumerate available Port-Monitors
6064 * pName [I] Servername or NULL (local Computer)
6065 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6066 * pMonitors [O] PTR to Buffer that receives the Result
6067 * cbBuf [I] Size of Buffer at pMonitors
6068 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6069 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6073 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6076 * Windows reads the Registry once and cache the Results.
6078 *| Language-Monitors are also installed in the same Registry-Location but
6079 *| they are filtered in Windows (not returned by EnumMonitors).
6080 *| We do no filtering to simplify our Code.
6083 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6084 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6087 DWORD numentries = 0;
6090 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6091 cbBuf, pcbNeeded, pcReturned);
6093 if (pName && (lstrlenW(pName))) {
6094 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6095 SetLastError(ERROR_ACCESS_DENIED);
6099 /* Level is not checked in win9x */
6100 if (!Level || (Level > 2)) {
6101 WARN("level (%d) is ignored in win9x\n", Level);
6102 SetLastError(ERROR_INVALID_LEVEL);
6106 SetLastError(RPC_X_NULL_REF_POINTER);
6110 /* Scan all Monitor-Keys */
6112 needed = get_local_monitors(Level, NULL, 0, &numentries);
6114 /* we calculated the needed buffersize. now do the error-checks */
6115 if (cbBuf < needed) {
6116 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6119 else if (!pMonitors || !pcReturned) {
6120 SetLastError(RPC_X_NULL_REF_POINTER);
6124 /* fill the Buffer with the Monitor-Keys */
6125 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6129 if (pcbNeeded) *pcbNeeded = needed;
6130 if (pcReturned) *pcReturned = numentries;
6132 TRACE("returning %d with %d (%d byte for %d entries)\n",
6133 res, GetLastError(), needed, numentries);
6138 /******************************************************************************
6139 * XcvDataW (WINSPOOL.@)
6142 * There doesn't seem to be an A version...
6144 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6145 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6146 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6148 FIXME("%p %s %p %d %p %d %p %p\n", hXcv, debugstr_w(pszDataName),
6149 pInputData, cbInputData, pOutputData,
6150 cbOutputData, pcbOutputNeeded, pdwStatus);
6154 /*****************************************************************************
6155 * EnumPrinterDataA [WINSPOOL.@]
6158 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6159 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6160 DWORD cbData, LPDWORD pcbData )
6162 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6163 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6164 return ERROR_NO_MORE_ITEMS;
6167 /*****************************************************************************
6168 * EnumPrinterDataW [WINSPOOL.@]
6171 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6172 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6173 DWORD cbData, LPDWORD pcbData )
6175 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6176 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6177 return ERROR_NO_MORE_ITEMS;
6180 /*****************************************************************************
6181 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6184 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6185 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6186 LPDWORD pcbNeeded, LPDWORD pcReturned)
6188 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6189 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6190 pcbNeeded, pcReturned);
6194 /*****************************************************************************
6195 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6198 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6199 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6200 LPDWORD pcbNeeded, LPDWORD pcReturned)
6202 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6203 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6204 pcbNeeded, pcReturned);
6208 /*****************************************************************************
6209 * EnumPrintProcessorsA [WINSPOOL.@]
6212 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6213 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6215 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6216 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6220 /*****************************************************************************
6221 * EnumPrintProcessorsW [WINSPOOL.@]
6224 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6225 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6227 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6228 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6229 cbBuf, pcbNeeded, pcbReturned);
6233 /*****************************************************************************
6234 * ExtDeviceMode [WINSPOOL.@]
6237 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6238 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6241 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6242 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6243 debugstr_a(pProfile), fMode);
6247 /*****************************************************************************
6248 * FindClosePrinterChangeNotification [WINSPOOL.@]
6251 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6253 FIXME("Stub: %p\n", hChange);
6257 /*****************************************************************************
6258 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6261 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6262 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6264 FIXME("Stub: %p %x %x %p\n",
6265 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6266 return INVALID_HANDLE_VALUE;
6269 /*****************************************************************************
6270 * FindNextPrinterChangeNotification [WINSPOOL.@]
6273 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6274 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6276 FIXME("Stub: %p %p %p %p\n",
6277 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6281 /*****************************************************************************
6282 * FreePrinterNotifyInfo [WINSPOOL.@]
6285 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6287 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6291 /*****************************************************************************
6294 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6295 * ansi depending on the unicode parameter.
6297 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6307 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6310 memcpy(ptr, str, *size);
6317 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6320 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6327 /*****************************************************************************
6330 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6331 LPDWORD pcbNeeded, BOOL unicode)
6333 DWORD size, left = cbBuf;
6334 BOOL space = (cbBuf > 0);
6341 ji1->JobId = job->job_id;
6344 string_to_buf(job->document_title, ptr, left, &size, unicode);
6345 if(space && size <= left)
6347 ji1->pDocument = (LPWSTR)ptr;
6358 /*****************************************************************************
6361 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6362 LPDWORD pcbNeeded, BOOL unicode)
6364 DWORD size, left = cbBuf;
6365 BOOL space = (cbBuf > 0);
6372 ji2->JobId = job->job_id;
6375 string_to_buf(job->document_title, ptr, left, &size, unicode);
6376 if(space && size <= left)
6378 ji2->pDocument = (LPWSTR)ptr;
6389 /*****************************************************************************
6392 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6393 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6396 DWORD needed = 0, size;
6400 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6402 EnterCriticalSection(&printer_handles_cs);
6403 job = get_job(hPrinter, JobId);
6410 size = sizeof(JOB_INFO_1W);
6415 memset(pJob, 0, size);
6419 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6424 size = sizeof(JOB_INFO_2W);
6429 memset(pJob, 0, size);
6433 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6438 size = sizeof(JOB_INFO_3);
6442 memset(pJob, 0, size);
6451 SetLastError(ERROR_INVALID_LEVEL);
6455 *pcbNeeded = needed;
6457 LeaveCriticalSection(&printer_handles_cs);
6461 /*****************************************************************************
6462 * GetJobA [WINSPOOL.@]
6465 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6466 DWORD cbBuf, LPDWORD pcbNeeded)
6468 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6471 /*****************************************************************************
6472 * GetJobW [WINSPOOL.@]
6475 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6476 DWORD cbBuf, LPDWORD pcbNeeded)
6478 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6481 /*****************************************************************************
6484 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6486 char *unixname, *queue, *cmd;
6487 char fmt[] = "lpr -P%s %s";
6490 if(!(unixname = wine_get_unix_file_name(filename)))
6493 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6494 queue = HeapAlloc(GetProcessHeap(), 0, len);
6495 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6497 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6498 sprintf(cmd, fmt, queue, unixname);
6500 TRACE("printing with: %s\n", cmd);
6503 HeapFree(GetProcessHeap(), 0, cmd);
6504 HeapFree(GetProcessHeap(), 0, queue);
6505 HeapFree(GetProcessHeap(), 0, unixname);
6509 /*****************************************************************************
6512 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6514 #if HAVE_CUPS_CUPS_H
6517 char *unixname, *queue, *doc_titleA;
6521 if(!(unixname = wine_get_unix_file_name(filename)))
6524 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6525 queue = HeapAlloc(GetProcessHeap(), 0, len);
6526 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6528 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6529 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6530 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6532 TRACE("printing via cups\n");
6533 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6534 HeapFree(GetProcessHeap(), 0, doc_titleA);
6535 HeapFree(GetProcessHeap(), 0, queue);
6536 HeapFree(GetProcessHeap(), 0, unixname);
6542 return schedule_lpr(printer_name, filename);
6546 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6553 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6557 if(HIWORD(wparam) == BN_CLICKED)
6559 if(LOWORD(wparam) == IDOK)
6562 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6565 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6566 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6568 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6570 WCHAR caption[200], message[200];
6573 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6574 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6575 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6576 if(mb_ret == IDCANCEL)
6578 HeapFree(GetProcessHeap(), 0, filename);
6582 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6583 if(hf == INVALID_HANDLE_VALUE)
6585 WCHAR caption[200], message[200];
6587 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6588 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6589 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6590 HeapFree(GetProcessHeap(), 0, filename);
6594 DeleteFileW(filename);
6595 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6597 EndDialog(hwnd, IDOK);
6600 if(LOWORD(wparam) == IDCANCEL)
6602 EndDialog(hwnd, IDCANCEL);
6611 /*****************************************************************************
6614 static BOOL get_filename(LPWSTR *filename)
6616 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6617 file_dlg_proc, (LPARAM)filename) == IDOK;
6620 /*****************************************************************************
6623 static BOOL schedule_file(LPCWSTR filename)
6625 LPWSTR output = NULL;
6627 if(get_filename(&output))
6629 TRACE("copy to %s\n", debugstr_w(output));
6630 CopyFileW(filename, output, FALSE);
6631 HeapFree(GetProcessHeap(), 0, output);
6637 /*****************************************************************************
6640 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6643 char *unixname, *cmdA;
6645 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6649 if(!(unixname = wine_get_unix_file_name(filename)))
6652 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6653 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6654 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6656 TRACE("printing with: %s\n", cmdA);
6658 if((file_fd = open(unixname, O_RDONLY)) == -1)
6663 ERR("pipe() failed!\n");
6673 /* reset signals that we previously set to SIG_IGN */
6674 signal(SIGPIPE, SIG_DFL);
6675 signal(SIGCHLD, SIG_DFL);
6681 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6682 write(fds[1], buf, no_read);
6687 if(file_fd != -1) close(file_fd);
6688 if(fds[0] != -1) close(fds[0]);
6689 if(fds[1] != -1) close(fds[1]);
6691 HeapFree(GetProcessHeap(), 0, cmdA);
6692 HeapFree(GetProcessHeap(), 0, unixname);
6699 /*****************************************************************************
6702 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6704 int in_fd, out_fd, no_read;
6707 char *unixname, *outputA;
6710 if(!(unixname = wine_get_unix_file_name(filename)))
6713 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6714 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6715 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6717 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6718 in_fd = open(unixname, O_RDONLY);
6719 if(out_fd == -1 || in_fd == -1)
6722 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6723 write(out_fd, buf, no_read);
6727 if(in_fd != -1) close(in_fd);
6728 if(out_fd != -1) close(out_fd);
6729 HeapFree(GetProcessHeap(), 0, outputA);
6730 HeapFree(GetProcessHeap(), 0, unixname);
6734 /*****************************************************************************
6735 * ScheduleJob [WINSPOOL.@]
6738 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6740 opened_printer_t *printer;
6742 struct list *cursor, *cursor2;
6744 TRACE("(%p, %x)\n", hPrinter, dwJobID);
6745 EnterCriticalSection(&printer_handles_cs);
6746 printer = get_opened_printer(hPrinter);
6750 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6752 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6755 if(job->job_id != dwJobID) continue;
6757 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6758 if(hf != INVALID_HANDLE_VALUE)
6760 PRINTER_INFO_5W *pi5;
6764 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6765 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6767 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6768 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6769 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6770 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6771 debugstr_w(pi5->pPortName));
6775 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6776 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6778 DWORD type, count = sizeof(output);
6779 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6782 if(output[0] == '|')
6784 schedule_pipe(output + 1, job->filename);
6788 schedule_unixfile(output, job->filename);
6790 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6792 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6794 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6796 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6798 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6800 schedule_file(job->filename);
6804 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6806 HeapFree(GetProcessHeap(), 0, pi5);
6808 DeleteFileW(job->filename);
6810 list_remove(cursor);
6811 HeapFree(GetProcessHeap(), 0, job->document_title);
6812 HeapFree(GetProcessHeap(), 0, job->filename);
6813 HeapFree(GetProcessHeap(), 0, job);
6818 LeaveCriticalSection(&printer_handles_cs);
6822 /*****************************************************************************
6823 * StartDocDlgA [WINSPOOL.@]
6825 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6827 UNICODE_STRING usBuffer;
6830 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
6833 docW.cbSize = sizeof(docW);
6834 if (doc->lpszDocName)
6836 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
6837 if (!(docW.lpszDocName = docnameW)) return NULL;
6839 if (doc->lpszOutput)
6841 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
6842 if (!(docW.lpszOutput = outputW)) return NULL;
6844 if (doc->lpszDatatype)
6846 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
6847 if (!(docW.lpszDatatype = datatypeW)) return NULL;
6849 docW.fwType = doc->fwType;
6851 retW = StartDocDlgW(hPrinter, &docW);
6855 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6856 ret = HeapAlloc(GetProcessHeap(), 0, len);
6857 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6858 HeapFree(GetProcessHeap(), 0, retW);
6861 HeapFree(GetProcessHeap(), 0, datatypeW);
6862 HeapFree(GetProcessHeap(), 0, outputW);
6863 HeapFree(GetProcessHeap(), 0, docnameW);
6868 /*****************************************************************************
6869 * StartDocDlgW [WINSPOOL.@]
6871 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6872 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6873 * port is "FILE:". Also returns the full path if passed a relative path.
6875 * The caller should free the returned string from the process heap.
6877 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6882 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6884 PRINTER_INFO_5W *pi5;
6885 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6886 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6888 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6889 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6890 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6892 HeapFree(GetProcessHeap(), 0, pi5);
6895 HeapFree(GetProcessHeap(), 0, pi5);
6898 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6901 get_filename(&name);
6904 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6906 HeapFree(GetProcessHeap(), 0, name);
6909 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6910 GetFullPathNameW(name, len, ret, NULL);
6911 HeapFree(GetProcessHeap(), 0, name);
6916 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6919 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6922 attr = GetFileAttributesW(ret);
6923 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6925 HeapFree(GetProcessHeap(), 0, ret);