4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
64 #include "ddk/winsplp.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
69 /* ############################### */
71 static CRITICAL_SECTION monitor_handles_cs;
72 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
74 0, 0, &monitor_handles_cs,
75 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
76 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
78 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
81 static CRITICAL_SECTION printer_handles_cs;
82 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
84 0, 0, &printer_handles_cs,
85 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
88 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
90 /* ############################### */
101 LPPORT_INFO_2W cache; /* cached PORT_INFO_2W data */
102 DWORD pi1_needed; /* size for PORT_INFO_1W */
103 DWORD pi2_needed; /* size for PORT_INFO_2W */
104 DWORD returned; /* number of cached PORT_INFO_2W - entries */
127 WCHAR *document_title;
135 LPCWSTR versionregpath;
136 LPCWSTR versionsubdir;
139 /* ############################### */
141 static struct list monitor_handles = LIST_INIT( monitor_handles );
143 static opened_printer_t **printer_handles;
144 static int nb_printer_handles;
145 static LONG next_job_id = 1;
147 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
148 WORD fwCapability, LPSTR lpszOutput,
150 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
151 LPSTR lpszDevice, LPSTR lpszPort,
152 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
155 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
156 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
157 'c','o','n','t','r','o','l','\\',
158 'P','r','i','n','t','\\',
159 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
160 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
162 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
163 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
164 'C','o','n','t','r','o','l','\\',
165 'P','r','i','n','t','\\',
166 'M','o','n','i','t','o','r','s','\\',0};
168 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
169 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
170 'C','o','n','t','r','o','l','\\',
171 'P','r','i','n','t','\\',
172 'P','r','i','n','t','e','r','s',0};
174 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
176 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
177 'M','i','c','r','o','s','o','f','t','\\',
178 'W','i','n','d','o','w','s',' ','N','T','\\',
179 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
180 'W','i','n','d','o','w','s',0};
182 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
183 'M','i','c','r','o','s','o','f','t','\\',
184 'W','i','n','d','o','w','s',' ','N','T','\\',
185 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
186 'D','e','v','i','c','e','s',0};
188 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
189 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
190 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
191 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
192 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
193 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
194 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
196 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
197 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
199 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
200 'i','o','n',' ','F','i','l','e',0};
201 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
202 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
203 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
205 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
207 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
208 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
209 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
210 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
211 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
212 static const WCHAR NameW[] = {'N','a','m','e',0};
213 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
214 static const WCHAR PortW[] = {'P','o','r','t',0};
215 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
217 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
219 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
220 'v','e','r','D','a','t','a',0};
221 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
223 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
224 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
225 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
226 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
227 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
228 static const WCHAR emptyStringW[] = {0};
230 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
232 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
233 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
234 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
236 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
237 'D','o','c','u','m','e','n','t',0};
239 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
240 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
241 DWORD Level, LPBYTE pDriverInfo,
242 DWORD cbBuf, LPDWORD pcbNeeded,
244 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
245 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
247 /******************************************************************
248 * validate the user-supplied printing-environment [internal]
251 * env [I] PTR to Environment-String or NULL
255 * Success: PTR to printenv_t
258 * An empty string is handled the same way as NULL.
259 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
263 static const printenv_t * validate_envW(LPCWSTR env)
265 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
266 3, Version3_RegPathW, Version3_SubdirW};
267 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
268 0, emptyStringW, emptyStringW};
269 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
271 const printenv_t *result = NULL;
274 TRACE("testing %s\n", debugstr_w(env));
277 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
279 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
281 result = all_printenv[i];
286 if (result == NULL) {
287 FIXME("unsupported Environment: %s\n", debugstr_w(env));
288 SetLastError(ERROR_INVALID_ENVIRONMENT);
290 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
294 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
296 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
302 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
303 if passed a NULL string. This returns NULLs to the result.
305 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
309 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
310 return usBufferPtr->Buffer;
312 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
316 static LPWSTR strdupW(LPCWSTR p)
322 len = (strlenW(p) + 1) * sizeof(WCHAR);
323 ret = HeapAlloc(GetProcessHeap(), 0, len);
329 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
332 /* If forcing, or no profile string entry for device yet, set the entry
334 * The always change entry if not WINEPS yet is discussable.
337 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
339 !strstr(qbuf,"WINEPS.DRV")
341 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
344 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
345 WriteProfileStringA("windows","device",buf);
346 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
347 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
350 HeapFree(GetProcessHeap(),0,buf);
354 #ifdef HAVE_CUPS_CUPS_H
355 static typeof(cupsGetDests) *pcupsGetDests;
356 static typeof(cupsGetPPD) *pcupsGetPPD;
357 static typeof(cupsPrintFile) *pcupsPrintFile;
358 static void *cupshandle;
360 static BOOL CUPS_LoadPrinters(void)
363 BOOL hadprinter = FALSE;
365 PRINTER_INFO_2A pinfo2a;
367 HKEY hkeyPrinter, hkeyPrinters, hkey;
369 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
372 TRACE("loaded %s\n", SONAME_LIBCUPS);
375 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
376 if (!p##x) return FALSE;
379 DYNCUPS(cupsGetDests);
380 DYNCUPS(cupsPrintFile);
383 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
385 ERR("Can't create Printers key\n");
389 nrofdests = pcupsGetDests(&dests);
390 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
391 for (i=0;i<nrofdests;i++) {
392 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
393 sprintf(port,"LPR:%s",dests[i].name);
394 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
395 sprintf(devline,"WINEPS.DRV,%s",port);
396 WriteProfileStringA("devices",dests[i].name,devline);
397 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
398 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
401 HeapFree(GetProcessHeap(),0,devline);
403 TRACE("Printer %d: %s\n", i, dests[i].name);
404 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
405 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
407 TRACE("Printer already exists\n");
408 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
409 RegCloseKey(hkeyPrinter);
411 static CHAR data_type[] = "RAW",
412 print_proc[] = "WinPrint",
413 driver_name[] = "PS Driver",
414 comment[] = "WINEPS Printer using CUPS",
415 location[] = "<physical location of printer>",
416 params[] = "<parameters?>",
417 share_name[] = "<share name?>",
418 sep_file[] = "<sep file?>";
420 memset(&pinfo2a,0,sizeof(pinfo2a));
421 pinfo2a.pPrinterName = dests[i].name;
422 pinfo2a.pDatatype = data_type;
423 pinfo2a.pPrintProcessor = print_proc;
424 pinfo2a.pDriverName = driver_name;
425 pinfo2a.pComment = comment;
426 pinfo2a.pLocation = location;
427 pinfo2a.pPortName = port;
428 pinfo2a.pParameters = params;
429 pinfo2a.pShareName = share_name;
430 pinfo2a.pSepFile = sep_file;
432 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
433 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
434 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
437 HeapFree(GetProcessHeap(),0,port);
440 if (dests[i].is_default)
441 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
443 RegCloseKey(hkeyPrinters);
449 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
450 PRINTER_INFO_2A pinfo2a;
451 char *e,*s,*name,*prettyname,*devname;
452 BOOL ret = FALSE, set_default = FALSE;
453 char *port,*devline,*env_default;
454 HKEY hkeyPrinter, hkeyPrinters, hkey;
456 while (isspace(*pent)) pent++;
457 s = strchr(pent,':');
459 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
467 TRACE("name=%s entry=%s\n",name, pent);
469 if(ispunct(*name)) { /* a tc entry, not a real printer */
470 TRACE("skipping tc entry\n");
474 if(strstr(pent,":server")) { /* server only version so skip */
475 TRACE("skipping server entry\n");
479 /* Determine whether this is a postscript printer. */
482 env_default = getenv("PRINTER");
484 /* Get longest name, usually the one at the right for later display. */
485 while((s=strchr(prettyname,'|'))) {
488 while(isspace(*--e)) *e = '\0';
489 TRACE("\t%s\n", debugstr_a(prettyname));
490 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
491 for(prettyname = s+1; isspace(*prettyname); prettyname++)
494 e = prettyname + strlen(prettyname);
495 while(isspace(*--e)) *e = '\0';
496 TRACE("\t%s\n", debugstr_a(prettyname));
497 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
499 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
500 * if it is too long, we use it as comment below. */
501 devname = prettyname;
502 if (strlen(devname)>=CCHDEVICENAME-1)
504 if (strlen(devname)>=CCHDEVICENAME-1) {
509 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
510 sprintf(port,"LPR:%s",name);
512 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
513 sprintf(devline,"WINEPS.DRV,%s",port);
514 WriteProfileStringA("devices",devname,devline);
515 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
516 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
519 HeapFree(GetProcessHeap(),0,devline);
521 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
523 ERR("Can't create Printers key\n");
527 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
528 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
530 TRACE("Printer already exists\n");
531 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
532 RegCloseKey(hkeyPrinter);
534 static CHAR data_type[] = "RAW",
535 print_proc[] = "WinPrint",
536 driver_name[] = "PS Driver",
537 comment[] = "WINEPS Printer using LPR",
538 params[] = "<parameters?>",
539 share_name[] = "<share name?>",
540 sep_file[] = "<sep file?>";
542 memset(&pinfo2a,0,sizeof(pinfo2a));
543 pinfo2a.pPrinterName = devname;
544 pinfo2a.pDatatype = data_type;
545 pinfo2a.pPrintProcessor = print_proc;
546 pinfo2a.pDriverName = driver_name;
547 pinfo2a.pComment = comment;
548 pinfo2a.pLocation = prettyname;
549 pinfo2a.pPortName = port;
550 pinfo2a.pParameters = params;
551 pinfo2a.pShareName = share_name;
552 pinfo2a.pSepFile = sep_file;
554 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
555 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
556 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
559 RegCloseKey(hkeyPrinters);
561 if (isfirst || set_default)
562 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
564 HeapFree(GetProcessHeap(), 0, port);
566 HeapFree(GetProcessHeap(), 0, name);
571 PRINTCAP_LoadPrinters(void) {
572 BOOL hadprinter = FALSE;
576 BOOL had_bash = FALSE;
578 f = fopen("/etc/printcap","r");
582 while(fgets(buf,sizeof(buf),f)) {
585 end=strchr(buf,'\n');
589 while(isspace(*start)) start++;
590 if(*start == '#' || *start == '\0')
593 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
594 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
595 HeapFree(GetProcessHeap(),0,pent);
599 if (end && *--end == '\\') {
606 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
609 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
615 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
616 HeapFree(GetProcessHeap(),0,pent);
622 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
625 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
626 lstrlenW(value) * sizeof(WCHAR));
628 return ERROR_FILE_NOT_FOUND;
631 void WINSPOOL_LoadSystemPrinters(void)
633 HKEY hkey, hkeyPrinters;
636 DWORD needed, num, i;
637 WCHAR PrinterName[256];
639 static CHAR name[] = "PS Driver",
640 driver_path[] = "wineps16",
641 data_file[] = "<datafile?>",
642 config_file[] = "wineps16",
643 help_file[] = "<helpfile?>",
644 dep_file[] = "<dependend files?>",
645 monitor_name[] = "<monitor name?>",
646 default_data_type[] = "RAW";
648 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
650 di3a.pEnvironment = NULL; /* NULL means auto */
651 di3a.pDriverPath = driver_path;
652 di3a.pDataFile = data_file;
653 di3a.pConfigFile = config_file;
654 di3a.pHelpFile = help_file;
655 di3a.pDependentFiles = dep_file;
656 di3a.pMonitorName = monitor_name;
657 di3a.pDefaultDataType = default_data_type;
659 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
660 ERR("Failed adding PS Driver (%d)\n",GetLastError());
664 /* This ensures that all printer entries have a valid Name value. If causes
665 problems later if they don't. If one is found to be missed we create one
666 and set it equal to the name of the key */
667 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
668 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
669 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
670 for(i = 0; i < num; i++) {
671 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
672 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
673 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
674 set_reg_szW(hkey, NameW, PrinterName);
681 RegCloseKey(hkeyPrinters);
684 /* We want to avoid calling AddPrinter on printers as much as
685 possible, because on cups printers this will (eventually) lead
686 to a call to cupsGetPPD which takes forever, even with non-cups
687 printers AddPrinter takes a while. So we'll tag all printers that
688 were automatically added last time around, if they still exist
689 we'll leave them be otherwise we'll delete them. */
690 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
692 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
693 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
694 for(i = 0; i < num; i++) {
695 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
696 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
697 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
699 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
707 HeapFree(GetProcessHeap(), 0, pi);
711 #ifdef HAVE_CUPS_CUPS_H
712 done = CUPS_LoadPrinters();
715 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
716 /* Check for [ppd] section in config file before parsing /etc/printcap */
717 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
718 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
719 &hkey) == ERROR_SUCCESS) {
721 PRINTCAP_LoadPrinters();
725 /* Now enumerate the list again and delete any printers that a still tagged */
726 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
728 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
729 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
730 for(i = 0; i < num; i++) {
731 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
732 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
733 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
734 DWORD dw, type, size = sizeof(dw);
735 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
736 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
746 HeapFree(GetProcessHeap(), 0, pi);
753 /*****************************************************************************
754 * enumerate the local monitors (INTERNAL)
756 * returns the needed size (in bytes) for pMonitors
757 * and *lpreturned is set to number of entries returned in pMonitors
760 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
765 LPMONITOR_INFO_2W mi;
766 WCHAR buffer[MAX_PATH];
767 WCHAR dllname[MAX_PATH];
775 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
777 numentries = *lpreturned; /* this is 0, when we scan the registry */
778 len = entrysize * numentries;
779 ptr = (LPWSTR) &pMonitors[len];
782 len = sizeof(buffer);
785 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
786 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
787 /* Scan all Monitor-Registry-Keys */
788 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
789 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
790 dllsize = sizeof(dllname);
793 /* The Monitor must have a Driver-DLL */
794 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
795 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
796 /* We found a valid DLL for this Monitor. */
797 TRACE("using Driver: %s\n", debugstr_w(dllname));
802 /* Windows returns only Port-Monitors here, but to simplify our code,
803 we do no filtering for Language-Monitors */
807 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
809 /* we install and return only monitors for "Windows NT x86" */
810 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
814 /* required size is calculated. Now fill the user-buffer */
815 if (pMonitors && (cbBuf >= needed)){
816 mi = (LPMONITOR_INFO_2W) pMonitors;
817 pMonitors += entrysize;
819 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
821 lstrcpyW(ptr, buffer); /* Name of the Monitor */
822 ptr += (len+1); /* len is lstrlenW(monitorname) */
824 mi->pEnvironment = ptr;
825 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
826 ptr += (lstrlenW(envname_x86W)+1);
829 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
830 ptr += (dllsize / sizeof(WCHAR));
835 len = sizeof(buffer);
840 *lpreturned = numentries;
841 TRACE("need %d byte for %d entries\n", needed, numentries);
845 /******************************************************************
846 * monitor_unload [internal]
848 * release a printmonitor and unload it from memory, when needed
851 static void monitor_unload(monitor_t * pm)
853 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
855 EnterCriticalSection(&monitor_handles_cs);
857 if (pm->refcount) pm->refcount--;
859 if (pm->refcount == 0) {
860 list_remove(&pm->entry);
861 FreeLibrary(pm->hdll);
862 HeapFree(GetProcessHeap(), 0, pm->name);
863 HeapFree(GetProcessHeap(), 0, pm->dllname);
864 HeapFree(GetProcessHeap(), 0, pm);
866 LeaveCriticalSection(&monitor_handles_cs);
869 /******************************************************************
870 * monitor_unloadall [internal]
872 * release all printmonitors and unload them from memory, when needed
875 static void monitor_unloadall(void)
880 EnterCriticalSection(&monitor_handles_cs);
881 /* iterate through the list, with safety against removal */
882 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
886 LeaveCriticalSection(&monitor_handles_cs);
889 /******************************************************************
890 * monitor_load [internal]
892 * load a printmonitor, get the dllname from the registry, when needed
893 * initialize the monitor and dump found function-pointers
895 * On failure, SetLastError() is called and NULL is returned
898 static monitor_t * monitor_load(LPWSTR name, LPWSTR dllname)
900 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
901 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
902 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
903 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
904 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
906 monitor_t * pm = NULL;
908 LPWSTR regroot = NULL;
909 LPWSTR driver = dllname;
911 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
912 /* Is the Monitor already loaded? */
913 EnterCriticalSection(&monitor_handles_cs);
915 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
917 if (lstrcmpW(name, cursor->name) == 0) {
924 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
925 if (pm == NULL) goto cleanup;
926 list_add_tail(&monitor_handles, &pm->entry);
930 if (pm->name == NULL) {
931 /* Load the monitor */
932 LPMONITOREX pmonitorEx;
935 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
936 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
939 lstrcpyW(regroot, MonitorsW);
940 lstrcatW(regroot, name);
941 /* Get the Driver from the Registry */
942 if (driver == NULL) {
945 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
946 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
947 &namesize) == ERROR_SUCCESS) {
948 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
949 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
956 pm->name = strdupW(name);
957 pm->dllname = strdupW(driver);
959 if (!regroot || !pm->name || !pm->dllname) {
961 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
966 pm->hdll = LoadLibraryW(driver);
967 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
969 if (pm->hdll == NULL) {
971 SetLastError(ERROR_MOD_NOT_FOUND);
976 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
977 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
978 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
979 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
980 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
983 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
984 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
985 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
986 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
987 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
989 if (pInitializePrintMonitorUI != NULL) {
990 pm->monitorUI = pInitializePrintMonitorUI();
991 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
993 TRACE( "0x%08x: dwMonitorSize (%d)\n",
994 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
999 if (pInitializePrintMonitor != NULL) {
1000 pmonitorEx = pInitializePrintMonitor(regroot);
1001 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1002 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1005 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1006 pm->monitor = &(pmonitorEx->Monitor);
1011 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1016 if (pInitializePrintMonitor2 != NULL) {
1017 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1019 if (pInitializeMonitorEx != NULL) {
1020 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1022 if (pInitializeMonitor != NULL) {
1023 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1026 if (!pm->monitor && !pm->monitorUI) {
1028 SetLastError(ERROR_PROC_NOT_FOUND);
1033 LeaveCriticalSection(&monitor_handles_cs);
1034 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1035 HeapFree(GetProcessHeap(), 0, regroot);
1036 TRACE("=> %p\n", pm);
1040 /******************************************************************
1041 * monitor_loadall [internal]
1043 * Load all registered monitors
1046 static DWORD monitor_loadall(void)
1049 DWORD registered = 0;
1052 WCHAR buffer[MAX_PATH];
1055 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1056 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1057 NULL, NULL, NULL, NULL, NULL);
1059 TRACE("%d monitors registered\n", registered);
1061 EnterCriticalSection(&monitor_handles_cs);
1062 while (id < registered) {
1064 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1065 pm = monitor_load(buffer, NULL);
1069 LeaveCriticalSection(&monitor_handles_cs);
1070 RegCloseKey(hmonitors);
1072 TRACE("%d monitors loaded\n", loaded);
1076 /******************************************************************
1077 * enumerate the local Ports from all loaded monitors (internal)
1079 * returns the needed size (in bytes) for pPorts
1080 * and *lpreturned is set to number of entries returned in pPorts
1083 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1087 LPPORT_INFO_2W cache;
1097 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1098 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1100 numentries = *lpreturned; /* this is 0, when we scan the registry */
1101 needed = entrysize * numentries;
1102 ptr = (LPWSTR) &pPorts[needed];
1107 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1109 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1110 if (pm->cache == NULL) {
1111 res = pm->monitor->pfnEnumPorts(NULL, 2, NULL, 0, &(pm->pi2_needed), &(pm->returned));
1112 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1113 pm->cache = HeapAlloc(GetProcessHeap(), 0, (pm->pi2_needed));
1114 res = pm->monitor->pfnEnumPorts(NULL, 2, (LPBYTE) pm->cache, pm->pi2_needed, &(pm->pi2_needed), &(pm->returned));
1116 TRACE("(%s) got %d with %d (cache need %d byte for %d entries)\n",
1117 debugstr_w(pm->name), res, GetLastError(), pm->pi2_needed, pm->returned);
1120 if (pm->cache && (level == 1) && (pm->pi1_needed == 0) && (pm->returned > 0)) {
1123 while (cacheindex < (pm->returned)) {
1124 pm->pi1_needed += sizeof(PORT_INFO_1W);
1125 pm->pi1_needed += (lstrlenW(cache->pPortName) + 1) * sizeof(WCHAR);
1129 TRACE("%d byte for %d cached PORT_INFO_1W entries (%s)\n",
1130 pm->pi1_needed, cacheindex, debugstr_w(pm->name));
1132 numentries += pm->returned;
1133 needed += (level == 1) ? pm->pi1_needed : pm->pi2_needed;
1135 /* fill the buffer, if we have one */
1136 if (pPorts && (cbBuf >= needed )) {
1139 while (cacheindex < pm->returned) {
1140 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1141 out->pPortName = ptr;
1142 lstrcpyW(ptr, cache->pPortName);
1143 ptr += (lstrlenW(ptr)+1);
1145 out->pMonitorName = ptr;
1146 lstrcpyW(ptr, cache->pMonitorName);
1147 ptr += (lstrlenW(ptr)+1);
1149 out->pDescription = ptr;
1150 lstrcpyW(ptr, cache->pDescription);
1151 ptr += (lstrlenW(ptr)+1);
1152 out->fPortType = cache->fPortType;
1153 out->Reserved = cache->Reserved;
1163 *lpreturned = numentries;
1164 TRACE("need %d byte for %d entries\n", needed, numentries);
1168 /******************************************************************
1169 * get_opened_printer_entry
1170 * Get the first place empty in the opened printer table
1173 * - pDefault is ignored
1175 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1177 UINT_PTR handle = nb_printer_handles, i;
1178 jobqueue_t *queue = NULL;
1179 opened_printer_t *printer = NULL;
1181 EnterCriticalSection(&printer_handles_cs);
1183 for (i = 0; i < nb_printer_handles; i++)
1185 if (!printer_handles[i])
1187 if(handle == nb_printer_handles)
1192 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1193 queue = printer_handles[i]->queue;
1197 if (handle >= nb_printer_handles)
1199 opened_printer_t **new_array;
1200 if (printer_handles)
1201 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1202 (nb_printer_handles + 16) * sizeof(*new_array) );
1204 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1205 (nb_printer_handles + 16) * sizeof(*new_array) );
1212 printer_handles = new_array;
1213 nb_printer_handles += 16;
1216 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1223 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
1224 if (!printer->name) {
1228 strcpyW(printer->name, name);
1232 printer->queue = queue;
1235 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1236 if (!printer->queue) {
1240 list_init(&printer->queue->jobs);
1241 printer->queue->ref = 0;
1243 InterlockedIncrement(&printer->queue->ref);
1245 printer_handles[handle] = printer;
1248 LeaveCriticalSection(&printer_handles_cs);
1249 if (!handle && printer) {
1250 /* Something Failed: Free the Buffers */
1251 HeapFree(GetProcessHeap(), 0, printer->name);
1252 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1253 HeapFree(GetProcessHeap(), 0, printer);
1256 return (HANDLE)handle;
1259 /******************************************************************
1260 * get_opened_printer
1261 * Get the pointer to the opened printer referred by the handle
1263 static opened_printer_t *get_opened_printer(HANDLE hprn)
1265 UINT_PTR idx = (UINT_PTR)hprn;
1266 opened_printer_t *ret = NULL;
1268 EnterCriticalSection(&printer_handles_cs);
1270 if ((idx <= 0) || (idx > nb_printer_handles))
1273 ret = printer_handles[idx - 1];
1275 LeaveCriticalSection(&printer_handles_cs);
1279 /******************************************************************
1280 * get_opened_printer_name
1281 * Get the pointer to the opened printer name referred by the handle
1283 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1285 opened_printer_t *printer = get_opened_printer(hprn);
1286 if(!printer) return NULL;
1287 return printer->name;
1290 /******************************************************************
1291 * WINSPOOL_GetOpenedPrinterRegKey
1294 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1296 LPCWSTR name = get_opened_printer_name(hPrinter);
1300 if(!name) return ERROR_INVALID_HANDLE;
1302 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1306 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1308 ERR("Can't find opened printer %s in registry\n",
1310 RegCloseKey(hkeyPrinters);
1311 return ERROR_INVALID_PRINTER_NAME; /* ? */
1313 RegCloseKey(hkeyPrinters);
1314 return ERROR_SUCCESS;
1317 /******************************************************************
1320 * Get the pointer to the specified job.
1321 * Should hold the printer_handles_cs before calling.
1323 static job_t *get_job(HANDLE hprn, DWORD JobId)
1325 opened_printer_t *printer = get_opened_printer(hprn);
1328 if(!printer) return NULL;
1329 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1331 if(job->job_id == JobId)
1337 /***********************************************************
1340 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1343 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1346 Formname = (dmA->dmSize > off_formname);
1347 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1348 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1349 dmW->dmDeviceName, CCHDEVICENAME);
1351 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1352 dmA->dmSize - CCHDEVICENAME);
1354 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1355 off_formname - CCHDEVICENAME);
1356 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1357 dmW->dmFormName, CCHFORMNAME);
1358 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1359 (off_formname + CCHFORMNAME));
1362 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1363 dmA->dmDriverExtra);
1367 /***********************************************************
1369 * Creates an ascii copy of supplied devmode on heap
1371 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1376 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1378 if(!dmW) return NULL;
1379 Formname = (dmW->dmSize > off_formname);
1380 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1381 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1382 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1383 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1385 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1386 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1388 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1389 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1390 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1391 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1392 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1393 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1396 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1397 dmW->dmDriverExtra);
1401 /***********************************************************
1402 * PRINTER_INFO_2AtoW
1403 * Creates a unicode copy of PRINTER_INFO_2A on heap
1405 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1407 LPPRINTER_INFO_2W piW;
1408 UNICODE_STRING usBuffer;
1410 if(!piA) return NULL;
1411 piW = HeapAlloc(heap, 0, sizeof(*piW));
1412 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1414 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1415 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1416 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1417 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1418 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1419 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1420 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1421 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1422 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1423 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1424 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1425 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1429 /***********************************************************
1430 * FREE_PRINTER_INFO_2W
1431 * Free PRINTER_INFO_2W and all strings
1433 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1437 HeapFree(heap,0,piW->pServerName);
1438 HeapFree(heap,0,piW->pPrinterName);
1439 HeapFree(heap,0,piW->pShareName);
1440 HeapFree(heap,0,piW->pPortName);
1441 HeapFree(heap,0,piW->pDriverName);
1442 HeapFree(heap,0,piW->pComment);
1443 HeapFree(heap,0,piW->pLocation);
1444 HeapFree(heap,0,piW->pDevMode);
1445 HeapFree(heap,0,piW->pSepFile);
1446 HeapFree(heap,0,piW->pPrintProcessor);
1447 HeapFree(heap,0,piW->pDatatype);
1448 HeapFree(heap,0,piW->pParameters);
1449 HeapFree(heap,0,piW);
1453 /******************************************************************
1454 * DeviceCapabilities [WINSPOOL.@]
1455 * DeviceCapabilitiesA [WINSPOOL.@]
1458 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1459 LPSTR pOutput, LPDEVMODEA lpdm)
1463 if (!GDI_CallDeviceCapabilities16)
1465 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1467 if (!GDI_CallDeviceCapabilities16) return -1;
1469 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1471 /* If DC_PAPERSIZE map POINT16s to POINTs */
1472 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1473 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1474 POINT *pt = (POINT *)pOutput;
1476 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1477 for(i = 0; i < ret; i++, pt++)
1482 HeapFree( GetProcessHeap(), 0, tmp );
1488 /*****************************************************************************
1489 * DeviceCapabilitiesW [WINSPOOL.@]
1491 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1494 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1495 WORD fwCapability, LPWSTR pOutput,
1496 const DEVMODEW *pDevMode)
1498 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1499 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1500 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1503 if(pOutput && (fwCapability == DC_BINNAMES ||
1504 fwCapability == DC_FILEDEPENDENCIES ||
1505 fwCapability == DC_PAPERNAMES)) {
1506 /* These need A -> W translation */
1509 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1513 switch(fwCapability) {
1518 case DC_FILEDEPENDENCIES:
1522 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1523 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1525 for(i = 0; i < ret; i++)
1526 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1527 pOutput + (i * size), size);
1528 HeapFree(GetProcessHeap(), 0, pOutputA);
1530 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1531 (LPSTR)pOutput, dmA);
1533 HeapFree(GetProcessHeap(),0,pPortA);
1534 HeapFree(GetProcessHeap(),0,pDeviceA);
1535 HeapFree(GetProcessHeap(),0,dmA);
1539 /******************************************************************
1540 * DocumentPropertiesA [WINSPOOL.@]
1542 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1544 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1545 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1546 LPDEVMODEA pDevModeInput,DWORD fMode )
1548 LPSTR lpName = pDeviceName;
1549 static CHAR port[] = "LPT1:";
1552 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1553 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1557 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1559 ERR("no name from hPrinter?\n");
1560 SetLastError(ERROR_INVALID_HANDLE);
1563 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1566 if (!GDI_CallExtDeviceMode16)
1568 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1570 if (!GDI_CallExtDeviceMode16) {
1571 ERR("No CallExtDeviceMode16?\n");
1575 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1576 pDevModeInput, NULL, fMode);
1579 HeapFree(GetProcessHeap(),0,lpName);
1584 /*****************************************************************************
1585 * DocumentPropertiesW (WINSPOOL.@)
1587 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1589 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1591 LPDEVMODEW pDevModeOutput,
1592 LPDEVMODEW pDevModeInput, DWORD fMode)
1595 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1596 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1597 LPDEVMODEA pDevModeOutputA = NULL;
1600 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1601 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1603 if(pDevModeOutput) {
1604 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1605 if(ret < 0) return ret;
1606 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1608 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1609 pDevModeInputA, fMode);
1610 if(pDevModeOutput) {
1611 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1612 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1614 if(fMode == 0 && ret > 0)
1615 ret += (CCHDEVICENAME + CCHFORMNAME);
1616 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1617 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1621 /******************************************************************
1622 * OpenPrinterA [WINSPOOL.@]
1627 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1628 LPPRINTER_DEFAULTSA pDefault)
1630 UNICODE_STRING lpPrinterNameW;
1631 UNICODE_STRING usBuffer;
1632 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1633 PWSTR pwstrPrinterNameW;
1636 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1639 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1640 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1641 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1642 pDefaultW = &DefaultW;
1644 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1646 RtlFreeUnicodeString(&usBuffer);
1647 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1649 RtlFreeUnicodeString(&lpPrinterNameW);
1653 /******************************************************************
1654 * OpenPrinterW [WINSPOOL.@]
1656 * Open a Printer / Printserver or a Printer-Object
1659 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1660 * phPrinter [O] The resulting Handle is stored here
1661 * pDefault [I] PTR to Default Printer Settings or NULL
1668 * lpPrinterName is one of:
1669 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1670 *| Printer: "PrinterName"
1671 *| Printer-Object: "PrinterName,Job xxx"
1672 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1673 *| XcvPort: "Servername,XcvPort PortName"
1676 *| Printer-Object not supported
1677 *| XcvMonitor not supported
1678 *| XcvPort not supported
1679 *| pDefaults is ignored
1682 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1684 HKEY hkeyPrinters = NULL;
1685 HKEY hkeyPrinter = NULL;
1687 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1689 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1690 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1693 if(lpPrinterName != NULL)
1695 /* Check any Printer exists */
1696 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1697 ERR("Can't create Printers key\n");
1698 SetLastError(ERROR_FILE_NOT_FOUND);
1701 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1702 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1704 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1705 RegCloseKey(hkeyPrinters);
1706 SetLastError(ERROR_INVALID_PRINTER_NAME);
1709 RegCloseKey(hkeyPrinter);
1710 RegCloseKey(hkeyPrinters);
1713 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1714 SetLastError(ERROR_INVALID_PARAMETER);
1718 /* Get the unique handle of the printer or Printserver */
1719 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1720 return (*phPrinter != 0);
1723 /******************************************************************
1724 * AddMonitorA [WINSPOOL.@]
1729 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1731 LPWSTR nameW = NULL;
1734 LPMONITOR_INFO_2A mi2a;
1735 MONITOR_INFO_2W mi2w;
1737 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1738 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1739 mi2a ? debugstr_a(mi2a->pName) : NULL,
1740 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1741 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1744 SetLastError(ERROR_INVALID_LEVEL);
1748 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1754 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1755 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1756 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1759 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1761 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1762 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1763 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1765 if (mi2a->pEnvironment) {
1766 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1767 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1768 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1770 if (mi2a->pDLLName) {
1771 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1772 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1773 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1776 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1778 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1779 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1780 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1782 HeapFree(GetProcessHeap(), 0, nameW);
1786 /******************************************************************************
1787 * AddMonitorW [WINSPOOL.@]
1789 * Install a Printmonitor
1792 * pName [I] Servername or NULL (local Computer)
1793 * Level [I] Structure-Level (Must be 2)
1794 * pMonitors [I] PTR to MONITOR_INFO_2
1801 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1804 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1806 monitor_t * pm = NULL;
1807 LPMONITOR_INFO_2W mi2w;
1813 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1814 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1815 mi2w ? debugstr_w(mi2w->pName) : NULL,
1816 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1817 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1820 SetLastError(ERROR_INVALID_LEVEL);
1824 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1829 if (pName && (pName[0])) {
1830 FIXME("for server %s not implemented\n", debugstr_w(pName));
1831 SetLastError(ERROR_ACCESS_DENIED);
1836 if (!mi2w->pName || (! mi2w->pName[0])) {
1837 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1838 SetLastError(ERROR_INVALID_PARAMETER);
1841 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1842 WARN("Environment %s requested (we support only %s)\n",
1843 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1844 SetLastError(ERROR_INVALID_ENVIRONMENT);
1848 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1849 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1850 SetLastError(ERROR_INVALID_PARAMETER);
1854 /* Load and initialize the monitor. SetLastError() is called on failure */
1855 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1860 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1861 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1865 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1866 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1867 &disposition) == ERROR_SUCCESS) {
1869 /* Some installers set options for the port before calling AddMonitor.
1870 We query the "Driver" entry to verify that the monitor is installed,
1871 before we return an error.
1872 When a user installs two print monitors at the same time with the
1873 same name but with a different driver DLL and a task switch comes
1874 between RegQueryValueExW and RegSetValueExW, a race condition
1875 is possible but silently ignored. */
1879 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1880 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1881 &namesize) == ERROR_SUCCESS)) {
1882 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1883 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1884 9x: ERROR_ALREADY_EXISTS (183) */
1885 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1890 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1891 res = (RegSetValueExW(hentry, DriverW, 0,
1892 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1894 RegCloseKey(hentry);
1901 /******************************************************************
1902 * DeletePrinterDriverA [WINSPOOL.@]
1906 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1908 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1909 debugstr_a(pDriverName));
1910 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1914 /******************************************************************
1915 * DeletePrinterDriverW [WINSPOOL.@]
1919 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1921 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1922 debugstr_w(pDriverName));
1923 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1927 /******************************************************************
1928 * DeleteMonitorA [WINSPOOL.@]
1930 * See DeleteMonitorW.
1933 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1935 LPWSTR nameW = NULL;
1936 LPWSTR EnvironmentW = NULL;
1937 LPWSTR MonitorNameW = NULL;
1942 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1943 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1944 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1948 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1949 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1950 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1953 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1954 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1955 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1958 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1960 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1961 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1962 HeapFree(GetProcessHeap(), 0, nameW);
1966 /******************************************************************
1967 * DeleteMonitorW [WINSPOOL.@]
1969 * Delete a specific Printmonitor from a Printing-Environment
1972 * pName [I] Servername or NULL (local Computer)
1973 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1974 * pMonitorName [I] Name of the Monitor, that should be deleted
1981 * pEnvironment is ignored in Windows for the local Computer.
1985 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1989 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1990 debugstr_w(pMonitorName));
1992 if (pName && (pName[0])) {
1993 FIXME("for server %s not implemented\n", debugstr_w(pName));
1994 SetLastError(ERROR_ACCESS_DENIED);
1998 /* pEnvironment is ignored in Windows for the local Computer */
2000 if (!pMonitorName || !pMonitorName[0]) {
2001 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2002 SetLastError(ERROR_INVALID_PARAMETER);
2006 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2007 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2011 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2012 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2013 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2018 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
2021 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2022 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2026 /******************************************************************
2027 * DeletePortA [WINSPOOL.@]
2033 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2035 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
2036 debugstr_a(pPortName));
2037 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2041 /******************************************************************
2042 * DeletePortW [WINSPOOL.@]
2044 * Delete a specific Port
2047 * pName [I] Servername or NULL (local Computer)
2048 * hWnd [I] Handle to parent Window for the Dialog-Box
2049 * pPortName [I] Name of the Port, that should be deleted
2060 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2062 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
2063 debugstr_w(pPortName));
2064 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2068 /******************************************************************************
2069 * SetPrinterW [WINSPOOL.@]
2071 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2073 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2074 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2078 /******************************************************************************
2079 * WritePrinter [WINSPOOL.@]
2081 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2083 opened_printer_t *printer;
2086 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2088 EnterCriticalSection(&printer_handles_cs);
2089 printer = get_opened_printer(hPrinter);
2092 SetLastError(ERROR_INVALID_HANDLE);
2098 SetLastError(ERROR_SPL_NO_STARTDOC);
2102 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2104 LeaveCriticalSection(&printer_handles_cs);
2108 /*****************************************************************************
2109 * AddFormA [WINSPOOL.@]
2111 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2113 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2117 /*****************************************************************************
2118 * AddFormW [WINSPOOL.@]
2120 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2122 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2126 /*****************************************************************************
2127 * AddJobA [WINSPOOL.@]
2129 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2132 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2136 SetLastError(ERROR_INVALID_LEVEL);
2140 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2143 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2144 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2145 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2146 if(*pcbNeeded > cbBuf) {
2147 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2150 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2151 addjobA->JobId = addjobW->JobId;
2152 addjobA->Path = (char *)(addjobA + 1);
2153 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2159 /*****************************************************************************
2160 * AddJobW [WINSPOOL.@]
2162 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2164 opened_printer_t *printer;
2167 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2168 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2169 WCHAR path[MAX_PATH], filename[MAX_PATH];
2171 ADDJOB_INFO_1W *addjob;
2173 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2175 EnterCriticalSection(&printer_handles_cs);
2177 printer = get_opened_printer(hPrinter);
2180 SetLastError(ERROR_INVALID_HANDLE);
2185 SetLastError(ERROR_INVALID_LEVEL);
2189 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2193 job->job_id = InterlockedIncrement(&next_job_id);
2195 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2196 if(path[len - 1] != '\\')
2198 memcpy(path + len, spool_path, sizeof(spool_path));
2199 sprintfW(filename, fmtW, path, job->job_id);
2201 len = strlenW(filename);
2202 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2203 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2204 job->document_title = strdupW(default_doc_title);
2205 list_add_tail(&printer->queue->jobs, &job->entry);
2207 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2208 if(*pcbNeeded <= cbBuf) {
2209 addjob = (ADDJOB_INFO_1W*)pData;
2210 addjob->JobId = job->job_id;
2211 addjob->Path = (WCHAR *)(addjob + 1);
2212 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2215 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2218 LeaveCriticalSection(&printer_handles_cs);
2222 /*****************************************************************************
2223 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2225 * Return the PATH for the Print-Processors
2227 * See GetPrintProcessorDirectoryW.
2231 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2232 DWORD level, LPBYTE Info,
2233 DWORD cbBuf, LPDWORD pcbNeeded)
2235 LPWSTR serverW = NULL;
2240 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2241 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2245 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2246 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2247 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2251 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2252 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2253 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2256 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2257 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2259 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2262 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2263 cbBuf, NULL, NULL) > 0;
2266 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2267 HeapFree(GetProcessHeap(), 0, envW);
2268 HeapFree(GetProcessHeap(), 0, serverW);
2272 /*****************************************************************************
2273 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2275 * Return the PATH for the Print-Processors
2278 * server [I] Servername (NT only) or NULL (local Computer)
2279 * env [I] Printing-Environment (see below) or NULL (Default)
2280 * level [I] Structure-Level (must be 1)
2281 * Info [O] PTR to Buffer that receives the Result
2282 * cbBuf [I] Size of Buffer at "Info"
2283 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2284 * required for the Buffer at "Info"
2287 * Success: TRUE and in pcbNeeded the Bytes used in Info
2288 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2289 * if cbBuf is too small
2291 * Native Values returned in Info on Success:
2292 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2293 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2294 *| win9x(Windows 4.0): "%winsysdir%"
2296 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2299 * Only NULL or "" is supported for server
2302 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2303 DWORD level, LPBYTE Info,
2304 DWORD cbBuf, LPDWORD pcbNeeded)
2307 const printenv_t * env_t;
2309 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2310 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2312 if(server != NULL && server[0]) {
2313 FIXME("server not supported: %s\n", debugstr_w(server));
2314 SetLastError(ERROR_INVALID_PARAMETER);
2318 env_t = validate_envW(env);
2319 if(!env_t) return FALSE; /* environment invalid or unsupported */
2322 WARN("(Level: %d) is ignored in win9x\n", level);
2323 SetLastError(ERROR_INVALID_LEVEL);
2327 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2328 needed = GetSystemDirectoryW(NULL, 0);
2329 /* add the Size for the Subdirectories */
2330 needed += lstrlenW(spoolprtprocsW);
2331 needed += lstrlenW(env_t->subdir);
2332 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2334 if(pcbNeeded) *pcbNeeded = needed;
2335 TRACE ("required: 0x%x/%d\n", needed, needed);
2336 if (needed > cbBuf) {
2337 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2340 if(pcbNeeded == NULL) {
2341 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2342 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2343 SetLastError(RPC_X_NULL_REF_POINTER);
2347 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2348 SetLastError(RPC_X_NULL_REF_POINTER);
2352 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2353 /* add the Subdirectories */
2354 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2355 lstrcatW((LPWSTR) Info, env_t->subdir);
2356 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2360 /*****************************************************************************
2361 * WINSPOOL_OpenDriverReg [internal]
2363 * opens the registry for the printer drivers depending on the given input
2364 * variable pEnvironment
2367 * the opened hkey on success
2370 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2374 const printenv_t * env;
2377 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2379 if (!pEnvironment || unicode) {
2380 /* pEnvironment was NULL or an Unicode-String: use it direct */
2381 env = validate_envW(pEnvironment);
2385 /* pEnvironment was an ANSI-String: convert to unicode first */
2387 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2388 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2389 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2390 env = validate_envW(buffer);
2391 HeapFree(GetProcessHeap(), 0, buffer);
2393 if (!env) return NULL;
2395 buffer = HeapAlloc( GetProcessHeap(), 0,
2396 (strlenW(DriversW) + strlenW(env->envname) +
2397 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2399 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2400 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2401 HeapFree(GetProcessHeap(), 0, buffer);
2406 /*****************************************************************************
2407 * AddPrinterW [WINSPOOL.@]
2409 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2411 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2415 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2418 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2421 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2422 SetLastError(ERROR_INVALID_PARAMETER);
2426 ERR("Level = %d, unsupported!\n", Level);
2427 SetLastError(ERROR_INVALID_LEVEL);
2431 SetLastError(ERROR_INVALID_PARAMETER);
2434 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2436 ERR("Can't create Printers key\n");
2439 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2440 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2441 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2442 RegCloseKey(hkeyPrinter);
2443 RegCloseKey(hkeyPrinters);
2446 RegCloseKey(hkeyPrinter);
2448 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2450 ERR("Can't create Drivers key\n");
2451 RegCloseKey(hkeyPrinters);
2454 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2456 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2457 RegCloseKey(hkeyPrinters);
2458 RegCloseKey(hkeyDrivers);
2459 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2462 RegCloseKey(hkeyDriver);
2463 RegCloseKey(hkeyDrivers);
2465 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2466 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2467 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2468 RegCloseKey(hkeyPrinters);
2472 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2474 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2475 SetLastError(ERROR_INVALID_PRINTER_NAME);
2476 RegCloseKey(hkeyPrinters);
2479 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2480 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2481 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2483 /* See if we can load the driver. We may need the devmode structure anyway
2486 * Note that DocumentPropertiesW will briefly try to open the printer we
2487 * just create to find a DEVMODEA struct (it will use the WINEPS default
2488 * one in case it is not there, so we are ok).
2490 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2493 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2494 size = sizeof(DEVMODEW);
2500 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2501 ZeroMemory(dmW,size);
2503 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2505 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2506 HeapFree(GetProcessHeap(),0,dmW);
2511 /* set devmode to printer name */
2512 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2516 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2517 and we support these drivers. NT writes DEVMODEW so somehow
2518 we'll need to distinguish between these when we support NT
2522 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2523 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2524 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2525 HeapFree(GetProcessHeap(), 0, dmA);
2527 HeapFree(GetProcessHeap(), 0, dmW);
2529 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2530 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2531 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2532 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2534 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2535 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2536 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2537 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2538 (LPBYTE)&pi->Priority, sizeof(DWORD));
2539 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2540 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2541 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2542 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2543 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2544 (LPBYTE)&pi->Status, sizeof(DWORD));
2545 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2546 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2548 RegCloseKey(hkeyPrinter);
2549 RegCloseKey(hkeyPrinters);
2550 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2551 ERR("OpenPrinter failing\n");
2557 /*****************************************************************************
2558 * AddPrinterA [WINSPOOL.@]
2560 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2562 UNICODE_STRING pNameW;
2564 PRINTER_INFO_2W *piW;
2565 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2568 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2570 ERR("Level = %d, unsupported!\n", Level);
2571 SetLastError(ERROR_INVALID_LEVEL);
2574 pwstrNameW = asciitounicode(&pNameW,pName);
2575 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2577 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2579 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2580 RtlFreeUnicodeString(&pNameW);
2585 /*****************************************************************************
2586 * ClosePrinter [WINSPOOL.@]
2588 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2590 UINT_PTR i = (UINT_PTR)hPrinter;
2591 opened_printer_t *printer = NULL;
2594 TRACE("Handle %p\n", hPrinter);
2596 EnterCriticalSection(&printer_handles_cs);
2598 if ((i > 0) && (i <= nb_printer_handles))
2599 printer = printer_handles[i - 1];
2603 struct list *cursor, *cursor2;
2606 EndDocPrinter(hPrinter);
2608 if(InterlockedDecrement(&printer->queue->ref) == 0)
2610 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2612 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2613 ScheduleJob(hPrinter, job->job_id);
2615 HeapFree(GetProcessHeap(), 0, printer->queue);
2617 HeapFree(GetProcessHeap(), 0, printer->name);
2618 HeapFree(GetProcessHeap(), 0, printer);
2619 printer_handles[i - 1] = NULL;
2622 LeaveCriticalSection(&printer_handles_cs);
2626 /*****************************************************************************
2627 * DeleteFormA [WINSPOOL.@]
2629 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2631 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2635 /*****************************************************************************
2636 * DeleteFormW [WINSPOOL.@]
2638 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2640 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2644 /*****************************************************************************
2645 * WINSPOOL_SHRegDeleteKey
2647 * Recursively delete subkeys.
2648 * Cut & paste from shlwapi.
2651 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2653 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2654 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2657 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2660 /* Find how many subkeys there are */
2661 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2662 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2666 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2667 /* Name too big: alloc a buffer for it */
2668 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2671 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2674 /* Recursively delete all the subkeys */
2675 for(i = 0; i < dwKeyCount && !dwRet; i++)
2677 dwSize = dwMaxSubkeyLen;
2678 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2680 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2683 if (lpszName != szNameBuf)
2684 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2688 RegCloseKey(hSubKey);
2690 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2695 /*****************************************************************************
2696 * DeletePrinter [WINSPOOL.@]
2698 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2700 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2701 HKEY hkeyPrinters, hkey;
2704 SetLastError(ERROR_INVALID_HANDLE);
2707 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2708 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2709 RegCloseKey(hkeyPrinters);
2711 WriteProfileStringW(devicesW, lpNameW, NULL);
2712 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2713 RegDeleteValueW(hkey, lpNameW);
2719 /*****************************************************************************
2720 * SetPrinterA [WINSPOOL.@]
2722 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2725 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2729 /*****************************************************************************
2730 * SetJobA [WINSPOOL.@]
2732 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2733 LPBYTE pJob, DWORD Command)
2737 UNICODE_STRING usBuffer;
2739 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2741 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2742 are all ignored by SetJob, so we don't bother copying them */
2750 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2751 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2753 JobW = (LPBYTE)info1W;
2754 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2755 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2756 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2757 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2758 info1W->Status = info1A->Status;
2759 info1W->Priority = info1A->Priority;
2760 info1W->Position = info1A->Position;
2761 info1W->PagesPrinted = info1A->PagesPrinted;
2766 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2767 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2769 JobW = (LPBYTE)info2W;
2770 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2771 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2772 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2773 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2774 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2775 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2776 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2777 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2778 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2779 info2W->Status = info2A->Status;
2780 info2W->Priority = info2A->Priority;
2781 info2W->Position = info2A->Position;
2782 info2W->StartTime = info2A->StartTime;
2783 info2W->UntilTime = info2A->UntilTime;
2784 info2W->PagesPrinted = info2A->PagesPrinted;
2788 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2789 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2792 SetLastError(ERROR_INVALID_LEVEL);
2796 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2802 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2803 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2804 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2805 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2806 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2811 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2812 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2813 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2814 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2815 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2816 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2817 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2818 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2819 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2823 HeapFree(GetProcessHeap(), 0, JobW);
2828 /*****************************************************************************
2829 * SetJobW [WINSPOOL.@]
2831 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2832 LPBYTE pJob, DWORD Command)
2837 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2838 FIXME("Ignoring everything other than document title\n");
2840 EnterCriticalSection(&printer_handles_cs);
2841 job = get_job(hPrinter, JobId);
2851 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2852 HeapFree(GetProcessHeap(), 0, job->document_title);
2853 job->document_title = strdupW(info1->pDocument);
2858 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2859 HeapFree(GetProcessHeap(), 0, job->document_title);
2860 job->document_title = strdupW(info2->pDocument);
2866 SetLastError(ERROR_INVALID_LEVEL);
2871 LeaveCriticalSection(&printer_handles_cs);
2875 /*****************************************************************************
2876 * EndDocPrinter [WINSPOOL.@]
2878 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2880 opened_printer_t *printer;
2882 TRACE("(%p)\n", hPrinter);
2884 EnterCriticalSection(&printer_handles_cs);
2886 printer = get_opened_printer(hPrinter);
2889 SetLastError(ERROR_INVALID_HANDLE);
2895 SetLastError(ERROR_SPL_NO_STARTDOC);
2899 CloseHandle(printer->doc->hf);
2900 ScheduleJob(hPrinter, printer->doc->job_id);
2901 HeapFree(GetProcessHeap(), 0, printer->doc);
2902 printer->doc = NULL;
2905 LeaveCriticalSection(&printer_handles_cs);
2909 /*****************************************************************************
2910 * EndPagePrinter [WINSPOOL.@]
2912 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2914 FIXME("(%p): stub\n", hPrinter);
2918 /*****************************************************************************
2919 * StartDocPrinterA [WINSPOOL.@]
2921 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2923 UNICODE_STRING usBuffer;
2925 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2928 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2929 or one (DOC_INFO_3) extra DWORDs */
2933 doc2W.JobId = doc2->JobId;
2936 doc2W.dwMode = doc2->dwMode;
2939 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2940 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2941 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2945 SetLastError(ERROR_INVALID_LEVEL);
2949 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2951 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2952 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2953 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2958 /*****************************************************************************
2959 * StartDocPrinterW [WINSPOOL.@]
2961 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2963 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2964 opened_printer_t *printer;
2965 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2966 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2967 JOB_INFO_1W job_info;
2968 DWORD needed, ret = 0;
2972 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2973 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2974 debugstr_w(doc->pDatatype));
2976 if(Level < 1 || Level > 3)
2978 SetLastError(ERROR_INVALID_LEVEL);
2982 EnterCriticalSection(&printer_handles_cs);
2983 printer = get_opened_printer(hPrinter);
2986 SetLastError(ERROR_INVALID_HANDLE);
2992 SetLastError(ERROR_INVALID_PRINTER_STATE);
2996 /* Even if we're printing to a file we still add a print job, we'll
2997 just ignore the spool file name */
2999 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3001 ERR("AddJob failed gle %08x\n", GetLastError());
3005 if(doc->pOutputFile)
3006 filename = doc->pOutputFile;
3008 filename = addjob->Path;
3010 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3011 if(hf == INVALID_HANDLE_VALUE)
3014 memset(&job_info, 0, sizeof(job_info));
3015 job_info.pDocument = doc->pDocName;
3016 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3018 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3019 printer->doc->hf = hf;
3020 ret = printer->doc->job_id = addjob->JobId;
3022 LeaveCriticalSection(&printer_handles_cs);
3027 /*****************************************************************************
3028 * StartPagePrinter [WINSPOOL.@]
3030 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3032 FIXME("(%p): stub\n", hPrinter);
3036 /*****************************************************************************
3037 * GetFormA [WINSPOOL.@]
3039 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3040 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3042 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3043 Level,pForm,cbBuf,pcbNeeded);
3047 /*****************************************************************************
3048 * GetFormW [WINSPOOL.@]
3050 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3051 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3053 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3054 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3058 /*****************************************************************************
3059 * SetFormA [WINSPOOL.@]
3061 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3064 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3068 /*****************************************************************************
3069 * SetFormW [WINSPOOL.@]
3071 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3074 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3078 /*****************************************************************************
3079 * ReadPrinter [WINSPOOL.@]
3081 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3082 LPDWORD pNoBytesRead)
3084 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3088 /*****************************************************************************
3089 * ResetPrinterA [WINSPOOL.@]
3091 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3093 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3097 /*****************************************************************************
3098 * ResetPrinterW [WINSPOOL.@]
3100 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3102 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3106 /*****************************************************************************
3107 * WINSPOOL_GetDWORDFromReg
3109 * Return DWORD associated with ValueName from hkey.
3111 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3113 DWORD sz = sizeof(DWORD), type, value = 0;
3116 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3118 if(ret != ERROR_SUCCESS) {
3119 WARN("Got ret = %d on name %s\n", ret, ValueName);
3122 if(type != REG_DWORD) {
3123 ERR("Got type %d\n", type);
3129 /*****************************************************************************
3130 * WINSPOOL_GetStringFromReg
3132 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3133 * String is stored either as unicode or ascii.
3134 * Bit of a hack here to get the ValueName if we want ascii.
3136 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3137 DWORD buflen, DWORD *needed,
3140 DWORD sz = buflen, type;
3144 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3146 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
3147 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3148 HeapFree(GetProcessHeap(),0,ValueNameA);
3150 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3151 WARN("Got ret = %d\n", ret);
3155 /* add space for terminating '\0' */
3156 sz += unicode ? sizeof(WCHAR) : 1;
3160 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3165 /*****************************************************************************
3166 * WINSPOOL_GetDefaultDevMode
3168 * Get a default DevMode values for wineps.
3172 static void WINSPOOL_GetDefaultDevMode(
3174 DWORD buflen, DWORD *needed,
3178 static const char szwps[] = "wineps.drv";
3180 /* fill default DEVMODE - should be read from ppd... */
3181 ZeroMemory( &dm, sizeof(dm) );
3182 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3183 dm.dmSpecVersion = DM_SPECVERSION;
3184 dm.dmDriverVersion = 1;
3185 dm.dmSize = sizeof(DEVMODEA);
3186 dm.dmDriverExtra = 0;
3188 DM_ORIENTATION | DM_PAPERSIZE |
3189 DM_PAPERLENGTH | DM_PAPERWIDTH |
3192 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3193 DM_YRESOLUTION | DM_TTOPTION;
3195 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3196 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3197 dm.u1.s1.dmPaperLength = 2970;
3198 dm.u1.s1.dmPaperWidth = 2100;
3202 dm.dmDefaultSource = DMBIN_AUTO;
3203 dm.dmPrintQuality = DMRES_MEDIUM;
3206 dm.dmYResolution = 300; /* 300dpi */
3207 dm.dmTTOption = DMTT_BITMAP;
3210 /* dm.dmLogPixels */
3211 /* dm.dmBitsPerPel */
3212 /* dm.dmPelsWidth */
3213 /* dm.dmPelsHeight */
3214 /* dm.dmDisplayFlags */
3215 /* dm.dmDisplayFrequency */
3216 /* dm.dmICMMethod */
3217 /* dm.dmICMIntent */
3218 /* dm.dmMediaType */
3219 /* dm.dmDitherType */
3220 /* dm.dmReserved1 */
3221 /* dm.dmReserved2 */
3222 /* dm.dmPanningWidth */
3223 /* dm.dmPanningHeight */
3226 if(buflen >= sizeof(DEVMODEW)) {
3227 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3228 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3229 HeapFree(GetProcessHeap(),0,pdmW);
3231 *needed = sizeof(DEVMODEW);
3235 if(buflen >= sizeof(DEVMODEA)) {
3236 memcpy(ptr, &dm, sizeof(DEVMODEA));
3238 *needed = sizeof(DEVMODEA);
3242 /*****************************************************************************
3243 * WINSPOOL_GetDevModeFromReg
3245 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3246 * DevMode is stored either as unicode or ascii.
3248 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3250 DWORD buflen, DWORD *needed,
3253 DWORD sz = buflen, type;
3256 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3257 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3258 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3259 if (sz < sizeof(DEVMODEA))
3261 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3264 /* ensures that dmSize is not erratically bogus if registry is invalid */
3265 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3266 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3268 sz += (CCHDEVICENAME + CCHFORMNAME);
3270 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3271 memcpy(ptr, dmW, sz);
3272 HeapFree(GetProcessHeap(),0,dmW);
3279 /*********************************************************************
3280 * WINSPOOL_GetPrinter_2
3282 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3283 * The strings are either stored as unicode or ascii.
3285 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3286 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3289 DWORD size, left = cbBuf;
3290 BOOL space = (cbBuf > 0);
3295 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3297 if(space && size <= left) {
3298 pi2->pPrinterName = (LPWSTR)ptr;
3305 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3307 if(space && size <= left) {
3308 pi2->pShareName = (LPWSTR)ptr;
3315 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3317 if(space && size <= left) {
3318 pi2->pPortName = (LPWSTR)ptr;
3325 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3327 if(space && size <= left) {
3328 pi2->pDriverName = (LPWSTR)ptr;
3335 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3337 if(space && size <= left) {
3338 pi2->pComment = (LPWSTR)ptr;
3345 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3347 if(space && size <= left) {
3348 pi2->pLocation = (LPWSTR)ptr;
3355 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3357 if(space && size <= left) {
3358 pi2->pDevMode = (LPDEVMODEW)ptr;
3367 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3368 if(space && size <= left) {
3369 pi2->pDevMode = (LPDEVMODEW)ptr;
3376 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3378 if(space && size <= left) {
3379 pi2->pSepFile = (LPWSTR)ptr;
3386 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3388 if(space && size <= left) {
3389 pi2->pPrintProcessor = (LPWSTR)ptr;
3396 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3398 if(space && size <= left) {
3399 pi2->pDatatype = (LPWSTR)ptr;
3406 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3408 if(space && size <= left) {
3409 pi2->pParameters = (LPWSTR)ptr;
3417 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3418 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3419 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3420 "Default Priority");
3421 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3422 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3425 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3426 memset(pi2, 0, sizeof(*pi2));
3431 /*********************************************************************
3432 * WINSPOOL_GetPrinter_4
3434 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3436 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3437 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3440 DWORD size, left = cbBuf;
3441 BOOL space = (cbBuf > 0);
3446 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3448 if(space && size <= left) {
3449 pi4->pPrinterName = (LPWSTR)ptr;
3457 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3460 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3461 memset(pi4, 0, sizeof(*pi4));
3466 /*********************************************************************
3467 * WINSPOOL_GetPrinter_5
3469 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3471 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3472 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3475 DWORD size, left = cbBuf;
3476 BOOL space = (cbBuf > 0);
3481 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3483 if(space && size <= left) {
3484 pi5->pPrinterName = (LPWSTR)ptr;
3491 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3493 if(space && size <= left) {
3494 pi5->pPortName = (LPWSTR)ptr;
3502 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3503 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3505 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3509 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3510 memset(pi5, 0, sizeof(*pi5));
3515 /*****************************************************************************
3516 * WINSPOOL_GetPrinter
3518 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3519 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3520 * just a collection of pointers to strings.
3522 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3523 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3526 DWORD size, needed = 0;
3528 HKEY hkeyPrinter, hkeyPrinters;
3531 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3533 if (!(name = get_opened_printer_name(hPrinter))) {
3534 SetLastError(ERROR_INVALID_HANDLE);
3538 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3540 ERR("Can't create Printers key\n");
3543 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3545 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3546 RegCloseKey(hkeyPrinters);
3547 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3554 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3556 size = sizeof(PRINTER_INFO_2W);
3558 ptr = pPrinter + size;
3560 memset(pPrinter, 0, size);
3565 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3573 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3575 size = sizeof(PRINTER_INFO_4W);
3577 ptr = pPrinter + size;
3579 memset(pPrinter, 0, size);
3584 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3593 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3595 size = sizeof(PRINTER_INFO_5W);
3597 ptr = pPrinter + size;
3599 memset(pPrinter, 0, size);
3605 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3612 FIXME("Unimplemented level %d\n", Level);
3613 SetLastError(ERROR_INVALID_LEVEL);
3614 RegCloseKey(hkeyPrinters);
3615 RegCloseKey(hkeyPrinter);
3619 RegCloseKey(hkeyPrinter);
3620 RegCloseKey(hkeyPrinters);
3622 TRACE("returning %d needed = %d\n", ret, needed);
3623 if(pcbNeeded) *pcbNeeded = needed;
3625 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3629 /*****************************************************************************
3630 * GetPrinterW [WINSPOOL.@]
3632 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3633 DWORD cbBuf, LPDWORD pcbNeeded)
3635 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3639 /*****************************************************************************
3640 * GetPrinterA [WINSPOOL.@]
3642 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3643 DWORD cbBuf, LPDWORD pcbNeeded)
3645 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3649 /*****************************************************************************
3650 * WINSPOOL_EnumPrinters
3652 * Implementation of EnumPrintersA|W
3654 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3655 DWORD dwLevel, LPBYTE lpbPrinters,
3656 DWORD cbBuf, LPDWORD lpdwNeeded,
3657 LPDWORD lpdwReturned, BOOL unicode)
3660 HKEY hkeyPrinters, hkeyPrinter;
3661 WCHAR PrinterName[255];
3662 DWORD needed = 0, number = 0;
3663 DWORD used, i, left;
3667 memset(lpbPrinters, 0, cbBuf);
3673 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3674 if(dwType == PRINTER_ENUM_DEFAULT)
3677 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3678 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3679 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3680 if(!dwType) return TRUE;
3683 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3684 FIXME("dwType = %08x\n", dwType);
3685 SetLastError(ERROR_INVALID_FLAGS);
3689 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3691 ERR("Can't create Printers key\n");
3695 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3696 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3697 RegCloseKey(hkeyPrinters);
3698 ERR("Can't query Printers key\n");
3701 TRACE("Found %d printers\n", number);
3705 RegCloseKey(hkeyPrinters);
3707 *lpdwReturned = number;
3711 used = number * sizeof(PRINTER_INFO_2W);
3714 used = number * sizeof(PRINTER_INFO_4W);
3717 used = number * sizeof(PRINTER_INFO_5W);
3721 SetLastError(ERROR_INVALID_LEVEL);
3722 RegCloseKey(hkeyPrinters);
3725 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3727 for(i = 0; i < number; i++) {
3728 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3730 ERR("Can't enum key number %d\n", i);
3731 RegCloseKey(hkeyPrinters);
3734 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3735 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3737 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3738 RegCloseKey(hkeyPrinters);
3743 buf = lpbPrinters + used;
3744 left = cbBuf - used;
3752 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3753 left, &needed, unicode);
3755 if(pi) pi += sizeof(PRINTER_INFO_2W);
3758 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3759 left, &needed, unicode);
3761 if(pi) pi += sizeof(PRINTER_INFO_4W);
3764 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3765 left, &needed, unicode);
3767 if(pi) pi += sizeof(PRINTER_INFO_5W);
3770 ERR("Shouldn't be here!\n");
3771 RegCloseKey(hkeyPrinter);
3772 RegCloseKey(hkeyPrinters);
3775 RegCloseKey(hkeyPrinter);
3777 RegCloseKey(hkeyPrinters);
3784 memset(lpbPrinters, 0, cbBuf);
3785 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3789 *lpdwReturned = number;
3790 SetLastError(ERROR_SUCCESS);
3795 /******************************************************************
3796 * EnumPrintersW [WINSPOOL.@]
3798 * Enumerates the available printers, print servers and print
3799 * providers, depending on the specified flags, name and level.
3803 * If level is set to 1:
3804 * Not implemented yet!
3805 * Returns TRUE with an empty list.
3807 * If level is set to 2:
3808 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3809 * Returns an array of PRINTER_INFO_2 data structures in the
3810 * lpbPrinters buffer. Note that according to MSDN also an
3811 * OpenPrinter should be performed on every remote printer.
3813 * If level is set to 4 (officially WinNT only):
3814 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3815 * Fast: Only the registry is queried to retrieve printer names,
3816 * no connection to the driver is made.
3817 * Returns an array of PRINTER_INFO_4 data structures in the
3818 * lpbPrinters buffer.
3820 * If level is set to 5 (officially WinNT4/Win9x only):
3821 * Fast: Only the registry is queried to retrieve printer names,
3822 * no connection to the driver is made.
3823 * Returns an array of PRINTER_INFO_5 data structures in the
3824 * lpbPrinters buffer.
3826 * If level set to 3 or 6+:
3827 * returns zero (failure!)
3829 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3833 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3834 * - Only levels 2, 4 and 5 are implemented at the moment.
3835 * - 16-bit printer drivers are not enumerated.
3836 * - Returned amount of bytes used/needed does not match the real Windoze
3837 * implementation (as in this implementation, all strings are part
3838 * of the buffer, whereas Win32 keeps them somewhere else)
3839 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3842 * - In a regular Wine installation, no registry settings for printers
3843 * exist, which makes this function return an empty list.
3845 BOOL WINAPI EnumPrintersW(
3846 DWORD dwType, /* [in] Types of print objects to enumerate */
3847 LPWSTR lpszName, /* [in] name of objects to enumerate */
3848 DWORD dwLevel, /* [in] type of printer info structure */
3849 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3850 DWORD cbBuf, /* [in] max size of buffer in bytes */
3851 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3852 LPDWORD lpdwReturned /* [out] number of entries returned */
3855 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3856 lpdwNeeded, lpdwReturned, TRUE);
3859 /******************************************************************
3860 * EnumPrintersA [WINSPOOL.@]
3863 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3864 DWORD dwLevel, LPBYTE lpbPrinters,
3865 DWORD cbBuf, LPDWORD lpdwNeeded,
3866 LPDWORD lpdwReturned)
3869 UNICODE_STRING lpszNameW;
3872 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3873 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3874 lpdwNeeded, lpdwReturned, FALSE);
3875 RtlFreeUnicodeString(&lpszNameW);
3879 /*****************************************************************************
3880 * WINSPOOL_GetDriverInfoFromReg [internal]
3882 * Enters the information from the registry into the DRIVER_INFO struct
3885 * zero if the printer driver does not exist in the registry
3886 * (only if Level > 1) otherwise nonzero
3888 static BOOL WINSPOOL_GetDriverInfoFromReg(
3891 LPCWSTR pEnvironment,
3893 LPBYTE ptr, /* DRIVER_INFO */
3894 LPBYTE pDriverStrings, /* strings buffer */
3895 DWORD cbBuf, /* size of string buffer */
3896 LPDWORD pcbNeeded, /* space needed for str. */
3897 BOOL unicode) /* type of strings */
3901 LPBYTE strPtr = pDriverStrings;
3903 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
3904 debugstr_w(DriverName), debugstr_w(pEnvironment),
3905 Level, ptr, pDriverStrings, cbBuf, unicode);
3908 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3909 if (*pcbNeeded <= cbBuf)
3910 strcpyW((LPWSTR)strPtr, DriverName);
3912 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3914 if(*pcbNeeded <= cbBuf)
3915 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3916 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3920 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3924 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3925 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3928 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3929 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3930 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3935 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3938 pEnvironment = DefaultEnvironmentW;
3940 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3942 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3945 if(*pcbNeeded <= cbBuf) {
3947 strcpyW((LPWSTR)strPtr, pEnvironment);
3949 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3950 (LPSTR)strPtr, size, NULL, NULL);
3952 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3953 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3956 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3959 if(*pcbNeeded <= cbBuf)
3960 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3963 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3964 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3967 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3970 if(*pcbNeeded <= cbBuf)
3971 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3974 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3975 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3978 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3979 0, &size, unicode)) {
3981 if(*pcbNeeded <= cbBuf)
3982 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3983 size, &tmp, unicode);
3985 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3986 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3990 RegCloseKey(hkeyDriver);
3991 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
3995 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3998 if(*pcbNeeded <= cbBuf)
3999 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4000 size, &tmp, unicode);
4002 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4003 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4006 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4009 if(*pcbNeeded <= cbBuf)
4010 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4011 size, &tmp, unicode);
4013 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4014 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4017 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4020 if(*pcbNeeded <= cbBuf)
4021 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4022 size, &tmp, unicode);
4024 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4025 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4028 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4031 if(*pcbNeeded <= cbBuf)
4032 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4033 size, &tmp, unicode);
4035 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4036 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4039 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4040 RegCloseKey(hkeyDriver);
4044 /*****************************************************************************
4045 * WINSPOOL_GetPrinterDriver
4047 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
4048 DWORD Level, LPBYTE pDriverInfo,
4049 DWORD cbBuf, LPDWORD pcbNeeded,
4053 WCHAR DriverName[100];
4054 DWORD ret, type, size, needed = 0;
4056 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4058 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4059 Level,pDriverInfo,cbBuf, pcbNeeded);
4061 ZeroMemory(pDriverInfo, cbBuf);
4063 if (!(name = get_opened_printer_name(hPrinter))) {
4064 SetLastError(ERROR_INVALID_HANDLE);
4067 if(Level < 1 || Level > 6) {
4068 SetLastError(ERROR_INVALID_LEVEL);
4071 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4073 ERR("Can't create Printers key\n");
4076 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4078 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4079 RegCloseKey(hkeyPrinters);
4080 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4083 size = sizeof(DriverName);
4085 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4086 (LPBYTE)DriverName, &size);
4087 RegCloseKey(hkeyPrinter);
4088 RegCloseKey(hkeyPrinters);
4089 if(ret != ERROR_SUCCESS) {
4090 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4094 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4096 ERR("Can't create Drivers key\n");
4102 size = sizeof(DRIVER_INFO_1W);
4105 size = sizeof(DRIVER_INFO_2W);
4108 size = sizeof(DRIVER_INFO_3W);
4111 size = sizeof(DRIVER_INFO_4W);
4114 size = sizeof(DRIVER_INFO_5W);
4117 size = sizeof(DRIVER_INFO_6W);
4120 ERR("Invalid level\n");
4125 ptr = pDriverInfo + size;
4127 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4128 pEnvironment, Level, pDriverInfo,
4129 (cbBuf < size) ? NULL : ptr,
4130 (cbBuf < size) ? 0 : cbBuf - size,
4131 &needed, unicode)) {
4132 RegCloseKey(hkeyDrivers);
4136 RegCloseKey(hkeyDrivers);
4138 if(pcbNeeded) *pcbNeeded = size + needed;
4139 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4140 if(cbBuf >= needed) return TRUE;
4141 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4145 /*****************************************************************************
4146 * GetPrinterDriverA [WINSPOOL.@]
4148 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4149 DWORD Level, LPBYTE pDriverInfo,
4150 DWORD cbBuf, LPDWORD pcbNeeded)
4153 UNICODE_STRING pEnvW;
4156 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4157 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4158 cbBuf, pcbNeeded, FALSE);
4159 RtlFreeUnicodeString(&pEnvW);
4162 /*****************************************************************************
4163 * GetPrinterDriverW [WINSPOOL.@]
4165 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4166 DWORD Level, LPBYTE pDriverInfo,
4167 DWORD cbBuf, LPDWORD pcbNeeded)
4169 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4170 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4173 /*****************************************************************************
4174 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4176 * Return the PATH for the Printer-Drivers (UNICODE)
4179 * pName [I] Servername (NT only) or NULL (local Computer)
4180 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4181 * Level [I] Structure-Level (must be 1)
4182 * pDriverDirectory [O] PTR to Buffer that receives the Result
4183 * cbBuf [I] Size of Buffer at pDriverDirectory
4184 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4185 * required for pDriverDirectory
4188 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4189 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4190 * if cbBuf is too small
4192 * Native Values returned in pDriverDirectory on Success:
4193 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4194 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4195 *| win9x(Windows 4.0): "%winsysdir%"
4197 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4200 *- Only NULL or "" is supported for pName
4203 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4204 DWORD Level, LPBYTE pDriverDirectory,
4205 DWORD cbBuf, LPDWORD pcbNeeded)
4208 const printenv_t * env;
4210 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4211 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4212 if(pName != NULL && pName[0]) {
4213 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4214 SetLastError(ERROR_INVALID_PARAMETER);
4218 env = validate_envW(pEnvironment);
4219 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4222 WARN("(Level: %d) is ignored in win9x\n", Level);
4223 SetLastError(ERROR_INVALID_LEVEL);
4227 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4228 needed = GetSystemDirectoryW(NULL, 0);
4229 /* add the Size for the Subdirectories */
4230 needed += lstrlenW(spooldriversW);
4231 needed += lstrlenW(env->subdir);
4232 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4235 *pcbNeeded = needed;
4236 TRACE("required: 0x%x/%d\n", needed, needed);
4237 if(needed > cbBuf) {
4238 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4241 if(pcbNeeded == NULL) {
4242 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4243 SetLastError(RPC_X_NULL_REF_POINTER);
4246 if(pDriverDirectory == NULL) {
4247 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4248 SetLastError(ERROR_INVALID_USER_BUFFER);
4252 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4253 /* add the Subdirectories */
4254 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4255 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4256 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4261 /*****************************************************************************
4262 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4264 * Return the PATH for the Printer-Drivers (ANSI)
4266 * See GetPrinterDriverDirectoryW.
4269 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4272 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4273 DWORD Level, LPBYTE pDriverDirectory,
4274 DWORD cbBuf, LPDWORD pcbNeeded)
4276 UNICODE_STRING nameW, environmentW;
4279 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4280 WCHAR *driverDirectoryW = NULL;
4282 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4283 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4285 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4287 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4288 else nameW.Buffer = NULL;
4289 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4290 else environmentW.Buffer = NULL;
4292 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4293 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4296 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4297 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4299 *pcbNeeded = needed;
4300 ret = (needed <= cbBuf) ? TRUE : FALSE;
4302 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4304 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4306 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4307 RtlFreeUnicodeString(&environmentW);
4308 RtlFreeUnicodeString(&nameW);
4313 /*****************************************************************************
4314 * AddPrinterDriverA [WINSPOOL.@]
4316 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4319 HKEY hkeyDrivers, hkeyName;
4320 static CHAR empty[] = "",
4323 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4325 if(level != 2 && level != 3) {
4326 SetLastError(ERROR_INVALID_LEVEL);
4329 if ((pName) && (pName[0])) {
4330 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4331 SetLastError(ERROR_INVALID_PARAMETER);
4335 WARN("pDriverInfo == NULL\n");
4336 SetLastError(ERROR_INVALID_PARAMETER);
4341 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4343 memset(&di3, 0, sizeof(di3));
4344 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4347 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4349 SetLastError(ERROR_INVALID_PARAMETER);
4353 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4354 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4355 if(!di3.pHelpFile) di3.pHelpFile = empty;
4356 if(!di3.pMonitorName) di3.pMonitorName = empty;
4358 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4361 ERR("Can't create Drivers key\n");
4365 if(level == 2) { /* apparently can't overwrite with level2 */
4366 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4367 RegCloseKey(hkeyName);
4368 RegCloseKey(hkeyDrivers);
4369 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4370 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4374 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4375 RegCloseKey(hkeyDrivers);
4376 ERR("Can't create Name key\n");
4379 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4381 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
4382 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
4383 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4385 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
4386 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4387 (LPBYTE) di3.pDependentFiles, 0);
4388 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
4389 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
4390 RegCloseKey(hkeyName);
4391 RegCloseKey(hkeyDrivers);
4396 /*****************************************************************************
4397 * AddPrinterDriverW [WINSPOOL.@]
4399 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4402 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4407 /*****************************************************************************
4408 * AddPrintProcessorA [WINSPOOL.@]
4410 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4411 LPSTR pPrintProcessorName)
4413 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4414 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4418 /*****************************************************************************
4419 * AddPrintProcessorW [WINSPOOL.@]
4421 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4422 LPWSTR pPrintProcessorName)
4424 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4425 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4429 /*****************************************************************************
4430 * AddPrintProvidorA [WINSPOOL.@]
4432 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4434 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4438 /*****************************************************************************
4439 * AddPrintProvidorW [WINSPOOL.@]
4441 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4443 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4447 /*****************************************************************************
4448 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4450 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4451 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4453 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4454 pDevModeOutput, pDevModeInput);
4458 /*****************************************************************************
4459 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4461 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4462 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4464 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4465 pDevModeOutput, pDevModeInput);
4469 /*****************************************************************************
4470 * PrinterProperties [WINSPOOL.@]
4472 * Displays a dialog to set the properties of the printer.
4475 * nonzero on success or zero on failure
4478 * implemented as stub only
4480 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4481 HANDLE hPrinter /* [in] handle to printer object */
4483 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4484 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4488 /*****************************************************************************
4489 * EnumJobsA [WINSPOOL.@]
4492 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4493 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4496 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4497 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4499 if(pcbNeeded) *pcbNeeded = 0;
4500 if(pcReturned) *pcReturned = 0;
4505 /*****************************************************************************
4506 * EnumJobsW [WINSPOOL.@]
4509 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4510 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4513 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4514 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4516 if(pcbNeeded) *pcbNeeded = 0;
4517 if(pcReturned) *pcReturned = 0;
4521 /*****************************************************************************
4522 * WINSPOOL_EnumPrinterDrivers [internal]
4524 * Delivers information about all printer drivers installed on the
4525 * localhost or a given server
4528 * nonzero on success or zero on failure. If the buffer for the returned
4529 * information is too small the function will return an error
4532 * - only implemented for localhost, foreign hosts will return an error
4534 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4535 DWORD Level, LPBYTE pDriverInfo,
4536 DWORD cbBuf, LPDWORD pcbNeeded,
4537 LPDWORD pcReturned, BOOL unicode)
4540 DWORD i, needed, number = 0, size = 0;
4541 WCHAR DriverNameW[255];
4544 TRACE("%s,%s,%d,%p,%d,%d\n",
4545 debugstr_w(pName), debugstr_w(pEnvironment),
4546 Level, pDriverInfo, cbBuf, unicode);
4548 /* check for local drivers */
4549 if((pName) && (pName[0])) {
4550 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4551 SetLastError(ERROR_ACCESS_DENIED);
4555 /* check input parameter */
4556 if((Level < 1) || (Level > 3)) {
4557 ERR("unsupported level %d\n", Level);
4558 SetLastError(ERROR_INVALID_LEVEL);
4562 /* initialize return values */
4564 memset( pDriverInfo, 0, cbBuf);
4568 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4570 ERR("Can't open Drivers key\n");
4574 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4575 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4576 RegCloseKey(hkeyDrivers);
4577 ERR("Can't query Drivers key\n");
4580 TRACE("Found %d Drivers\n", number);
4582 /* get size of single struct
4583 * unicode and ascii structure have the same size
4587 size = sizeof(DRIVER_INFO_1A);
4590 size = sizeof(DRIVER_INFO_2A);
4593 size = sizeof(DRIVER_INFO_3A);
4597 /* calculate required buffer size */
4598 *pcbNeeded = size * number;
4600 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4602 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4603 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4605 ERR("Can't enum key number %d\n", i);
4606 RegCloseKey(hkeyDrivers);
4609 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4610 pEnvironment, Level, ptr,
4611 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4612 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4613 &needed, unicode)) {
4614 RegCloseKey(hkeyDrivers);
4617 (*pcbNeeded) += needed;
4620 RegCloseKey(hkeyDrivers);
4622 if(cbBuf < *pcbNeeded){
4623 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4627 *pcReturned = number;
4631 /*****************************************************************************
4632 * EnumPrinterDriversW [WINSPOOL.@]
4634 * see function EnumPrinterDrivers for RETURNS, BUGS
4636 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4637 LPBYTE pDriverInfo, DWORD cbBuf,
4638 LPDWORD pcbNeeded, LPDWORD pcReturned)
4640 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4641 cbBuf, pcbNeeded, pcReturned, TRUE);
4644 /*****************************************************************************
4645 * EnumPrinterDriversA [WINSPOOL.@]
4647 * see function EnumPrinterDrivers for RETURNS, BUGS
4649 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4650 LPBYTE pDriverInfo, DWORD cbBuf,
4651 LPDWORD pcbNeeded, LPDWORD pcReturned)
4653 UNICODE_STRING pNameW, pEnvironmentW;
4654 PWSTR pwstrNameW, pwstrEnvironmentW;
4656 pwstrNameW = asciitounicode(&pNameW, pName);
4657 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4659 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4660 Level, pDriverInfo, cbBuf, pcbNeeded,
4662 RtlFreeUnicodeString(&pNameW);
4663 RtlFreeUnicodeString(&pEnvironmentW);
4668 static CHAR PortMonitor[] = "Wine Port Monitor";
4669 static CHAR PortDescription[] = "Wine Port";
4671 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4675 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4676 NULL, OPEN_EXISTING, 0, NULL );
4677 if (handle == INVALID_HANDLE_VALUE)
4679 TRACE("Checking %s exists\n", name );
4680 CloseHandle( handle );
4684 static DWORD WINSPOOL_CountSerialPorts(void)
4691 strcpy( name, "COMx:" );
4693 if (WINSPOOL_ComPortExists( name ))
4700 /******************************************************************************
4701 * EnumPortsA (WINSPOOL.@)
4706 * ANSI-Version did not call the UNICODE-Version
4709 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4710 LPDWORD bufneeded,LPDWORD bufreturned)
4713 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4714 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4718 TRACE("(%s,%d,%p,%d,%p,%p)\n",
4719 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4724 info_size = sizeof (PORT_INFO_1A);
4727 info_size = sizeof (PORT_INFO_2A);
4730 SetLastError(ERROR_INVALID_LEVEL);
4734 /* see how many exist */
4737 serial_count = WINSPOOL_CountSerialPorts();
4740 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4741 if ( r == ERROR_SUCCESS )
4743 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4744 &printer_count, NULL, NULL, NULL, NULL);
4746 count = serial_count + printer_count;
4748 /* then fill in the structure info structure once
4749 we know the offset to the first string */
4751 memset( buffer, 0, bufsize );
4753 ofs = info_size*count;
4754 for ( i=0; i<count; i++)
4756 DWORD vallen = sizeof(portname) - 1;
4758 /* get the serial port values, then the printer values */
4759 if ( i < serial_count )
4761 strcpy( portname, "COMx:" );
4762 portname[3] = '1' + i;
4763 if (!WINSPOOL_ComPortExists( portname ))
4766 TRACE("Found %s\n", portname );
4767 vallen = strlen( portname );
4771 r = RegEnumValueA( hkey_printer, i-serial_count,
4772 portname, &vallen, NULL, NULL, NULL, 0 );
4777 /* add a colon if necessary, and make it upper case */
4778 CharUpperBuffA(portname,vallen);
4779 if (strcasecmp(portname,"nul")!=0)
4780 if (vallen && (portname[vallen-1] != ':') )
4781 lstrcatA(portname,":");
4783 /* add the port info structure if we can fit it */
4784 if ( info_size*(n+1) < bufsize )
4788 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4789 info->pName = (LPSTR) &buffer[ofs];
4791 else if ( level == 2)
4793 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4794 info->pPortName = (LPSTR) &buffer[ofs];
4795 /* FIXME: fill in more stuff here */
4796 info->pMonitorName = PortMonitor;
4797 info->pDescription = PortDescription;
4798 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4801 /* add the name of the port if we can fit it */
4802 if ( ofs < bufsize )
4803 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4809 ofs += lstrlenA(portname)+1;
4812 RegCloseKey(hkey_printer);
4823 /******************************************************************************
4824 * EnumPortsW (WINSPOOL.@)
4826 * Enumerate available Ports
4829 * name [I] Servername or NULL (local Computer)
4830 * level [I] Structure-Level (1 or 2)
4831 * buffer [O] PTR to Buffer that receives the Result
4832 * bufsize [I] Size of Buffer at buffer
4833 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4834 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4838 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4842 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4845 DWORD numentries = 0;
4848 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
4849 cbBuf, pcbNeeded, pcReturned);
4851 if (pName && (pName[0])) {
4852 FIXME("not implemented for Server %s\n", debugstr_w(pName));
4853 SetLastError(ERROR_ACCESS_DENIED);
4857 /* Level is not checked in win9x */
4858 if (!Level || (Level > 2)) {
4859 WARN("level (%d) is ignored in win9x\n", Level);
4860 SetLastError(ERROR_INVALID_LEVEL);
4864 SetLastError(RPC_X_NULL_REF_POINTER);
4868 EnterCriticalSection(&monitor_handles_cs);
4871 /* Scan all local Ports */
4873 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
4875 /* we calculated the needed buffersize. now do the error-checks */
4876 if (cbBuf < needed) {
4877 monitor_unloadall();
4878 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4879 goto emP_cleanup_cs;
4881 else if (!pPorts || !pcReturned) {
4882 monitor_unloadall();
4883 SetLastError(RPC_X_NULL_REF_POINTER);
4884 goto emP_cleanup_cs;
4887 /* Fill the Buffer */
4888 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
4890 monitor_unloadall();
4893 LeaveCriticalSection(&monitor_handles_cs);
4896 if (pcbNeeded) *pcbNeeded = needed;
4897 if (pcReturned) *pcReturned = (res) ? numentries : 0;
4899 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
4900 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
4905 /******************************************************************************
4906 * GetDefaultPrinterW (WINSPOOL.@)
4909 * This function must read the value from data 'device' of key
4910 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4912 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4916 WCHAR *buffer, *ptr;
4920 SetLastError(ERROR_INVALID_PARAMETER);
4924 /* make the buffer big enough for the stuff from the profile/registry,
4925 * the content must fit into the local buffer to compute the correct
4926 * size even if the extern buffer is too small or not given.
4927 * (20 for ,driver,port) */
4929 len = max(100, (insize + 20));
4930 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4932 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4934 SetLastError (ERROR_FILE_NOT_FOUND);
4938 TRACE("%s\n", debugstr_w(buffer));
4940 if ((ptr = strchrW(buffer, ',')) == NULL)
4942 SetLastError(ERROR_INVALID_NAME);
4948 *namesize = strlenW(buffer) + 1;
4949 if(!name || (*namesize > insize))
4951 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4955 strcpyW(name, buffer);
4958 HeapFree( GetProcessHeap(), 0, buffer);
4963 /******************************************************************************
4964 * GetDefaultPrinterA (WINSPOOL.@)
4966 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4970 WCHAR *bufferW = NULL;
4974 SetLastError(ERROR_INVALID_PARAMETER);
4978 if(name && *namesize) {
4980 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4983 if(!GetDefaultPrinterW( bufferW, namesize)) {
4988 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4992 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4995 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
4998 HeapFree( GetProcessHeap(), 0, bufferW);
5003 /******************************************************************************
5004 * SetDefaultPrinterW (WINSPOOL.204)
5006 * Set the Name of the Default Printer
5009 * pszPrinter [I] Name of the Printer or NULL
5016 * When the Parameter is NULL or points to an Empty String and
5017 * a Default Printer was already present, then this Function changes nothing.
5018 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5019 * the First enumerated local Printer is used.
5022 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5025 TRACE("(%s)\n", debugstr_w(pszPrinter));
5027 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5031 /******************************************************************************
5032 * SetDefaultPrinterA (WINSPOOL.202)
5034 * See SetDefaultPrinterW.
5037 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5040 TRACE("(%s)\n", debugstr_a(pszPrinter));
5042 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5047 /******************************************************************************
5048 * SetPrinterDataExA (WINSPOOL.@)
5050 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5051 LPCSTR pValueName, DWORD Type,
5052 LPBYTE pData, DWORD cbData)
5054 HKEY hkeyPrinter, hkeySubkey;
5057 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5058 debugstr_a(pValueName), Type, pData, cbData);
5060 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5064 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5066 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5067 RegCloseKey(hkeyPrinter);
5070 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5071 RegCloseKey(hkeySubkey);
5072 RegCloseKey(hkeyPrinter);
5076 /******************************************************************************
5077 * SetPrinterDataExW (WINSPOOL.@)
5079 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5080 LPCWSTR pValueName, DWORD Type,
5081 LPBYTE pData, DWORD cbData)
5083 HKEY hkeyPrinter, hkeySubkey;
5086 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5087 debugstr_w(pValueName), Type, pData, cbData);
5089 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5093 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5095 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5096 RegCloseKey(hkeyPrinter);
5099 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5100 RegCloseKey(hkeySubkey);
5101 RegCloseKey(hkeyPrinter);
5105 /******************************************************************************
5106 * SetPrinterDataA (WINSPOOL.@)
5108 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5109 LPBYTE pData, DWORD cbData)
5111 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5115 /******************************************************************************
5116 * SetPrinterDataW (WINSPOOL.@)
5118 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5119 LPBYTE pData, DWORD cbData)
5121 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5125 /******************************************************************************
5126 * GetPrinterDataExA (WINSPOOL.@)
5128 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5129 LPCSTR pValueName, LPDWORD pType,
5130 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5132 HKEY hkeyPrinter, hkeySubkey;
5135 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5136 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5139 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5143 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5145 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5146 RegCloseKey(hkeyPrinter);
5150 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5151 RegCloseKey(hkeySubkey);
5152 RegCloseKey(hkeyPrinter);
5156 /******************************************************************************
5157 * GetPrinterDataExW (WINSPOOL.@)
5159 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5160 LPCWSTR pValueName, LPDWORD pType,
5161 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5163 HKEY hkeyPrinter, hkeySubkey;
5166 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5167 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5170 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5174 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5176 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5177 RegCloseKey(hkeyPrinter);
5181 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5182 RegCloseKey(hkeySubkey);
5183 RegCloseKey(hkeyPrinter);
5187 /******************************************************************************
5188 * GetPrinterDataA (WINSPOOL.@)
5190 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5191 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5193 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5194 pData, nSize, pcbNeeded);
5197 /******************************************************************************
5198 * GetPrinterDataW (WINSPOOL.@)
5200 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5201 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5203 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5204 pData, nSize, pcbNeeded);
5207 /*******************************************************************************
5208 * EnumPrinterDataExW [WINSPOOL.@]
5210 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5211 LPBYTE pEnumValues, DWORD cbEnumValues,
5212 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5214 HKEY hkPrinter, hkSubKey;
5215 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5216 cbValueNameLen, cbMaxValueLen, cbValueLen,
5221 PPRINTER_ENUM_VALUESW ppev;
5223 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5225 if (pKeyName == NULL || *pKeyName == 0)
5226 return ERROR_INVALID_PARAMETER;
5228 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5229 if (ret != ERROR_SUCCESS)
5231 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5236 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5237 if (ret != ERROR_SUCCESS)
5239 r = RegCloseKey (hkPrinter);
5240 if (r != ERROR_SUCCESS)
5241 WARN ("RegCloseKey returned %i\n", r);
5242 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5243 debugstr_w (pKeyName), ret);
5247 ret = RegCloseKey (hkPrinter);
5248 if (ret != ERROR_SUCCESS)
5250 ERR ("RegCloseKey returned %i\n", ret);
5251 r = RegCloseKey (hkSubKey);
5252 if (r != ERROR_SUCCESS)
5253 WARN ("RegCloseKey returned %i\n", r);
5257 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5258 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5259 if (ret != ERROR_SUCCESS)
5261 r = RegCloseKey (hkSubKey);
5262 if (r != ERROR_SUCCESS)
5263 WARN ("RegCloseKey returned %i\n", r);
5264 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5268 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5269 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5271 if (cValues == 0) /* empty key */
5273 r = RegCloseKey (hkSubKey);
5274 if (r != ERROR_SUCCESS)
5275 WARN ("RegCloseKey returned %i\n", r);
5276 *pcbEnumValues = *pnEnumValues = 0;
5277 return ERROR_SUCCESS;
5280 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5282 hHeap = GetProcessHeap ();
5285 ERR ("GetProcessHeap failed\n");
5286 r = RegCloseKey (hkSubKey);
5287 if (r != ERROR_SUCCESS)
5288 WARN ("RegCloseKey returned %i\n", r);
5289 return ERROR_OUTOFMEMORY;
5292 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5293 if (lpValueName == NULL)
5295 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5296 r = RegCloseKey (hkSubKey);
5297 if (r != ERROR_SUCCESS)
5298 WARN ("RegCloseKey returned %i\n", r);
5299 return ERROR_OUTOFMEMORY;
5302 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5303 if (lpValue == NULL)
5305 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5306 if (HeapFree (hHeap, 0, lpValueName) == 0)
5307 WARN ("HeapFree failed with code %i\n", GetLastError ());
5308 r = RegCloseKey (hkSubKey);
5309 if (r != ERROR_SUCCESS)
5310 WARN ("RegCloseKey returned %i\n", r);
5311 return ERROR_OUTOFMEMORY;
5314 TRACE ("pass 1: calculating buffer required for all names and values\n");
5316 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5318 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5320 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5322 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5323 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5324 NULL, NULL, lpValue, &cbValueLen);
5325 if (ret != ERROR_SUCCESS)
5327 if (HeapFree (hHeap, 0, lpValue) == 0)
5328 WARN ("HeapFree failed with code %i\n", GetLastError ());
5329 if (HeapFree (hHeap, 0, lpValueName) == 0)
5330 WARN ("HeapFree failed with code %i\n", GetLastError ());
5331 r = RegCloseKey (hkSubKey);
5332 if (r != ERROR_SUCCESS)
5333 WARN ("RegCloseKey returned %i\n", r);
5334 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5338 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5339 debugstr_w (lpValueName), dwIndex,
5340 cbValueNameLen + 1, cbValueLen);
5342 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5343 cbBufSize += cbValueLen;
5346 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5348 *pcbEnumValues = cbBufSize;
5349 *pnEnumValues = cValues;
5351 if (cbEnumValues < cbBufSize) /* buffer too small */
5353 if (HeapFree (hHeap, 0, lpValue) == 0)
5354 WARN ("HeapFree failed with code %i\n", GetLastError ());
5355 if (HeapFree (hHeap, 0, lpValueName) == 0)
5356 WARN ("HeapFree failed with code %i\n", GetLastError ());
5357 r = RegCloseKey (hkSubKey);
5358 if (r != ERROR_SUCCESS)
5359 WARN ("RegCloseKey returned %i\n", r);
5360 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5361 return ERROR_MORE_DATA;
5364 TRACE ("pass 2: copying all names and values to buffer\n");
5366 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5367 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5369 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5371 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5372 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5373 NULL, &dwType, lpValue, &cbValueLen);
5374 if (ret != ERROR_SUCCESS)
5376 if (HeapFree (hHeap, 0, lpValue) == 0)
5377 WARN ("HeapFree failed with code %i\n", GetLastError ());
5378 if (HeapFree (hHeap, 0, lpValueName) == 0)
5379 WARN ("HeapFree failed with code %i\n", GetLastError ());
5380 r = RegCloseKey (hkSubKey);
5381 if (r != ERROR_SUCCESS)
5382 WARN ("RegCloseKey returned %i\n", r);
5383 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5387 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5388 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5389 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5390 pEnumValues += cbValueNameLen;
5392 /* return # of *bytes* (including trailing \0), not # of chars */
5393 ppev[dwIndex].cbValueName = cbValueNameLen;
5395 ppev[dwIndex].dwType = dwType;
5397 memcpy (pEnumValues, lpValue, cbValueLen);
5398 ppev[dwIndex].pData = pEnumValues;
5399 pEnumValues += cbValueLen;
5401 ppev[dwIndex].cbData = cbValueLen;
5403 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5404 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5407 if (HeapFree (hHeap, 0, lpValue) == 0)
5409 ret = GetLastError ();
5410 ERR ("HeapFree failed with code %i\n", ret);
5411 if (HeapFree (hHeap, 0, lpValueName) == 0)
5412 WARN ("HeapFree failed with code %i\n", GetLastError ());
5413 r = RegCloseKey (hkSubKey);
5414 if (r != ERROR_SUCCESS)
5415 WARN ("RegCloseKey returned %i\n", r);
5419 if (HeapFree (hHeap, 0, lpValueName) == 0)
5421 ret = GetLastError ();
5422 ERR ("HeapFree failed with code %i\n", ret);
5423 r = RegCloseKey (hkSubKey);
5424 if (r != ERROR_SUCCESS)
5425 WARN ("RegCloseKey returned %i\n", r);
5429 ret = RegCloseKey (hkSubKey);
5430 if (ret != ERROR_SUCCESS)
5432 ERR ("RegCloseKey returned %i\n", ret);
5436 return ERROR_SUCCESS;
5439 /*******************************************************************************
5440 * EnumPrinterDataExA [WINSPOOL.@]
5442 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5443 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5444 * what Windows 2000 SP1 does.
5447 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5448 LPBYTE pEnumValues, DWORD cbEnumValues,
5449 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5453 DWORD ret, dwIndex, dwBufSize;
5457 TRACE ("%p %s\n", hPrinter, pKeyName);
5459 if (pKeyName == NULL || *pKeyName == 0)
5460 return ERROR_INVALID_PARAMETER;
5462 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5465 ret = GetLastError ();
5466 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5470 hHeap = GetProcessHeap ();
5473 ERR ("GetProcessHeap failed\n");
5474 return ERROR_OUTOFMEMORY;
5477 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5478 if (pKeyNameW == NULL)
5480 ERR ("Failed to allocate %i bytes from process heap\n",
5481 (LONG)(len * sizeof (WCHAR)));
5482 return ERROR_OUTOFMEMORY;
5485 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5487 ret = GetLastError ();
5488 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5489 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5490 WARN ("HeapFree failed with code %i\n", GetLastError ());
5494 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5495 pcbEnumValues, pnEnumValues);
5496 if (ret != ERROR_SUCCESS)
5498 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5499 WARN ("HeapFree failed with code %i\n", GetLastError ());
5500 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5504 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5506 ret = GetLastError ();
5507 ERR ("HeapFree failed with code %i\n", ret);
5511 if (*pnEnumValues == 0) /* empty key */
5512 return ERROR_SUCCESS;
5515 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5517 PPRINTER_ENUM_VALUESW ppev =
5518 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5520 if (dwBufSize < ppev->cbValueName)
5521 dwBufSize = ppev->cbValueName;
5523 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5524 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5525 dwBufSize = ppev->cbData;
5528 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5530 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5531 if (pBuffer == NULL)
5533 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5534 return ERROR_OUTOFMEMORY;
5537 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5539 PPRINTER_ENUM_VALUESW ppev =
5540 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5542 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5543 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5547 ret = GetLastError ();
5548 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5549 if (HeapFree (hHeap, 0, pBuffer) == 0)
5550 WARN ("HeapFree failed with code %i\n", GetLastError ());
5554 memcpy (ppev->pValueName, pBuffer, len);
5556 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5558 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5559 ppev->dwType != REG_MULTI_SZ)
5562 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5563 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5566 ret = GetLastError ();
5567 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5568 if (HeapFree (hHeap, 0, pBuffer) == 0)
5569 WARN ("HeapFree failed with code %i\n", GetLastError ());
5573 memcpy (ppev->pData, pBuffer, len);
5575 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5576 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5579 if (HeapFree (hHeap, 0, pBuffer) == 0)
5581 ret = GetLastError ();
5582 ERR ("HeapFree failed with code %i\n", ret);
5586 return ERROR_SUCCESS;
5589 /******************************************************************************
5590 * AbortPrinter (WINSPOOL.@)
5592 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5594 FIXME("(%p), stub!\n", hPrinter);
5598 /******************************************************************************
5599 * AddPortA (WINSPOOL.@)
5604 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5606 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5610 /******************************************************************************
5611 * AddPortW (WINSPOOL.@)
5613 * Add a Port for a specific Monitor
5616 * pName [I] Servername or NULL (local Computer)
5617 * hWnd [I] Handle to parent Window for the Dialog-Box
5618 * pMonitorName [I] Name of the Monitor that manage the Port
5628 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5630 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5634 /******************************************************************************
5635 * AddPortExA (WINSPOOL.@)
5640 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5642 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5643 lpBuffer, debugstr_a(lpMonitorName));
5647 /******************************************************************************
5648 * AddPortExW (WINSPOOL.@)
5650 * Add a Port for a specific Monitor, without presenting a user interface
5653 * hMonitor [I] Handle from InitializePrintMonitor2()
5654 * pName [I] Servername or NULL (local Computer)
5655 * Level [I] Structure-Level (1 or 2) for lpBuffer
5656 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5657 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5667 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5669 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5670 lpBuffer, debugstr_w(lpMonitorName));
5674 /******************************************************************************
5675 * AddPrinterConnectionA (WINSPOOL.@)
5677 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5679 FIXME("%s\n", debugstr_a(pName));
5683 /******************************************************************************
5684 * AddPrinterConnectionW (WINSPOOL.@)
5686 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5688 FIXME("%s\n", debugstr_w(pName));
5692 /******************************************************************************
5693 * AddPrinterDriverExW (WINSPOOL.@)
5695 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5696 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5698 FIXME("%s %d %p %d\n", debugstr_w(pName),
5699 Level, pDriverInfo, dwFileCopyFlags);
5700 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5704 /******************************************************************************
5705 * AddPrinterDriverExA (WINSPOOL.@)
5707 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5708 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5710 FIXME("%s %d %p %d\n", debugstr_a(pName),
5711 Level, pDriverInfo, dwFileCopyFlags);
5712 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5716 /******************************************************************************
5717 * ConfigurePortA (WINSPOOL.@)
5719 * See ConfigurePortW.
5722 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5724 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5728 /******************************************************************************
5729 * ConfigurePortW (WINSPOOL.@)
5731 * Display the Configuration-Dialog for a specific Port
5734 * pName [I] Servername or NULL (local Computer)
5735 * hWnd [I] Handle to parent Window for the Dialog-Box
5736 * pPortName [I] Name of the Port, that should be configured
5746 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5748 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5752 /******************************************************************************
5753 * ConnectToPrinterDlg (WINSPOOL.@)
5755 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5757 FIXME("%p %x\n", hWnd, Flags);
5761 /******************************************************************************
5762 * DeletePrinterConnectionA (WINSPOOL.@)
5764 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5766 FIXME("%s\n", debugstr_a(pName));
5770 /******************************************************************************
5771 * DeletePrinterConnectionW (WINSPOOL.@)
5773 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5775 FIXME("%s\n", debugstr_w(pName));
5779 /******************************************************************************
5780 * DeletePrinterDriverExW (WINSPOOL.@)
5782 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5783 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5785 FIXME("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
5786 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5790 /******************************************************************************
5791 * DeletePrinterDriverExA (WINSPOOL.@)
5793 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5794 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5796 FIXME("%s %s %s %x %x\n", debugstr_a(pName), debugstr_a(pEnvironment),
5797 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5801 /******************************************************************************
5802 * DeletePrinterDataExW (WINSPOOL.@)
5804 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5807 FIXME("%p %s %s\n", hPrinter,
5808 debugstr_w(pKeyName), debugstr_w(pValueName));
5809 return ERROR_INVALID_PARAMETER;
5812 /******************************************************************************
5813 * DeletePrinterDataExA (WINSPOOL.@)
5815 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5818 FIXME("%p %s %s\n", hPrinter,
5819 debugstr_a(pKeyName), debugstr_a(pValueName));
5820 return ERROR_INVALID_PARAMETER;
5823 /******************************************************************************
5824 * DeletePrintProcessorA (WINSPOOL.@)
5826 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5828 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5829 debugstr_a(pPrintProcessorName));
5833 /******************************************************************************
5834 * DeletePrintProcessorW (WINSPOOL.@)
5836 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5838 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5839 debugstr_w(pPrintProcessorName));
5843 /******************************************************************************
5844 * DeletePrintProvidorA (WINSPOOL.@)
5846 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5848 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5849 debugstr_a(pPrintProviderName));
5853 /******************************************************************************
5854 * DeletePrintProvidorW (WINSPOOL.@)
5856 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5858 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5859 debugstr_w(pPrintProviderName));
5863 /******************************************************************************
5864 * EnumFormsA (WINSPOOL.@)
5866 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5867 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5869 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5870 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5874 /******************************************************************************
5875 * EnumFormsW (WINSPOOL.@)
5877 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5878 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5880 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5881 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5885 /*****************************************************************************
5886 * EnumMonitorsA [WINSPOOL.@]
5888 * See EnumMonitorsW.
5891 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5892 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5895 LPBYTE bufferW = NULL;
5896 LPWSTR nameW = NULL;
5898 DWORD numentries = 0;
5901 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5902 cbBuf, pcbNeeded, pcReturned);
5904 /* convert servername to unicode */
5906 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5907 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5908 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5910 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5911 needed = cbBuf * sizeof(WCHAR);
5912 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5913 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5915 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5916 if (pcbNeeded) needed = *pcbNeeded;
5917 /* HeapReAlloc return NULL, when bufferW was NULL */
5918 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5919 HeapAlloc(GetProcessHeap(), 0, needed);
5921 /* Try again with the large Buffer */
5922 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5924 numentries = pcReturned ? *pcReturned : 0;
5927 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5928 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5931 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5932 DWORD entrysize = 0;
5935 LPMONITOR_INFO_2W mi2w;
5936 LPMONITOR_INFO_2A mi2a;
5938 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5939 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5941 /* First pass: calculate the size for all Entries */
5942 mi2w = (LPMONITOR_INFO_2W) bufferW;
5943 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5945 while (index < numentries) {
5947 needed += entrysize; /* MONITOR_INFO_?A */
5948 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5950 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5951 NULL, 0, NULL, NULL);
5953 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5954 NULL, 0, NULL, NULL);
5955 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5956 NULL, 0, NULL, NULL);
5958 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5959 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5960 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5963 /* check for errors and quit on failure */
5964 if (cbBuf < needed) {
5965 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5969 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5970 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5971 cbBuf -= len ; /* free Bytes in the user-Buffer */
5972 mi2w = (LPMONITOR_INFO_2W) bufferW;
5973 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5975 /* Second Pass: Fill the User Buffer (if we have one) */
5976 while ((index < numentries) && pMonitors) {
5978 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
5980 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5981 ptr, cbBuf , NULL, NULL);
5985 mi2a->pEnvironment = ptr;
5986 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5987 ptr, cbBuf, NULL, NULL);
5991 mi2a->pDLLName = ptr;
5992 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5993 ptr, cbBuf, NULL, NULL);
5997 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5998 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5999 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6003 if (pcbNeeded) *pcbNeeded = needed;
6004 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6006 HeapFree(GetProcessHeap(), 0, nameW);
6007 HeapFree(GetProcessHeap(), 0, bufferW);
6009 TRACE("returning %d with %d (%d byte for %d entries)\n",
6010 (res), GetLastError(), needed, numentries);
6016 /*****************************************************************************
6017 * EnumMonitorsW [WINSPOOL.@]
6019 * Enumerate available Port-Monitors
6022 * pName [I] Servername or NULL (local Computer)
6023 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6024 * pMonitors [O] PTR to Buffer that receives the Result
6025 * cbBuf [I] Size of Buffer at pMonitors
6026 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6027 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6031 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6034 * Windows reads the Registry once and cache the Results.
6036 *| Language-Monitors are also installed in the same Registry-Location but
6037 *| they are filtered in Windows (not returned by EnumMonitors).
6038 *| We do no filtering to simplify our Code.
6041 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6042 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6045 DWORD numentries = 0;
6048 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6049 cbBuf, pcbNeeded, pcReturned);
6051 if (pName && (lstrlenW(pName))) {
6052 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6053 SetLastError(ERROR_ACCESS_DENIED);
6057 /* Level is not checked in win9x */
6058 if (!Level || (Level > 2)) {
6059 WARN("level (%d) is ignored in win9x\n", Level);
6060 SetLastError(ERROR_INVALID_LEVEL);
6064 SetLastError(RPC_X_NULL_REF_POINTER);
6068 /* Scan all Monitor-Keys */
6070 needed = get_local_monitors(Level, NULL, 0, &numentries);
6072 /* we calculated the needed buffersize. now do the error-checks */
6073 if (cbBuf < needed) {
6074 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6077 else if (!pMonitors || !pcReturned) {
6078 SetLastError(RPC_X_NULL_REF_POINTER);
6082 /* fill the Buffer with the Monitor-Keys */
6083 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6087 if (pcbNeeded) *pcbNeeded = needed;
6088 if (pcReturned) *pcReturned = numentries;
6090 TRACE("returning %d with %d (%d byte for %d entries)\n",
6091 res, GetLastError(), needed, numentries);
6096 /******************************************************************************
6097 * XcvDataW (WINSPOOL.@)
6100 * There doesn't seem to be an A version...
6102 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6103 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6104 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6106 FIXME("%p %s %p %d %p %d %p %p\n", hXcv, debugstr_w(pszDataName),
6107 pInputData, cbInputData, pOutputData,
6108 cbOutputData, pcbOutputNeeded, pdwStatus);
6112 /*****************************************************************************
6113 * EnumPrinterDataA [WINSPOOL.@]
6116 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6117 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6118 DWORD cbData, LPDWORD pcbData )
6120 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6121 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6122 return ERROR_NO_MORE_ITEMS;
6125 /*****************************************************************************
6126 * EnumPrinterDataW [WINSPOOL.@]
6129 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6130 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6131 DWORD cbData, LPDWORD pcbData )
6133 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6134 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6135 return ERROR_NO_MORE_ITEMS;
6138 /*****************************************************************************
6139 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6142 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6143 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6144 LPDWORD pcbNeeded, LPDWORD pcReturned)
6146 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6147 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6148 pcbNeeded, pcReturned);
6152 /*****************************************************************************
6153 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6156 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6157 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6158 LPDWORD pcbNeeded, LPDWORD pcReturned)
6160 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6161 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6162 pcbNeeded, pcReturned);
6166 /*****************************************************************************
6167 * EnumPrintProcessorsA [WINSPOOL.@]
6170 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6171 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6173 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6174 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6178 /*****************************************************************************
6179 * EnumPrintProcessorsW [WINSPOOL.@]
6182 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6183 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6185 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6186 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6187 cbBuf, pcbNeeded, pcbReturned);
6191 /*****************************************************************************
6192 * ExtDeviceMode [WINSPOOL.@]
6195 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6196 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6199 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6200 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6201 debugstr_a(pProfile), fMode);
6205 /*****************************************************************************
6206 * FindClosePrinterChangeNotification [WINSPOOL.@]
6209 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6211 FIXME("Stub: %p\n", hChange);
6215 /*****************************************************************************
6216 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6219 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6220 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6222 FIXME("Stub: %p %x %x %p\n",
6223 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6224 return INVALID_HANDLE_VALUE;
6227 /*****************************************************************************
6228 * FindNextPrinterChangeNotification [WINSPOOL.@]
6231 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6232 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6234 FIXME("Stub: %p %p %p %p\n",
6235 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6239 /*****************************************************************************
6240 * FreePrinterNotifyInfo [WINSPOOL.@]
6243 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6245 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6249 /*****************************************************************************
6252 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6253 * ansi depending on the unicode parameter.
6255 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6265 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6268 memcpy(ptr, str, *size);
6275 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6278 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6285 /*****************************************************************************
6288 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6289 LPDWORD pcbNeeded, BOOL unicode)
6291 DWORD size, left = cbBuf;
6292 BOOL space = (cbBuf > 0);
6299 ji1->JobId = job->job_id;
6302 string_to_buf(job->document_title, ptr, left, &size, unicode);
6303 if(space && size <= left)
6305 ji1->pDocument = (LPWSTR)ptr;
6316 /*****************************************************************************
6319 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6320 LPDWORD pcbNeeded, BOOL unicode)
6322 DWORD size, left = cbBuf;
6323 BOOL space = (cbBuf > 0);
6330 ji2->JobId = job->job_id;
6333 string_to_buf(job->document_title, ptr, left, &size, unicode);
6334 if(space && size <= left)
6336 ji2->pDocument = (LPWSTR)ptr;
6347 /*****************************************************************************
6350 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6351 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6354 DWORD needed = 0, size;
6358 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6360 EnterCriticalSection(&printer_handles_cs);
6361 job = get_job(hPrinter, JobId);
6368 size = sizeof(JOB_INFO_1W);
6373 memset(pJob, 0, size);
6377 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6382 size = sizeof(JOB_INFO_2W);
6387 memset(pJob, 0, size);
6391 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6396 size = sizeof(JOB_INFO_3);
6400 memset(pJob, 0, size);
6409 SetLastError(ERROR_INVALID_LEVEL);
6413 *pcbNeeded = needed;
6415 LeaveCriticalSection(&printer_handles_cs);
6419 /*****************************************************************************
6420 * GetJobA [WINSPOOL.@]
6423 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6424 DWORD cbBuf, LPDWORD pcbNeeded)
6426 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6429 /*****************************************************************************
6430 * GetJobW [WINSPOOL.@]
6433 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6434 DWORD cbBuf, LPDWORD pcbNeeded)
6436 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6439 /*****************************************************************************
6442 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6444 char *unixname, *queue, *cmd;
6445 char fmt[] = "lpr -P%s %s";
6448 if(!(unixname = wine_get_unix_file_name(filename)))
6451 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6452 queue = HeapAlloc(GetProcessHeap(), 0, len);
6453 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6455 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6456 sprintf(cmd, fmt, queue, unixname);
6458 TRACE("printing with: %s\n", cmd);
6461 HeapFree(GetProcessHeap(), 0, cmd);
6462 HeapFree(GetProcessHeap(), 0, queue);
6463 HeapFree(GetProcessHeap(), 0, unixname);
6467 /*****************************************************************************
6470 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6472 #if HAVE_CUPS_CUPS_H
6475 char *unixname, *queue, *doc_titleA;
6479 if(!(unixname = wine_get_unix_file_name(filename)))
6482 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6483 queue = HeapAlloc(GetProcessHeap(), 0, len);
6484 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6486 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6487 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6488 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6490 TRACE("printing via cups\n");
6491 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6492 HeapFree(GetProcessHeap(), 0, doc_titleA);
6493 HeapFree(GetProcessHeap(), 0, queue);
6494 HeapFree(GetProcessHeap(), 0, unixname);
6500 return schedule_lpr(printer_name, filename);
6504 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6511 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6515 if(HIWORD(wparam) == BN_CLICKED)
6517 if(LOWORD(wparam) == IDOK)
6520 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6523 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6524 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6526 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6528 WCHAR caption[200], message[200];
6531 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6532 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6533 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6534 if(mb_ret == IDCANCEL)
6536 HeapFree(GetProcessHeap(), 0, filename);
6540 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6541 if(hf == INVALID_HANDLE_VALUE)
6543 WCHAR caption[200], message[200];
6545 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6546 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6547 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6548 HeapFree(GetProcessHeap(), 0, filename);
6552 DeleteFileW(filename);
6553 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6555 EndDialog(hwnd, IDOK);
6558 if(LOWORD(wparam) == IDCANCEL)
6560 EndDialog(hwnd, IDCANCEL);
6569 /*****************************************************************************
6572 static BOOL get_filename(LPWSTR *filename)
6574 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6575 file_dlg_proc, (LPARAM)filename) == IDOK;
6578 /*****************************************************************************
6581 static BOOL schedule_file(LPCWSTR filename)
6583 LPWSTR output = NULL;
6585 if(get_filename(&output))
6587 TRACE("copy to %s\n", debugstr_w(output));
6588 CopyFileW(filename, output, FALSE);
6589 HeapFree(GetProcessHeap(), 0, output);
6595 /*****************************************************************************
6598 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6601 char *unixname, *cmdA;
6603 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6607 if(!(unixname = wine_get_unix_file_name(filename)))
6610 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6611 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6612 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6614 TRACE("printing with: %s\n", cmdA);
6616 if((file_fd = open(unixname, O_RDONLY)) == -1)
6621 ERR("pipe() failed!\n");
6631 /* reset signals that we previously set to SIG_IGN */
6632 signal(SIGPIPE, SIG_DFL);
6633 signal(SIGCHLD, SIG_DFL);
6639 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6640 write(fds[1], buf, no_read);
6645 if(file_fd != -1) close(file_fd);
6646 if(fds[0] != -1) close(fds[0]);
6647 if(fds[1] != -1) close(fds[1]);
6649 HeapFree(GetProcessHeap(), 0, cmdA);
6650 HeapFree(GetProcessHeap(), 0, unixname);
6657 /*****************************************************************************
6660 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6662 int in_fd, out_fd, no_read;
6665 char *unixname, *outputA;
6668 if(!(unixname = wine_get_unix_file_name(filename)))
6671 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6672 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6673 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6675 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6676 in_fd = open(unixname, O_RDONLY);
6677 if(out_fd == -1 || in_fd == -1)
6680 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6681 write(out_fd, buf, no_read);
6685 if(in_fd != -1) close(in_fd);
6686 if(out_fd != -1) close(out_fd);
6687 HeapFree(GetProcessHeap(), 0, outputA);
6688 HeapFree(GetProcessHeap(), 0, unixname);
6692 /*****************************************************************************
6693 * ScheduleJob [WINSPOOL.@]
6696 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6698 opened_printer_t *printer;
6700 struct list *cursor, *cursor2;
6702 TRACE("(%p, %x)\n", hPrinter, dwJobID);
6703 EnterCriticalSection(&printer_handles_cs);
6704 printer = get_opened_printer(hPrinter);
6708 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6710 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6713 if(job->job_id != dwJobID) continue;
6715 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6716 if(hf != INVALID_HANDLE_VALUE)
6718 PRINTER_INFO_5W *pi5;
6722 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6723 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6725 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6726 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6727 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6728 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6729 debugstr_w(pi5->pPortName));
6733 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6734 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6736 DWORD type, count = sizeof(output);
6737 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6740 if(output[0] == '|')
6742 schedule_pipe(output + 1, job->filename);
6746 schedule_unixfile(output, job->filename);
6748 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6750 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6752 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6754 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6756 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6758 schedule_file(job->filename);
6762 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6764 HeapFree(GetProcessHeap(), 0, pi5);
6766 DeleteFileW(job->filename);
6768 list_remove(cursor);
6769 HeapFree(GetProcessHeap(), 0, job->document_title);
6770 HeapFree(GetProcessHeap(), 0, job->filename);
6771 HeapFree(GetProcessHeap(), 0, job);
6776 LeaveCriticalSection(&printer_handles_cs);
6780 /*****************************************************************************
6781 * StartDocDlgA [WINSPOOL.@]
6783 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6785 UNICODE_STRING usBuffer;
6788 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
6791 docW.cbSize = sizeof(docW);
6792 if (doc->lpszDocName)
6794 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
6795 if (!(docW.lpszDocName = docnameW)) return NULL;
6797 if (doc->lpszOutput)
6799 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
6800 if (!(docW.lpszOutput = outputW)) return NULL;
6802 if (doc->lpszDatatype)
6804 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
6805 if (!(docW.lpszDatatype = datatypeW)) return NULL;
6807 docW.fwType = doc->fwType;
6809 retW = StartDocDlgW(hPrinter, &docW);
6813 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6814 ret = HeapAlloc(GetProcessHeap(), 0, len);
6815 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6816 HeapFree(GetProcessHeap(), 0, retW);
6819 HeapFree(GetProcessHeap(), 0, datatypeW);
6820 HeapFree(GetProcessHeap(), 0, outputW);
6821 HeapFree(GetProcessHeap(), 0, docnameW);
6826 /*****************************************************************************
6827 * StartDocDlgW [WINSPOOL.@]
6829 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6830 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6831 * port is "FILE:". Also returns the full path if passed a relative path.
6833 * The caller should free the returned string from the process heap.
6835 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6840 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6842 PRINTER_INFO_5W *pi5;
6843 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6844 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6846 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6847 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6848 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6850 HeapFree(GetProcessHeap(), 0, pi5);
6853 HeapFree(GetProcessHeap(), 0, pi5);
6856 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6859 get_filename(&name);
6862 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6864 HeapFree(GetProcessHeap(), 0, name);
6867 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6868 GetFullPathNameW(name, len, ret, NULL);
6869 HeapFree(GetProcessHeap(), 0, name);
6874 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6877 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6878 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6880 attr = GetFileAttributesW(ret);
6881 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6883 HeapFree(GetProcessHeap(), 0, ret);