4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
64 #include "ddk/winsplp.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
69 /* ############################### */
71 static CRITICAL_SECTION monitor_handles_cs;
72 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
74 0, 0, &monitor_handles_cs,
75 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
76 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
78 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
81 static CRITICAL_SECTION printer_handles_cs;
82 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
84 0, 0, &printer_handles_cs,
85 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
88 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
90 /* ############################### */
123 WCHAR *document_title;
131 LPCWSTR versionregpath;
132 LPCWSTR versionsubdir;
135 /* ############################### */
137 static struct list monitor_handles = LIST_INIT( monitor_handles );
139 static opened_printer_t **printer_handles;
140 static int nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
185 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
186 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
187 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
188 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
189 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
190 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
192 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
193 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
195 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
196 'i','o','n',' ','F','i','l','e',0};
197 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
198 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
199 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
201 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
203 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
204 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
205 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
206 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
207 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
208 static const WCHAR NameW[] = {'N','a','m','e',0};
209 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
210 static const WCHAR PortW[] = {'P','o','r','t',0};
211 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
213 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
215 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
216 'v','e','r','D','a','t','a',0};
217 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
219 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
220 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
221 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
222 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
223 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
224 static const WCHAR emptyStringW[] = {0};
226 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
228 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
229 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
230 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
232 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
233 'D','o','c','u','m','e','n','t',0};
235 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
236 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
237 DWORD Level, LPBYTE pDriverInfo,
238 DWORD cbBuf, LPDWORD pcbNeeded,
240 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
241 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
243 /******************************************************************
244 * validate the user-supplied printing-environment [internal]
247 * env [I] PTR to Environment-String or NULL
251 * Success: PTR to printenv_t
254 * An empty string is handled the same way as NULL.
255 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
259 static const printenv_t * validate_envW(LPCWSTR env)
261 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
262 3, Version3_RegPathW, Version3_SubdirW};
263 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
264 0, emptyStringW, emptyStringW};
265 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
267 const printenv_t *result = NULL;
270 TRACE("testing %s\n", debugstr_w(env));
273 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
275 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
277 result = all_printenv[i];
282 if (result == NULL) {
283 FIXME("unsupported Environment: %s\n", debugstr_w(env));
284 SetLastError(ERROR_INVALID_ENVIRONMENT);
286 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
290 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
292 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
298 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
299 if passed a NULL string. This returns NULLs to the result.
301 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
305 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
306 return usBufferPtr->Buffer;
308 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
312 static LPWSTR strdupW(LPCWSTR p)
318 len = (strlenW(p) + 1) * sizeof(WCHAR);
319 ret = HeapAlloc(GetProcessHeap(), 0, len);
325 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
328 /* If forcing, or no profile string entry for device yet, set the entry
330 * The always change entry if not WINEPS yet is discussable.
333 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
335 !strstr(qbuf,"WINEPS.DRV")
337 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
340 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
341 WriteProfileStringA("windows","device",buf);
342 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
343 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
346 HeapFree(GetProcessHeap(),0,buf);
350 #ifdef HAVE_CUPS_CUPS_H
351 static typeof(cupsGetDests) *pcupsGetDests;
352 static typeof(cupsGetPPD) *pcupsGetPPD;
353 static typeof(cupsPrintFile) *pcupsPrintFile;
354 static void *cupshandle;
356 static BOOL CUPS_LoadPrinters(void)
359 BOOL hadprinter = FALSE;
361 PRINTER_INFO_2A pinfo2a;
363 HKEY hkeyPrinter, hkeyPrinters, hkey;
365 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
368 TRACE("loaded %s\n", SONAME_LIBCUPS);
371 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
372 if (!p##x) return FALSE;
375 DYNCUPS(cupsGetDests);
376 DYNCUPS(cupsPrintFile);
379 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
381 ERR("Can't create Printers key\n");
385 nrofdests = pcupsGetDests(&dests);
386 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
387 for (i=0;i<nrofdests;i++) {
388 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
389 sprintf(port,"LPR:%s",dests[i].name);
390 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
391 sprintf(devline,"WINEPS.DRV,%s",port);
392 WriteProfileStringA("devices",dests[i].name,devline);
393 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
394 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
397 HeapFree(GetProcessHeap(),0,devline);
399 TRACE("Printer %d: %s\n", i, dests[i].name);
400 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
401 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
403 TRACE("Printer already exists\n");
404 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
405 RegCloseKey(hkeyPrinter);
407 static CHAR data_type[] = "RAW",
408 print_proc[] = "WinPrint",
409 driver_name[] = "PS Driver",
410 comment[] = "WINEPS Printer using CUPS",
411 location[] = "<physical location of printer>",
412 params[] = "<parameters?>",
413 share_name[] = "<share name?>",
414 sep_file[] = "<sep file?>";
416 memset(&pinfo2a,0,sizeof(pinfo2a));
417 pinfo2a.pPrinterName = dests[i].name;
418 pinfo2a.pDatatype = data_type;
419 pinfo2a.pPrintProcessor = print_proc;
420 pinfo2a.pDriverName = driver_name;
421 pinfo2a.pComment = comment;
422 pinfo2a.pLocation = location;
423 pinfo2a.pPortName = port;
424 pinfo2a.pParameters = params;
425 pinfo2a.pShareName = share_name;
426 pinfo2a.pSepFile = sep_file;
428 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
429 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
430 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
433 HeapFree(GetProcessHeap(),0,port);
436 if (dests[i].is_default)
437 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
439 RegCloseKey(hkeyPrinters);
445 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
446 PRINTER_INFO_2A pinfo2a;
447 char *e,*s,*name,*prettyname,*devname;
448 BOOL ret = FALSE, set_default = FALSE;
449 char *port,*devline,*env_default;
450 HKEY hkeyPrinter, hkeyPrinters, hkey;
452 while (isspace(*pent)) pent++;
453 s = strchr(pent,':');
455 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
463 TRACE("name=%s entry=%s\n",name, pent);
465 if(ispunct(*name)) { /* a tc entry, not a real printer */
466 TRACE("skipping tc entry\n");
470 if(strstr(pent,":server")) { /* server only version so skip */
471 TRACE("skipping server entry\n");
475 /* Determine whether this is a postscript printer. */
478 env_default = getenv("PRINTER");
480 /* Get longest name, usually the one at the right for later display. */
481 while((s=strchr(prettyname,'|'))) {
484 while(isspace(*--e)) *e = '\0';
485 TRACE("\t%s\n", debugstr_a(prettyname));
486 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
487 for(prettyname = s+1; isspace(*prettyname); prettyname++)
490 e = prettyname + strlen(prettyname);
491 while(isspace(*--e)) *e = '\0';
492 TRACE("\t%s\n", debugstr_a(prettyname));
493 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
495 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
496 * if it is too long, we use it as comment below. */
497 devname = prettyname;
498 if (strlen(devname)>=CCHDEVICENAME-1)
500 if (strlen(devname)>=CCHDEVICENAME-1) {
505 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
506 sprintf(port,"LPR:%s",name);
508 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
509 sprintf(devline,"WINEPS.DRV,%s",port);
510 WriteProfileStringA("devices",devname,devline);
511 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
512 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
515 HeapFree(GetProcessHeap(),0,devline);
517 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
519 ERR("Can't create Printers key\n");
523 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
524 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
526 TRACE("Printer already exists\n");
527 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
528 RegCloseKey(hkeyPrinter);
530 static CHAR data_type[] = "RAW",
531 print_proc[] = "WinPrint",
532 driver_name[] = "PS Driver",
533 comment[] = "WINEPS Printer using LPR",
534 params[] = "<parameters?>",
535 share_name[] = "<share name?>",
536 sep_file[] = "<sep file?>";
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = devname;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = driver_name;
543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = prettyname;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
555 RegCloseKey(hkeyPrinters);
557 if (isfirst || set_default)
558 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
560 HeapFree(GetProcessHeap(), 0, port);
562 HeapFree(GetProcessHeap(), 0, name);
567 PRINTCAP_LoadPrinters(void) {
568 BOOL hadprinter = FALSE;
572 BOOL had_bash = FALSE;
574 f = fopen("/etc/printcap","r");
578 while(fgets(buf,sizeof(buf),f)) {
581 end=strchr(buf,'\n');
585 while(isspace(*start)) start++;
586 if(*start == '#' || *start == '\0')
589 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
590 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
591 HeapFree(GetProcessHeap(),0,pent);
595 if (end && *--end == '\\') {
602 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
605 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
611 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
612 HeapFree(GetProcessHeap(),0,pent);
618 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
621 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
622 lstrlenW(value) * sizeof(WCHAR));
624 return ERROR_FILE_NOT_FOUND;
627 void WINSPOOL_LoadSystemPrinters(void)
629 HKEY hkey, hkeyPrinters;
632 DWORD needed, num, i;
633 WCHAR PrinterName[256];
635 static CHAR name[] = "PS Driver",
636 driver_path[] = "wineps16",
637 data_file[] = "<datafile?>",
638 config_file[] = "wineps16",
639 help_file[] = "<helpfile?>",
640 dep_file[] = "<dependend files?>",
641 monitor_name[] = "<monitor name?>",
642 default_data_type[] = "RAW";
644 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
646 di3a.pEnvironment = NULL; /* NULL means auto */
647 di3a.pDriverPath = driver_path;
648 di3a.pDataFile = data_file;
649 di3a.pConfigFile = config_file;
650 di3a.pHelpFile = help_file;
651 di3a.pDependentFiles = dep_file;
652 di3a.pMonitorName = monitor_name;
653 di3a.pDefaultDataType = default_data_type;
655 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
656 ERR("Failed adding PS Driver (%d)\n",GetLastError());
660 /* This ensures that all printer entries have a valid Name value. If causes
661 problems later if they don't. If one is found to be missed we create one
662 and set it equal to the name of the key */
663 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
664 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
665 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
666 for(i = 0; i < num; i++) {
667 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
668 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
669 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
670 set_reg_szW(hkey, NameW, PrinterName);
677 RegCloseKey(hkeyPrinters);
680 /* We want to avoid calling AddPrinter on printers as much as
681 possible, because on cups printers this will (eventually) lead
682 to a call to cupsGetPPD which takes forever, even with non-cups
683 printers AddPrinter takes a while. So we'll tag all printers that
684 were automatically added last time around, if they still exist
685 we'll leave them be otherwise we'll delete them. */
686 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
688 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
689 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
690 for(i = 0; i < num; i++) {
691 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
692 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
693 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
695 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
703 HeapFree(GetProcessHeap(), 0, pi);
707 #ifdef HAVE_CUPS_CUPS_H
708 done = CUPS_LoadPrinters();
711 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
712 /* Check for [ppd] section in config file before parsing /etc/printcap */
713 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
714 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
715 &hkey) == ERROR_SUCCESS) {
717 PRINTCAP_LoadPrinters();
721 /* Now enumerate the list again and delete any printers that a still tagged */
722 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
724 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
725 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
726 for(i = 0; i < num; i++) {
727 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
728 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
729 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
730 DWORD dw, type, size = sizeof(dw);
731 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
732 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
742 HeapFree(GetProcessHeap(), 0, pi);
749 /*****************************************************************************
750 * enumerate the local monitors (INTERNAL)
752 * returns the needed size (in bytes) for pMonitors
753 * and *lpreturned is set to number of entries returned in pMonitors
756 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
761 LPMONITOR_INFO_2W mi;
762 WCHAR buffer[MAX_PATH];
763 WCHAR dllname[MAX_PATH];
771 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
773 numentries = *lpreturned; /* this is 0, when we scan the registry */
774 len = entrysize * numentries;
775 ptr = (LPWSTR) &pMonitors[len];
778 len = sizeof(buffer);
781 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
782 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
783 /* Scan all Monitor-Registry-Keys */
784 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
785 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
786 dllsize = sizeof(dllname);
789 /* The Monitor must have a Driver-DLL */
790 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
791 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
792 /* We found a valid DLL for this Monitor. */
793 TRACE("using Driver: %s\n", debugstr_w(dllname));
798 /* Windows returns only Port-Monitors here, but to simplify our code,
799 we do no filtering for Language-Monitors */
803 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
805 /* we install and return only monitors for "Windows NT x86" */
806 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
810 /* required size is calculated. Now fill the user-buffer */
811 if (pMonitors && (cbBuf >= needed)){
812 mi = (LPMONITOR_INFO_2W) pMonitors;
813 pMonitors += entrysize;
815 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
817 lstrcpyW(ptr, buffer); /* Name of the Monitor */
818 ptr += (len+1); /* len is lstrlenW(monitorname) */
820 mi->pEnvironment = ptr;
821 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
822 ptr += (lstrlenW(envname_x86W)+1);
825 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
826 ptr += (dllsize / sizeof(WCHAR));
831 len = sizeof(buffer);
836 *lpreturned = numentries;
837 TRACE("need %d byte for %d entries\n", needed, numentries);
841 /******************************************************************
842 * monitor_unload [internal]
844 * release a printmonitor and unload it from memory, when needed
847 static void monitor_unload(monitor_t * pm)
849 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
851 EnterCriticalSection(&monitor_handles_cs);
853 if (pm->refcount) pm->refcount--;
855 if (pm->refcount == 0) {
856 list_remove(&pm->entry);
857 FreeLibrary(pm->hdll);
858 HeapFree(GetProcessHeap(), 0, pm->name);
859 HeapFree(GetProcessHeap(), 0, pm->dllname);
860 HeapFree(GetProcessHeap(), 0, pm);
862 LeaveCriticalSection(&monitor_handles_cs);
865 /******************************************************************
866 * monitor_load [internal]
868 * load a printmonitor, get the dllname from the registry, when needed
869 * initialize the monitor and dump found function-pointers
871 * On failure, SetLastError() is called and NULL is returned
874 static monitor_t * monitor_load(LPWSTR name, LPWSTR dllname)
876 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
877 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
878 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
879 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
880 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
882 monitor_t * pm = NULL;
884 LPWSTR regroot = NULL;
885 LPWSTR driver = dllname;
887 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
888 /* Is the Monitor already loaded? */
889 EnterCriticalSection(&monitor_handles_cs);
891 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
893 if (lstrcmpW(name, cursor->name) == 0) {
900 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
901 if (pm == NULL) goto cleanup;
902 list_add_tail(&monitor_handles, &pm->entry);
906 if (pm->name == NULL) {
907 /* Load the monitor */
908 LPMONITOREX pmonitorEx;
911 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
912 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
915 lstrcpyW(regroot, MonitorsW);
916 lstrcatW(regroot, name);
917 /* Get the Driver from the Registry */
918 if (driver == NULL) {
921 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
922 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
923 &namesize) == ERROR_SUCCESS) {
924 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
925 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
932 pm->name = strdupW(name);
933 pm->dllname = strdupW(driver);
935 if (!regroot || !pm->name || !pm->dllname) {
937 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
942 pm->hdll = LoadLibraryW(driver);
943 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
945 if (pm->hdll == NULL) {
947 SetLastError(ERROR_MOD_NOT_FOUND);
952 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
953 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
954 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
955 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
956 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
959 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
960 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
961 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
962 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
963 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
965 if (pInitializePrintMonitorUI != NULL) {
966 pm->monitorUI = pInitializePrintMonitorUI();
967 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
969 TRACE( "0x%08x: dwMonitorSize (%d)\n",
970 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
975 if (pInitializePrintMonitor != NULL) {
976 pmonitorEx = pInitializePrintMonitor(regroot);
977 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
978 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
981 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
982 pm->monitor = &(pmonitorEx->Monitor);
987 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
992 if (pInitializePrintMonitor2 != NULL) {
993 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
995 if (pInitializeMonitorEx != NULL) {
996 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
998 if (pInitializeMonitor != NULL) {
999 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1002 if (!pm->monitor && !pm->monitorUI) {
1004 SetLastError(ERROR_PROC_NOT_FOUND);
1009 LeaveCriticalSection(&monitor_handles_cs);
1010 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1011 HeapFree(GetProcessHeap(), 0, regroot);
1012 TRACE("=> %p\n", pm);
1016 /******************************************************************
1017 * get_opened_printer_entry
1018 * Get the first place empty in the opened printer table
1021 * - pDefault is ignored
1023 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1025 UINT_PTR handle = nb_printer_handles, i;
1026 jobqueue_t *queue = NULL;
1027 opened_printer_t *printer = NULL;
1029 EnterCriticalSection(&printer_handles_cs);
1031 for (i = 0; i < nb_printer_handles; i++)
1033 if (!printer_handles[i])
1035 if(handle == nb_printer_handles)
1040 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1041 queue = printer_handles[i]->queue;
1045 if (handle >= nb_printer_handles)
1047 opened_printer_t **new_array;
1048 if (printer_handles)
1049 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1050 (nb_printer_handles + 16) * sizeof(*new_array) );
1052 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1053 (nb_printer_handles + 16) * sizeof(*new_array) );
1060 printer_handles = new_array;
1061 nb_printer_handles += 16;
1064 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1071 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
1072 if (!printer->name) {
1076 strcpyW(printer->name, name);
1080 printer->queue = queue;
1083 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1084 if (!printer->queue) {
1088 list_init(&printer->queue->jobs);
1089 printer->queue->ref = 0;
1091 InterlockedIncrement(&printer->queue->ref);
1093 printer_handles[handle] = printer;
1096 LeaveCriticalSection(&printer_handles_cs);
1097 if (!handle && printer) {
1098 /* Something Failed: Free the Buffers */
1099 HeapFree(GetProcessHeap(), 0, printer->name);
1100 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1101 HeapFree(GetProcessHeap(), 0, printer);
1104 return (HANDLE)handle;
1107 /******************************************************************
1108 * get_opened_printer
1109 * Get the pointer to the opened printer referred by the handle
1111 static opened_printer_t *get_opened_printer(HANDLE hprn)
1113 UINT_PTR idx = (UINT_PTR)hprn;
1114 opened_printer_t *ret = NULL;
1116 EnterCriticalSection(&printer_handles_cs);
1118 if ((idx <= 0) || (idx > nb_printer_handles))
1121 ret = printer_handles[idx - 1];
1123 LeaveCriticalSection(&printer_handles_cs);
1127 /******************************************************************
1128 * get_opened_printer_name
1129 * Get the pointer to the opened printer name referred by the handle
1131 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1133 opened_printer_t *printer = get_opened_printer(hprn);
1134 if(!printer) return NULL;
1135 return printer->name;
1138 /******************************************************************
1139 * WINSPOOL_GetOpenedPrinterRegKey
1142 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1144 LPCWSTR name = get_opened_printer_name(hPrinter);
1148 if(!name) return ERROR_INVALID_HANDLE;
1150 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1154 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1156 ERR("Can't find opened printer %s in registry\n",
1158 RegCloseKey(hkeyPrinters);
1159 return ERROR_INVALID_PRINTER_NAME; /* ? */
1161 RegCloseKey(hkeyPrinters);
1162 return ERROR_SUCCESS;
1165 /******************************************************************
1168 * Get the pointer to the specified job.
1169 * Should hold the printer_handles_cs before calling.
1171 static job_t *get_job(HANDLE hprn, DWORD JobId)
1173 opened_printer_t *printer = get_opened_printer(hprn);
1176 if(!printer) return NULL;
1177 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1179 if(job->job_id == JobId)
1185 /***********************************************************
1188 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1191 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1194 Formname = (dmA->dmSize > off_formname);
1195 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1196 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1197 dmW->dmDeviceName, CCHDEVICENAME);
1199 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1200 dmA->dmSize - CCHDEVICENAME);
1202 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1203 off_formname - CCHDEVICENAME);
1204 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1205 dmW->dmFormName, CCHFORMNAME);
1206 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1207 (off_formname + CCHFORMNAME));
1210 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1211 dmA->dmDriverExtra);
1215 /***********************************************************
1217 * Creates an ascii copy of supplied devmode on heap
1219 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1224 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1226 if(!dmW) return NULL;
1227 Formname = (dmW->dmSize > off_formname);
1228 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1229 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1230 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1231 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1233 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1234 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1236 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1237 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1238 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1239 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1240 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1241 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1244 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1245 dmW->dmDriverExtra);
1249 /***********************************************************
1250 * PRINTER_INFO_2AtoW
1251 * Creates a unicode copy of PRINTER_INFO_2A on heap
1253 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1255 LPPRINTER_INFO_2W piW;
1256 UNICODE_STRING usBuffer;
1258 if(!piA) return NULL;
1259 piW = HeapAlloc(heap, 0, sizeof(*piW));
1260 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1262 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1263 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1264 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1265 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1266 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1267 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1268 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1269 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1270 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1271 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1272 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1273 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1277 /***********************************************************
1278 * FREE_PRINTER_INFO_2W
1279 * Free PRINTER_INFO_2W and all strings
1281 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1285 HeapFree(heap,0,piW->pServerName);
1286 HeapFree(heap,0,piW->pPrinterName);
1287 HeapFree(heap,0,piW->pShareName);
1288 HeapFree(heap,0,piW->pPortName);
1289 HeapFree(heap,0,piW->pDriverName);
1290 HeapFree(heap,0,piW->pComment);
1291 HeapFree(heap,0,piW->pLocation);
1292 HeapFree(heap,0,piW->pDevMode);
1293 HeapFree(heap,0,piW->pSepFile);
1294 HeapFree(heap,0,piW->pPrintProcessor);
1295 HeapFree(heap,0,piW->pDatatype);
1296 HeapFree(heap,0,piW->pParameters);
1297 HeapFree(heap,0,piW);
1301 /******************************************************************
1302 * DeviceCapabilities [WINSPOOL.@]
1303 * DeviceCapabilitiesA [WINSPOOL.@]
1306 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1307 LPSTR pOutput, LPDEVMODEA lpdm)
1311 if (!GDI_CallDeviceCapabilities16)
1313 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1315 if (!GDI_CallDeviceCapabilities16) return -1;
1317 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1319 /* If DC_PAPERSIZE map POINT16s to POINTs */
1320 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1321 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1322 POINT *pt = (POINT *)pOutput;
1324 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1325 for(i = 0; i < ret; i++, pt++)
1330 HeapFree( GetProcessHeap(), 0, tmp );
1336 /*****************************************************************************
1337 * DeviceCapabilitiesW [WINSPOOL.@]
1339 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1342 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1343 WORD fwCapability, LPWSTR pOutput,
1344 const DEVMODEW *pDevMode)
1346 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1347 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1348 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1351 if(pOutput && (fwCapability == DC_BINNAMES ||
1352 fwCapability == DC_FILEDEPENDENCIES ||
1353 fwCapability == DC_PAPERNAMES)) {
1354 /* These need A -> W translation */
1357 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1361 switch(fwCapability) {
1366 case DC_FILEDEPENDENCIES:
1370 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1371 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1373 for(i = 0; i < ret; i++)
1374 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1375 pOutput + (i * size), size);
1376 HeapFree(GetProcessHeap(), 0, pOutputA);
1378 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1379 (LPSTR)pOutput, dmA);
1381 HeapFree(GetProcessHeap(),0,pPortA);
1382 HeapFree(GetProcessHeap(),0,pDeviceA);
1383 HeapFree(GetProcessHeap(),0,dmA);
1387 /******************************************************************
1388 * DocumentPropertiesA [WINSPOOL.@]
1390 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1392 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1393 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1394 LPDEVMODEA pDevModeInput,DWORD fMode )
1396 LPSTR lpName = pDeviceName;
1397 static CHAR port[] = "LPT1:";
1400 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1401 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1405 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1407 ERR("no name from hPrinter?\n");
1408 SetLastError(ERROR_INVALID_HANDLE);
1411 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1414 if (!GDI_CallExtDeviceMode16)
1416 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1418 if (!GDI_CallExtDeviceMode16) {
1419 ERR("No CallExtDeviceMode16?\n");
1423 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1424 pDevModeInput, NULL, fMode);
1427 HeapFree(GetProcessHeap(),0,lpName);
1432 /*****************************************************************************
1433 * DocumentPropertiesW (WINSPOOL.@)
1435 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1437 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1439 LPDEVMODEW pDevModeOutput,
1440 LPDEVMODEW pDevModeInput, DWORD fMode)
1443 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1444 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1445 LPDEVMODEA pDevModeOutputA = NULL;
1448 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1449 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1451 if(pDevModeOutput) {
1452 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1453 if(ret < 0) return ret;
1454 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1456 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1457 pDevModeInputA, fMode);
1458 if(pDevModeOutput) {
1459 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1460 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1462 if(fMode == 0 && ret > 0)
1463 ret += (CCHDEVICENAME + CCHFORMNAME);
1464 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1465 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1469 /******************************************************************
1470 * OpenPrinterA [WINSPOOL.@]
1475 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1476 LPPRINTER_DEFAULTSA pDefault)
1478 UNICODE_STRING lpPrinterNameW;
1479 UNICODE_STRING usBuffer;
1480 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1481 PWSTR pwstrPrinterNameW;
1484 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1487 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1488 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1489 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1490 pDefaultW = &DefaultW;
1492 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1494 RtlFreeUnicodeString(&usBuffer);
1495 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1497 RtlFreeUnicodeString(&lpPrinterNameW);
1501 /******************************************************************
1502 * OpenPrinterW [WINSPOOL.@]
1504 * Open a Printer / Printserver or a Printer-Object
1507 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1508 * phPrinter [O] The resulting Handle is stored here
1509 * pDefault [I] PTR to Default Printer Settings or NULL
1516 * lpPrinterName is one of:
1517 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1518 *| Printer: "PrinterName"
1519 *| Printer-Object: "PrinterName,Job xxx"
1520 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1521 *| XcvPort: "Servername,XcvPort PortName"
1524 *| Printer-Object not supported
1525 *| XcvMonitor not supported
1526 *| XcvPort not supported
1527 *| pDefaults is ignored
1530 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1532 HKEY hkeyPrinters = NULL;
1533 HKEY hkeyPrinter = NULL;
1535 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1537 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1538 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1541 if(lpPrinterName != NULL)
1543 /* Check any Printer exists */
1544 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1545 ERR("Can't create Printers key\n");
1546 SetLastError(ERROR_FILE_NOT_FOUND);
1549 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1550 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1552 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1553 RegCloseKey(hkeyPrinters);
1554 SetLastError(ERROR_INVALID_PRINTER_NAME);
1557 RegCloseKey(hkeyPrinter);
1558 RegCloseKey(hkeyPrinters);
1561 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1562 SetLastError(ERROR_INVALID_PARAMETER);
1566 /* Get the unique handle of the printer or Printserver */
1567 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1568 return (*phPrinter != 0);
1571 /******************************************************************
1572 * AddMonitorA [WINSPOOL.@]
1577 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1579 LPWSTR nameW = NULL;
1582 LPMONITOR_INFO_2A mi2a;
1583 MONITOR_INFO_2W mi2w;
1585 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1586 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1587 mi2a ? debugstr_a(mi2a->pName) : NULL,
1588 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1589 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1592 SetLastError(ERROR_INVALID_LEVEL);
1596 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1602 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1603 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1604 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1607 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1609 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1610 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1611 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1613 if (mi2a->pEnvironment) {
1614 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1615 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1616 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1618 if (mi2a->pDLLName) {
1619 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1620 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1621 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1624 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1626 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1627 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1628 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1630 HeapFree(GetProcessHeap(), 0, nameW);
1634 /******************************************************************************
1635 * AddMonitorW [WINSPOOL.@]
1637 * Install a Printmonitor
1640 * pName [I] Servername or NULL (local Computer)
1641 * Level [I] Structure-Level (Must be 2)
1642 * pMonitors [I] PTR to MONITOR_INFO_2
1649 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1652 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1654 monitor_t * pm = NULL;
1655 LPMONITOR_INFO_2W mi2w;
1661 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1662 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1663 mi2w ? debugstr_w(mi2w->pName) : NULL,
1664 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1665 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1668 SetLastError(ERROR_INVALID_LEVEL);
1672 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1677 if (pName && (pName[0])) {
1678 FIXME("for server %s not implemented\n", debugstr_w(pName));
1679 SetLastError(ERROR_ACCESS_DENIED);
1684 if (!mi2w->pName || (! mi2w->pName[0])) {
1685 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1686 SetLastError(ERROR_INVALID_PARAMETER);
1689 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1690 WARN("Environment %s requested (we support only %s)\n",
1691 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1692 SetLastError(ERROR_INVALID_ENVIRONMENT);
1696 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1697 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1698 SetLastError(ERROR_INVALID_PARAMETER);
1702 /* Load and initialize the monitor. SetLastError() is called on failure */
1703 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1708 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1709 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1713 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1714 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1715 &disposition) == ERROR_SUCCESS) {
1717 /* Some installers set options for the port before calling AddMonitor.
1718 We query the "Driver" entry to verify that the monitor is installed,
1719 before we return an error.
1720 When a user installs two print monitors at the same time with the
1721 same name but with a different driver DLL and a task switch comes
1722 between RegQueryValueExW and RegSetValueExW, a race condition
1723 is possible but silently ignored. */
1727 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1728 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1729 &namesize) == ERROR_SUCCESS)) {
1730 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1731 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1732 9x: ERROR_ALREADY_EXISTS (183) */
1733 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1738 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1739 res = (RegSetValueExW(hentry, DriverW, 0,
1740 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1742 RegCloseKey(hentry);
1749 /******************************************************************
1750 * DeletePrinterDriverA [WINSPOOL.@]
1754 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1756 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1757 debugstr_a(pDriverName));
1758 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1762 /******************************************************************
1763 * DeletePrinterDriverW [WINSPOOL.@]
1767 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1769 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1770 debugstr_w(pDriverName));
1771 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1775 /******************************************************************
1776 * DeleteMonitorA [WINSPOOL.@]
1778 * See DeleteMonitorW.
1781 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1783 LPWSTR nameW = NULL;
1784 LPWSTR EnvironmentW = NULL;
1785 LPWSTR MonitorNameW = NULL;
1790 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1791 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1792 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1796 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1797 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1798 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1801 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1802 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1803 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1806 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1808 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1809 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1810 HeapFree(GetProcessHeap(), 0, nameW);
1814 /******************************************************************
1815 * DeleteMonitorW [WINSPOOL.@]
1817 * Delete a specific Printmonitor from a Printing-Environment
1820 * pName [I] Servername or NULL (local Computer)
1821 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1822 * pMonitorName [I] Name of the Monitor, that should be deleted
1829 * pEnvironment is ignored in Windows for the local Computer.
1833 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1837 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1838 debugstr_w(pMonitorName));
1840 if (pName && (pName[0])) {
1841 FIXME("for server %s not implemented\n", debugstr_w(pName));
1842 SetLastError(ERROR_ACCESS_DENIED);
1846 /* pEnvironment is ignored in Windows for the local Computer */
1848 if (!pMonitorName || !pMonitorName[0]) {
1849 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1850 SetLastError(ERROR_INVALID_PARAMETER);
1854 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1855 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1859 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1860 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1861 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1866 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1869 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1870 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1874 /******************************************************************
1875 * DeletePortA [WINSPOOL.@]
1881 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1883 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1884 debugstr_a(pPortName));
1885 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1889 /******************************************************************
1890 * DeletePortW [WINSPOOL.@]
1892 * Delete a specific Port
1895 * pName [I] Servername or NULL (local Computer)
1896 * hWnd [I] Handle to parent Window for the Dialog-Box
1897 * pPortName [I] Name of the Port, that should be deleted
1908 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1910 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1911 debugstr_w(pPortName));
1912 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1916 /******************************************************************************
1917 * SetPrinterW [WINSPOOL.@]
1919 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1921 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
1922 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1926 /******************************************************************************
1927 * WritePrinter [WINSPOOL.@]
1929 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1931 opened_printer_t *printer;
1934 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1936 EnterCriticalSection(&printer_handles_cs);
1937 printer = get_opened_printer(hPrinter);
1940 SetLastError(ERROR_INVALID_HANDLE);
1946 SetLastError(ERROR_SPL_NO_STARTDOC);
1950 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1952 LeaveCriticalSection(&printer_handles_cs);
1956 /*****************************************************************************
1957 * AddFormA [WINSPOOL.@]
1959 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1961 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1965 /*****************************************************************************
1966 * AddFormW [WINSPOOL.@]
1968 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1970 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1974 /*****************************************************************************
1975 * AddJobA [WINSPOOL.@]
1977 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1980 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1984 SetLastError(ERROR_INVALID_LEVEL);
1988 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1991 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1992 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1993 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1994 if(*pcbNeeded > cbBuf) {
1995 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1998 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1999 addjobA->JobId = addjobW->JobId;
2000 addjobA->Path = (char *)(addjobA + 1);
2001 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2007 /*****************************************************************************
2008 * AddJobW [WINSPOOL.@]
2010 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2012 opened_printer_t *printer;
2015 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2016 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2017 WCHAR path[MAX_PATH], filename[MAX_PATH];
2019 ADDJOB_INFO_1W *addjob;
2021 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2023 EnterCriticalSection(&printer_handles_cs);
2025 printer = get_opened_printer(hPrinter);
2028 SetLastError(ERROR_INVALID_HANDLE);
2033 SetLastError(ERROR_INVALID_LEVEL);
2037 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2041 job->job_id = InterlockedIncrement(&next_job_id);
2043 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2044 if(path[len - 1] != '\\')
2046 memcpy(path + len, spool_path, sizeof(spool_path));
2047 sprintfW(filename, fmtW, path, job->job_id);
2049 len = strlenW(filename);
2050 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2051 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2052 job->document_title = strdupW(default_doc_title);
2053 list_add_tail(&printer->queue->jobs, &job->entry);
2055 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2056 if(*pcbNeeded <= cbBuf) {
2057 addjob = (ADDJOB_INFO_1W*)pData;
2058 addjob->JobId = job->job_id;
2059 addjob->Path = (WCHAR *)(addjob + 1);
2060 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2063 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2066 LeaveCriticalSection(&printer_handles_cs);
2070 /*****************************************************************************
2071 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2073 * Return the PATH for the Print-Processors
2075 * See GetPrintProcessorDirectoryW.
2079 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2080 DWORD level, LPBYTE Info,
2081 DWORD cbBuf, LPDWORD pcbNeeded)
2083 LPWSTR serverW = NULL;
2088 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2089 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2093 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2094 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2095 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2099 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2100 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2101 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2104 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2105 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2107 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2110 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2111 cbBuf, NULL, NULL) > 0;
2114 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2115 HeapFree(GetProcessHeap(), 0, envW);
2116 HeapFree(GetProcessHeap(), 0, serverW);
2120 /*****************************************************************************
2121 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2123 * Return the PATH for the Print-Processors
2126 * server [I] Servername (NT only) or NULL (local Computer)
2127 * env [I] Printing-Environment (see below) or NULL (Default)
2128 * level [I] Structure-Level (must be 1)
2129 * Info [O] PTR to Buffer that receives the Result
2130 * cbBuf [I] Size of Buffer at "Info"
2131 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2132 * required for the Buffer at "Info"
2135 * Success: TRUE and in pcbNeeded the Bytes used in Info
2136 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2137 * if cbBuf is too small
2139 * Native Values returned in Info on Success:
2140 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2141 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2142 *| win9x(Windows 4.0): "%winsysdir%"
2144 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2147 * Only NULL or "" is supported for server
2150 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2151 DWORD level, LPBYTE Info,
2152 DWORD cbBuf, LPDWORD pcbNeeded)
2155 const printenv_t * env_t;
2157 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2158 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2160 if(server != NULL && server[0]) {
2161 FIXME("server not supported: %s\n", debugstr_w(server));
2162 SetLastError(ERROR_INVALID_PARAMETER);
2166 env_t = validate_envW(env);
2167 if(!env_t) return FALSE; /* environment invalid or unsupported */
2170 WARN("(Level: %d) is ignored in win9x\n", level);
2171 SetLastError(ERROR_INVALID_LEVEL);
2175 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2176 needed = GetSystemDirectoryW(NULL, 0);
2177 /* add the Size for the Subdirectories */
2178 needed += lstrlenW(spoolprtprocsW);
2179 needed += lstrlenW(env_t->subdir);
2180 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2182 if(pcbNeeded) *pcbNeeded = needed;
2183 TRACE ("required: 0x%x/%d\n", needed, needed);
2184 if (needed > cbBuf) {
2185 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2188 if(pcbNeeded == NULL) {
2189 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2190 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2191 SetLastError(RPC_X_NULL_REF_POINTER);
2195 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2196 SetLastError(RPC_X_NULL_REF_POINTER);
2200 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2201 /* add the Subdirectories */
2202 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2203 lstrcatW((LPWSTR) Info, env_t->subdir);
2204 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2208 /*****************************************************************************
2209 * WINSPOOL_OpenDriverReg [internal]
2211 * opens the registry for the printer drivers depending on the given input
2212 * variable pEnvironment
2215 * the opened hkey on success
2218 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2222 const printenv_t * env;
2225 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2227 if (!pEnvironment || unicode) {
2228 /* pEnvironment was NULL or an Unicode-String: use it direct */
2229 env = validate_envW(pEnvironment);
2233 /* pEnvironment was an ANSI-String: convert to unicode first */
2235 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2236 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2237 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2238 env = validate_envW(buffer);
2239 HeapFree(GetProcessHeap(), 0, buffer);
2241 if (!env) return NULL;
2243 buffer = HeapAlloc( GetProcessHeap(), 0,
2244 (strlenW(DriversW) + strlenW(env->envname) +
2245 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2247 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2248 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2249 HeapFree(GetProcessHeap(), 0, buffer);
2254 /*****************************************************************************
2255 * AddPrinterW [WINSPOOL.@]
2257 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2259 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2263 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2266 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2269 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2270 SetLastError(ERROR_INVALID_PARAMETER);
2274 ERR("Level = %d, unsupported!\n", Level);
2275 SetLastError(ERROR_INVALID_LEVEL);
2279 SetLastError(ERROR_INVALID_PARAMETER);
2282 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2284 ERR("Can't create Printers key\n");
2287 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2288 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2289 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2290 RegCloseKey(hkeyPrinter);
2291 RegCloseKey(hkeyPrinters);
2294 RegCloseKey(hkeyPrinter);
2296 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2298 ERR("Can't create Drivers key\n");
2299 RegCloseKey(hkeyPrinters);
2302 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2304 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2305 RegCloseKey(hkeyPrinters);
2306 RegCloseKey(hkeyDrivers);
2307 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2310 RegCloseKey(hkeyDriver);
2311 RegCloseKey(hkeyDrivers);
2313 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2314 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2315 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2316 RegCloseKey(hkeyPrinters);
2320 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2322 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2323 SetLastError(ERROR_INVALID_PRINTER_NAME);
2324 RegCloseKey(hkeyPrinters);
2327 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2328 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2329 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2331 /* See if we can load the driver. We may need the devmode structure anyway
2334 * Note that DocumentPropertiesW will briefly try to open the printer we
2335 * just create to find a DEVMODEA struct (it will use the WINEPS default
2336 * one in case it is not there, so we are ok).
2338 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2341 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2342 size = sizeof(DEVMODEW);
2348 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2349 ZeroMemory(dmW,size);
2351 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2353 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2354 HeapFree(GetProcessHeap(),0,dmW);
2359 /* set devmode to printer name */
2360 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2364 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2365 and we support these drivers. NT writes DEVMODEW so somehow
2366 we'll need to distinguish between these when we support NT
2370 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2371 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2372 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2373 HeapFree(GetProcessHeap(), 0, dmA);
2375 HeapFree(GetProcessHeap(), 0, dmW);
2377 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2378 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2379 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2380 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2382 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2383 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2384 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2385 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2386 (LPBYTE)&pi->Priority, sizeof(DWORD));
2387 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2388 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2389 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2390 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2391 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2392 (LPBYTE)&pi->Status, sizeof(DWORD));
2393 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2394 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2396 RegCloseKey(hkeyPrinter);
2397 RegCloseKey(hkeyPrinters);
2398 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2399 ERR("OpenPrinter failing\n");
2405 /*****************************************************************************
2406 * AddPrinterA [WINSPOOL.@]
2408 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2410 UNICODE_STRING pNameW;
2412 PRINTER_INFO_2W *piW;
2413 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2416 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2418 ERR("Level = %d, unsupported!\n", Level);
2419 SetLastError(ERROR_INVALID_LEVEL);
2422 pwstrNameW = asciitounicode(&pNameW,pName);
2423 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2425 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2427 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2428 RtlFreeUnicodeString(&pNameW);
2433 /*****************************************************************************
2434 * ClosePrinter [WINSPOOL.@]
2436 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2438 UINT_PTR i = (UINT_PTR)hPrinter;
2439 opened_printer_t *printer = NULL;
2442 TRACE("Handle %p\n", hPrinter);
2444 EnterCriticalSection(&printer_handles_cs);
2446 if ((i > 0) && (i <= nb_printer_handles))
2447 printer = printer_handles[i - 1];
2451 struct list *cursor, *cursor2;
2454 EndDocPrinter(hPrinter);
2456 if(InterlockedDecrement(&printer->queue->ref) == 0)
2458 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2460 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2461 ScheduleJob(hPrinter, job->job_id);
2463 HeapFree(GetProcessHeap(), 0, printer->queue);
2465 HeapFree(GetProcessHeap(), 0, printer->name);
2466 HeapFree(GetProcessHeap(), 0, printer);
2467 printer_handles[i - 1] = NULL;
2470 LeaveCriticalSection(&printer_handles_cs);
2474 /*****************************************************************************
2475 * DeleteFormA [WINSPOOL.@]
2477 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2479 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2483 /*****************************************************************************
2484 * DeleteFormW [WINSPOOL.@]
2486 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2488 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2492 /*****************************************************************************
2493 * WINSPOOL_SHRegDeleteKey
2495 * Recursively delete subkeys.
2496 * Cut & paste from shlwapi.
2499 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2501 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2502 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2505 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2508 /* Find how many subkeys there are */
2509 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2510 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2514 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2515 /* Name too big: alloc a buffer for it */
2516 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2519 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2522 /* Recursively delete all the subkeys */
2523 for(i = 0; i < dwKeyCount && !dwRet; i++)
2525 dwSize = dwMaxSubkeyLen;
2526 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2528 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2531 if (lpszName != szNameBuf)
2532 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2536 RegCloseKey(hSubKey);
2538 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2543 /*****************************************************************************
2544 * DeletePrinter [WINSPOOL.@]
2546 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2548 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2549 HKEY hkeyPrinters, hkey;
2552 SetLastError(ERROR_INVALID_HANDLE);
2555 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2556 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2557 RegCloseKey(hkeyPrinters);
2559 WriteProfileStringW(devicesW, lpNameW, NULL);
2560 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2561 RegDeleteValueW(hkey, lpNameW);
2567 /*****************************************************************************
2568 * SetPrinterA [WINSPOOL.@]
2570 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2573 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2577 /*****************************************************************************
2578 * SetJobA [WINSPOOL.@]
2580 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2581 LPBYTE pJob, DWORD Command)
2585 UNICODE_STRING usBuffer;
2587 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2589 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2590 are all ignored by SetJob, so we don't bother copying them */
2598 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2599 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2601 JobW = (LPBYTE)info1W;
2602 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2603 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2604 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2605 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2606 info1W->Status = info1A->Status;
2607 info1W->Priority = info1A->Priority;
2608 info1W->Position = info1A->Position;
2609 info1W->PagesPrinted = info1A->PagesPrinted;
2614 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2615 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2617 JobW = (LPBYTE)info2W;
2618 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2619 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2620 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2621 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2622 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2623 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2624 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2625 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2626 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2627 info2W->Status = info2A->Status;
2628 info2W->Priority = info2A->Priority;
2629 info2W->Position = info2A->Position;
2630 info2W->StartTime = info2A->StartTime;
2631 info2W->UntilTime = info2A->UntilTime;
2632 info2W->PagesPrinted = info2A->PagesPrinted;
2636 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2637 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2640 SetLastError(ERROR_INVALID_LEVEL);
2644 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2650 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2651 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2652 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2653 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2654 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2659 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2660 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2661 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2662 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2663 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2664 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2665 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2666 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2667 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2671 HeapFree(GetProcessHeap(), 0, JobW);
2676 /*****************************************************************************
2677 * SetJobW [WINSPOOL.@]
2679 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2680 LPBYTE pJob, DWORD Command)
2685 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2686 FIXME("Ignoring everything other than document title\n");
2688 EnterCriticalSection(&printer_handles_cs);
2689 job = get_job(hPrinter, JobId);
2699 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2700 HeapFree(GetProcessHeap(), 0, job->document_title);
2701 job->document_title = strdupW(info1->pDocument);
2706 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2707 HeapFree(GetProcessHeap(), 0, job->document_title);
2708 job->document_title = strdupW(info2->pDocument);
2714 SetLastError(ERROR_INVALID_LEVEL);
2719 LeaveCriticalSection(&printer_handles_cs);
2723 /*****************************************************************************
2724 * EndDocPrinter [WINSPOOL.@]
2726 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2728 opened_printer_t *printer;
2730 TRACE("(%p)\n", hPrinter);
2732 EnterCriticalSection(&printer_handles_cs);
2734 printer = get_opened_printer(hPrinter);
2737 SetLastError(ERROR_INVALID_HANDLE);
2743 SetLastError(ERROR_SPL_NO_STARTDOC);
2747 CloseHandle(printer->doc->hf);
2748 ScheduleJob(hPrinter, printer->doc->job_id);
2749 HeapFree(GetProcessHeap(), 0, printer->doc);
2750 printer->doc = NULL;
2753 LeaveCriticalSection(&printer_handles_cs);
2757 /*****************************************************************************
2758 * EndPagePrinter [WINSPOOL.@]
2760 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2762 FIXME("(%p): stub\n", hPrinter);
2766 /*****************************************************************************
2767 * StartDocPrinterA [WINSPOOL.@]
2769 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2771 UNICODE_STRING usBuffer;
2773 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2776 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2777 or one (DOC_INFO_3) extra DWORDs */
2781 doc2W.JobId = doc2->JobId;
2784 doc2W.dwMode = doc2->dwMode;
2787 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2788 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2789 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2793 SetLastError(ERROR_INVALID_LEVEL);
2797 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2799 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2800 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2801 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2806 /*****************************************************************************
2807 * StartDocPrinterW [WINSPOOL.@]
2809 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2811 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2812 opened_printer_t *printer;
2813 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2814 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2815 JOB_INFO_1W job_info;
2816 DWORD needed, ret = 0;
2820 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2821 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2822 debugstr_w(doc->pDatatype));
2824 if(Level < 1 || Level > 3)
2826 SetLastError(ERROR_INVALID_LEVEL);
2830 EnterCriticalSection(&printer_handles_cs);
2831 printer = get_opened_printer(hPrinter);
2834 SetLastError(ERROR_INVALID_HANDLE);
2840 SetLastError(ERROR_INVALID_PRINTER_STATE);
2844 /* Even if we're printing to a file we still add a print job, we'll
2845 just ignore the spool file name */
2847 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2849 ERR("AddJob failed gle %08x\n", GetLastError());
2853 if(doc->pOutputFile)
2854 filename = doc->pOutputFile;
2856 filename = addjob->Path;
2858 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2859 if(hf == INVALID_HANDLE_VALUE)
2862 memset(&job_info, 0, sizeof(job_info));
2863 job_info.pDocument = doc->pDocName;
2864 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2866 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2867 printer->doc->hf = hf;
2868 ret = printer->doc->job_id = addjob->JobId;
2870 LeaveCriticalSection(&printer_handles_cs);
2875 /*****************************************************************************
2876 * StartPagePrinter [WINSPOOL.@]
2878 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2880 FIXME("(%p): stub\n", hPrinter);
2884 /*****************************************************************************
2885 * GetFormA [WINSPOOL.@]
2887 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2888 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2890 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
2891 Level,pForm,cbBuf,pcbNeeded);
2895 /*****************************************************************************
2896 * GetFormW [WINSPOOL.@]
2898 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2899 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2901 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
2902 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2906 /*****************************************************************************
2907 * SetFormA [WINSPOOL.@]
2909 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2912 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2916 /*****************************************************************************
2917 * SetFormW [WINSPOOL.@]
2919 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2922 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2926 /*****************************************************************************
2927 * ReadPrinter [WINSPOOL.@]
2929 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2930 LPDWORD pNoBytesRead)
2932 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2936 /*****************************************************************************
2937 * ResetPrinterA [WINSPOOL.@]
2939 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2941 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2945 /*****************************************************************************
2946 * ResetPrinterW [WINSPOOL.@]
2948 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2950 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2954 /*****************************************************************************
2955 * WINSPOOL_GetDWORDFromReg
2957 * Return DWORD associated with ValueName from hkey.
2959 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2961 DWORD sz = sizeof(DWORD), type, value = 0;
2964 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2966 if(ret != ERROR_SUCCESS) {
2967 WARN("Got ret = %d on name %s\n", ret, ValueName);
2970 if(type != REG_DWORD) {
2971 ERR("Got type %d\n", type);
2977 /*****************************************************************************
2978 * WINSPOOL_GetStringFromReg
2980 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2981 * String is stored either as unicode or ascii.
2982 * Bit of a hack here to get the ValueName if we want ascii.
2984 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2985 DWORD buflen, DWORD *needed,
2988 DWORD sz = buflen, type;
2992 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2994 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2995 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2996 HeapFree(GetProcessHeap(),0,ValueNameA);
2998 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2999 WARN("Got ret = %d\n", ret);
3003 /* add space for terminating '\0' */
3004 sz += unicode ? sizeof(WCHAR) : 1;
3008 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3013 /*****************************************************************************
3014 * WINSPOOL_GetDefaultDevMode
3016 * Get a default DevMode values for wineps.
3020 static void WINSPOOL_GetDefaultDevMode(
3022 DWORD buflen, DWORD *needed,
3026 static const char szwps[] = "wineps.drv";
3028 /* fill default DEVMODE - should be read from ppd... */
3029 ZeroMemory( &dm, sizeof(dm) );
3030 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3031 dm.dmSpecVersion = DM_SPECVERSION;
3032 dm.dmDriverVersion = 1;
3033 dm.dmSize = sizeof(DEVMODEA);
3034 dm.dmDriverExtra = 0;
3036 DM_ORIENTATION | DM_PAPERSIZE |
3037 DM_PAPERLENGTH | DM_PAPERWIDTH |
3040 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3041 DM_YRESOLUTION | DM_TTOPTION;
3043 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3044 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3045 dm.u1.s1.dmPaperLength = 2970;
3046 dm.u1.s1.dmPaperWidth = 2100;
3050 dm.dmDefaultSource = DMBIN_AUTO;
3051 dm.dmPrintQuality = DMRES_MEDIUM;
3054 dm.dmYResolution = 300; /* 300dpi */
3055 dm.dmTTOption = DMTT_BITMAP;
3058 /* dm.dmLogPixels */
3059 /* dm.dmBitsPerPel */
3060 /* dm.dmPelsWidth */
3061 /* dm.dmPelsHeight */
3062 /* dm.dmDisplayFlags */
3063 /* dm.dmDisplayFrequency */
3064 /* dm.dmICMMethod */
3065 /* dm.dmICMIntent */
3066 /* dm.dmMediaType */
3067 /* dm.dmDitherType */
3068 /* dm.dmReserved1 */
3069 /* dm.dmReserved2 */
3070 /* dm.dmPanningWidth */
3071 /* dm.dmPanningHeight */
3074 if(buflen >= sizeof(DEVMODEW)) {
3075 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3076 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3077 HeapFree(GetProcessHeap(),0,pdmW);
3079 *needed = sizeof(DEVMODEW);
3083 if(buflen >= sizeof(DEVMODEA)) {
3084 memcpy(ptr, &dm, sizeof(DEVMODEA));
3086 *needed = sizeof(DEVMODEA);
3090 /*****************************************************************************
3091 * WINSPOOL_GetDevModeFromReg
3093 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3094 * DevMode is stored either as unicode or ascii.
3096 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3098 DWORD buflen, DWORD *needed,
3101 DWORD sz = buflen, type;
3104 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3105 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3106 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3107 if (sz < sizeof(DEVMODEA))
3109 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3112 /* ensures that dmSize is not erratically bogus if registry is invalid */
3113 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3114 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3116 sz += (CCHDEVICENAME + CCHFORMNAME);
3118 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3119 memcpy(ptr, dmW, sz);
3120 HeapFree(GetProcessHeap(),0,dmW);
3127 /*********************************************************************
3128 * WINSPOOL_GetPrinter_2
3130 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3131 * The strings are either stored as unicode or ascii.
3133 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3134 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3137 DWORD size, left = cbBuf;
3138 BOOL space = (cbBuf > 0);
3143 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3145 if(space && size <= left) {
3146 pi2->pPrinterName = (LPWSTR)ptr;
3153 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3155 if(space && size <= left) {
3156 pi2->pShareName = (LPWSTR)ptr;
3163 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3165 if(space && size <= left) {
3166 pi2->pPortName = (LPWSTR)ptr;
3173 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3175 if(space && size <= left) {
3176 pi2->pDriverName = (LPWSTR)ptr;
3183 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3185 if(space && size <= left) {
3186 pi2->pComment = (LPWSTR)ptr;
3193 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3195 if(space && size <= left) {
3196 pi2->pLocation = (LPWSTR)ptr;
3203 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3205 if(space && size <= left) {
3206 pi2->pDevMode = (LPDEVMODEW)ptr;
3215 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3216 if(space && size <= left) {
3217 pi2->pDevMode = (LPDEVMODEW)ptr;
3224 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3226 if(space && size <= left) {
3227 pi2->pSepFile = (LPWSTR)ptr;
3234 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3236 if(space && size <= left) {
3237 pi2->pPrintProcessor = (LPWSTR)ptr;
3244 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3246 if(space && size <= left) {
3247 pi2->pDatatype = (LPWSTR)ptr;
3254 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3256 if(space && size <= left) {
3257 pi2->pParameters = (LPWSTR)ptr;
3265 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3266 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3267 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3268 "Default Priority");
3269 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3270 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3273 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3274 memset(pi2, 0, sizeof(*pi2));
3279 /*********************************************************************
3280 * WINSPOOL_GetPrinter_4
3282 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3284 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3285 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3288 DWORD size, left = cbBuf;
3289 BOOL space = (cbBuf > 0);
3294 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3296 if(space && size <= left) {
3297 pi4->pPrinterName = (LPWSTR)ptr;
3305 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3308 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3309 memset(pi4, 0, sizeof(*pi4));
3314 /*********************************************************************
3315 * WINSPOOL_GetPrinter_5
3317 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3319 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3320 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3323 DWORD size, left = cbBuf;
3324 BOOL space = (cbBuf > 0);
3329 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3331 if(space && size <= left) {
3332 pi5->pPrinterName = (LPWSTR)ptr;
3339 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3341 if(space && size <= left) {
3342 pi5->pPortName = (LPWSTR)ptr;
3350 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3351 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3353 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3357 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3358 memset(pi5, 0, sizeof(*pi5));
3363 /*****************************************************************************
3364 * WINSPOOL_GetPrinter
3366 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3367 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3368 * just a collection of pointers to strings.
3370 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3371 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3374 DWORD size, needed = 0;
3376 HKEY hkeyPrinter, hkeyPrinters;
3379 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3381 if (!(name = get_opened_printer_name(hPrinter))) {
3382 SetLastError(ERROR_INVALID_HANDLE);
3386 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3388 ERR("Can't create Printers key\n");
3391 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3393 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3394 RegCloseKey(hkeyPrinters);
3395 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3402 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3404 size = sizeof(PRINTER_INFO_2W);
3406 ptr = pPrinter + size;
3408 memset(pPrinter, 0, size);
3413 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3421 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3423 size = sizeof(PRINTER_INFO_4W);
3425 ptr = pPrinter + size;
3427 memset(pPrinter, 0, size);
3432 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3441 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3443 size = sizeof(PRINTER_INFO_5W);
3445 ptr = pPrinter + size;
3447 memset(pPrinter, 0, size);
3453 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3460 FIXME("Unimplemented level %d\n", Level);
3461 SetLastError(ERROR_INVALID_LEVEL);
3462 RegCloseKey(hkeyPrinters);
3463 RegCloseKey(hkeyPrinter);
3467 RegCloseKey(hkeyPrinter);
3468 RegCloseKey(hkeyPrinters);
3470 TRACE("returning %d needed = %d\n", ret, needed);
3471 if(pcbNeeded) *pcbNeeded = needed;
3473 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3477 /*****************************************************************************
3478 * GetPrinterW [WINSPOOL.@]
3480 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3481 DWORD cbBuf, LPDWORD pcbNeeded)
3483 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3487 /*****************************************************************************
3488 * GetPrinterA [WINSPOOL.@]
3490 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3491 DWORD cbBuf, LPDWORD pcbNeeded)
3493 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3497 /*****************************************************************************
3498 * WINSPOOL_EnumPrinters
3500 * Implementation of EnumPrintersA|W
3502 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3503 DWORD dwLevel, LPBYTE lpbPrinters,
3504 DWORD cbBuf, LPDWORD lpdwNeeded,
3505 LPDWORD lpdwReturned, BOOL unicode)
3508 HKEY hkeyPrinters, hkeyPrinter;
3509 WCHAR PrinterName[255];
3510 DWORD needed = 0, number = 0;
3511 DWORD used, i, left;
3515 memset(lpbPrinters, 0, cbBuf);
3521 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3522 if(dwType == PRINTER_ENUM_DEFAULT)
3525 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3526 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3527 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3528 if(!dwType) return TRUE;
3531 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3532 FIXME("dwType = %08x\n", dwType);
3533 SetLastError(ERROR_INVALID_FLAGS);
3537 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3539 ERR("Can't create Printers key\n");
3543 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3544 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3545 RegCloseKey(hkeyPrinters);
3546 ERR("Can't query Printers key\n");
3549 TRACE("Found %d printers\n", number);
3553 RegCloseKey(hkeyPrinters);
3555 *lpdwReturned = number;
3559 used = number * sizeof(PRINTER_INFO_2W);
3562 used = number * sizeof(PRINTER_INFO_4W);
3565 used = number * sizeof(PRINTER_INFO_5W);
3569 SetLastError(ERROR_INVALID_LEVEL);
3570 RegCloseKey(hkeyPrinters);
3573 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3575 for(i = 0; i < number; i++) {
3576 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3578 ERR("Can't enum key number %d\n", i);
3579 RegCloseKey(hkeyPrinters);
3582 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3583 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3585 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3586 RegCloseKey(hkeyPrinters);
3591 buf = lpbPrinters + used;
3592 left = cbBuf - used;
3600 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3601 left, &needed, unicode);
3603 if(pi) pi += sizeof(PRINTER_INFO_2W);
3606 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3607 left, &needed, unicode);
3609 if(pi) pi += sizeof(PRINTER_INFO_4W);
3612 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3613 left, &needed, unicode);
3615 if(pi) pi += sizeof(PRINTER_INFO_5W);
3618 ERR("Shouldn't be here!\n");
3619 RegCloseKey(hkeyPrinter);
3620 RegCloseKey(hkeyPrinters);
3623 RegCloseKey(hkeyPrinter);
3625 RegCloseKey(hkeyPrinters);
3632 memset(lpbPrinters, 0, cbBuf);
3633 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3637 *lpdwReturned = number;
3638 SetLastError(ERROR_SUCCESS);
3643 /******************************************************************
3644 * EnumPrintersW [WINSPOOL.@]
3646 * Enumerates the available printers, print servers and print
3647 * providers, depending on the specified flags, name and level.
3651 * If level is set to 1:
3652 * Not implemented yet!
3653 * Returns TRUE with an empty list.
3655 * If level is set to 2:
3656 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3657 * Returns an array of PRINTER_INFO_2 data structures in the
3658 * lpbPrinters buffer. Note that according to MSDN also an
3659 * OpenPrinter should be performed on every remote printer.
3661 * If level is set to 4 (officially WinNT only):
3662 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3663 * Fast: Only the registry is queried to retrieve printer names,
3664 * no connection to the driver is made.
3665 * Returns an array of PRINTER_INFO_4 data structures in the
3666 * lpbPrinters buffer.
3668 * If level is set to 5 (officially WinNT4/Win9x only):
3669 * Fast: Only the registry is queried to retrieve printer names,
3670 * no connection to the driver is made.
3671 * Returns an array of PRINTER_INFO_5 data structures in the
3672 * lpbPrinters buffer.
3674 * If level set to 3 or 6+:
3675 * returns zero (failure!)
3677 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3681 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3682 * - Only levels 2, 4 and 5 are implemented at the moment.
3683 * - 16-bit printer drivers are not enumerated.
3684 * - Returned amount of bytes used/needed does not match the real Windoze
3685 * implementation (as in this implementation, all strings are part
3686 * of the buffer, whereas Win32 keeps them somewhere else)
3687 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3690 * - In a regular Wine installation, no registry settings for printers
3691 * exist, which makes this function return an empty list.
3693 BOOL WINAPI EnumPrintersW(
3694 DWORD dwType, /* [in] Types of print objects to enumerate */
3695 LPWSTR lpszName, /* [in] name of objects to enumerate */
3696 DWORD dwLevel, /* [in] type of printer info structure */
3697 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3698 DWORD cbBuf, /* [in] max size of buffer in bytes */
3699 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3700 LPDWORD lpdwReturned /* [out] number of entries returned */
3703 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3704 lpdwNeeded, lpdwReturned, TRUE);
3707 /******************************************************************
3708 * EnumPrintersA [WINSPOOL.@]
3711 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3712 DWORD dwLevel, LPBYTE lpbPrinters,
3713 DWORD cbBuf, LPDWORD lpdwNeeded,
3714 LPDWORD lpdwReturned)
3717 UNICODE_STRING lpszNameW;
3720 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3721 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3722 lpdwNeeded, lpdwReturned, FALSE);
3723 RtlFreeUnicodeString(&lpszNameW);
3727 /*****************************************************************************
3728 * WINSPOOL_GetDriverInfoFromReg [internal]
3730 * Enters the information from the registry into the DRIVER_INFO struct
3733 * zero if the printer driver does not exist in the registry
3734 * (only if Level > 1) otherwise nonzero
3736 static BOOL WINSPOOL_GetDriverInfoFromReg(
3739 LPCWSTR pEnvironment,
3741 LPBYTE ptr, /* DRIVER_INFO */
3742 LPBYTE pDriverStrings, /* strings buffer */
3743 DWORD cbBuf, /* size of string buffer */
3744 LPDWORD pcbNeeded, /* space needed for str. */
3745 BOOL unicode) /* type of strings */
3749 LPBYTE strPtr = pDriverStrings;
3751 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
3752 debugstr_w(DriverName), debugstr_w(pEnvironment),
3753 Level, ptr, pDriverStrings, cbBuf, unicode);
3756 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3757 if (*pcbNeeded <= cbBuf)
3758 strcpyW((LPWSTR)strPtr, DriverName);
3760 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3762 if(*pcbNeeded <= cbBuf)
3763 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3764 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3768 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3772 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3773 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3776 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3777 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3778 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3783 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3786 pEnvironment = DefaultEnvironmentW;
3788 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3790 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3793 if(*pcbNeeded <= cbBuf) {
3795 strcpyW((LPWSTR)strPtr, pEnvironment);
3797 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3798 (LPSTR)strPtr, size, NULL, NULL);
3800 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3801 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3804 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3807 if(*pcbNeeded <= cbBuf)
3808 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3811 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3812 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3815 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3818 if(*pcbNeeded <= cbBuf)
3819 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3822 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3823 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3826 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3827 0, &size, unicode)) {
3829 if(*pcbNeeded <= cbBuf)
3830 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3831 size, &tmp, unicode);
3833 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3834 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3838 RegCloseKey(hkeyDriver);
3839 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
3843 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3846 if(*pcbNeeded <= cbBuf)
3847 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3848 size, &tmp, unicode);
3850 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3851 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3854 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3857 if(*pcbNeeded <= cbBuf)
3858 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3859 size, &tmp, unicode);
3861 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3862 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3865 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3868 if(*pcbNeeded <= cbBuf)
3869 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3870 size, &tmp, unicode);
3872 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3873 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3876 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3879 if(*pcbNeeded <= cbBuf)
3880 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3881 size, &tmp, unicode);
3883 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3884 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3887 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
3888 RegCloseKey(hkeyDriver);
3892 /*****************************************************************************
3893 * WINSPOOL_GetPrinterDriver
3895 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3896 DWORD Level, LPBYTE pDriverInfo,
3897 DWORD cbBuf, LPDWORD pcbNeeded,
3901 WCHAR DriverName[100];
3902 DWORD ret, type, size, needed = 0;
3904 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3906 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
3907 Level,pDriverInfo,cbBuf, pcbNeeded);
3909 ZeroMemory(pDriverInfo, cbBuf);
3911 if (!(name = get_opened_printer_name(hPrinter))) {
3912 SetLastError(ERROR_INVALID_HANDLE);
3915 if(Level < 1 || Level > 6) {
3916 SetLastError(ERROR_INVALID_LEVEL);
3919 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3921 ERR("Can't create Printers key\n");
3924 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3926 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3927 RegCloseKey(hkeyPrinters);
3928 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3931 size = sizeof(DriverName);
3933 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3934 (LPBYTE)DriverName, &size);
3935 RegCloseKey(hkeyPrinter);
3936 RegCloseKey(hkeyPrinters);
3937 if(ret != ERROR_SUCCESS) {
3938 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3942 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3944 ERR("Can't create Drivers key\n");
3950 size = sizeof(DRIVER_INFO_1W);
3953 size = sizeof(DRIVER_INFO_2W);
3956 size = sizeof(DRIVER_INFO_3W);
3959 size = sizeof(DRIVER_INFO_4W);
3962 size = sizeof(DRIVER_INFO_5W);
3965 size = sizeof(DRIVER_INFO_6W);
3968 ERR("Invalid level\n");
3973 ptr = pDriverInfo + size;
3975 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3976 pEnvironment, Level, pDriverInfo,
3977 (cbBuf < size) ? NULL : ptr,
3978 (cbBuf < size) ? 0 : cbBuf - size,
3979 &needed, unicode)) {
3980 RegCloseKey(hkeyDrivers);
3984 RegCloseKey(hkeyDrivers);
3986 if(pcbNeeded) *pcbNeeded = size + needed;
3987 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
3988 if(cbBuf >= needed) return TRUE;
3989 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3993 /*****************************************************************************
3994 * GetPrinterDriverA [WINSPOOL.@]
3996 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3997 DWORD Level, LPBYTE pDriverInfo,
3998 DWORD cbBuf, LPDWORD pcbNeeded)
4001 UNICODE_STRING pEnvW;
4004 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4005 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4006 cbBuf, pcbNeeded, FALSE);
4007 RtlFreeUnicodeString(&pEnvW);
4010 /*****************************************************************************
4011 * GetPrinterDriverW [WINSPOOL.@]
4013 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4014 DWORD Level, LPBYTE pDriverInfo,
4015 DWORD cbBuf, LPDWORD pcbNeeded)
4017 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4018 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4021 /*****************************************************************************
4022 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4024 * Return the PATH for the Printer-Drivers (UNICODE)
4027 * pName [I] Servername (NT only) or NULL (local Computer)
4028 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4029 * Level [I] Structure-Level (must be 1)
4030 * pDriverDirectory [O] PTR to Buffer that receives the Result
4031 * cbBuf [I] Size of Buffer at pDriverDirectory
4032 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4033 * required for pDriverDirectory
4036 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4037 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4038 * if cbBuf is too small
4040 * Native Values returned in pDriverDirectory on Success:
4041 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4042 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4043 *| win9x(Windows 4.0): "%winsysdir%"
4045 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4048 *- Only NULL or "" is supported for pName
4051 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4052 DWORD Level, LPBYTE pDriverDirectory,
4053 DWORD cbBuf, LPDWORD pcbNeeded)
4056 const printenv_t * env;
4058 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4059 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4060 if(pName != NULL && pName[0]) {
4061 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4062 SetLastError(ERROR_INVALID_PARAMETER);
4066 env = validate_envW(pEnvironment);
4067 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4070 WARN("(Level: %d) is ignored in win9x\n", Level);
4071 SetLastError(ERROR_INVALID_LEVEL);
4075 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4076 needed = GetSystemDirectoryW(NULL, 0);
4077 /* add the Size for the Subdirectories */
4078 needed += lstrlenW(spooldriversW);
4079 needed += lstrlenW(env->subdir);
4080 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4083 *pcbNeeded = needed;
4084 TRACE("required: 0x%x/%d\n", needed, needed);
4085 if(needed > cbBuf) {
4086 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4089 if(pcbNeeded == NULL) {
4090 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4091 SetLastError(RPC_X_NULL_REF_POINTER);
4094 if(pDriverDirectory == NULL) {
4095 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4096 SetLastError(ERROR_INVALID_USER_BUFFER);
4100 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4101 /* add the Subdirectories */
4102 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4103 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4104 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4109 /*****************************************************************************
4110 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4112 * Return the PATH for the Printer-Drivers (ANSI)
4114 * See GetPrinterDriverDirectoryW.
4117 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4120 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4121 DWORD Level, LPBYTE pDriverDirectory,
4122 DWORD cbBuf, LPDWORD pcbNeeded)
4124 UNICODE_STRING nameW, environmentW;
4127 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4128 WCHAR *driverDirectoryW = NULL;
4130 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4131 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4133 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4135 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4136 else nameW.Buffer = NULL;
4137 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4138 else environmentW.Buffer = NULL;
4140 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4141 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4144 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4145 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4147 *pcbNeeded = needed;
4148 ret = (needed <= cbBuf) ? TRUE : FALSE;
4150 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4152 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4154 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4155 RtlFreeUnicodeString(&environmentW);
4156 RtlFreeUnicodeString(&nameW);
4161 /*****************************************************************************
4162 * AddPrinterDriverA [WINSPOOL.@]
4164 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4167 HKEY hkeyDrivers, hkeyName;
4168 static CHAR empty[] = "",
4171 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4173 if(level != 2 && level != 3) {
4174 SetLastError(ERROR_INVALID_LEVEL);
4177 if ((pName) && (pName[0])) {
4178 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4179 SetLastError(ERROR_INVALID_PARAMETER);
4183 WARN("pDriverInfo == NULL\n");
4184 SetLastError(ERROR_INVALID_PARAMETER);
4189 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4191 memset(&di3, 0, sizeof(di3));
4192 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4195 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4197 SetLastError(ERROR_INVALID_PARAMETER);
4201 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4202 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4203 if(!di3.pHelpFile) di3.pHelpFile = empty;
4204 if(!di3.pMonitorName) di3.pMonitorName = empty;
4206 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4209 ERR("Can't create Drivers key\n");
4213 if(level == 2) { /* apparently can't overwrite with level2 */
4214 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4215 RegCloseKey(hkeyName);
4216 RegCloseKey(hkeyDrivers);
4217 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4218 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4222 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4223 RegCloseKey(hkeyDrivers);
4224 ERR("Can't create Name key\n");
4227 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4229 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
4230 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
4231 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4233 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
4234 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4235 (LPBYTE) di3.pDependentFiles, 0);
4236 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
4237 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
4238 RegCloseKey(hkeyName);
4239 RegCloseKey(hkeyDrivers);
4244 /*****************************************************************************
4245 * AddPrinterDriverW [WINSPOOL.@]
4247 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4250 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4255 /*****************************************************************************
4256 * AddPrintProcessorA [WINSPOOL.@]
4258 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4259 LPSTR pPrintProcessorName)
4261 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4262 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4266 /*****************************************************************************
4267 * AddPrintProcessorW [WINSPOOL.@]
4269 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4270 LPWSTR pPrintProcessorName)
4272 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4273 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4277 /*****************************************************************************
4278 * AddPrintProvidorA [WINSPOOL.@]
4280 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4282 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4286 /*****************************************************************************
4287 * AddPrintProvidorW [WINSPOOL.@]
4289 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4291 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4295 /*****************************************************************************
4296 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4298 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4299 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4301 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4302 pDevModeOutput, pDevModeInput);
4306 /*****************************************************************************
4307 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4309 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4310 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4312 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4313 pDevModeOutput, pDevModeInput);
4317 /*****************************************************************************
4318 * PrinterProperties [WINSPOOL.@]
4320 * Displays a dialog to set the properties of the printer.
4323 * nonzero on success or zero on failure
4326 * implemented as stub only
4328 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4329 HANDLE hPrinter /* [in] handle to printer object */
4331 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4332 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4336 /*****************************************************************************
4337 * EnumJobsA [WINSPOOL.@]
4340 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4341 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4344 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4345 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4347 if(pcbNeeded) *pcbNeeded = 0;
4348 if(pcReturned) *pcReturned = 0;
4353 /*****************************************************************************
4354 * EnumJobsW [WINSPOOL.@]
4357 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4358 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4361 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4362 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4364 if(pcbNeeded) *pcbNeeded = 0;
4365 if(pcReturned) *pcReturned = 0;
4369 /*****************************************************************************
4370 * WINSPOOL_EnumPrinterDrivers [internal]
4372 * Delivers information about all printer drivers installed on the
4373 * localhost or a given server
4376 * nonzero on success or zero on failure. If the buffer for the returned
4377 * information is too small the function will return an error
4380 * - only implemented for localhost, foreign hosts will return an error
4382 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4383 DWORD Level, LPBYTE pDriverInfo,
4384 DWORD cbBuf, LPDWORD pcbNeeded,
4385 LPDWORD pcReturned, BOOL unicode)
4388 DWORD i, needed, number = 0, size = 0;
4389 WCHAR DriverNameW[255];
4392 TRACE("%s,%s,%d,%p,%d,%d\n",
4393 debugstr_w(pName), debugstr_w(pEnvironment),
4394 Level, pDriverInfo, cbBuf, unicode);
4396 /* check for local drivers */
4397 if((pName) && (pName[0])) {
4398 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4399 SetLastError(ERROR_ACCESS_DENIED);
4403 /* check input parameter */
4404 if((Level < 1) || (Level > 3)) {
4405 ERR("unsupported level %d\n", Level);
4406 SetLastError(ERROR_INVALID_LEVEL);
4410 /* initialize return values */
4412 memset( pDriverInfo, 0, cbBuf);
4416 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4418 ERR("Can't open Drivers key\n");
4422 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4423 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4424 RegCloseKey(hkeyDrivers);
4425 ERR("Can't query Drivers key\n");
4428 TRACE("Found %d Drivers\n", number);
4430 /* get size of single struct
4431 * unicode and ascii structure have the same size
4435 size = sizeof(DRIVER_INFO_1A);
4438 size = sizeof(DRIVER_INFO_2A);
4441 size = sizeof(DRIVER_INFO_3A);
4445 /* calculate required buffer size */
4446 *pcbNeeded = size * number;
4448 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4450 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4451 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4453 ERR("Can't enum key number %d\n", i);
4454 RegCloseKey(hkeyDrivers);
4457 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4458 pEnvironment, Level, ptr,
4459 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4460 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4461 &needed, unicode)) {
4462 RegCloseKey(hkeyDrivers);
4465 (*pcbNeeded) += needed;
4468 RegCloseKey(hkeyDrivers);
4470 if(cbBuf < *pcbNeeded){
4471 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4475 *pcReturned = number;
4479 /*****************************************************************************
4480 * EnumPrinterDriversW [WINSPOOL.@]
4482 * see function EnumPrinterDrivers for RETURNS, BUGS
4484 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4485 LPBYTE pDriverInfo, DWORD cbBuf,
4486 LPDWORD pcbNeeded, LPDWORD pcReturned)
4488 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4489 cbBuf, pcbNeeded, pcReturned, TRUE);
4492 /*****************************************************************************
4493 * EnumPrinterDriversA [WINSPOOL.@]
4495 * see function EnumPrinterDrivers for RETURNS, BUGS
4497 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4498 LPBYTE pDriverInfo, DWORD cbBuf,
4499 LPDWORD pcbNeeded, LPDWORD pcReturned)
4501 UNICODE_STRING pNameW, pEnvironmentW;
4502 PWSTR pwstrNameW, pwstrEnvironmentW;
4504 pwstrNameW = asciitounicode(&pNameW, pName);
4505 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4507 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4508 Level, pDriverInfo, cbBuf, pcbNeeded,
4510 RtlFreeUnicodeString(&pNameW);
4511 RtlFreeUnicodeString(&pEnvironmentW);
4516 static CHAR PortMonitor[] = "Wine Port Monitor";
4517 static CHAR PortDescription[] = "Wine Port";
4519 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4523 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4524 NULL, OPEN_EXISTING, 0, NULL );
4525 if (handle == INVALID_HANDLE_VALUE)
4527 TRACE("Checking %s exists\n", name );
4528 CloseHandle( handle );
4532 static DWORD WINSPOOL_CountSerialPorts(void)
4539 strcpy( name, "COMx:" );
4541 if (WINSPOOL_ComPortExists( name ))
4548 /******************************************************************************
4549 * EnumPortsA (WINSPOOL.@)
4554 * ANSI-Version did not call the UNICODE-Version
4557 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4558 LPDWORD bufneeded,LPDWORD bufreturned)
4561 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4562 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4566 TRACE("(%s,%d,%p,%d,%p,%p)\n",
4567 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4572 info_size = sizeof (PORT_INFO_1A);
4575 info_size = sizeof (PORT_INFO_2A);
4578 SetLastError(ERROR_INVALID_LEVEL);
4582 /* see how many exist */
4585 serial_count = WINSPOOL_CountSerialPorts();
4588 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4589 if ( r == ERROR_SUCCESS )
4591 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4592 &printer_count, NULL, NULL, NULL, NULL);
4594 count = serial_count + printer_count;
4596 /* then fill in the structure info structure once
4597 we know the offset to the first string */
4599 memset( buffer, 0, bufsize );
4601 ofs = info_size*count;
4602 for ( i=0; i<count; i++)
4604 DWORD vallen = sizeof(portname) - 1;
4606 /* get the serial port values, then the printer values */
4607 if ( i < serial_count )
4609 strcpy( portname, "COMx:" );
4610 portname[3] = '1' + i;
4611 if (!WINSPOOL_ComPortExists( portname ))
4614 TRACE("Found %s\n", portname );
4615 vallen = strlen( portname );
4619 r = RegEnumValueA( hkey_printer, i-serial_count,
4620 portname, &vallen, NULL, NULL, NULL, 0 );
4625 /* add a colon if necessary, and make it upper case */
4626 CharUpperBuffA(portname,vallen);
4627 if (strcasecmp(portname,"nul")!=0)
4628 if (vallen && (portname[vallen-1] != ':') )
4629 lstrcatA(portname,":");
4631 /* add the port info structure if we can fit it */
4632 if ( info_size*(n+1) < bufsize )
4636 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4637 info->pName = (LPSTR) &buffer[ofs];
4639 else if ( level == 2)
4641 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4642 info->pPortName = (LPSTR) &buffer[ofs];
4643 /* FIXME: fill in more stuff here */
4644 info->pMonitorName = PortMonitor;
4645 info->pDescription = PortDescription;
4646 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4649 /* add the name of the port if we can fit it */
4650 if ( ofs < bufsize )
4651 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4657 ofs += lstrlenA(portname)+1;
4660 RegCloseKey(hkey_printer);
4671 /******************************************************************************
4672 * EnumPortsW (WINSPOOL.@)
4674 * Enumerate available Ports
4677 * name [I] Servername or NULL (local Computer)
4678 * level [I] Structure-Level (1 or 2)
4679 * buffer [O] PTR to Buffer that receives the Result
4680 * bufsize [I] Size of Buffer at buffer
4681 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4682 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4686 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4689 * UNICODE-Version is a stub
4692 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4693 LPDWORD bufneeded,LPDWORD bufreturned)
4695 FIXME("(%s,%d,%p,%d,%p,%p) - stub\n",
4696 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4700 /******************************************************************************
4701 * GetDefaultPrinterW (WINSPOOL.@)
4704 * This function must read the value from data 'device' of key
4705 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4707 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4711 WCHAR *buffer, *ptr;
4715 SetLastError(ERROR_INVALID_PARAMETER);
4719 /* make the buffer big enough for the stuff from the profile/registry,
4720 * the content must fit into the local buffer to compute the correct
4721 * size even if the extern buffer is too small or not given.
4722 * (20 for ,driver,port) */
4724 len = max(100, (insize + 20));
4725 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4727 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4729 SetLastError (ERROR_FILE_NOT_FOUND);
4733 TRACE("%s\n", debugstr_w(buffer));
4735 if ((ptr = strchrW(buffer, ',')) == NULL)
4737 SetLastError(ERROR_INVALID_NAME);
4743 *namesize = strlenW(buffer) + 1;
4744 if(!name || (*namesize > insize))
4746 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4750 strcpyW(name, buffer);
4753 HeapFree( GetProcessHeap(), 0, buffer);
4758 /******************************************************************************
4759 * GetDefaultPrinterA (WINSPOOL.@)
4761 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4765 WCHAR *bufferW = NULL;
4769 SetLastError(ERROR_INVALID_PARAMETER);
4773 if(name && *namesize) {
4775 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4778 if(!GetDefaultPrinterW( bufferW, namesize)) {
4783 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4787 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4790 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
4793 HeapFree( GetProcessHeap(), 0, bufferW);
4798 /******************************************************************************
4799 * SetDefaultPrinterW (WINSPOOL.204)
4801 * Set the Name of the Default Printer
4804 * pszPrinter [I] Name of the Printer or NULL
4811 * When the Parameter is NULL or points to an Empty String and
4812 * a Default Printer was already present, then this Function changes nothing.
4813 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4814 * the First enumerated local Printer is used.
4817 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4820 TRACE("(%s)\n", debugstr_w(pszPrinter));
4822 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4826 /******************************************************************************
4827 * SetDefaultPrinterA (WINSPOOL.202)
4829 * See SetDefaultPrinterW.
4832 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4835 TRACE("(%s)\n", debugstr_a(pszPrinter));
4837 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4842 /******************************************************************************
4843 * SetPrinterDataExA (WINSPOOL.@)
4845 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4846 LPCSTR pValueName, DWORD Type,
4847 LPBYTE pData, DWORD cbData)
4849 HKEY hkeyPrinter, hkeySubkey;
4852 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
4853 debugstr_a(pValueName), Type, pData, cbData);
4855 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4859 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4861 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4862 RegCloseKey(hkeyPrinter);
4865 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4866 RegCloseKey(hkeySubkey);
4867 RegCloseKey(hkeyPrinter);
4871 /******************************************************************************
4872 * SetPrinterDataExW (WINSPOOL.@)
4874 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4875 LPCWSTR pValueName, DWORD Type,
4876 LPBYTE pData, DWORD cbData)
4878 HKEY hkeyPrinter, hkeySubkey;
4881 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
4882 debugstr_w(pValueName), Type, pData, cbData);
4884 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4888 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4890 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4891 RegCloseKey(hkeyPrinter);
4894 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4895 RegCloseKey(hkeySubkey);
4896 RegCloseKey(hkeyPrinter);
4900 /******************************************************************************
4901 * SetPrinterDataA (WINSPOOL.@)
4903 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4904 LPBYTE pData, DWORD cbData)
4906 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4910 /******************************************************************************
4911 * SetPrinterDataW (WINSPOOL.@)
4913 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4914 LPBYTE pData, DWORD cbData)
4916 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4920 /******************************************************************************
4921 * GetPrinterDataExA (WINSPOOL.@)
4923 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4924 LPCSTR pValueName, LPDWORD pType,
4925 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4927 HKEY hkeyPrinter, hkeySubkey;
4930 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
4931 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4934 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4938 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4940 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4941 RegCloseKey(hkeyPrinter);
4945 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4946 RegCloseKey(hkeySubkey);
4947 RegCloseKey(hkeyPrinter);
4951 /******************************************************************************
4952 * GetPrinterDataExW (WINSPOOL.@)
4954 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4955 LPCWSTR pValueName, LPDWORD pType,
4956 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4958 HKEY hkeyPrinter, hkeySubkey;
4961 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
4962 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4965 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4969 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4971 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4972 RegCloseKey(hkeyPrinter);
4976 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4977 RegCloseKey(hkeySubkey);
4978 RegCloseKey(hkeyPrinter);
4982 /******************************************************************************
4983 * GetPrinterDataA (WINSPOOL.@)
4985 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4986 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4988 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4989 pData, nSize, pcbNeeded);
4992 /******************************************************************************
4993 * GetPrinterDataW (WINSPOOL.@)
4995 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4996 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4998 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4999 pData, nSize, pcbNeeded);
5002 /*******************************************************************************
5003 * EnumPrinterDataExW [WINSPOOL.@]
5005 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5006 LPBYTE pEnumValues, DWORD cbEnumValues,
5007 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5009 HKEY hkPrinter, hkSubKey;
5010 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5011 cbValueNameLen, cbMaxValueLen, cbValueLen,
5016 PPRINTER_ENUM_VALUESW ppev;
5018 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5020 if (pKeyName == NULL || *pKeyName == 0)
5021 return ERROR_INVALID_PARAMETER;
5023 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5024 if (ret != ERROR_SUCCESS)
5026 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5031 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5032 if (ret != ERROR_SUCCESS)
5034 r = RegCloseKey (hkPrinter);
5035 if (r != ERROR_SUCCESS)
5036 WARN ("RegCloseKey returned %i\n", r);
5037 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5038 debugstr_w (pKeyName), ret);
5042 ret = RegCloseKey (hkPrinter);
5043 if (ret != ERROR_SUCCESS)
5045 ERR ("RegCloseKey returned %i\n", ret);
5046 r = RegCloseKey (hkSubKey);
5047 if (r != ERROR_SUCCESS)
5048 WARN ("RegCloseKey returned %i\n", r);
5052 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5053 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5054 if (ret != ERROR_SUCCESS)
5056 r = RegCloseKey (hkSubKey);
5057 if (r != ERROR_SUCCESS)
5058 WARN ("RegCloseKey returned %i\n", r);
5059 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5063 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5064 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5066 if (cValues == 0) /* empty key */
5068 r = RegCloseKey (hkSubKey);
5069 if (r != ERROR_SUCCESS)
5070 WARN ("RegCloseKey returned %i\n", r);
5071 *pcbEnumValues = *pnEnumValues = 0;
5072 return ERROR_SUCCESS;
5075 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5077 hHeap = GetProcessHeap ();
5080 ERR ("GetProcessHeap failed\n");
5081 r = RegCloseKey (hkSubKey);
5082 if (r != ERROR_SUCCESS)
5083 WARN ("RegCloseKey returned %i\n", r);
5084 return ERROR_OUTOFMEMORY;
5087 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5088 if (lpValueName == NULL)
5090 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5091 r = RegCloseKey (hkSubKey);
5092 if (r != ERROR_SUCCESS)
5093 WARN ("RegCloseKey returned %i\n", r);
5094 return ERROR_OUTOFMEMORY;
5097 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5098 if (lpValue == NULL)
5100 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5101 if (HeapFree (hHeap, 0, lpValueName) == 0)
5102 WARN ("HeapFree failed with code %i\n", GetLastError ());
5103 r = RegCloseKey (hkSubKey);
5104 if (r != ERROR_SUCCESS)
5105 WARN ("RegCloseKey returned %i\n", r);
5106 return ERROR_OUTOFMEMORY;
5109 TRACE ("pass 1: calculating buffer required for all names and values\n");
5111 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5113 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5115 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5117 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5118 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5119 NULL, NULL, lpValue, &cbValueLen);
5120 if (ret != ERROR_SUCCESS)
5122 if (HeapFree (hHeap, 0, lpValue) == 0)
5123 WARN ("HeapFree failed with code %i\n", GetLastError ());
5124 if (HeapFree (hHeap, 0, lpValueName) == 0)
5125 WARN ("HeapFree failed with code %i\n", GetLastError ());
5126 r = RegCloseKey (hkSubKey);
5127 if (r != ERROR_SUCCESS)
5128 WARN ("RegCloseKey returned %i\n", r);
5129 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5133 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5134 debugstr_w (lpValueName), dwIndex,
5135 cbValueNameLen + 1, cbValueLen);
5137 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5138 cbBufSize += cbValueLen;
5141 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5143 *pcbEnumValues = cbBufSize;
5144 *pnEnumValues = cValues;
5146 if (cbEnumValues < cbBufSize) /* buffer too small */
5148 if (HeapFree (hHeap, 0, lpValue) == 0)
5149 WARN ("HeapFree failed with code %i\n", GetLastError ());
5150 if (HeapFree (hHeap, 0, lpValueName) == 0)
5151 WARN ("HeapFree failed with code %i\n", GetLastError ());
5152 r = RegCloseKey (hkSubKey);
5153 if (r != ERROR_SUCCESS)
5154 WARN ("RegCloseKey returned %i\n", r);
5155 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5156 return ERROR_MORE_DATA;
5159 TRACE ("pass 2: copying all names and values to buffer\n");
5161 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5162 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5164 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5166 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5167 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5168 NULL, &dwType, lpValue, &cbValueLen);
5169 if (ret != ERROR_SUCCESS)
5171 if (HeapFree (hHeap, 0, lpValue) == 0)
5172 WARN ("HeapFree failed with code %i\n", GetLastError ());
5173 if (HeapFree (hHeap, 0, lpValueName) == 0)
5174 WARN ("HeapFree failed with code %i\n", GetLastError ());
5175 r = RegCloseKey (hkSubKey);
5176 if (r != ERROR_SUCCESS)
5177 WARN ("RegCloseKey returned %i\n", r);
5178 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5182 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5183 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5184 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5185 pEnumValues += cbValueNameLen;
5187 /* return # of *bytes* (including trailing \0), not # of chars */
5188 ppev[dwIndex].cbValueName = cbValueNameLen;
5190 ppev[dwIndex].dwType = dwType;
5192 memcpy (pEnumValues, lpValue, cbValueLen);
5193 ppev[dwIndex].pData = pEnumValues;
5194 pEnumValues += cbValueLen;
5196 ppev[dwIndex].cbData = cbValueLen;
5198 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5199 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5202 if (HeapFree (hHeap, 0, lpValue) == 0)
5204 ret = GetLastError ();
5205 ERR ("HeapFree failed with code %i\n", ret);
5206 if (HeapFree (hHeap, 0, lpValueName) == 0)
5207 WARN ("HeapFree failed with code %i\n", GetLastError ());
5208 r = RegCloseKey (hkSubKey);
5209 if (r != ERROR_SUCCESS)
5210 WARN ("RegCloseKey returned %i\n", r);
5214 if (HeapFree (hHeap, 0, lpValueName) == 0)
5216 ret = GetLastError ();
5217 ERR ("HeapFree failed with code %i\n", ret);
5218 r = RegCloseKey (hkSubKey);
5219 if (r != ERROR_SUCCESS)
5220 WARN ("RegCloseKey returned %i\n", r);
5224 ret = RegCloseKey (hkSubKey);
5225 if (ret != ERROR_SUCCESS)
5227 ERR ("RegCloseKey returned %i\n", ret);
5231 return ERROR_SUCCESS;
5234 /*******************************************************************************
5235 * EnumPrinterDataExA [WINSPOOL.@]
5237 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5238 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5239 * what Windows 2000 SP1 does.
5242 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5243 LPBYTE pEnumValues, DWORD cbEnumValues,
5244 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5248 DWORD ret, dwIndex, dwBufSize;
5252 TRACE ("%p %s\n", hPrinter, pKeyName);
5254 if (pKeyName == NULL || *pKeyName == 0)
5255 return ERROR_INVALID_PARAMETER;
5257 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5260 ret = GetLastError ();
5261 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5265 hHeap = GetProcessHeap ();
5268 ERR ("GetProcessHeap failed\n");
5269 return ERROR_OUTOFMEMORY;
5272 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5273 if (pKeyNameW == NULL)
5275 ERR ("Failed to allocate %i bytes from process heap\n",
5276 (LONG)(len * sizeof (WCHAR)));
5277 return ERROR_OUTOFMEMORY;
5280 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5282 ret = GetLastError ();
5283 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5284 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5285 WARN ("HeapFree failed with code %i\n", GetLastError ());
5289 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5290 pcbEnumValues, pnEnumValues);
5291 if (ret != ERROR_SUCCESS)
5293 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5294 WARN ("HeapFree failed with code %i\n", GetLastError ());
5295 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5299 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5301 ret = GetLastError ();
5302 ERR ("HeapFree failed with code %i\n", ret);
5306 if (*pnEnumValues == 0) /* empty key */
5307 return ERROR_SUCCESS;
5310 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5312 PPRINTER_ENUM_VALUESW ppev =
5313 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5315 if (dwBufSize < ppev->cbValueName)
5316 dwBufSize = ppev->cbValueName;
5318 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5319 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5320 dwBufSize = ppev->cbData;
5323 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5325 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5326 if (pBuffer == NULL)
5328 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5329 return ERROR_OUTOFMEMORY;
5332 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5334 PPRINTER_ENUM_VALUESW ppev =
5335 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5337 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5338 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5342 ret = GetLastError ();
5343 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5344 if (HeapFree (hHeap, 0, pBuffer) == 0)
5345 WARN ("HeapFree failed with code %i\n", GetLastError ());
5349 memcpy (ppev->pValueName, pBuffer, len);
5351 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5353 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5354 ppev->dwType != REG_MULTI_SZ)
5357 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5358 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5361 ret = GetLastError ();
5362 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5363 if (HeapFree (hHeap, 0, pBuffer) == 0)
5364 WARN ("HeapFree failed with code %i\n", GetLastError ());
5368 memcpy (ppev->pData, pBuffer, len);
5370 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5371 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5374 if (HeapFree (hHeap, 0, pBuffer) == 0)
5376 ret = GetLastError ();
5377 ERR ("HeapFree failed with code %i\n", ret);
5381 return ERROR_SUCCESS;
5384 /******************************************************************************
5385 * AbortPrinter (WINSPOOL.@)
5387 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5389 FIXME("(%p), stub!\n", hPrinter);
5393 /******************************************************************************
5394 * AddPortA (WINSPOOL.@)
5399 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5401 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5405 /******************************************************************************
5406 * AddPortW (WINSPOOL.@)
5408 * Add a Port for a specific Monitor
5411 * pName [I] Servername or NULL (local Computer)
5412 * hWnd [I] Handle to parent Window for the Dialog-Box
5413 * pMonitorName [I] Name of the Monitor that manage the Port
5423 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5425 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5429 /******************************************************************************
5430 * AddPortExA (WINSPOOL.@)
5435 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5437 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5438 lpBuffer, debugstr_a(lpMonitorName));
5442 /******************************************************************************
5443 * AddPortExW (WINSPOOL.@)
5445 * Add a Port for a specific Monitor, without presenting a user interface
5448 * hMonitor [I] Handle from InitializePrintMonitor2()
5449 * pName [I] Servername or NULL (local Computer)
5450 * Level [I] Structure-Level (1 or 2) for lpBuffer
5451 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5452 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5462 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5464 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5465 lpBuffer, debugstr_w(lpMonitorName));
5469 /******************************************************************************
5470 * AddPrinterConnectionA (WINSPOOL.@)
5472 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5474 FIXME("%s\n", debugstr_a(pName));
5478 /******************************************************************************
5479 * AddPrinterConnectionW (WINSPOOL.@)
5481 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5483 FIXME("%s\n", debugstr_w(pName));
5487 /******************************************************************************
5488 * AddPrinterDriverExW (WINSPOOL.@)
5490 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5491 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5493 FIXME("%s %d %p %d\n", debugstr_w(pName),
5494 Level, pDriverInfo, dwFileCopyFlags);
5495 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5499 /******************************************************************************
5500 * AddPrinterDriverExA (WINSPOOL.@)
5502 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5503 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5505 FIXME("%s %d %p %d\n", debugstr_a(pName),
5506 Level, pDriverInfo, dwFileCopyFlags);
5507 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5511 /******************************************************************************
5512 * ConfigurePortA (WINSPOOL.@)
5514 * See ConfigurePortW.
5517 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5519 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5523 /******************************************************************************
5524 * ConfigurePortW (WINSPOOL.@)
5526 * Display the Configuration-Dialog for a specific Port
5529 * pName [I] Servername or NULL (local Computer)
5530 * hWnd [I] Handle to parent Window for the Dialog-Box
5531 * pPortName [I] Name of the Port, that should be configured
5541 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5543 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5547 /******************************************************************************
5548 * ConnectToPrinterDlg (WINSPOOL.@)
5550 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5552 FIXME("%p %x\n", hWnd, Flags);
5556 /******************************************************************************
5557 * DeletePrinterConnectionA (WINSPOOL.@)
5559 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5561 FIXME("%s\n", debugstr_a(pName));
5565 /******************************************************************************
5566 * DeletePrinterConnectionW (WINSPOOL.@)
5568 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5570 FIXME("%s\n", debugstr_w(pName));
5574 /******************************************************************************
5575 * DeletePrinterDriverExW (WINSPOOL.@)
5577 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5578 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5580 FIXME("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
5581 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5585 /******************************************************************************
5586 * DeletePrinterDriverExA (WINSPOOL.@)
5588 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5589 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5591 FIXME("%s %s %s %x %x\n", debugstr_a(pName), debugstr_a(pEnvironment),
5592 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5596 /******************************************************************************
5597 * DeletePrinterDataExW (WINSPOOL.@)
5599 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5602 FIXME("%p %s %s\n", hPrinter,
5603 debugstr_w(pKeyName), debugstr_w(pValueName));
5604 return ERROR_INVALID_PARAMETER;
5607 /******************************************************************************
5608 * DeletePrinterDataExA (WINSPOOL.@)
5610 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5613 FIXME("%p %s %s\n", hPrinter,
5614 debugstr_a(pKeyName), debugstr_a(pValueName));
5615 return ERROR_INVALID_PARAMETER;
5618 /******************************************************************************
5619 * DeletePrintProcessorA (WINSPOOL.@)
5621 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5623 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5624 debugstr_a(pPrintProcessorName));
5628 /******************************************************************************
5629 * DeletePrintProcessorW (WINSPOOL.@)
5631 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5633 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5634 debugstr_w(pPrintProcessorName));
5638 /******************************************************************************
5639 * DeletePrintProvidorA (WINSPOOL.@)
5641 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5643 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5644 debugstr_a(pPrintProviderName));
5648 /******************************************************************************
5649 * DeletePrintProvidorW (WINSPOOL.@)
5651 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5653 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5654 debugstr_w(pPrintProviderName));
5658 /******************************************************************************
5659 * EnumFormsA (WINSPOOL.@)
5661 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5662 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5664 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5665 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5669 /******************************************************************************
5670 * EnumFormsW (WINSPOOL.@)
5672 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5673 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5675 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5676 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5680 /*****************************************************************************
5681 * EnumMonitorsA [WINSPOOL.@]
5683 * See EnumMonitorsW.
5686 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5687 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5690 LPBYTE bufferW = NULL;
5691 LPWSTR nameW = NULL;
5693 DWORD numentries = 0;
5696 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5697 cbBuf, pcbNeeded, pcReturned);
5699 /* convert servername to unicode */
5701 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5702 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5703 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5705 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5706 needed = cbBuf * sizeof(WCHAR);
5707 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5708 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5710 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5711 if (pcbNeeded) needed = *pcbNeeded;
5712 /* HeapReAlloc return NULL, when bufferW was NULL */
5713 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5714 HeapAlloc(GetProcessHeap(), 0, needed);
5716 /* Try again with the large Buffer */
5717 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5719 numentries = pcReturned ? *pcReturned : 0;
5722 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5723 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5726 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5727 DWORD entrysize = 0;
5730 LPMONITOR_INFO_2W mi2w;
5731 LPMONITOR_INFO_2A mi2a;
5733 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5734 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5736 /* First pass: calculate the size for all Entries */
5737 mi2w = (LPMONITOR_INFO_2W) bufferW;
5738 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5740 while (index < numentries) {
5742 needed += entrysize; /* MONITOR_INFO_?A */
5743 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5745 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5746 NULL, 0, NULL, NULL);
5748 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5749 NULL, 0, NULL, NULL);
5750 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5751 NULL, 0, NULL, NULL);
5753 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5754 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5755 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5758 /* check for errors and quit on failure */
5759 if (cbBuf < needed) {
5760 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5764 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5765 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5766 cbBuf -= len ; /* free Bytes in the user-Buffer */
5767 mi2w = (LPMONITOR_INFO_2W) bufferW;
5768 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5770 /* Second Pass: Fill the User Buffer (if we have one) */
5771 while ((index < numentries) && pMonitors) {
5773 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
5775 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5776 ptr, cbBuf , NULL, NULL);
5780 mi2a->pEnvironment = ptr;
5781 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5782 ptr, cbBuf, NULL, NULL);
5786 mi2a->pDLLName = ptr;
5787 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5788 ptr, cbBuf, NULL, NULL);
5792 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5793 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5794 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5798 if (pcbNeeded) *pcbNeeded = needed;
5799 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5801 HeapFree(GetProcessHeap(), 0, nameW);
5802 HeapFree(GetProcessHeap(), 0, bufferW);
5804 TRACE("returning %d with %d (%d byte for %d entries)\n",
5805 (res), GetLastError(), needed, numentries);
5811 /*****************************************************************************
5812 * EnumMonitorsW [WINSPOOL.@]
5814 * Enumerate available Port-Monitors
5817 * pName [I] Servername or NULL (local Computer)
5818 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5819 * pMonitors [O] PTR to Buffer that receives the Result
5820 * cbBuf [I] Size of Buffer at pMonitors
5821 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5822 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5826 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5829 * Windows reads the Registry once and cache the Results.
5831 *| Language-Monitors are also installed in the same Registry-Location but
5832 *| they are filtered in Windows (not returned by EnumMonitors).
5833 *| We do no filtering to simplify our Code.
5836 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5837 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5840 DWORD numentries = 0;
5843 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5844 cbBuf, pcbNeeded, pcReturned);
5846 if (pName && (lstrlenW(pName))) {
5847 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5848 SetLastError(ERROR_ACCESS_DENIED);
5852 /* Level is not checked in win9x */
5853 if (!Level || (Level > 2)) {
5854 WARN("level (%d) is ignored in win9x\n", Level);
5855 SetLastError(ERROR_INVALID_LEVEL);
5859 SetLastError(RPC_X_NULL_REF_POINTER);
5863 /* Scan all Monitor-Keys */
5865 needed = get_local_monitors(Level, NULL, 0, &numentries);
5867 /* we calculated the needed buffersize. now do the error-checks */
5868 if (cbBuf < needed) {
5869 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5872 else if (!pMonitors || !pcReturned) {
5873 SetLastError(RPC_X_NULL_REF_POINTER);
5877 /* fill the Buffer with the Monitor-Keys */
5878 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5882 if (pcbNeeded) *pcbNeeded = needed;
5883 if (pcReturned) *pcReturned = numentries;
5885 TRACE("returning %d with %d (%d byte for %d entries)\n",
5886 res, GetLastError(), needed, numentries);
5891 /******************************************************************************
5892 * XcvDataW (WINSPOOL.@)
5895 * There doesn't seem to be an A version...
5897 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5898 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5899 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5901 FIXME("%p %s %p %d %p %d %p %p\n", hXcv, debugstr_w(pszDataName),
5902 pInputData, cbInputData, pOutputData,
5903 cbOutputData, pcbOutputNeeded, pdwStatus);
5907 /*****************************************************************************
5908 * EnumPrinterDataA [WINSPOOL.@]
5911 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5912 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5913 DWORD cbData, LPDWORD pcbData )
5915 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
5916 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5917 return ERROR_NO_MORE_ITEMS;
5920 /*****************************************************************************
5921 * EnumPrinterDataW [WINSPOOL.@]
5924 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5925 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5926 DWORD cbData, LPDWORD pcbData )
5928 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
5929 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5930 return ERROR_NO_MORE_ITEMS;
5933 /*****************************************************************************
5934 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5937 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5938 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5939 LPDWORD pcbNeeded, LPDWORD pcReturned)
5941 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
5942 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5943 pcbNeeded, pcReturned);
5947 /*****************************************************************************
5948 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5951 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5952 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5953 LPDWORD pcbNeeded, LPDWORD pcReturned)
5955 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
5956 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5957 pcbNeeded, pcReturned);
5961 /*****************************************************************************
5962 * EnumPrintProcessorsA [WINSPOOL.@]
5965 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5966 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5968 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
5969 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5973 /*****************************************************************************
5974 * EnumPrintProcessorsW [WINSPOOL.@]
5977 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5978 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5980 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
5981 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5982 cbBuf, pcbNeeded, pcbReturned);
5986 /*****************************************************************************
5987 * ExtDeviceMode [WINSPOOL.@]
5990 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5991 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5994 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
5995 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5996 debugstr_a(pProfile), fMode);
6000 /*****************************************************************************
6001 * FindClosePrinterChangeNotification [WINSPOOL.@]
6004 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6006 FIXME("Stub: %p\n", hChange);
6010 /*****************************************************************************
6011 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6014 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6015 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6017 FIXME("Stub: %p %x %x %p\n",
6018 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6019 return INVALID_HANDLE_VALUE;
6022 /*****************************************************************************
6023 * FindNextPrinterChangeNotification [WINSPOOL.@]
6026 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6027 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6029 FIXME("Stub: %p %p %p %p\n",
6030 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6034 /*****************************************************************************
6035 * FreePrinterNotifyInfo [WINSPOOL.@]
6038 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6040 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6044 /*****************************************************************************
6047 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6048 * ansi depending on the unicode parameter.
6050 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6060 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6063 memcpy(ptr, str, *size);
6070 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6073 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6080 /*****************************************************************************
6083 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6084 LPDWORD pcbNeeded, BOOL unicode)
6086 DWORD size, left = cbBuf;
6087 BOOL space = (cbBuf > 0);
6094 ji1->JobId = job->job_id;
6097 string_to_buf(job->document_title, ptr, left, &size, unicode);
6098 if(space && size <= left)
6100 ji1->pDocument = (LPWSTR)ptr;
6111 /*****************************************************************************
6114 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6115 LPDWORD pcbNeeded, BOOL unicode)
6117 DWORD size, left = cbBuf;
6118 BOOL space = (cbBuf > 0);
6125 ji2->JobId = job->job_id;
6128 string_to_buf(job->document_title, ptr, left, &size, unicode);
6129 if(space && size <= left)
6131 ji2->pDocument = (LPWSTR)ptr;
6142 /*****************************************************************************
6145 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6146 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6149 DWORD needed = 0, size;
6153 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6155 EnterCriticalSection(&printer_handles_cs);
6156 job = get_job(hPrinter, JobId);
6163 size = sizeof(JOB_INFO_1W);
6168 memset(pJob, 0, size);
6172 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6177 size = sizeof(JOB_INFO_2W);
6182 memset(pJob, 0, size);
6186 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6191 size = sizeof(JOB_INFO_3);
6195 memset(pJob, 0, size);
6204 SetLastError(ERROR_INVALID_LEVEL);
6208 *pcbNeeded = needed;
6210 LeaveCriticalSection(&printer_handles_cs);
6214 /*****************************************************************************
6215 * GetJobA [WINSPOOL.@]
6218 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6219 DWORD cbBuf, LPDWORD pcbNeeded)
6221 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6224 /*****************************************************************************
6225 * GetJobW [WINSPOOL.@]
6228 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6229 DWORD cbBuf, LPDWORD pcbNeeded)
6231 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6234 /*****************************************************************************
6237 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6239 char *unixname, *queue, *cmd;
6240 char fmt[] = "lpr -P%s %s";
6243 if(!(unixname = wine_get_unix_file_name(filename)))
6246 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6247 queue = HeapAlloc(GetProcessHeap(), 0, len);
6248 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6250 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6251 sprintf(cmd, fmt, queue, unixname);
6253 TRACE("printing with: %s\n", cmd);
6256 HeapFree(GetProcessHeap(), 0, cmd);
6257 HeapFree(GetProcessHeap(), 0, queue);
6258 HeapFree(GetProcessHeap(), 0, unixname);
6262 /*****************************************************************************
6265 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6267 #if HAVE_CUPS_CUPS_H
6270 char *unixname, *queue, *doc_titleA;
6274 if(!(unixname = wine_get_unix_file_name(filename)))
6277 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6278 queue = HeapAlloc(GetProcessHeap(), 0, len);
6279 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6281 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6282 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6283 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6285 TRACE("printing via cups\n");
6286 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6287 HeapFree(GetProcessHeap(), 0, doc_titleA);
6288 HeapFree(GetProcessHeap(), 0, queue);
6289 HeapFree(GetProcessHeap(), 0, unixname);
6295 return schedule_lpr(printer_name, filename);
6299 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6306 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6310 if(HIWORD(wparam) == BN_CLICKED)
6312 if(LOWORD(wparam) == IDOK)
6315 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6318 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6319 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6321 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6323 WCHAR caption[200], message[200];
6326 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6327 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6328 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6329 if(mb_ret == IDCANCEL)
6331 HeapFree(GetProcessHeap(), 0, filename);
6335 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6336 if(hf == INVALID_HANDLE_VALUE)
6338 WCHAR caption[200], message[200];
6340 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6341 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6342 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6343 HeapFree(GetProcessHeap(), 0, filename);
6347 DeleteFileW(filename);
6348 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6350 EndDialog(hwnd, IDOK);
6353 if(LOWORD(wparam) == IDCANCEL)
6355 EndDialog(hwnd, IDCANCEL);
6364 /*****************************************************************************
6367 static BOOL get_filename(LPWSTR *filename)
6369 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6370 file_dlg_proc, (LPARAM)filename) == IDOK;
6373 /*****************************************************************************
6376 static BOOL schedule_file(LPCWSTR filename)
6378 LPWSTR output = NULL;
6380 if(get_filename(&output))
6382 TRACE("copy to %s\n", debugstr_w(output));
6383 CopyFileW(filename, output, FALSE);
6384 HeapFree(GetProcessHeap(), 0, output);
6390 /*****************************************************************************
6393 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6396 char *unixname, *cmdA;
6398 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6402 if(!(unixname = wine_get_unix_file_name(filename)))
6405 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6406 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6407 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6409 TRACE("printing with: %s\n", cmdA);
6411 if((file_fd = open(unixname, O_RDONLY)) == -1)
6416 ERR("pipe() failed!\n");
6426 /* reset signals that we previously set to SIG_IGN */
6427 signal(SIGPIPE, SIG_DFL);
6428 signal(SIGCHLD, SIG_DFL);
6434 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6435 write(fds[1], buf, no_read);
6440 if(file_fd != -1) close(file_fd);
6441 if(fds[0] != -1) close(fds[0]);
6442 if(fds[1] != -1) close(fds[1]);
6444 HeapFree(GetProcessHeap(), 0, cmdA);
6445 HeapFree(GetProcessHeap(), 0, unixname);
6452 /*****************************************************************************
6455 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6457 int in_fd, out_fd, no_read;
6460 char *unixname, *outputA;
6463 if(!(unixname = wine_get_unix_file_name(filename)))
6466 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6467 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6468 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6470 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6471 in_fd = open(unixname, O_RDONLY);
6472 if(out_fd == -1 || in_fd == -1)
6475 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6476 write(out_fd, buf, no_read);
6480 if(in_fd != -1) close(in_fd);
6481 if(out_fd != -1) close(out_fd);
6482 HeapFree(GetProcessHeap(), 0, outputA);
6483 HeapFree(GetProcessHeap(), 0, unixname);
6487 /*****************************************************************************
6488 * ScheduleJob [WINSPOOL.@]
6491 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6493 opened_printer_t *printer;
6495 struct list *cursor, *cursor2;
6497 TRACE("(%p, %x)\n", hPrinter, dwJobID);
6498 EnterCriticalSection(&printer_handles_cs);
6499 printer = get_opened_printer(hPrinter);
6503 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6505 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6508 if(job->job_id != dwJobID) continue;
6510 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6511 if(hf != INVALID_HANDLE_VALUE)
6513 PRINTER_INFO_5W *pi5;
6517 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6518 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6520 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6521 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6522 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6523 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6524 debugstr_w(pi5->pPortName));
6528 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6529 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6531 DWORD type, count = sizeof(output);
6532 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6535 if(output[0] == '|')
6537 schedule_pipe(output + 1, job->filename);
6541 schedule_unixfile(output, job->filename);
6543 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6545 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6547 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6549 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6551 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6553 schedule_file(job->filename);
6557 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6559 HeapFree(GetProcessHeap(), 0, pi5);
6561 DeleteFileW(job->filename);
6563 list_remove(cursor);
6564 HeapFree(GetProcessHeap(), 0, job->document_title);
6565 HeapFree(GetProcessHeap(), 0, job->filename);
6566 HeapFree(GetProcessHeap(), 0, job);
6571 LeaveCriticalSection(&printer_handles_cs);
6575 /*****************************************************************************
6576 * StartDocDlgA [WINSPOOL.@]
6578 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6580 UNICODE_STRING usBuffer;
6583 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
6586 docW.cbSize = sizeof(docW);
6587 if (doc->lpszDocName)
6589 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
6590 if (!(docW.lpszDocName = docnameW)) return NULL;
6592 if (doc->lpszOutput)
6594 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
6595 if (!(docW.lpszOutput = outputW)) return NULL;
6597 if (doc->lpszDatatype)
6599 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
6600 if (!(docW.lpszDatatype = datatypeW)) return NULL;
6602 docW.fwType = doc->fwType;
6604 retW = StartDocDlgW(hPrinter, &docW);
6608 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6609 ret = HeapAlloc(GetProcessHeap(), 0, len);
6610 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6611 HeapFree(GetProcessHeap(), 0, retW);
6614 HeapFree(GetProcessHeap(), 0, datatypeW);
6615 HeapFree(GetProcessHeap(), 0, outputW);
6616 HeapFree(GetProcessHeap(), 0, docnameW);
6621 /*****************************************************************************
6622 * StartDocDlgW [WINSPOOL.@]
6624 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6625 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6626 * port is "FILE:". Also returns the full path if passed a relative path.
6628 * The caller should free the returned string from the process heap.
6630 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6635 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6637 PRINTER_INFO_5W *pi5;
6638 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6639 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6641 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6642 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6643 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6645 HeapFree(GetProcessHeap(), 0, pi5);
6648 HeapFree(GetProcessHeap(), 0, pi5);
6651 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6654 get_filename(&name);
6657 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6659 HeapFree(GetProcessHeap(), 0, name);
6662 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6663 GetFullPathNameW(name, len, ret, NULL);
6664 HeapFree(GetProcessHeap(), 0, name);
6669 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6672 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6673 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6675 attr = GetFileAttributesW(ret);
6676 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6678 HeapFree(GetProcessHeap(), 0, ret);