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, 2007 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"
63 #include "ddk/winsplp.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
68 /* ############################### */
70 static CRITICAL_SECTION monitor_handles_cs;
71 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
73 0, 0, &monitor_handles_cs,
74 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
75 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
77 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
80 static CRITICAL_SECTION printer_handles_cs;
81 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
83 0, 0, &printer_handles_cs,
84 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
85 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
87 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
89 /* ############################### */
100 LPPORT_INFO_2W cache; /* cached PORT_INFO_2W data */
101 DWORD pi1_needed; /* size for PORT_INFO_1W */
102 DWORD pi2_needed; /* size for PORT_INFO_2W */
103 DWORD returned; /* number of cached PORT_INFO_2W - entries */
129 WCHAR *document_title;
137 LPCWSTR versionregpath;
138 LPCWSTR versionsubdir;
141 /* ############################### */
143 static struct list monitor_handles = LIST_INIT( monitor_handles );
144 static monitor_t * pm_localport;
146 static opened_printer_t **printer_handles;
147 static int nb_printer_handles;
148 static LONG next_job_id = 1;
150 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
151 WORD fwCapability, LPSTR lpszOutput,
153 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
154 LPSTR lpszDevice, LPSTR lpszPort,
155 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
158 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'c','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
163 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
165 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
166 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
167 'C','o','n','t','r','o','l','\\',
168 'P','r','i','n','t','\\',
169 'M','o','n','i','t','o','r','s','\\',0};
171 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
172 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
173 'C','o','n','t','r','o','l','\\',
174 'P','r','i','n','t','\\',
175 'P','r','i','n','t','e','r','s',0};
177 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
179 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
180 'M','i','c','r','o','s','o','f','t','\\',
181 'W','i','n','d','o','w','s',' ','N','T','\\',
182 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
183 'W','i','n','d','o','w','s',0};
185 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
186 'M','i','c','r','o','s','o','f','t','\\',
187 'W','i','n','d','o','w','s',' ','N','T','\\',
188 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
189 'D','e','v','i','c','e','s',0};
191 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
192 'M','i','c','r','o','s','o','f','t','\\',
193 'W','i','n','d','o','w','s',' ','N','T','\\',
194 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
195 'P','o','r','t','s',0};
197 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
198 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
199 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
200 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
201 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
202 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
203 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
205 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
206 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
208 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
209 'i','o','n',' ','F','i','l','e',0};
210 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
211 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
212 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
214 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
216 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
217 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
218 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
219 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
220 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
221 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
222 static const WCHAR NameW[] = {'N','a','m','e',0};
223 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
224 static const WCHAR PortW[] = {'P','o','r','t',0};
225 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
226 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
228 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
230 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
231 'v','e','r','D','a','t','a',0};
232 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
234 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
235 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
236 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
237 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
238 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
239 static const WCHAR emptyStringW[] = {0};
240 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
241 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
243 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
245 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
246 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
247 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
249 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
250 'D','o','c','u','m','e','n','t',0};
253 /*****************************************************************************
254 * WINSPOOL_SHRegDeleteKey
256 * Recursively delete subkeys.
257 * Cut & paste from shlwapi.
260 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
262 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
263 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
266 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
269 /* Find how many subkeys there are */
270 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
271 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
275 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
276 /* Name too big: alloc a buffer for it */
277 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
280 dwRet = ERROR_NOT_ENOUGH_MEMORY;
283 /* Recursively delete all the subkeys */
284 for(i = 0; i < dwKeyCount && !dwRet; i++)
286 dwSize = dwMaxSubkeyLen;
287 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
289 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
292 if (lpszName != szNameBuf)
293 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
297 RegCloseKey(hSubKey);
299 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
305 /******************************************************************
306 * validate the user-supplied printing-environment [internal]
309 * env [I] PTR to Environment-String or NULL
313 * Success: PTR to printenv_t
316 * An empty string is handled the same way as NULL.
317 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
321 static const printenv_t * validate_envW(LPCWSTR env)
323 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
324 3, Version3_RegPathW, Version3_SubdirW};
325 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
326 0, emptyStringW, emptyStringW};
327 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
329 const printenv_t *result = NULL;
332 TRACE("testing %s\n", debugstr_w(env));
335 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
337 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
339 result = all_printenv[i];
344 if (result == NULL) {
345 FIXME("unsupported Environment: %s\n", debugstr_w(env));
346 SetLastError(ERROR_INVALID_ENVIRONMENT);
348 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
352 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
354 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
360 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
361 if passed a NULL string. This returns NULLs to the result.
363 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
367 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
368 return usBufferPtr->Buffer;
370 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
374 static LPWSTR strdupW(LPCWSTR p)
380 len = (strlenW(p) + 1) * sizeof(WCHAR);
381 ret = HeapAlloc(GetProcessHeap(), 0, len);
386 static LPSTR strdupWtoA( LPCWSTR str )
391 if (!str) return NULL;
392 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
393 ret = HeapAlloc( GetProcessHeap(), 0, len );
394 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
398 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
399 The result includes all \0s (specifically the last two). */
400 static int multi_sz_lenA(const char *str)
402 const char *ptr = str;
406 ptr += lstrlenA(ptr) + 1;
409 return ptr - str + 1;
413 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
416 /* If forcing, or no profile string entry for device yet, set the entry
418 * The always change entry if not WINEPS yet is discussable.
421 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
423 !strstr(qbuf,"WINEPS.DRV")
425 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
428 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
429 WriteProfileStringA("windows","device",buf);
430 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
431 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
434 HeapFree(GetProcessHeap(),0,buf);
438 static BOOL add_printer_driver(const char *name)
442 static char driver_path[] = "wineps16",
443 data_file[] = "<datafile?>",
444 config_file[] = "wineps16",
445 help_file[] = "<helpfile?>",
446 dep_file[] = "<dependent files?>\0",
447 monitor_name[] = "<monitor name?>",
448 default_data_type[] = "RAW";
450 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
451 di3a.pName = (char *)name;
452 di3a.pEnvironment = NULL; /* NULL means auto */
453 di3a.pDriverPath = driver_path;
454 di3a.pDataFile = data_file;
455 di3a.pConfigFile = config_file;
456 di3a.pHelpFile = help_file;
457 di3a.pDependentFiles = dep_file;
458 di3a.pMonitorName = monitor_name;
459 di3a.pDefaultDataType = default_data_type;
461 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
463 ERR("Failed adding driver (%d)\n", GetLastError());
469 #ifdef HAVE_CUPS_CUPS_H
470 static typeof(cupsGetDests) *pcupsGetDests;
471 static typeof(cupsGetPPD) *pcupsGetPPD;
472 static typeof(cupsPrintFile) *pcupsPrintFile;
473 static void *cupshandle;
475 static BOOL CUPS_LoadPrinters(void)
478 BOOL hadprinter = FALSE;
480 PRINTER_INFO_2A pinfo2a;
482 HKEY hkeyPrinter, hkeyPrinters, hkey;
484 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
487 TRACE("loaded %s\n", SONAME_LIBCUPS);
490 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
491 if (!p##x) return FALSE;
494 DYNCUPS(cupsGetDests);
495 DYNCUPS(cupsPrintFile);
498 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
500 ERR("Can't create Printers key\n");
504 nrofdests = pcupsGetDests(&dests);
505 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
506 for (i=0;i<nrofdests;i++) {
507 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
508 sprintf(port,"LPR:%s",dests[i].name);
509 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
510 sprintf(devline,"WINEPS.DRV,%s",port);
511 WriteProfileStringA("devices",dests[i].name,devline);
512 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
513 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
516 HeapFree(GetProcessHeap(),0,devline);
518 TRACE("Printer %d: %s\n", i, dests[i].name);
519 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
520 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
522 TRACE("Printer already exists\n");
523 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
524 RegCloseKey(hkeyPrinter);
526 static CHAR data_type[] = "RAW",
527 print_proc[] = "WinPrint",
528 comment[] = "WINEPS Printer using CUPS",
529 location[] = "<physical location of printer>",
530 params[] = "<parameters?>",
531 share_name[] = "<share name?>",
532 sep_file[] = "<sep file?>";
534 add_printer_driver(dests[i].name);
536 memset(&pinfo2a,0,sizeof(pinfo2a));
537 pinfo2a.pPrinterName = dests[i].name;
538 pinfo2a.pDatatype = data_type;
539 pinfo2a.pPrintProcessor = print_proc;
540 pinfo2a.pDriverName = dests[i].name;
541 pinfo2a.pComment = comment;
542 pinfo2a.pLocation = location;
543 pinfo2a.pPortName = port;
544 pinfo2a.pParameters = params;
545 pinfo2a.pShareName = share_name;
546 pinfo2a.pSepFile = sep_file;
548 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
549 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
550 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
553 HeapFree(GetProcessHeap(),0,port);
556 if (dests[i].is_default)
557 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
559 RegCloseKey(hkeyPrinters);
565 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
566 PRINTER_INFO_2A pinfo2a;
567 char *e,*s,*name,*prettyname,*devname;
568 BOOL ret = FALSE, set_default = FALSE;
569 char *port,*devline,*env_default;
570 HKEY hkeyPrinter, hkeyPrinters, hkey;
572 while (isspace(*pent)) pent++;
573 s = strchr(pent,':');
575 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
583 TRACE("name=%s entry=%s\n",name, pent);
585 if(ispunct(*name)) { /* a tc entry, not a real printer */
586 TRACE("skipping tc entry\n");
590 if(strstr(pent,":server")) { /* server only version so skip */
591 TRACE("skipping server entry\n");
595 /* Determine whether this is a postscript printer. */
598 env_default = getenv("PRINTER");
600 /* Get longest name, usually the one at the right for later display. */
601 while((s=strchr(prettyname,'|'))) {
604 while(isspace(*--e)) *e = '\0';
605 TRACE("\t%s\n", debugstr_a(prettyname));
606 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
607 for(prettyname = s+1; isspace(*prettyname); prettyname++)
610 e = prettyname + strlen(prettyname);
611 while(isspace(*--e)) *e = '\0';
612 TRACE("\t%s\n", debugstr_a(prettyname));
613 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
615 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
616 * if it is too long, we use it as comment below. */
617 devname = prettyname;
618 if (strlen(devname)>=CCHDEVICENAME-1)
620 if (strlen(devname)>=CCHDEVICENAME-1) {
625 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
626 sprintf(port,"LPR:%s",name);
628 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
629 sprintf(devline,"WINEPS.DRV,%s",port);
630 WriteProfileStringA("devices",devname,devline);
631 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
632 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
635 HeapFree(GetProcessHeap(),0,devline);
637 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
639 ERR("Can't create Printers key\n");
643 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
644 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
646 TRACE("Printer already exists\n");
647 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
648 RegCloseKey(hkeyPrinter);
650 static CHAR data_type[] = "RAW",
651 print_proc[] = "WinPrint",
652 comment[] = "WINEPS Printer using LPR",
653 params[] = "<parameters?>",
654 share_name[] = "<share name?>",
655 sep_file[] = "<sep file?>";
657 add_printer_driver(devname);
659 memset(&pinfo2a,0,sizeof(pinfo2a));
660 pinfo2a.pPrinterName = devname;
661 pinfo2a.pDatatype = data_type;
662 pinfo2a.pPrintProcessor = print_proc;
663 pinfo2a.pDriverName = devname;
664 pinfo2a.pComment = comment;
665 pinfo2a.pLocation = prettyname;
666 pinfo2a.pPortName = port;
667 pinfo2a.pParameters = params;
668 pinfo2a.pShareName = share_name;
669 pinfo2a.pSepFile = sep_file;
671 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
672 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
673 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
676 RegCloseKey(hkeyPrinters);
678 if (isfirst || set_default)
679 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
681 HeapFree(GetProcessHeap(), 0, port);
683 HeapFree(GetProcessHeap(), 0, name);
688 PRINTCAP_LoadPrinters(void) {
689 BOOL hadprinter = FALSE;
693 BOOL had_bash = FALSE;
695 f = fopen("/etc/printcap","r");
699 while(fgets(buf,sizeof(buf),f)) {
702 end=strchr(buf,'\n');
706 while(isspace(*start)) start++;
707 if(*start == '#' || *start == '\0')
710 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
711 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
712 HeapFree(GetProcessHeap(),0,pent);
716 if (end && *--end == '\\') {
723 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
726 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
732 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
733 HeapFree(GetProcessHeap(),0,pent);
739 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
742 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
743 (lstrlenW(value) + 1) * sizeof(WCHAR));
745 return ERROR_FILE_NOT_FOUND;
748 /*****************************************************************************
749 * enumerate the local monitors (INTERNAL)
751 * returns the needed size (in bytes) for pMonitors
752 * and *lpreturned is set to number of entries returned in pMonitors
755 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
760 LPMONITOR_INFO_2W mi;
761 WCHAR buffer[MAX_PATH];
762 WCHAR dllname[MAX_PATH];
770 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
772 numentries = *lpreturned; /* this is 0, when we scan the registry */
773 len = entrysize * numentries;
774 ptr = (LPWSTR) &pMonitors[len];
777 len = sizeof(buffer);
780 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
781 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
782 /* Scan all Monitor-Registry-Keys */
783 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
784 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
785 dllsize = sizeof(dllname);
788 /* The Monitor must have a Driver-DLL */
789 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
790 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
791 /* We found a valid DLL for this Monitor. */
792 TRACE("using Driver: %s\n", debugstr_w(dllname));
797 /* Windows returns only Port-Monitors here, but to simplify our code,
798 we do no filtering for Language-Monitors */
802 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
804 /* we install and return only monitors for "Windows NT x86" */
805 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
809 /* required size is calculated. Now fill the user-buffer */
810 if (pMonitors && (cbBuf >= needed)){
811 mi = (LPMONITOR_INFO_2W) pMonitors;
812 pMonitors += entrysize;
814 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
816 lstrcpyW(ptr, buffer); /* Name of the Monitor */
817 ptr += (len+1); /* len is lstrlenW(monitorname) */
819 mi->pEnvironment = ptr;
820 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
821 ptr += (lstrlenW(envname_x86W)+1);
824 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
825 ptr += (dllsize / sizeof(WCHAR));
830 len = sizeof(buffer);
835 *lpreturned = numentries;
836 TRACE("need %d byte for %d entries\n", needed, numentries);
840 /******************************************************************
841 * monitor_flush [internal]
843 * flush the cached PORT_INFO_2W - data
846 static void monitor_flush(monitor_t * pm)
850 EnterCriticalSection(&monitor_handles_cs);
852 TRACE("%p (%s) cache: %p (%d, %d)\n", pm, debugstr_w(pm->name), pm->cache, pm->pi1_needed, pm->pi2_needed);
854 HeapFree(GetProcessHeap(), 0, pm->cache);
859 LeaveCriticalSection(&monitor_handles_cs);
862 /******************************************************************
863 * monitor_unload [internal]
865 * release a printmonitor and unload it from memory, when needed
868 static void monitor_unload(monitor_t * pm)
870 if (pm == NULL) return;
871 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
873 EnterCriticalSection(&monitor_handles_cs);
875 if (pm->refcount) pm->refcount--;
877 if (pm->refcount == 0) {
878 list_remove(&pm->entry);
879 FreeLibrary(pm->hdll);
880 HeapFree(GetProcessHeap(), 0, pm->name);
881 HeapFree(GetProcessHeap(), 0, pm->dllname);
882 HeapFree(GetProcessHeap(), 0, pm);
884 LeaveCriticalSection(&monitor_handles_cs);
887 /******************************************************************
888 * monitor_unloadall [internal]
890 * release all printmonitors and unload them from memory, when needed
893 static void monitor_unloadall(void)
898 EnterCriticalSection(&monitor_handles_cs);
899 /* iterate through the list, with safety against removal */
900 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
904 LeaveCriticalSection(&monitor_handles_cs);
907 /******************************************************************
908 * monitor_load [internal]
910 * load a printmonitor, get the dllname from the registry, when needed
911 * initialize the monitor and dump found function-pointers
913 * On failure, SetLastError() is called and NULL is returned
916 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
918 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
919 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
920 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
921 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
922 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
924 monitor_t * pm = NULL;
926 LPWSTR regroot = NULL;
927 LPWSTR driver = dllname;
929 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
930 /* Is the Monitor already loaded? */
931 EnterCriticalSection(&monitor_handles_cs);
934 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
936 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
944 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
945 if (pm == NULL) goto cleanup;
946 list_add_tail(&monitor_handles, &pm->entry);
950 if (pm->name == NULL) {
951 /* Load the monitor */
952 LPMONITOREX pmonitorEx;
956 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
957 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
961 lstrcpyW(regroot, MonitorsW);
962 lstrcatW(regroot, name);
963 /* Get the Driver from the Registry */
964 if (driver == NULL) {
967 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
968 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
969 &namesize) == ERROR_SUCCESS) {
970 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
971 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
978 pm->name = strdupW(name);
979 pm->dllname = strdupW(driver);
981 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
983 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
988 pm->hdll = LoadLibraryW(driver);
989 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
991 if (pm->hdll == NULL) {
993 SetLastError(ERROR_MOD_NOT_FOUND);
998 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
999 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1000 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1001 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1002 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1005 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1006 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1007 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1008 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1009 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1011 if (pInitializePrintMonitorUI != NULL) {
1012 pm->monitorUI = pInitializePrintMonitorUI();
1013 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1014 if (pm->monitorUI) {
1015 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1016 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1021 if (pInitializePrintMonitor && regroot) {
1022 pmonitorEx = pInitializePrintMonitor(regroot);
1023 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1024 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1027 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1028 pm->monitor = &(pmonitorEx->Monitor);
1033 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1037 if (!pm->monitor && regroot) {
1038 if (pInitializePrintMonitor2 != NULL) {
1039 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1041 if (pInitializeMonitorEx != NULL) {
1042 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1044 if (pInitializeMonitor != NULL) {
1045 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1048 if (!pm->monitor && !pm->monitorUI) {
1050 SetLastError(ERROR_PROC_NOT_FOUND);
1055 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1059 LeaveCriticalSection(&monitor_handles_cs);
1060 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1061 HeapFree(GetProcessHeap(), 0, regroot);
1062 TRACE("=> %p\n", pm);
1066 /******************************************************************
1067 * monitor_loadall [internal]
1069 * Load all registered monitors
1072 static DWORD monitor_loadall(void)
1075 DWORD registered = 0;
1078 WCHAR buffer[MAX_PATH];
1081 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1082 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1083 NULL, NULL, NULL, NULL, NULL);
1085 TRACE("%d monitors registered\n", registered);
1087 EnterCriticalSection(&monitor_handles_cs);
1088 while (id < registered) {
1090 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1091 pm = monitor_load(buffer, NULL);
1095 LeaveCriticalSection(&monitor_handles_cs);
1096 RegCloseKey(hmonitors);
1098 TRACE("%d monitors loaded\n", loaded);
1102 /******************************************************************
1103 * monitor_loadui [internal]
1105 * load the userinterface-dll for a given portmonitor
1107 * On failure, NULL is returned
1110 static monitor_t * monitor_loadui(monitor_t * pm)
1112 monitor_t * pui = NULL;
1113 LPWSTR buffer[MAX_PATH];
1118 if (pm == NULL) return NULL;
1119 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1121 /* Try the Portmonitor first; works for many monitors */
1122 if (pm->monitorUI) {
1123 EnterCriticalSection(&monitor_handles_cs);
1125 LeaveCriticalSection(&monitor_handles_cs);
1129 /* query the userinterface-dllname from the Portmonitor */
1130 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1131 /* building (",XcvMonitor %s",pm->name) not needed yet */
1132 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1133 TRACE("got %u with %p\n", res, hXcv);
1135 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1136 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1137 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1138 pm->monitor->pfnXcvClosePort(hXcv);
1145 /******************************************************************
1146 * monitor_load_by_port [internal]
1148 * load a printmonitor for a given port
1150 * On failure, NULL is returned
1153 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1158 monitor_t * pm = NULL;
1159 DWORD registered = 0;
1163 TRACE("(%s)\n", debugstr_w(portname));
1165 /* Try the Local Monitor first */
1166 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1167 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1168 /* found the portname */
1170 return monitor_load(LocalPortW, NULL);
1175 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1176 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1177 if (buffer == NULL) return NULL;
1179 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1180 EnterCriticalSection(&monitor_handles_cs);
1181 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1183 while ((pm == NULL) && (id < registered)) {
1185 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1186 TRACE("testing %s\n", debugstr_w(buffer));
1187 len = lstrlenW(buffer);
1188 lstrcatW(buffer, bs_Ports_bsW);
1189 lstrcatW(buffer, portname);
1190 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1192 buffer[len] = '\0'; /* use only the Monitor-Name */
1193 pm = monitor_load(buffer, NULL);
1197 LeaveCriticalSection(&monitor_handles_cs);
1200 HeapFree(GetProcessHeap(), 0, buffer);
1204 /******************************************************************
1205 * enumerate the local Ports from all loaded monitors (internal)
1207 * returns the needed size (in bytes) for pPorts
1208 * and *lpreturned is set to number of entries returned in pPorts
1211 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1215 LPPORT_INFO_2W cache;
1225 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1226 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1228 numentries = *lpreturned; /* this is 0, when we scan the registry */
1229 needed = entrysize * numentries;
1230 ptr = (LPWSTR) &pPorts[needed];
1235 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1237 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1238 if (pm->cache == NULL) {
1239 res = pm->monitor->pfnEnumPorts(NULL, 2, NULL, 0, &(pm->pi2_needed), &(pm->returned));
1240 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1241 pm->cache = HeapAlloc(GetProcessHeap(), 0, (pm->pi2_needed));
1242 res = pm->monitor->pfnEnumPorts(NULL, 2, (LPBYTE) pm->cache, pm->pi2_needed, &(pm->pi2_needed), &(pm->returned));
1244 TRACE("(%s) got %d with %d (cache need %d byte for %d entries)\n",
1245 debugstr_w(pm->name), res, GetLastError(), pm->pi2_needed, pm->returned);
1248 if (pm->cache && (level == 1) && (pm->pi1_needed == 0) && (pm->returned > 0)) {
1251 while (cacheindex < (pm->returned)) {
1252 pm->pi1_needed += sizeof(PORT_INFO_1W);
1253 pm->pi1_needed += (lstrlenW(cache->pPortName) + 1) * sizeof(WCHAR);
1257 TRACE("%d byte for %d cached PORT_INFO_1W entries (%s)\n",
1258 pm->pi1_needed, cacheindex, debugstr_w(pm->name));
1260 numentries += pm->returned;
1261 needed += (level == 1) ? pm->pi1_needed : pm->pi2_needed;
1263 /* fill the buffer, if we have one */
1264 if (pPorts && (cbBuf >= needed ) && pm->cache) {
1267 while (cacheindex < pm->returned) {
1268 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1269 out->pPortName = ptr;
1270 lstrcpyW(ptr, cache->pPortName);
1271 ptr += (lstrlenW(ptr)+1);
1273 out->pMonitorName = ptr;
1274 lstrcpyW(ptr, cache->pMonitorName);
1275 ptr += (lstrlenW(ptr)+1);
1277 out->pDescription = ptr;
1278 lstrcpyW(ptr, cache->pDescription);
1279 ptr += (lstrlenW(ptr)+1);
1280 out->fPortType = cache->fPortType;
1281 out->Reserved = cache->Reserved;
1291 *lpreturned = numentries;
1292 TRACE("need %d byte for %d entries\n", needed, numentries);
1296 /******************************************************************
1297 * get_servername_from_name (internal)
1299 * for an external server, a copy of the serverpart from the full name is returned
1302 static LPWSTR get_servername_from_name(LPCWSTR name)
1306 WCHAR buffer[MAX_PATH];
1309 if (name == NULL) return NULL;
1310 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1312 server = strdupW(&name[2]); /* skip over both backslash */
1313 if (server == NULL) return NULL;
1315 /* strip '\' and the printername */
1316 ptr = strchrW(server, '\\');
1317 if (ptr) ptr[0] = '\0';
1319 TRACE("found %s\n", debugstr_w(server));
1321 len = sizeof(buffer)/sizeof(buffer[0]);
1322 if (GetComputerNameW(buffer, &len)) {
1323 if (lstrcmpW(buffer, server) == 0) {
1324 /* The requested Servername is our computername */
1325 HeapFree(GetProcessHeap(), 0, server);
1332 /******************************************************************
1333 * get_basename_from_name (internal)
1335 * skip over the serverpart from the full name
1338 static LPCWSTR get_basename_from_name(LPCWSTR name)
1340 if (name == NULL) return NULL;
1341 if ((name[0] == '\\') && (name[1] == '\\')) {
1342 /* skip over the servername and search for the following '\' */
1343 name = strchrW(&name[2], '\\');
1344 if ((name) && (name[1])) {
1345 /* found a separator ('\') followed by a name:
1346 skip over the separator and return the rest */
1351 /* no basename present (we found only a servername) */
1358 /******************************************************************
1359 * get_opened_printer_entry
1360 * Get the first place empty in the opened printer table
1363 * - pDefault is ignored
1365 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1367 UINT_PTR handle = nb_printer_handles, i;
1368 jobqueue_t *queue = NULL;
1369 opened_printer_t *printer = NULL;
1371 LPCWSTR printername;
1376 servername = get_servername_from_name(name);
1378 FIXME("server %s not supported\n", debugstr_w(servername));
1379 HeapFree(GetProcessHeap(), 0, servername);
1380 SetLastError(ERROR_INVALID_PRINTER_NAME);
1384 printername = get_basename_from_name(name);
1385 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1387 /* an empty printername is invalid */
1388 if (printername && (!printername[0])) {
1389 SetLastError(ERROR_INVALID_PARAMETER);
1393 EnterCriticalSection(&printer_handles_cs);
1395 for (i = 0; i < nb_printer_handles; i++)
1397 if (!printer_handles[i])
1399 if(handle == nb_printer_handles)
1404 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1405 queue = printer_handles[i]->queue;
1409 if (handle >= nb_printer_handles)
1411 opened_printer_t **new_array;
1412 if (printer_handles)
1413 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1414 (nb_printer_handles + 16) * sizeof(*new_array) );
1416 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1417 (nb_printer_handles + 16) * sizeof(*new_array) );
1424 printer_handles = new_array;
1425 nb_printer_handles += 16;
1428 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1435 /* clone the base name. This is NULL for the printserver */
1436 printer->printername = strdupW(printername);
1438 /* clone the full name */
1439 printer->name = strdupW(name);
1440 if (name && (!printer->name)) {
1446 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1447 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1448 /* OpenPrinter(",XcvMonitor " detected */
1449 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1450 printer->pm = monitor_load(&printername[len], NULL);
1451 if (printer->pm == NULL) {
1452 SetLastError(ERROR_INVALID_PARAMETER);
1459 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1460 if (strncmpW( printername, XcvPortW, len) == 0) {
1461 /* OpenPrinter(",XcvPort " detected */
1462 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1463 printer->pm = monitor_load_by_port(&printername[len]);
1464 if (printer->pm == NULL) {
1465 SetLastError(ERROR_INVALID_PARAMETER);
1473 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1474 printer->pm->monitor->pfnXcvOpenPort(&printername[len], pDefault->DesiredAccess, &printer->hXcv);
1476 if (printer->hXcv == NULL) {
1477 SetLastError(ERROR_INVALID_PARAMETER);
1484 /* Does the Printer exist? */
1485 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1486 ERR("Can't create Printers key\n");
1490 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1491 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1492 RegCloseKey(hkeyPrinters);
1493 SetLastError(ERROR_INVALID_PRINTER_NAME);
1497 RegCloseKey(hkeyPrinter);
1498 RegCloseKey(hkeyPrinters);
1503 TRACE("using the local printserver\n");
1507 printer->queue = queue;
1510 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1511 if (!printer->queue) {
1515 list_init(&printer->queue->jobs);
1516 printer->queue->ref = 0;
1518 InterlockedIncrement(&printer->queue->ref);
1520 printer_handles[handle] = printer;
1523 LeaveCriticalSection(&printer_handles_cs);
1524 if (!handle && printer) {
1525 /* Something failed: Free all resources */
1526 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1527 monitor_unload(printer->pm);
1528 HeapFree(GetProcessHeap(), 0, printer->printername);
1529 HeapFree(GetProcessHeap(), 0, printer->name);
1530 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1531 HeapFree(GetProcessHeap(), 0, printer);
1534 return (HANDLE)handle;
1537 /******************************************************************
1538 * get_opened_printer
1539 * Get the pointer to the opened printer referred by the handle
1541 static opened_printer_t *get_opened_printer(HANDLE hprn)
1543 UINT_PTR idx = (UINT_PTR)hprn;
1544 opened_printer_t *ret = NULL;
1546 EnterCriticalSection(&printer_handles_cs);
1548 if ((idx <= 0) || (idx > nb_printer_handles))
1551 ret = printer_handles[idx - 1];
1553 LeaveCriticalSection(&printer_handles_cs);
1557 /******************************************************************
1558 * get_opened_printer_name
1559 * Get the pointer to the opened printer name referred by the handle
1561 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1563 opened_printer_t *printer = get_opened_printer(hprn);
1564 if(!printer) return NULL;
1565 return printer->name;
1568 /******************************************************************
1569 * WINSPOOL_GetOpenedPrinterRegKey
1572 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1574 LPCWSTR name = get_opened_printer_name(hPrinter);
1578 if(!name) return ERROR_INVALID_HANDLE;
1580 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1584 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1586 ERR("Can't find opened printer %s in registry\n",
1588 RegCloseKey(hkeyPrinters);
1589 return ERROR_INVALID_PRINTER_NAME; /* ? */
1591 RegCloseKey(hkeyPrinters);
1592 return ERROR_SUCCESS;
1595 void WINSPOOL_LoadSystemPrinters(void)
1597 HKEY hkey, hkeyPrinters;
1599 DWORD needed, num, i;
1600 WCHAR PrinterName[256];
1603 /* This ensures that all printer entries have a valid Name value. If causes
1604 problems later if they don't. If one is found to be missed we create one
1605 and set it equal to the name of the key */
1606 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1607 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1608 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1609 for(i = 0; i < num; i++) {
1610 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
1611 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1612 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1613 set_reg_szW(hkey, NameW, PrinterName);
1620 RegCloseKey(hkeyPrinters);
1623 /* We want to avoid calling AddPrinter on printers as much as
1624 possible, because on cups printers this will (eventually) lead
1625 to a call to cupsGetPPD which takes forever, even with non-cups
1626 printers AddPrinter takes a while. So we'll tag all printers that
1627 were automatically added last time around, if they still exist
1628 we'll leave them be otherwise we'll delete them. */
1629 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1631 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1632 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1633 for(i = 0; i < num; i++) {
1634 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1635 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1636 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1638 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1646 HeapFree(GetProcessHeap(), 0, pi);
1650 #ifdef HAVE_CUPS_CUPS_H
1651 done = CUPS_LoadPrinters();
1654 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1655 PRINTCAP_LoadPrinters();
1657 /* Now enumerate the list again and delete any printers that a still tagged */
1658 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1660 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1661 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1662 for(i = 0; i < num; i++) {
1663 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1664 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1665 BOOL delete_driver = FALSE;
1666 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1667 DWORD dw, type, size = sizeof(dw);
1668 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1669 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1670 DeletePrinter(hprn);
1671 delete_driver = TRUE;
1677 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1682 HeapFree(GetProcessHeap(), 0, pi);
1689 /******************************************************************
1692 * Get the pointer to the specified job.
1693 * Should hold the printer_handles_cs before calling.
1695 static job_t *get_job(HANDLE hprn, DWORD JobId)
1697 opened_printer_t *printer = get_opened_printer(hprn);
1700 if(!printer) return NULL;
1701 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1703 if(job->job_id == JobId)
1709 /***********************************************************
1712 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1715 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1718 Formname = (dmA->dmSize > off_formname);
1719 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1720 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1721 dmW->dmDeviceName, CCHDEVICENAME);
1723 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1724 dmA->dmSize - CCHDEVICENAME);
1726 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1727 off_formname - CCHDEVICENAME);
1728 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1729 dmW->dmFormName, CCHFORMNAME);
1730 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1731 (off_formname + CCHFORMNAME));
1734 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1735 dmA->dmDriverExtra);
1739 /***********************************************************
1741 * Creates an ascii copy of supplied devmode on heap
1743 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1748 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1750 if(!dmW) return NULL;
1751 Formname = (dmW->dmSize > off_formname);
1752 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1753 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1754 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1755 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1757 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1758 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1760 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1761 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1762 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1763 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1764 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1765 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1768 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1769 dmW->dmDriverExtra);
1773 /***********************************************************
1774 * PRINTER_INFO_2AtoW
1775 * Creates a unicode copy of PRINTER_INFO_2A on heap
1777 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1779 LPPRINTER_INFO_2W piW;
1780 UNICODE_STRING usBuffer;
1782 if(!piA) return NULL;
1783 piW = HeapAlloc(heap, 0, sizeof(*piW));
1784 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1786 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1787 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1788 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1789 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1790 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1791 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1792 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1793 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1794 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1795 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1796 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1797 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1801 /***********************************************************
1802 * FREE_PRINTER_INFO_2W
1803 * Free PRINTER_INFO_2W and all strings
1805 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1809 HeapFree(heap,0,piW->pServerName);
1810 HeapFree(heap,0,piW->pPrinterName);
1811 HeapFree(heap,0,piW->pShareName);
1812 HeapFree(heap,0,piW->pPortName);
1813 HeapFree(heap,0,piW->pDriverName);
1814 HeapFree(heap,0,piW->pComment);
1815 HeapFree(heap,0,piW->pLocation);
1816 HeapFree(heap,0,piW->pDevMode);
1817 HeapFree(heap,0,piW->pSepFile);
1818 HeapFree(heap,0,piW->pPrintProcessor);
1819 HeapFree(heap,0,piW->pDatatype);
1820 HeapFree(heap,0,piW->pParameters);
1821 HeapFree(heap,0,piW);
1825 /******************************************************************
1826 * DeviceCapabilities [WINSPOOL.@]
1827 * DeviceCapabilitiesA [WINSPOOL.@]
1830 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1831 LPSTR pOutput, LPDEVMODEA lpdm)
1835 if (!GDI_CallDeviceCapabilities16)
1837 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1839 if (!GDI_CallDeviceCapabilities16) return -1;
1841 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1843 /* If DC_PAPERSIZE map POINT16s to POINTs */
1844 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1845 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1846 POINT *pt = (POINT *)pOutput;
1848 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1849 for(i = 0; i < ret; i++, pt++)
1854 HeapFree( GetProcessHeap(), 0, tmp );
1860 /*****************************************************************************
1861 * DeviceCapabilitiesW [WINSPOOL.@]
1863 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1866 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1867 WORD fwCapability, LPWSTR pOutput,
1868 const DEVMODEW *pDevMode)
1870 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1871 LPSTR pDeviceA = strdupWtoA(pDevice);
1872 LPSTR pPortA = strdupWtoA(pPort);
1875 if(pOutput && (fwCapability == DC_BINNAMES ||
1876 fwCapability == DC_FILEDEPENDENCIES ||
1877 fwCapability == DC_PAPERNAMES)) {
1878 /* These need A -> W translation */
1881 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1885 switch(fwCapability) {
1890 case DC_FILEDEPENDENCIES:
1894 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1895 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1897 for(i = 0; i < ret; i++)
1898 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1899 pOutput + (i * size), size);
1900 HeapFree(GetProcessHeap(), 0, pOutputA);
1902 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1903 (LPSTR)pOutput, dmA);
1905 HeapFree(GetProcessHeap(),0,pPortA);
1906 HeapFree(GetProcessHeap(),0,pDeviceA);
1907 HeapFree(GetProcessHeap(),0,dmA);
1911 /******************************************************************
1912 * DocumentPropertiesA [WINSPOOL.@]
1914 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1916 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1917 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1918 LPDEVMODEA pDevModeInput,DWORD fMode )
1920 LPSTR lpName = pDeviceName;
1921 static CHAR port[] = "LPT1:";
1924 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1925 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1929 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1931 ERR("no name from hPrinter?\n");
1932 SetLastError(ERROR_INVALID_HANDLE);
1935 lpName = strdupWtoA(lpNameW);
1938 if (!GDI_CallExtDeviceMode16)
1940 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1942 if (!GDI_CallExtDeviceMode16) {
1943 ERR("No CallExtDeviceMode16?\n");
1947 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1948 pDevModeInput, NULL, fMode);
1951 HeapFree(GetProcessHeap(),0,lpName);
1956 /*****************************************************************************
1957 * DocumentPropertiesW (WINSPOOL.@)
1959 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1961 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1963 LPDEVMODEW pDevModeOutput,
1964 LPDEVMODEW pDevModeInput, DWORD fMode)
1967 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1968 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1969 LPDEVMODEA pDevModeOutputA = NULL;
1972 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1973 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1975 if(pDevModeOutput) {
1976 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1977 if(ret < 0) return ret;
1978 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1980 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1981 pDevModeInputA, fMode);
1982 if(pDevModeOutput) {
1983 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1984 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1986 if(fMode == 0 && ret > 0)
1987 ret += (CCHDEVICENAME + CCHFORMNAME);
1988 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1989 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1993 /******************************************************************
1994 * OpenPrinterA [WINSPOOL.@]
1999 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2000 LPPRINTER_DEFAULTSA pDefault)
2002 UNICODE_STRING lpPrinterNameW;
2003 UNICODE_STRING usBuffer;
2004 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2005 PWSTR pwstrPrinterNameW;
2008 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2011 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2012 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2013 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2014 pDefaultW = &DefaultW;
2016 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2018 RtlFreeUnicodeString(&usBuffer);
2019 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2021 RtlFreeUnicodeString(&lpPrinterNameW);
2025 /******************************************************************
2026 * OpenPrinterW [WINSPOOL.@]
2028 * Open a Printer / Printserver or a Printer-Object
2031 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2032 * phPrinter [O] The resulting Handle is stored here
2033 * pDefault [I] PTR to Default Printer Settings or NULL
2040 * lpPrinterName is one of:
2041 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2042 *| Printer: "PrinterName"
2043 *| Printer-Object: "PrinterName,Job xxx"
2044 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2045 *| XcvPort: "Servername,XcvPort PortName"
2048 *| Printer-Object not supported
2049 *| pDefaults is ignored
2052 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2055 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2057 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2058 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2062 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2063 SetLastError(ERROR_INVALID_PARAMETER);
2067 /* Get the unique handle of the printer or Printserver */
2068 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2069 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2070 return (*phPrinter != 0);
2073 /******************************************************************
2074 * AddMonitorA [WINSPOOL.@]
2079 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2081 LPWSTR nameW = NULL;
2084 LPMONITOR_INFO_2A mi2a;
2085 MONITOR_INFO_2W mi2w;
2087 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2088 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2089 mi2a ? debugstr_a(mi2a->pName) : NULL,
2090 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2091 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2094 SetLastError(ERROR_INVALID_LEVEL);
2098 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2104 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2105 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2106 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2109 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2111 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2112 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2113 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2115 if (mi2a->pEnvironment) {
2116 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2117 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2118 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2120 if (mi2a->pDLLName) {
2121 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2122 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2123 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2126 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2128 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2129 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2130 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2132 HeapFree(GetProcessHeap(), 0, nameW);
2136 /******************************************************************************
2137 * AddMonitorW [WINSPOOL.@]
2139 * Install a Printmonitor
2142 * pName [I] Servername or NULL (local Computer)
2143 * Level [I] Structure-Level (Must be 2)
2144 * pMonitors [I] PTR to MONITOR_INFO_2
2151 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2154 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2156 monitor_t * pm = NULL;
2157 LPMONITOR_INFO_2W mi2w;
2163 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2164 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2165 mi2w ? debugstr_w(mi2w->pName) : NULL,
2166 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2167 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2170 SetLastError(ERROR_INVALID_LEVEL);
2174 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2179 if (pName && (pName[0])) {
2180 FIXME("for server %s not implemented\n", debugstr_w(pName));
2181 SetLastError(ERROR_ACCESS_DENIED);
2186 if (!mi2w->pName || (! mi2w->pName[0])) {
2187 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2188 SetLastError(ERROR_INVALID_PARAMETER);
2191 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2192 WARN("Environment %s requested (we support only %s)\n",
2193 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2194 SetLastError(ERROR_INVALID_ENVIRONMENT);
2198 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2199 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2200 SetLastError(ERROR_INVALID_PARAMETER);
2204 /* Load and initialize the monitor. SetLastError() is called on failure */
2205 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2210 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2211 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2215 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2216 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2217 &disposition) == ERROR_SUCCESS) {
2219 /* Some installers set options for the port before calling AddMonitor.
2220 We query the "Driver" entry to verify that the monitor is installed,
2221 before we return an error.
2222 When a user installs two print monitors at the same time with the
2223 same name but with a different driver DLL and a task switch comes
2224 between RegQueryValueExW and RegSetValueExW, a race condition
2225 is possible but silently ignored. */
2229 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2230 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2231 &namesize) == ERROR_SUCCESS)) {
2232 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2233 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2234 9x: ERROR_ALREADY_EXISTS (183) */
2235 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2240 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2241 res = (RegSetValueExW(hentry, DriverW, 0,
2242 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2244 RegCloseKey(hentry);
2251 /******************************************************************
2252 * DeletePrinterDriverA [WINSPOOL.@]
2255 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2257 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2260 /******************************************************************
2261 * DeletePrinterDriverW [WINSPOOL.@]
2264 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2266 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2269 /******************************************************************
2270 * DeleteMonitorA [WINSPOOL.@]
2272 * See DeleteMonitorW.
2275 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2277 LPWSTR nameW = NULL;
2278 LPWSTR EnvironmentW = NULL;
2279 LPWSTR MonitorNameW = NULL;
2284 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2285 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2286 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2290 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2291 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2292 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2295 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2296 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2297 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2300 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2302 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2303 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2304 HeapFree(GetProcessHeap(), 0, nameW);
2308 /******************************************************************
2309 * DeleteMonitorW [WINSPOOL.@]
2311 * Delete a specific Printmonitor from a Printing-Environment
2314 * pName [I] Servername or NULL (local Computer)
2315 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2316 * pMonitorName [I] Name of the Monitor, that should be deleted
2323 * pEnvironment is ignored in Windows for the local Computer.
2327 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2331 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2332 debugstr_w(pMonitorName));
2334 if (pName && (pName[0])) {
2335 FIXME("for server %s not implemented\n", debugstr_w(pName));
2336 SetLastError(ERROR_ACCESS_DENIED);
2340 /* pEnvironment is ignored in Windows for the local Computer */
2342 if (!pMonitorName || !pMonitorName[0]) {
2343 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2344 SetLastError(ERROR_INVALID_PARAMETER);
2348 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2349 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2353 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2354 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2355 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2360 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2363 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2364 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2368 /******************************************************************
2369 * DeletePortA [WINSPOOL.@]
2374 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2376 LPWSTR nameW = NULL;
2377 LPWSTR portW = NULL;
2381 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2383 /* convert servername to unicode */
2385 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2386 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2387 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2390 /* convert portname to unicode */
2392 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2393 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2394 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2397 res = DeletePortW(nameW, hWnd, portW);
2398 HeapFree(GetProcessHeap(), 0, nameW);
2399 HeapFree(GetProcessHeap(), 0, portW);
2403 /******************************************************************
2404 * DeletePortW [WINSPOOL.@]
2406 * Delete a specific Port
2409 * pName [I] Servername or NULL (local Computer)
2410 * hWnd [I] Handle to parent Window for the Dialog-Box
2411 * pPortName [I] Name of the Port, that should be deleted
2418 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2424 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2426 if (pName && pName[0]) {
2427 SetLastError(ERROR_INVALID_PARAMETER);
2432 SetLastError(RPC_X_NULL_REF_POINTER);
2436 /* an empty Portname is Invalid */
2437 if (!pPortName[0]) {
2438 SetLastError(ERROR_NOT_SUPPORTED);
2442 pm = monitor_load_by_port(pPortName);
2443 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2444 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2445 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2446 TRACE("got %d with %u\n", res, GetLastError());
2450 pui = monitor_loadui(pm);
2451 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2452 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2453 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2454 TRACE("got %d with %u\n", res, GetLastError());
2458 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2459 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2461 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2462 SetLastError(ERROR_NOT_SUPPORTED);
2465 monitor_unload(pui);
2467 /* always invalidate cached PORT_INFO_2W */
2472 TRACE("returning %d with %u\n", res, GetLastError());
2476 /******************************************************************************
2477 * SetPrinterW [WINSPOOL.@]
2479 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2481 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2482 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2486 /******************************************************************************
2487 * WritePrinter [WINSPOOL.@]
2489 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2491 opened_printer_t *printer;
2494 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2496 EnterCriticalSection(&printer_handles_cs);
2497 printer = get_opened_printer(hPrinter);
2500 SetLastError(ERROR_INVALID_HANDLE);
2506 SetLastError(ERROR_SPL_NO_STARTDOC);
2510 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2512 LeaveCriticalSection(&printer_handles_cs);
2516 /*****************************************************************************
2517 * AddFormA [WINSPOOL.@]
2519 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2521 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2525 /*****************************************************************************
2526 * AddFormW [WINSPOOL.@]
2528 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2530 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2534 /*****************************************************************************
2535 * AddJobA [WINSPOOL.@]
2537 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2540 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2544 SetLastError(ERROR_INVALID_LEVEL);
2548 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2551 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2552 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2553 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2554 if(*pcbNeeded > cbBuf) {
2555 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2558 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2559 addjobA->JobId = addjobW->JobId;
2560 addjobA->Path = (char *)(addjobA + 1);
2561 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2567 /*****************************************************************************
2568 * AddJobW [WINSPOOL.@]
2570 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2572 opened_printer_t *printer;
2575 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2576 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2577 WCHAR path[MAX_PATH], filename[MAX_PATH];
2579 ADDJOB_INFO_1W *addjob;
2581 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2583 EnterCriticalSection(&printer_handles_cs);
2585 printer = get_opened_printer(hPrinter);
2588 SetLastError(ERROR_INVALID_HANDLE);
2593 SetLastError(ERROR_INVALID_LEVEL);
2597 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2601 job->job_id = InterlockedIncrement(&next_job_id);
2603 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2604 if(path[len - 1] != '\\')
2606 memcpy(path + len, spool_path, sizeof(spool_path));
2607 sprintfW(filename, fmtW, path, job->job_id);
2609 len = strlenW(filename);
2610 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2611 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2612 job->document_title = strdupW(default_doc_title);
2613 list_add_tail(&printer->queue->jobs, &job->entry);
2615 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2616 if(*pcbNeeded <= cbBuf) {
2617 addjob = (ADDJOB_INFO_1W*)pData;
2618 addjob->JobId = job->job_id;
2619 addjob->Path = (WCHAR *)(addjob + 1);
2620 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2623 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2626 LeaveCriticalSection(&printer_handles_cs);
2630 /*****************************************************************************
2631 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2633 * Return the PATH for the Print-Processors
2635 * See GetPrintProcessorDirectoryW.
2639 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2640 DWORD level, LPBYTE Info,
2641 DWORD cbBuf, LPDWORD pcbNeeded)
2643 LPWSTR serverW = NULL;
2648 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2649 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2653 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2654 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2655 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2659 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2660 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2661 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2664 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2665 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2667 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2670 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2671 cbBuf, NULL, NULL) > 0;
2674 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2675 HeapFree(GetProcessHeap(), 0, envW);
2676 HeapFree(GetProcessHeap(), 0, serverW);
2680 /*****************************************************************************
2681 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2683 * Return the PATH for the Print-Processors
2686 * server [I] Servername (NT only) or NULL (local Computer)
2687 * env [I] Printing-Environment (see below) or NULL (Default)
2688 * level [I] Structure-Level (must be 1)
2689 * Info [O] PTR to Buffer that receives the Result
2690 * cbBuf [I] Size of Buffer at "Info"
2691 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2692 * required for the Buffer at "Info"
2695 * Success: TRUE and in pcbNeeded the Bytes used in Info
2696 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2697 * if cbBuf is too small
2699 * Native Values returned in Info on Success:
2700 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2701 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2702 *| win9x(Windows 4.0): "%winsysdir%"
2704 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2707 * Only NULL or "" is supported for server
2710 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2711 DWORD level, LPBYTE Info,
2712 DWORD cbBuf, LPDWORD pcbNeeded)
2715 const printenv_t * env_t;
2717 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2718 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2720 if(server != NULL && server[0]) {
2721 FIXME("server not supported: %s\n", debugstr_w(server));
2722 SetLastError(ERROR_INVALID_PARAMETER);
2726 env_t = validate_envW(env);
2727 if(!env_t) return FALSE; /* environment invalid or unsupported */
2730 WARN("(Level: %d) is ignored in win9x\n", level);
2731 SetLastError(ERROR_INVALID_LEVEL);
2735 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2736 needed = GetSystemDirectoryW(NULL, 0);
2737 /* add the Size for the Subdirectories */
2738 needed += lstrlenW(spoolprtprocsW);
2739 needed += lstrlenW(env_t->subdir);
2740 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2742 if(pcbNeeded) *pcbNeeded = needed;
2743 TRACE ("required: 0x%x/%d\n", needed, needed);
2744 if (needed > cbBuf) {
2745 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2748 if(pcbNeeded == NULL) {
2749 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2750 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2751 SetLastError(RPC_X_NULL_REF_POINTER);
2755 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2756 SetLastError(RPC_X_NULL_REF_POINTER);
2760 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2761 /* add the Subdirectories */
2762 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2763 lstrcatW((LPWSTR) Info, env_t->subdir);
2764 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2768 /*****************************************************************************
2769 * WINSPOOL_OpenDriverReg [internal]
2771 * opens the registry for the printer drivers depending on the given input
2772 * variable pEnvironment
2775 * the opened hkey on success
2778 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2782 const printenv_t * env;
2785 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2787 if (!pEnvironment || unicode) {
2788 /* pEnvironment was NULL or an Unicode-String: use it direct */
2789 env = validate_envW(pEnvironment);
2793 /* pEnvironment was an ANSI-String: convert to unicode first */
2795 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2796 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2797 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2798 env = validate_envW(buffer);
2799 HeapFree(GetProcessHeap(), 0, buffer);
2801 if (!env) return NULL;
2803 buffer = HeapAlloc( GetProcessHeap(), 0,
2804 (strlenW(DriversW) + strlenW(env->envname) +
2805 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2807 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2808 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2809 HeapFree(GetProcessHeap(), 0, buffer);
2814 /*****************************************************************************
2815 * AddPrinterW [WINSPOOL.@]
2817 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2819 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2823 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2825 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2826 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2827 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2828 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2829 statusW[] = {'S','t','a','t','u','s',0},
2830 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2832 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2835 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2836 SetLastError(ERROR_INVALID_PARAMETER);
2840 ERR("Level = %d, unsupported!\n", Level);
2841 SetLastError(ERROR_INVALID_LEVEL);
2845 SetLastError(ERROR_INVALID_PARAMETER);
2848 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2850 ERR("Can't create Printers key\n");
2853 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2854 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2855 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2856 RegCloseKey(hkeyPrinter);
2857 RegCloseKey(hkeyPrinters);
2860 RegCloseKey(hkeyPrinter);
2862 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2864 ERR("Can't create Drivers key\n");
2865 RegCloseKey(hkeyPrinters);
2868 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2870 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2871 RegCloseKey(hkeyPrinters);
2872 RegCloseKey(hkeyDrivers);
2873 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2876 RegCloseKey(hkeyDriver);
2877 RegCloseKey(hkeyDrivers);
2879 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2880 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2881 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2882 RegCloseKey(hkeyPrinters);
2886 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2888 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2889 SetLastError(ERROR_INVALID_PRINTER_NAME);
2890 RegCloseKey(hkeyPrinters);
2893 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2894 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2895 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2897 /* See if we can load the driver. We may need the devmode structure anyway
2900 * Note that DocumentPropertiesW will briefly try to open the printer we
2901 * just create to find a DEVMODEA struct (it will use the WINEPS default
2902 * one in case it is not there, so we are ok).
2904 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2907 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2908 size = sizeof(DEVMODEW);
2914 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2915 ZeroMemory(dmW,size);
2917 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2919 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2920 HeapFree(GetProcessHeap(),0,dmW);
2925 /* set devmode to printer name */
2926 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2930 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2931 and we support these drivers. NT writes DEVMODEW so somehow
2932 we'll need to distinguish between these when we support NT
2936 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2937 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2938 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2939 HeapFree(GetProcessHeap(), 0, dmA);
2941 HeapFree(GetProcessHeap(), 0, dmW);
2943 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2944 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2945 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2946 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2948 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2949 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2950 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2951 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2952 (LPBYTE)&pi->Priority, sizeof(DWORD));
2953 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2954 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2955 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2956 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2957 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2958 (LPBYTE)&pi->Status, sizeof(DWORD));
2959 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2960 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2962 RegCloseKey(hkeyPrinter);
2963 RegCloseKey(hkeyPrinters);
2964 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2965 ERR("OpenPrinter failing\n");
2971 /*****************************************************************************
2972 * AddPrinterA [WINSPOOL.@]
2974 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2976 UNICODE_STRING pNameW;
2978 PRINTER_INFO_2W *piW;
2979 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2982 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2984 ERR("Level = %d, unsupported!\n", Level);
2985 SetLastError(ERROR_INVALID_LEVEL);
2988 pwstrNameW = asciitounicode(&pNameW,pName);
2989 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2991 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2993 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2994 RtlFreeUnicodeString(&pNameW);
2999 /*****************************************************************************
3000 * ClosePrinter [WINSPOOL.@]
3002 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3004 UINT_PTR i = (UINT_PTR)hPrinter;
3005 opened_printer_t *printer = NULL;
3008 TRACE("(%p)\n", hPrinter);
3010 EnterCriticalSection(&printer_handles_cs);
3012 if ((i > 0) && (i <= nb_printer_handles))
3013 printer = printer_handles[i - 1];
3018 struct list *cursor, *cursor2;
3020 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3021 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3022 printer->hXcv, debugstr_w(printer->name), printer->doc );
3025 EndDocPrinter(hPrinter);
3027 if(InterlockedDecrement(&printer->queue->ref) == 0)
3029 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3031 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3032 ScheduleJob(hPrinter, job->job_id);
3034 HeapFree(GetProcessHeap(), 0, printer->queue);
3036 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3037 monitor_unload(printer->pm);
3038 HeapFree(GetProcessHeap(), 0, printer->printername);
3039 HeapFree(GetProcessHeap(), 0, printer->name);
3040 HeapFree(GetProcessHeap(), 0, printer);
3041 printer_handles[i - 1] = NULL;
3044 LeaveCriticalSection(&printer_handles_cs);
3048 /*****************************************************************************
3049 * DeleteFormA [WINSPOOL.@]
3051 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3053 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3057 /*****************************************************************************
3058 * DeleteFormW [WINSPOOL.@]
3060 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3062 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3066 /*****************************************************************************
3067 * DeletePrinter [WINSPOOL.@]
3069 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3071 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3072 HKEY hkeyPrinters, hkey;
3075 SetLastError(ERROR_INVALID_HANDLE);
3078 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3079 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
3080 RegCloseKey(hkeyPrinters);
3082 WriteProfileStringW(devicesW, lpNameW, NULL);
3083 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3084 RegDeleteValueW(hkey, lpNameW);
3090 /*****************************************************************************
3091 * SetPrinterA [WINSPOOL.@]
3093 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3096 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3100 /*****************************************************************************
3101 * SetJobA [WINSPOOL.@]
3103 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3104 LPBYTE pJob, DWORD Command)
3108 UNICODE_STRING usBuffer;
3110 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3112 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3113 are all ignored by SetJob, so we don't bother copying them */
3121 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3122 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3124 JobW = (LPBYTE)info1W;
3125 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3126 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3127 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3128 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3129 info1W->Status = info1A->Status;
3130 info1W->Priority = info1A->Priority;
3131 info1W->Position = info1A->Position;
3132 info1W->PagesPrinted = info1A->PagesPrinted;
3137 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3138 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3140 JobW = (LPBYTE)info2W;
3141 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3142 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3143 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3144 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3145 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3146 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3147 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3148 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3149 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3150 info2W->Status = info2A->Status;
3151 info2W->Priority = info2A->Priority;
3152 info2W->Position = info2A->Position;
3153 info2W->StartTime = info2A->StartTime;
3154 info2W->UntilTime = info2A->UntilTime;
3155 info2W->PagesPrinted = info2A->PagesPrinted;
3159 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3160 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3163 SetLastError(ERROR_INVALID_LEVEL);
3167 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3173 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3174 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3175 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3176 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3177 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3182 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3183 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3184 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3185 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3186 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3187 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3188 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3189 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3190 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3194 HeapFree(GetProcessHeap(), 0, JobW);
3199 /*****************************************************************************
3200 * SetJobW [WINSPOOL.@]
3202 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3203 LPBYTE pJob, DWORD Command)
3208 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3209 FIXME("Ignoring everything other than document title\n");
3211 EnterCriticalSection(&printer_handles_cs);
3212 job = get_job(hPrinter, JobId);
3222 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3223 HeapFree(GetProcessHeap(), 0, job->document_title);
3224 job->document_title = strdupW(info1->pDocument);
3229 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3230 HeapFree(GetProcessHeap(), 0, job->document_title);
3231 job->document_title = strdupW(info2->pDocument);
3237 SetLastError(ERROR_INVALID_LEVEL);
3242 LeaveCriticalSection(&printer_handles_cs);
3246 /*****************************************************************************
3247 * EndDocPrinter [WINSPOOL.@]
3249 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3251 opened_printer_t *printer;
3253 TRACE("(%p)\n", hPrinter);
3255 EnterCriticalSection(&printer_handles_cs);
3257 printer = get_opened_printer(hPrinter);
3260 SetLastError(ERROR_INVALID_HANDLE);
3266 SetLastError(ERROR_SPL_NO_STARTDOC);
3270 CloseHandle(printer->doc->hf);
3271 ScheduleJob(hPrinter, printer->doc->job_id);
3272 HeapFree(GetProcessHeap(), 0, printer->doc);
3273 printer->doc = NULL;
3276 LeaveCriticalSection(&printer_handles_cs);
3280 /*****************************************************************************
3281 * EndPagePrinter [WINSPOOL.@]
3283 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3285 FIXME("(%p): stub\n", hPrinter);
3289 /*****************************************************************************
3290 * StartDocPrinterA [WINSPOOL.@]
3292 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3294 UNICODE_STRING usBuffer;
3296 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3299 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3300 or one (DOC_INFO_3) extra DWORDs */
3304 doc2W.JobId = doc2->JobId;
3307 doc2W.dwMode = doc2->dwMode;
3310 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3311 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3312 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3316 SetLastError(ERROR_INVALID_LEVEL);
3320 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3322 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3323 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3324 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3329 /*****************************************************************************
3330 * StartDocPrinterW [WINSPOOL.@]
3332 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3334 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3335 opened_printer_t *printer;
3336 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3337 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3338 JOB_INFO_1W job_info;
3339 DWORD needed, ret = 0;
3343 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3344 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3345 debugstr_w(doc->pDatatype));
3347 if(Level < 1 || Level > 3)
3349 SetLastError(ERROR_INVALID_LEVEL);
3353 EnterCriticalSection(&printer_handles_cs);
3354 printer = get_opened_printer(hPrinter);
3357 SetLastError(ERROR_INVALID_HANDLE);
3363 SetLastError(ERROR_INVALID_PRINTER_STATE);
3367 /* Even if we're printing to a file we still add a print job, we'll
3368 just ignore the spool file name */
3370 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3372 ERR("AddJob failed gle %u\n", GetLastError());
3376 if(doc->pOutputFile)
3377 filename = doc->pOutputFile;
3379 filename = addjob->Path;
3381 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3382 if(hf == INVALID_HANDLE_VALUE)
3385 memset(&job_info, 0, sizeof(job_info));
3386 job_info.pDocument = doc->pDocName;
3387 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3389 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3390 printer->doc->hf = hf;
3391 ret = printer->doc->job_id = addjob->JobId;
3393 LeaveCriticalSection(&printer_handles_cs);
3398 /*****************************************************************************
3399 * StartPagePrinter [WINSPOOL.@]
3401 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3403 FIXME("(%p): stub\n", hPrinter);
3407 /*****************************************************************************
3408 * GetFormA [WINSPOOL.@]
3410 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3411 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3413 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3414 Level,pForm,cbBuf,pcbNeeded);
3418 /*****************************************************************************
3419 * GetFormW [WINSPOOL.@]
3421 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3422 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3424 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3425 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3429 /*****************************************************************************
3430 * SetFormA [WINSPOOL.@]
3432 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3435 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3439 /*****************************************************************************
3440 * SetFormW [WINSPOOL.@]
3442 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3445 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3449 /*****************************************************************************
3450 * ReadPrinter [WINSPOOL.@]
3452 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3453 LPDWORD pNoBytesRead)
3455 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3459 /*****************************************************************************
3460 * ResetPrinterA [WINSPOOL.@]
3462 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3464 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3468 /*****************************************************************************
3469 * ResetPrinterW [WINSPOOL.@]
3471 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3473 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3477 /*****************************************************************************
3478 * WINSPOOL_GetDWORDFromReg
3480 * Return DWORD associated with ValueName from hkey.
3482 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3484 DWORD sz = sizeof(DWORD), type, value = 0;
3487 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3489 if(ret != ERROR_SUCCESS) {
3490 WARN("Got ret = %d on name %s\n", ret, ValueName);
3493 if(type != REG_DWORD) {
3494 ERR("Got type %d\n", type);
3500 /*****************************************************************************
3501 * WINSPOOL_GetStringFromReg
3503 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3504 * String is stored either as unicode or ascii.
3505 * Bit of a hack here to get the ValueName if we want ascii.
3507 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3508 DWORD buflen, DWORD *needed,
3511 DWORD sz = buflen, type;
3515 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3517 LPSTR ValueNameA = strdupWtoA(ValueName);
3518 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3519 HeapFree(GetProcessHeap(),0,ValueNameA);
3521 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3522 WARN("Got ret = %d\n", ret);
3526 /* add space for terminating '\0' */
3527 sz += unicode ? sizeof(WCHAR) : 1;
3531 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3536 /*****************************************************************************
3537 * WINSPOOL_GetDefaultDevMode
3539 * Get a default DevMode values for wineps.
3543 static void WINSPOOL_GetDefaultDevMode(
3545 DWORD buflen, DWORD *needed,
3549 static const char szwps[] = "wineps.drv";
3551 /* fill default DEVMODE - should be read from ppd... */
3552 ZeroMemory( &dm, sizeof(dm) );
3553 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3554 dm.dmSpecVersion = DM_SPECVERSION;
3555 dm.dmDriverVersion = 1;
3556 dm.dmSize = sizeof(DEVMODEA);
3557 dm.dmDriverExtra = 0;
3559 DM_ORIENTATION | DM_PAPERSIZE |
3560 DM_PAPERLENGTH | DM_PAPERWIDTH |
3563 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3564 DM_YRESOLUTION | DM_TTOPTION;
3566 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3567 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3568 dm.u1.s1.dmPaperLength = 2970;
3569 dm.u1.s1.dmPaperWidth = 2100;
3573 dm.dmDefaultSource = DMBIN_AUTO;
3574 dm.dmPrintQuality = DMRES_MEDIUM;
3577 dm.dmYResolution = 300; /* 300dpi */
3578 dm.dmTTOption = DMTT_BITMAP;
3581 /* dm.dmLogPixels */
3582 /* dm.dmBitsPerPel */
3583 /* dm.dmPelsWidth */
3584 /* dm.dmPelsHeight */
3585 /* dm.dmDisplayFlags */
3586 /* dm.dmDisplayFrequency */
3587 /* dm.dmICMMethod */
3588 /* dm.dmICMIntent */
3589 /* dm.dmMediaType */
3590 /* dm.dmDitherType */
3591 /* dm.dmReserved1 */
3592 /* dm.dmReserved2 */
3593 /* dm.dmPanningWidth */
3594 /* dm.dmPanningHeight */
3597 if(buflen >= sizeof(DEVMODEW)) {
3598 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3599 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3600 HeapFree(GetProcessHeap(),0,pdmW);
3602 *needed = sizeof(DEVMODEW);
3606 if(buflen >= sizeof(DEVMODEA)) {
3607 memcpy(ptr, &dm, sizeof(DEVMODEA));
3609 *needed = sizeof(DEVMODEA);
3613 /*****************************************************************************
3614 * WINSPOOL_GetDevModeFromReg
3616 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3617 * DevMode is stored either as unicode or ascii.
3619 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3621 DWORD buflen, DWORD *needed,
3624 DWORD sz = buflen, type;
3627 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3628 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3629 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3630 if (sz < sizeof(DEVMODEA))
3632 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3635 /* ensures that dmSize is not erratically bogus if registry is invalid */
3636 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3637 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3639 sz += (CCHDEVICENAME + CCHFORMNAME);
3641 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3642 memcpy(ptr, dmW, sz);
3643 HeapFree(GetProcessHeap(),0,dmW);
3650 /*********************************************************************
3651 * WINSPOOL_GetPrinter_2
3653 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3654 * The strings are either stored as unicode or ascii.
3656 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3657 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3660 DWORD size, left = cbBuf;
3661 BOOL space = (cbBuf > 0);
3666 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3668 if(space && size <= left) {
3669 pi2->pPrinterName = (LPWSTR)ptr;
3676 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3678 if(space && size <= left) {
3679 pi2->pShareName = (LPWSTR)ptr;
3686 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3688 if(space && size <= left) {
3689 pi2->pPortName = (LPWSTR)ptr;
3696 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3698 if(space && size <= left) {
3699 pi2->pDriverName = (LPWSTR)ptr;
3706 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3708 if(space && size <= left) {
3709 pi2->pComment = (LPWSTR)ptr;
3716 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3718 if(space && size <= left) {
3719 pi2->pLocation = (LPWSTR)ptr;
3726 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3728 if(space && size <= left) {
3729 pi2->pDevMode = (LPDEVMODEW)ptr;
3738 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3739 if(space && size <= left) {
3740 pi2->pDevMode = (LPDEVMODEW)ptr;
3747 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3749 if(space && size <= left) {
3750 pi2->pSepFile = (LPWSTR)ptr;
3757 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3759 if(space && size <= left) {
3760 pi2->pPrintProcessor = (LPWSTR)ptr;
3767 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3769 if(space && size <= left) {
3770 pi2->pDatatype = (LPWSTR)ptr;
3777 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3779 if(space && size <= left) {
3780 pi2->pParameters = (LPWSTR)ptr;
3788 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3789 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3790 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3791 "Default Priority");
3792 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3793 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3796 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3797 memset(pi2, 0, sizeof(*pi2));
3802 /*********************************************************************
3803 * WINSPOOL_GetPrinter_4
3805 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3807 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3808 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3811 DWORD size, left = cbBuf;
3812 BOOL space = (cbBuf > 0);
3817 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3819 if(space && size <= left) {
3820 pi4->pPrinterName = (LPWSTR)ptr;
3828 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3831 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3832 memset(pi4, 0, sizeof(*pi4));
3837 /*********************************************************************
3838 * WINSPOOL_GetPrinter_5
3840 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3842 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3843 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3846 DWORD size, left = cbBuf;
3847 BOOL space = (cbBuf > 0);
3852 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3854 if(space && size <= left) {
3855 pi5->pPrinterName = (LPWSTR)ptr;
3862 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3864 if(space && size <= left) {
3865 pi5->pPortName = (LPWSTR)ptr;
3873 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3874 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3876 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3880 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3881 memset(pi5, 0, sizeof(*pi5));
3886 /*****************************************************************************
3887 * WINSPOOL_GetPrinter
3889 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3890 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3891 * just a collection of pointers to strings.
3893 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3894 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3897 DWORD size, needed = 0;
3899 HKEY hkeyPrinter, hkeyPrinters;
3902 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3904 if (!(name = get_opened_printer_name(hPrinter))) {
3905 SetLastError(ERROR_INVALID_HANDLE);
3909 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3911 ERR("Can't create Printers key\n");
3914 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3916 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3917 RegCloseKey(hkeyPrinters);
3918 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3925 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3927 size = sizeof(PRINTER_INFO_2W);
3929 ptr = pPrinter + size;
3931 memset(pPrinter, 0, size);
3936 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3944 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3946 size = sizeof(PRINTER_INFO_4W);
3948 ptr = pPrinter + size;
3950 memset(pPrinter, 0, size);
3955 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3964 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3966 size = sizeof(PRINTER_INFO_5W);
3968 ptr = pPrinter + size;
3970 memset(pPrinter, 0, size);
3976 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3983 FIXME("Unimplemented level %d\n", Level);
3984 SetLastError(ERROR_INVALID_LEVEL);
3985 RegCloseKey(hkeyPrinters);
3986 RegCloseKey(hkeyPrinter);
3990 RegCloseKey(hkeyPrinter);
3991 RegCloseKey(hkeyPrinters);
3993 TRACE("returning %d needed = %d\n", ret, needed);
3994 if(pcbNeeded) *pcbNeeded = needed;
3996 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4000 /*****************************************************************************
4001 * GetPrinterW [WINSPOOL.@]
4003 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4004 DWORD cbBuf, LPDWORD pcbNeeded)
4006 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4010 /*****************************************************************************
4011 * GetPrinterA [WINSPOOL.@]
4013 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4014 DWORD cbBuf, LPDWORD pcbNeeded)
4016 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4020 /*****************************************************************************
4021 * WINSPOOL_EnumPrinters
4023 * Implementation of EnumPrintersA|W
4025 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4026 DWORD dwLevel, LPBYTE lpbPrinters,
4027 DWORD cbBuf, LPDWORD lpdwNeeded,
4028 LPDWORD lpdwReturned, BOOL unicode)
4031 HKEY hkeyPrinters, hkeyPrinter;
4032 WCHAR PrinterName[255];
4033 DWORD needed = 0, number = 0;
4034 DWORD used, i, left;
4038 memset(lpbPrinters, 0, cbBuf);
4044 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4045 if(dwType == PRINTER_ENUM_DEFAULT)
4048 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4049 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4050 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4052 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4060 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4061 FIXME("dwType = %08x\n", dwType);
4062 SetLastError(ERROR_INVALID_FLAGS);
4066 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4068 ERR("Can't create Printers key\n");
4072 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4073 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4074 RegCloseKey(hkeyPrinters);
4075 ERR("Can't query Printers key\n");
4078 TRACE("Found %d printers\n", number);
4082 RegCloseKey(hkeyPrinters);
4084 *lpdwReturned = number;
4088 used = number * sizeof(PRINTER_INFO_2W);
4091 used = number * sizeof(PRINTER_INFO_4W);
4094 used = number * sizeof(PRINTER_INFO_5W);
4098 SetLastError(ERROR_INVALID_LEVEL);
4099 RegCloseKey(hkeyPrinters);
4102 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4104 for(i = 0; i < number; i++) {
4105 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4107 ERR("Can't enum key number %d\n", i);
4108 RegCloseKey(hkeyPrinters);
4111 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4112 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4114 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4115 RegCloseKey(hkeyPrinters);
4120 buf = lpbPrinters + used;
4121 left = cbBuf - used;
4129 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4130 left, &needed, unicode);
4132 if(pi) pi += sizeof(PRINTER_INFO_2W);
4135 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4136 left, &needed, unicode);
4138 if(pi) pi += sizeof(PRINTER_INFO_4W);
4141 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4142 left, &needed, unicode);
4144 if(pi) pi += sizeof(PRINTER_INFO_5W);
4147 ERR("Shouldn't be here!\n");
4148 RegCloseKey(hkeyPrinter);
4149 RegCloseKey(hkeyPrinters);
4152 RegCloseKey(hkeyPrinter);
4154 RegCloseKey(hkeyPrinters);
4161 memset(lpbPrinters, 0, cbBuf);
4162 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4166 *lpdwReturned = number;
4167 SetLastError(ERROR_SUCCESS);
4172 /******************************************************************
4173 * EnumPrintersW [WINSPOOL.@]
4175 * Enumerates the available printers, print servers and print
4176 * providers, depending on the specified flags, name and level.
4180 * If level is set to 1:
4181 * Not implemented yet!
4182 * Returns TRUE with an empty list.
4184 * If level is set to 2:
4185 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4186 * Returns an array of PRINTER_INFO_2 data structures in the
4187 * lpbPrinters buffer. Note that according to MSDN also an
4188 * OpenPrinter should be performed on every remote printer.
4190 * If level is set to 4 (officially WinNT only):
4191 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4192 * Fast: Only the registry is queried to retrieve printer names,
4193 * no connection to the driver is made.
4194 * Returns an array of PRINTER_INFO_4 data structures in the
4195 * lpbPrinters buffer.
4197 * If level is set to 5 (officially WinNT4/Win9x only):
4198 * Fast: Only the registry is queried to retrieve printer names,
4199 * no connection to the driver is made.
4200 * Returns an array of PRINTER_INFO_5 data structures in the
4201 * lpbPrinters buffer.
4203 * If level set to 3 or 6+:
4204 * returns zero (failure!)
4206 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4210 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4211 * - Only levels 2, 4 and 5 are implemented at the moment.
4212 * - 16-bit printer drivers are not enumerated.
4213 * - Returned amount of bytes used/needed does not match the real Windoze
4214 * implementation (as in this implementation, all strings are part
4215 * of the buffer, whereas Win32 keeps them somewhere else)
4216 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4219 * - In a regular Wine installation, no registry settings for printers
4220 * exist, which makes this function return an empty list.
4222 BOOL WINAPI EnumPrintersW(
4223 DWORD dwType, /* [in] Types of print objects to enumerate */
4224 LPWSTR lpszName, /* [in] name of objects to enumerate */
4225 DWORD dwLevel, /* [in] type of printer info structure */
4226 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4227 DWORD cbBuf, /* [in] max size of buffer in bytes */
4228 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4229 LPDWORD lpdwReturned /* [out] number of entries returned */
4232 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4233 lpdwNeeded, lpdwReturned, TRUE);
4236 /******************************************************************
4237 * EnumPrintersA [WINSPOOL.@]
4240 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4241 DWORD dwLevel, LPBYTE lpbPrinters,
4242 DWORD cbBuf, LPDWORD lpdwNeeded,
4243 LPDWORD lpdwReturned)
4245 BOOL ret, unicode = FALSE;
4246 UNICODE_STRING lpszNameW;
4249 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4250 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4251 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4252 lpdwNeeded, lpdwReturned, unicode);
4253 RtlFreeUnicodeString(&lpszNameW);
4257 /*****************************************************************************
4258 * WINSPOOL_GetDriverInfoFromReg [internal]
4260 * Enters the information from the registry into the DRIVER_INFO struct
4263 * zero if the printer driver does not exist in the registry
4264 * (only if Level > 1) otherwise nonzero
4266 static BOOL WINSPOOL_GetDriverInfoFromReg(
4269 LPCWSTR pEnvironment,
4271 LPBYTE ptr, /* DRIVER_INFO */
4272 LPBYTE pDriverStrings, /* strings buffer */
4273 DWORD cbBuf, /* size of string buffer */
4274 LPDWORD pcbNeeded, /* space needed for str. */
4275 BOOL unicode) /* type of strings */
4279 LPBYTE strPtr = pDriverStrings;
4281 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4282 debugstr_w(DriverName), debugstr_w(pEnvironment),
4283 Level, ptr, pDriverStrings, cbBuf, unicode);
4286 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4287 if (*pcbNeeded <= cbBuf)
4288 strcpyW((LPWSTR)strPtr, DriverName);
4290 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4292 if(*pcbNeeded <= cbBuf)
4293 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4294 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4298 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4302 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4303 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4306 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4307 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4308 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4313 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4316 pEnvironment = DefaultEnvironmentW;
4318 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4320 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4323 if(*pcbNeeded <= cbBuf) {
4325 strcpyW((LPWSTR)strPtr, pEnvironment);
4327 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4328 (LPSTR)strPtr, size, NULL, NULL);
4330 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4331 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4334 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4337 if(*pcbNeeded <= cbBuf)
4338 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4341 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4342 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4345 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4348 if(*pcbNeeded <= cbBuf)
4349 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4352 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4353 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4356 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4357 0, &size, unicode)) {
4359 if(*pcbNeeded <= cbBuf)
4360 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4361 size, &tmp, unicode);
4363 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4364 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4368 RegCloseKey(hkeyDriver);
4369 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4373 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4376 if(*pcbNeeded <= cbBuf)
4377 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4378 size, &tmp, unicode);
4380 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4381 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4384 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4387 if(*pcbNeeded <= cbBuf)
4388 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4389 size, &tmp, unicode);
4391 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4392 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4395 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4398 if(*pcbNeeded <= cbBuf)
4399 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4400 size, &tmp, unicode);
4402 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4403 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4406 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4409 if(*pcbNeeded <= cbBuf)
4410 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4411 size, &tmp, unicode);
4413 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4414 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4417 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4418 RegCloseKey(hkeyDriver);
4422 /*****************************************************************************
4423 * WINSPOOL_GetPrinterDriver
4425 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4426 DWORD Level, LPBYTE pDriverInfo,
4427 DWORD cbBuf, LPDWORD pcbNeeded,
4431 WCHAR DriverName[100];
4432 DWORD ret, type, size, needed = 0;
4434 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4436 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4437 Level,pDriverInfo,cbBuf, pcbNeeded);
4439 ZeroMemory(pDriverInfo, cbBuf);
4441 if (!(name = get_opened_printer_name(hPrinter))) {
4442 SetLastError(ERROR_INVALID_HANDLE);
4445 if(Level < 1 || Level > 6) {
4446 SetLastError(ERROR_INVALID_LEVEL);
4449 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4451 ERR("Can't create Printers key\n");
4454 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4456 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4457 RegCloseKey(hkeyPrinters);
4458 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4461 size = sizeof(DriverName);
4463 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4464 (LPBYTE)DriverName, &size);
4465 RegCloseKey(hkeyPrinter);
4466 RegCloseKey(hkeyPrinters);
4467 if(ret != ERROR_SUCCESS) {
4468 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4472 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4474 ERR("Can't create Drivers key\n");
4480 size = sizeof(DRIVER_INFO_1W);
4483 size = sizeof(DRIVER_INFO_2W);
4486 size = sizeof(DRIVER_INFO_3W);
4489 size = sizeof(DRIVER_INFO_4W);
4492 size = sizeof(DRIVER_INFO_5W);
4495 size = sizeof(DRIVER_INFO_6W);
4498 ERR("Invalid level\n");
4503 ptr = pDriverInfo + size;
4505 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4506 pEnvironment, Level, pDriverInfo,
4507 (cbBuf < size) ? NULL : ptr,
4508 (cbBuf < size) ? 0 : cbBuf - size,
4509 &needed, unicode)) {
4510 RegCloseKey(hkeyDrivers);
4514 RegCloseKey(hkeyDrivers);
4516 if(pcbNeeded) *pcbNeeded = size + needed;
4517 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4518 if(cbBuf >= needed) return TRUE;
4519 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4523 /*****************************************************************************
4524 * GetPrinterDriverA [WINSPOOL.@]
4526 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4527 DWORD Level, LPBYTE pDriverInfo,
4528 DWORD cbBuf, LPDWORD pcbNeeded)
4531 UNICODE_STRING pEnvW;
4534 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4535 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4536 cbBuf, pcbNeeded, FALSE);
4537 RtlFreeUnicodeString(&pEnvW);
4540 /*****************************************************************************
4541 * GetPrinterDriverW [WINSPOOL.@]
4543 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4544 DWORD Level, LPBYTE pDriverInfo,
4545 DWORD cbBuf, LPDWORD pcbNeeded)
4547 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4548 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4551 /*****************************************************************************
4552 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4554 * Return the PATH for the Printer-Drivers (UNICODE)
4557 * pName [I] Servername (NT only) or NULL (local Computer)
4558 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4559 * Level [I] Structure-Level (must be 1)
4560 * pDriverDirectory [O] PTR to Buffer that receives the Result
4561 * cbBuf [I] Size of Buffer at pDriverDirectory
4562 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4563 * required for pDriverDirectory
4566 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4567 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4568 * if cbBuf is too small
4570 * Native Values returned in pDriverDirectory on Success:
4571 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4572 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4573 *| win9x(Windows 4.0): "%winsysdir%"
4575 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4578 *- Only NULL or "" is supported for pName
4581 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4582 DWORD Level, LPBYTE pDriverDirectory,
4583 DWORD cbBuf, LPDWORD pcbNeeded)
4586 const printenv_t * env;
4588 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4589 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4590 if(pName != NULL && pName[0]) {
4591 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4592 SetLastError(ERROR_INVALID_PARAMETER);
4596 env = validate_envW(pEnvironment);
4597 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4600 WARN("(Level: %d) is ignored in win9x\n", Level);
4601 SetLastError(ERROR_INVALID_LEVEL);
4605 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4606 needed = GetSystemDirectoryW(NULL, 0);
4607 /* add the Size for the Subdirectories */
4608 needed += lstrlenW(spooldriversW);
4609 needed += lstrlenW(env->subdir);
4610 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4613 *pcbNeeded = needed;
4614 TRACE("required: 0x%x/%d\n", needed, needed);
4615 if(needed > cbBuf) {
4616 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4619 if(pcbNeeded == NULL) {
4620 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4621 SetLastError(RPC_X_NULL_REF_POINTER);
4624 if(pDriverDirectory == NULL) {
4625 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4626 SetLastError(ERROR_INVALID_USER_BUFFER);
4630 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4631 /* add the Subdirectories */
4632 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4633 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4634 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4639 /*****************************************************************************
4640 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4642 * Return the PATH for the Printer-Drivers (ANSI)
4644 * See GetPrinterDriverDirectoryW.
4647 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4650 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4651 DWORD Level, LPBYTE pDriverDirectory,
4652 DWORD cbBuf, LPDWORD pcbNeeded)
4654 UNICODE_STRING nameW, environmentW;
4657 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4658 WCHAR *driverDirectoryW = NULL;
4660 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4661 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4663 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4665 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4666 else nameW.Buffer = NULL;
4667 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4668 else environmentW.Buffer = NULL;
4670 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4671 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4674 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4675 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4677 *pcbNeeded = needed;
4678 ret = (needed <= cbBuf) ? TRUE : FALSE;
4680 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4682 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4684 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4685 RtlFreeUnicodeString(&environmentW);
4686 RtlFreeUnicodeString(&nameW);
4691 /*****************************************************************************
4692 * AddPrinterDriverA [WINSPOOL.@]
4694 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4697 HKEY hkeyDrivers, hkeyName;
4698 static CHAR empty[] = "",
4701 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4703 if(level != 2 && level != 3) {
4704 SetLastError(ERROR_INVALID_LEVEL);
4707 if ((pName) && (pName[0])) {
4708 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4709 SetLastError(ERROR_INVALID_PARAMETER);
4713 WARN("pDriverInfo == NULL\n");
4714 SetLastError(ERROR_INVALID_PARAMETER);
4719 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4721 memset(&di3, 0, sizeof(di3));
4722 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4725 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4727 SetLastError(ERROR_INVALID_PARAMETER);
4731 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4732 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4733 if(!di3.pHelpFile) di3.pHelpFile = empty;
4734 if(!di3.pMonitorName) di3.pMonitorName = empty;
4736 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4739 ERR("Can't create Drivers key\n");
4743 if(level == 2) { /* apparently can't overwrite with level2 */
4744 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4745 RegCloseKey(hkeyName);
4746 RegCloseKey(hkeyDrivers);
4747 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4748 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4752 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4753 RegCloseKey(hkeyDrivers);
4754 ERR("Can't create Name key\n");
4757 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4758 lstrlenA(di3.pConfigFile) + 1);
4759 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4760 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4761 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4763 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4764 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4765 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4766 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4767 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4768 RegCloseKey(hkeyName);
4769 RegCloseKey(hkeyDrivers);
4774 /*****************************************************************************
4775 * AddPrinterDriverW [WINSPOOL.@]
4777 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4780 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4785 /*****************************************************************************
4786 * AddPrintProcessorA [WINSPOOL.@]
4788 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4789 LPSTR pPrintProcessorName)
4791 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4792 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4796 /*****************************************************************************
4797 * AddPrintProcessorW [WINSPOOL.@]
4799 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4800 LPWSTR pPrintProcessorName)
4802 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4803 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4807 /*****************************************************************************
4808 * AddPrintProvidorA [WINSPOOL.@]
4810 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4812 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4816 /*****************************************************************************
4817 * AddPrintProvidorW [WINSPOOL.@]
4819 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4821 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4825 /*****************************************************************************
4826 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4828 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4829 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4831 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4832 pDevModeOutput, pDevModeInput);
4836 /*****************************************************************************
4837 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4839 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4840 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4842 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4843 pDevModeOutput, pDevModeInput);
4847 /*****************************************************************************
4848 * PrinterProperties [WINSPOOL.@]
4850 * Displays a dialog to set the properties of the printer.
4853 * nonzero on success or zero on failure
4856 * implemented as stub only
4858 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4859 HANDLE hPrinter /* [in] handle to printer object */
4861 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4862 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4866 /*****************************************************************************
4867 * EnumJobsA [WINSPOOL.@]
4870 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4871 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4874 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4875 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4877 if(pcbNeeded) *pcbNeeded = 0;
4878 if(pcReturned) *pcReturned = 0;
4883 /*****************************************************************************
4884 * EnumJobsW [WINSPOOL.@]
4887 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4888 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4891 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4892 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4894 if(pcbNeeded) *pcbNeeded = 0;
4895 if(pcReturned) *pcReturned = 0;
4899 /*****************************************************************************
4900 * WINSPOOL_EnumPrinterDrivers [internal]
4902 * Delivers information about all printer drivers installed on the
4903 * localhost or a given server
4906 * nonzero on success or zero on failure. If the buffer for the returned
4907 * information is too small the function will return an error
4910 * - only implemented for localhost, foreign hosts will return an error
4912 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4913 DWORD Level, LPBYTE pDriverInfo,
4914 DWORD cbBuf, LPDWORD pcbNeeded,
4915 LPDWORD pcReturned, BOOL unicode)
4918 DWORD i, needed, number = 0, size = 0;
4919 WCHAR DriverNameW[255];
4922 TRACE("%s,%s,%d,%p,%d,%d\n",
4923 debugstr_w(pName), debugstr_w(pEnvironment),
4924 Level, pDriverInfo, cbBuf, unicode);
4926 /* check for local drivers */
4927 if((pName) && (pName[0])) {
4928 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4929 SetLastError(ERROR_ACCESS_DENIED);
4933 /* check input parameter */
4934 if((Level < 1) || (Level > 3)) {
4935 ERR("unsupported level %d\n", Level);
4936 SetLastError(ERROR_INVALID_LEVEL);
4940 /* initialize return values */
4942 memset( pDriverInfo, 0, cbBuf);
4946 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4948 ERR("Can't open Drivers key\n");
4952 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4953 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4954 RegCloseKey(hkeyDrivers);
4955 ERR("Can't query Drivers key\n");
4958 TRACE("Found %d Drivers\n", number);
4960 /* get size of single struct
4961 * unicode and ascii structure have the same size
4965 size = sizeof(DRIVER_INFO_1A);
4968 size = sizeof(DRIVER_INFO_2A);
4971 size = sizeof(DRIVER_INFO_3A);
4975 /* calculate required buffer size */
4976 *pcbNeeded = size * number;
4978 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4980 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4981 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4983 ERR("Can't enum key number %d\n", i);
4984 RegCloseKey(hkeyDrivers);
4987 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4988 pEnvironment, Level, ptr,
4989 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4990 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4991 &needed, unicode)) {
4992 RegCloseKey(hkeyDrivers);
4995 (*pcbNeeded) += needed;
4998 RegCloseKey(hkeyDrivers);
5000 if(cbBuf < *pcbNeeded){
5001 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5005 *pcReturned = number;
5009 /*****************************************************************************
5010 * EnumPrinterDriversW [WINSPOOL.@]
5012 * see function EnumPrinterDrivers for RETURNS, BUGS
5014 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5015 LPBYTE pDriverInfo, DWORD cbBuf,
5016 LPDWORD pcbNeeded, LPDWORD pcReturned)
5018 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5019 cbBuf, pcbNeeded, pcReturned, TRUE);
5022 /*****************************************************************************
5023 * EnumPrinterDriversA [WINSPOOL.@]
5025 * see function EnumPrinterDrivers for RETURNS, BUGS
5027 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5028 LPBYTE pDriverInfo, DWORD cbBuf,
5029 LPDWORD pcbNeeded, LPDWORD pcReturned)
5031 UNICODE_STRING pNameW, pEnvironmentW;
5032 PWSTR pwstrNameW, pwstrEnvironmentW;
5034 pwstrNameW = asciitounicode(&pNameW, pName);
5035 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5037 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5038 Level, pDriverInfo, cbBuf, pcbNeeded,
5040 RtlFreeUnicodeString(&pNameW);
5041 RtlFreeUnicodeString(&pEnvironmentW);
5046 /******************************************************************************
5047 * EnumPortsA (WINSPOOL.@)
5052 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5053 LPDWORD pcbNeeded, LPDWORD pcReturned)
5056 LPBYTE bufferW = NULL;
5057 LPWSTR nameW = NULL;
5059 DWORD numentries = 0;
5062 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5063 cbBuf, pcbNeeded, pcReturned);
5065 /* convert servername to unicode */
5067 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5068 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5069 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5071 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5072 needed = cbBuf * sizeof(WCHAR);
5073 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5074 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5076 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5077 if (pcbNeeded) needed = *pcbNeeded;
5078 /* HeapReAlloc return NULL, when bufferW was NULL */
5079 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5080 HeapAlloc(GetProcessHeap(), 0, needed);
5082 /* Try again with the large Buffer */
5083 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5085 needed = pcbNeeded ? *pcbNeeded : 0;
5086 numentries = pcReturned ? *pcReturned : 0;
5089 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5090 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5093 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5094 DWORD entrysize = 0;
5097 LPPORT_INFO_2W pi2w;
5098 LPPORT_INFO_2A pi2a;
5101 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5103 /* First pass: calculate the size for all Entries */
5104 pi2w = (LPPORT_INFO_2W) bufferW;
5105 pi2a = (LPPORT_INFO_2A) pPorts;
5107 while (index < numentries) {
5109 needed += entrysize; /* PORT_INFO_?A */
5110 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5112 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5113 NULL, 0, NULL, NULL);
5115 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5116 NULL, 0, NULL, NULL);
5117 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5118 NULL, 0, NULL, NULL);
5120 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5121 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5122 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5125 /* check for errors and quit on failure */
5126 if (cbBuf < needed) {
5127 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5131 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5132 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5133 cbBuf -= len ; /* free Bytes in the user-Buffer */
5134 pi2w = (LPPORT_INFO_2W) bufferW;
5135 pi2a = (LPPORT_INFO_2A) pPorts;
5137 /* Second Pass: Fill the User Buffer (if we have one) */
5138 while ((index < numentries) && pPorts) {
5140 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5141 pi2a->pPortName = ptr;
5142 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5143 ptr, cbBuf , NULL, NULL);
5147 pi2a->pMonitorName = ptr;
5148 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5149 ptr, cbBuf, NULL, NULL);
5153 pi2a->pDescription = ptr;
5154 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5155 ptr, cbBuf, NULL, NULL);
5159 pi2a->fPortType = pi2w->fPortType;
5160 pi2a->Reserved = 0; /* documented: "must be zero" */
5163 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5164 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5165 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5170 if (pcbNeeded) *pcbNeeded = needed;
5171 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5173 HeapFree(GetProcessHeap(), 0, nameW);
5174 HeapFree(GetProcessHeap(), 0, bufferW);
5176 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5177 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5183 /******************************************************************************
5184 * EnumPortsW (WINSPOOL.@)
5186 * Enumerate available Ports
5189 * name [I] Servername or NULL (local Computer)
5190 * level [I] Structure-Level (1 or 2)
5191 * buffer [O] PTR to Buffer that receives the Result
5192 * bufsize [I] Size of Buffer at buffer
5193 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5194 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5198 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5202 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5205 DWORD numentries = 0;
5208 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5209 cbBuf, pcbNeeded, pcReturned);
5211 if (pName && (pName[0])) {
5212 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5213 SetLastError(ERROR_ACCESS_DENIED);
5217 /* Level is not checked in win9x */
5218 if (!Level || (Level > 2)) {
5219 WARN("level (%d) is ignored in win9x\n", Level);
5220 SetLastError(ERROR_INVALID_LEVEL);
5224 SetLastError(RPC_X_NULL_REF_POINTER);
5228 EnterCriticalSection(&monitor_handles_cs);
5231 /* Scan all local Ports */
5233 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5235 /* we calculated the needed buffersize. now do the error-checks */
5236 if (cbBuf < needed) {
5237 monitor_unloadall();
5238 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5239 goto emP_cleanup_cs;
5241 else if (!pPorts || !pcReturned) {
5242 monitor_unloadall();
5243 SetLastError(RPC_X_NULL_REF_POINTER);
5244 goto emP_cleanup_cs;
5247 /* Fill the Buffer */
5248 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5250 monitor_unloadall();
5253 LeaveCriticalSection(&monitor_handles_cs);
5256 if (pcbNeeded) *pcbNeeded = needed;
5257 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5259 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5260 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5265 /******************************************************************************
5266 * GetDefaultPrinterW (WINSPOOL.@)
5269 * This function must read the value from data 'device' of key
5270 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5272 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5276 WCHAR *buffer, *ptr;
5280 SetLastError(ERROR_INVALID_PARAMETER);
5284 /* make the buffer big enough for the stuff from the profile/registry,
5285 * the content must fit into the local buffer to compute the correct
5286 * size even if the extern buffer is too small or not given.
5287 * (20 for ,driver,port) */
5289 len = max(100, (insize + 20));
5290 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5292 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5294 SetLastError (ERROR_FILE_NOT_FOUND);
5298 TRACE("%s\n", debugstr_w(buffer));
5300 if ((ptr = strchrW(buffer, ',')) == NULL)
5302 SetLastError(ERROR_INVALID_NAME);
5308 *namesize = strlenW(buffer) + 1;
5309 if(!name || (*namesize > insize))
5311 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5315 strcpyW(name, buffer);
5318 HeapFree( GetProcessHeap(), 0, buffer);
5323 /******************************************************************************
5324 * GetDefaultPrinterA (WINSPOOL.@)
5326 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5330 WCHAR *bufferW = NULL;
5334 SetLastError(ERROR_INVALID_PARAMETER);
5338 if(name && *namesize) {
5340 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5343 if(!GetDefaultPrinterW( bufferW, namesize)) {
5348 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5352 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5355 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5358 HeapFree( GetProcessHeap(), 0, bufferW);
5363 /******************************************************************************
5364 * SetDefaultPrinterW (WINSPOOL.204)
5366 * Set the Name of the Default Printer
5369 * pszPrinter [I] Name of the Printer or NULL
5376 * When the Parameter is NULL or points to an Empty String and
5377 * a Default Printer was already present, then this Function changes nothing.
5378 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5379 * the First enumerated local Printer is used.
5382 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5385 TRACE("(%s)\n", debugstr_w(pszPrinter));
5387 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5391 /******************************************************************************
5392 * SetDefaultPrinterA (WINSPOOL.202)
5394 * See SetDefaultPrinterW.
5397 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5400 TRACE("(%s)\n", debugstr_a(pszPrinter));
5402 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5407 /******************************************************************************
5408 * SetPrinterDataExA (WINSPOOL.@)
5410 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5411 LPCSTR pValueName, DWORD Type,
5412 LPBYTE pData, DWORD cbData)
5414 HKEY hkeyPrinter, hkeySubkey;
5417 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5418 debugstr_a(pValueName), Type, pData, cbData);
5420 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5424 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5426 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5427 RegCloseKey(hkeyPrinter);
5430 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5431 RegCloseKey(hkeySubkey);
5432 RegCloseKey(hkeyPrinter);
5436 /******************************************************************************
5437 * SetPrinterDataExW (WINSPOOL.@)
5439 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5440 LPCWSTR pValueName, DWORD Type,
5441 LPBYTE pData, DWORD cbData)
5443 HKEY hkeyPrinter, hkeySubkey;
5446 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5447 debugstr_w(pValueName), Type, pData, cbData);
5449 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5453 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5455 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5456 RegCloseKey(hkeyPrinter);
5459 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5460 RegCloseKey(hkeySubkey);
5461 RegCloseKey(hkeyPrinter);
5465 /******************************************************************************
5466 * SetPrinterDataA (WINSPOOL.@)
5468 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5469 LPBYTE pData, DWORD cbData)
5471 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5475 /******************************************************************************
5476 * SetPrinterDataW (WINSPOOL.@)
5478 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5479 LPBYTE pData, DWORD cbData)
5481 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5485 /******************************************************************************
5486 * GetPrinterDataExA (WINSPOOL.@)
5488 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5489 LPCSTR pValueName, LPDWORD pType,
5490 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5492 HKEY hkeyPrinter, hkeySubkey;
5495 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5496 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5499 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5503 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5505 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5506 RegCloseKey(hkeyPrinter);
5510 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5511 RegCloseKey(hkeySubkey);
5512 RegCloseKey(hkeyPrinter);
5516 /******************************************************************************
5517 * GetPrinterDataExW (WINSPOOL.@)
5519 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5520 LPCWSTR pValueName, LPDWORD pType,
5521 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5523 HKEY hkeyPrinter, hkeySubkey;
5526 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5527 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5530 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5534 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5536 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5537 RegCloseKey(hkeyPrinter);
5541 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5542 RegCloseKey(hkeySubkey);
5543 RegCloseKey(hkeyPrinter);
5547 /******************************************************************************
5548 * GetPrinterDataA (WINSPOOL.@)
5550 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5551 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5553 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5554 pData, nSize, pcbNeeded);
5557 /******************************************************************************
5558 * GetPrinterDataW (WINSPOOL.@)
5560 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5561 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5563 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5564 pData, nSize, pcbNeeded);
5567 /*******************************************************************************
5568 * EnumPrinterDataExW [WINSPOOL.@]
5570 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5571 LPBYTE pEnumValues, DWORD cbEnumValues,
5572 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5574 HKEY hkPrinter, hkSubKey;
5575 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5576 cbValueNameLen, cbMaxValueLen, cbValueLen,
5581 PPRINTER_ENUM_VALUESW ppev;
5583 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5585 if (pKeyName == NULL || *pKeyName == 0)
5586 return ERROR_INVALID_PARAMETER;
5588 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5589 if (ret != ERROR_SUCCESS)
5591 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5596 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5597 if (ret != ERROR_SUCCESS)
5599 r = RegCloseKey (hkPrinter);
5600 if (r != ERROR_SUCCESS)
5601 WARN ("RegCloseKey returned %i\n", r);
5602 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5603 debugstr_w (pKeyName), ret);
5607 ret = RegCloseKey (hkPrinter);
5608 if (ret != ERROR_SUCCESS)
5610 ERR ("RegCloseKey returned %i\n", ret);
5611 r = RegCloseKey (hkSubKey);
5612 if (r != ERROR_SUCCESS)
5613 WARN ("RegCloseKey returned %i\n", r);
5617 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5618 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5619 if (ret != ERROR_SUCCESS)
5621 r = RegCloseKey (hkSubKey);
5622 if (r != ERROR_SUCCESS)
5623 WARN ("RegCloseKey returned %i\n", r);
5624 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5628 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5629 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5631 if (cValues == 0) /* empty key */
5633 r = RegCloseKey (hkSubKey);
5634 if (r != ERROR_SUCCESS)
5635 WARN ("RegCloseKey returned %i\n", r);
5636 *pcbEnumValues = *pnEnumValues = 0;
5637 return ERROR_SUCCESS;
5640 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5642 hHeap = GetProcessHeap ();
5645 ERR ("GetProcessHeap failed\n");
5646 r = RegCloseKey (hkSubKey);
5647 if (r != ERROR_SUCCESS)
5648 WARN ("RegCloseKey returned %i\n", r);
5649 return ERROR_OUTOFMEMORY;
5652 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5653 if (lpValueName == NULL)
5655 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5656 r = RegCloseKey (hkSubKey);
5657 if (r != ERROR_SUCCESS)
5658 WARN ("RegCloseKey returned %i\n", r);
5659 return ERROR_OUTOFMEMORY;
5662 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5663 if (lpValue == NULL)
5665 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5666 if (HeapFree (hHeap, 0, lpValueName) == 0)
5667 WARN ("HeapFree failed with code %i\n", GetLastError ());
5668 r = RegCloseKey (hkSubKey);
5669 if (r != ERROR_SUCCESS)
5670 WARN ("RegCloseKey returned %i\n", r);
5671 return ERROR_OUTOFMEMORY;
5674 TRACE ("pass 1: calculating buffer required for all names and values\n");
5676 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5678 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5680 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5682 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5683 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5684 NULL, NULL, lpValue, &cbValueLen);
5685 if (ret != ERROR_SUCCESS)
5687 if (HeapFree (hHeap, 0, lpValue) == 0)
5688 WARN ("HeapFree failed with code %i\n", GetLastError ());
5689 if (HeapFree (hHeap, 0, lpValueName) == 0)
5690 WARN ("HeapFree failed with code %i\n", GetLastError ());
5691 r = RegCloseKey (hkSubKey);
5692 if (r != ERROR_SUCCESS)
5693 WARN ("RegCloseKey returned %i\n", r);
5694 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5698 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5699 debugstr_w (lpValueName), dwIndex,
5700 cbValueNameLen + 1, cbValueLen);
5702 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5703 cbBufSize += cbValueLen;
5706 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5708 *pcbEnumValues = cbBufSize;
5709 *pnEnumValues = cValues;
5711 if (cbEnumValues < cbBufSize) /* buffer too small */
5713 if (HeapFree (hHeap, 0, lpValue) == 0)
5714 WARN ("HeapFree failed with code %i\n", GetLastError ());
5715 if (HeapFree (hHeap, 0, lpValueName) == 0)
5716 WARN ("HeapFree failed with code %i\n", GetLastError ());
5717 r = RegCloseKey (hkSubKey);
5718 if (r != ERROR_SUCCESS)
5719 WARN ("RegCloseKey returned %i\n", r);
5720 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5721 return ERROR_MORE_DATA;
5724 TRACE ("pass 2: copying all names and values to buffer\n");
5726 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5727 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5729 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5731 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5732 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5733 NULL, &dwType, lpValue, &cbValueLen);
5734 if (ret != ERROR_SUCCESS)
5736 if (HeapFree (hHeap, 0, lpValue) == 0)
5737 WARN ("HeapFree failed with code %i\n", GetLastError ());
5738 if (HeapFree (hHeap, 0, lpValueName) == 0)
5739 WARN ("HeapFree failed with code %i\n", GetLastError ());
5740 r = RegCloseKey (hkSubKey);
5741 if (r != ERROR_SUCCESS)
5742 WARN ("RegCloseKey returned %i\n", r);
5743 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5747 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5748 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5749 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5750 pEnumValues += cbValueNameLen;
5752 /* return # of *bytes* (including trailing \0), not # of chars */
5753 ppev[dwIndex].cbValueName = cbValueNameLen;
5755 ppev[dwIndex].dwType = dwType;
5757 memcpy (pEnumValues, lpValue, cbValueLen);
5758 ppev[dwIndex].pData = pEnumValues;
5759 pEnumValues += cbValueLen;
5761 ppev[dwIndex].cbData = cbValueLen;
5763 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5764 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5767 if (HeapFree (hHeap, 0, lpValue) == 0)
5769 ret = GetLastError ();
5770 ERR ("HeapFree failed with code %i\n", ret);
5771 if (HeapFree (hHeap, 0, lpValueName) == 0)
5772 WARN ("HeapFree failed with code %i\n", GetLastError ());
5773 r = RegCloseKey (hkSubKey);
5774 if (r != ERROR_SUCCESS)
5775 WARN ("RegCloseKey returned %i\n", r);
5779 if (HeapFree (hHeap, 0, lpValueName) == 0)
5781 ret = GetLastError ();
5782 ERR ("HeapFree failed with code %i\n", ret);
5783 r = RegCloseKey (hkSubKey);
5784 if (r != ERROR_SUCCESS)
5785 WARN ("RegCloseKey returned %i\n", r);
5789 ret = RegCloseKey (hkSubKey);
5790 if (ret != ERROR_SUCCESS)
5792 ERR ("RegCloseKey returned %i\n", ret);
5796 return ERROR_SUCCESS;
5799 /*******************************************************************************
5800 * EnumPrinterDataExA [WINSPOOL.@]
5802 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5803 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5804 * what Windows 2000 SP1 does.
5807 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5808 LPBYTE pEnumValues, DWORD cbEnumValues,
5809 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5813 DWORD ret, dwIndex, dwBufSize;
5817 TRACE ("%p %s\n", hPrinter, pKeyName);
5819 if (pKeyName == NULL || *pKeyName == 0)
5820 return ERROR_INVALID_PARAMETER;
5822 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5825 ret = GetLastError ();
5826 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5830 hHeap = GetProcessHeap ();
5833 ERR ("GetProcessHeap failed\n");
5834 return ERROR_OUTOFMEMORY;
5837 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5838 if (pKeyNameW == NULL)
5840 ERR ("Failed to allocate %i bytes from process heap\n",
5841 (LONG)(len * sizeof (WCHAR)));
5842 return ERROR_OUTOFMEMORY;
5845 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5847 ret = GetLastError ();
5848 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5849 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5850 WARN ("HeapFree failed with code %i\n", GetLastError ());
5854 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5855 pcbEnumValues, pnEnumValues);
5856 if (ret != ERROR_SUCCESS)
5858 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5859 WARN ("HeapFree failed with code %i\n", GetLastError ());
5860 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5864 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5866 ret = GetLastError ();
5867 ERR ("HeapFree failed with code %i\n", ret);
5871 if (*pnEnumValues == 0) /* empty key */
5872 return ERROR_SUCCESS;
5875 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5877 PPRINTER_ENUM_VALUESW ppev =
5878 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5880 if (dwBufSize < ppev->cbValueName)
5881 dwBufSize = ppev->cbValueName;
5883 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5884 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5885 dwBufSize = ppev->cbData;
5888 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5890 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5891 if (pBuffer == NULL)
5893 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5894 return ERROR_OUTOFMEMORY;
5897 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5899 PPRINTER_ENUM_VALUESW ppev =
5900 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5902 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5903 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5907 ret = GetLastError ();
5908 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5909 if (HeapFree (hHeap, 0, pBuffer) == 0)
5910 WARN ("HeapFree failed with code %i\n", GetLastError ());
5914 memcpy (ppev->pValueName, pBuffer, len);
5916 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5918 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5919 ppev->dwType != REG_MULTI_SZ)
5922 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5923 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5926 ret = GetLastError ();
5927 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5928 if (HeapFree (hHeap, 0, pBuffer) == 0)
5929 WARN ("HeapFree failed with code %i\n", GetLastError ());
5933 memcpy (ppev->pData, pBuffer, len);
5935 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5936 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5939 if (HeapFree (hHeap, 0, pBuffer) == 0)
5941 ret = GetLastError ();
5942 ERR ("HeapFree failed with code %i\n", ret);
5946 return ERROR_SUCCESS;
5949 /******************************************************************************
5950 * AbortPrinter (WINSPOOL.@)
5952 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5954 FIXME("(%p), stub!\n", hPrinter);
5958 /******************************************************************************
5959 * AddPortA (WINSPOOL.@)
5964 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5966 LPWSTR nameW = NULL;
5967 LPWSTR monitorW = NULL;
5971 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5974 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5975 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5976 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5980 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5981 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5982 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5984 res = AddPortW(nameW, hWnd, monitorW);
5985 HeapFree(GetProcessHeap(), 0, nameW);
5986 HeapFree(GetProcessHeap(), 0, monitorW);
5990 /******************************************************************************
5991 * AddPortW (WINSPOOL.@)
5993 * Add a Port for a specific Monitor
5996 * pName [I] Servername or NULL (local Computer)
5997 * hWnd [I] Handle to parent Window for the Dialog-Box
5998 * pMonitorName [I] Name of the Monitor that manage the Port
6005 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6011 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6013 if (pName && pName[0]) {
6014 SetLastError(ERROR_INVALID_PARAMETER);
6018 if (!pMonitorName) {
6019 SetLastError(RPC_X_NULL_REF_POINTER);
6023 /* an empty Monitorname is Invalid */
6024 if (!pMonitorName[0]) {
6025 SetLastError(ERROR_NOT_SUPPORTED);
6029 pm = monitor_load(pMonitorName, NULL);
6030 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6031 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6032 TRACE("got %d with %u\n", res, GetLastError());
6037 pui = monitor_loadui(pm);
6038 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6039 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6040 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6041 TRACE("got %d with %u\n", res, GetLastError());
6046 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6047 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6049 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6050 SetLastError(ERROR_NOT_SUPPORTED);
6053 monitor_unload(pui);
6055 /* invalidate cached PORT_INFO_2W */
6059 TRACE("returning %d with %u\n", res, GetLastError());
6063 /******************************************************************************
6064 * AddPortExA (WINSPOOL.@)
6069 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
6071 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
6072 lpBuffer, debugstr_a(lpMonitorName));
6076 /******************************************************************************
6077 * AddPortExW (WINSPOOL.@)
6079 * Add a Port for a specific Monitor, without presenting a user interface
6082 * hMonitor [I] Handle from InitializePrintMonitor2()
6083 * pName [I] Servername or NULL (local Computer)
6084 * Level [I] Structure-Level (1 or 2) for lpBuffer
6085 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6086 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
6096 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
6098 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
6099 lpBuffer, debugstr_w(lpMonitorName));
6103 /******************************************************************************
6104 * AddPrinterConnectionA (WINSPOOL.@)
6106 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6108 FIXME("%s\n", debugstr_a(pName));
6112 /******************************************************************************
6113 * AddPrinterConnectionW (WINSPOOL.@)
6115 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6117 FIXME("%s\n", debugstr_w(pName));
6121 /******************************************************************************
6122 * AddPrinterDriverExW (WINSPOOL.@)
6124 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6125 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6127 FIXME("%s %d %p %d\n", debugstr_w(pName),
6128 Level, pDriverInfo, dwFileCopyFlags);
6129 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6133 /******************************************************************************
6134 * AddPrinterDriverExA (WINSPOOL.@)
6136 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6137 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6139 FIXME("%s %d %p %d\n", debugstr_a(pName),
6140 Level, pDriverInfo, dwFileCopyFlags);
6141 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6145 /******************************************************************************
6146 * ConfigurePortA (WINSPOOL.@)
6148 * See ConfigurePortW.
6151 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6153 LPWSTR nameW = NULL;
6154 LPWSTR portW = NULL;
6158 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6160 /* convert servername to unicode */
6162 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6163 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6164 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6167 /* convert portname to unicode */
6169 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6170 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6171 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6174 res = ConfigurePortW(nameW, hWnd, portW);
6175 HeapFree(GetProcessHeap(), 0, nameW);
6176 HeapFree(GetProcessHeap(), 0, portW);
6180 /******************************************************************************
6181 * ConfigurePortW (WINSPOOL.@)
6183 * Display the Configuration-Dialog for a specific Port
6186 * pName [I] Servername or NULL (local Computer)
6187 * hWnd [I] Handle to parent Window for the Dialog-Box
6188 * pPortName [I] Name of the Port, that should be configured
6195 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6201 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6203 if (pName && pName[0]) {
6204 SetLastError(ERROR_INVALID_PARAMETER);
6209 SetLastError(RPC_X_NULL_REF_POINTER);
6213 /* an empty Portname is Invalid, but can popup a Dialog */
6214 if (!pPortName[0]) {
6215 SetLastError(ERROR_NOT_SUPPORTED);
6219 pm = monitor_load_by_port(pPortName);
6220 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6221 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6222 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6223 TRACE("got %d with %u\n", res, GetLastError());
6227 pui = monitor_loadui(pm);
6228 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6229 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6230 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6231 TRACE("got %d with %u\n", res, GetLastError());
6235 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6236 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6238 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6239 SetLastError(ERROR_NOT_SUPPORTED);
6242 monitor_unload(pui);
6246 TRACE("returning %d with %u\n", res, GetLastError());
6250 /******************************************************************************
6251 * ConnectToPrinterDlg (WINSPOOL.@)
6253 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6255 FIXME("%p %x\n", hWnd, Flags);
6259 /******************************************************************************
6260 * DeletePrinterConnectionA (WINSPOOL.@)
6262 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6264 FIXME("%s\n", debugstr_a(pName));
6268 /******************************************************************************
6269 * DeletePrinterConnectionW (WINSPOOL.@)
6271 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6273 FIXME("%s\n", debugstr_w(pName));
6277 /******************************************************************************
6278 * DeletePrinterDriverExW (WINSPOOL.@)
6280 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6281 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6286 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6287 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6289 if(pName && pName[0])
6291 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6292 SetLastError(ERROR_INVALID_PARAMETER);
6298 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6299 SetLastError(ERROR_INVALID_PARAMETER);
6303 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6307 ERR("Can't open drivers key\n");
6311 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6314 RegCloseKey(hkey_drivers);
6319 /******************************************************************************
6320 * DeletePrinterDriverExA (WINSPOOL.@)
6322 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6323 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6325 UNICODE_STRING NameW, EnvW, DriverW;
6328 asciitounicode(&NameW, pName);
6329 asciitounicode(&EnvW, pEnvironment);
6330 asciitounicode(&DriverW, pDriverName);
6332 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6334 RtlFreeUnicodeString(&DriverW);
6335 RtlFreeUnicodeString(&EnvW);
6336 RtlFreeUnicodeString(&NameW);
6341 /******************************************************************************
6342 * DeletePrinterDataExW (WINSPOOL.@)
6344 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6347 FIXME("%p %s %s\n", hPrinter,
6348 debugstr_w(pKeyName), debugstr_w(pValueName));
6349 return ERROR_INVALID_PARAMETER;
6352 /******************************************************************************
6353 * DeletePrinterDataExA (WINSPOOL.@)
6355 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6358 FIXME("%p %s %s\n", hPrinter,
6359 debugstr_a(pKeyName), debugstr_a(pValueName));
6360 return ERROR_INVALID_PARAMETER;
6363 /******************************************************************************
6364 * DeletePrintProcessorA (WINSPOOL.@)
6366 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6368 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6369 debugstr_a(pPrintProcessorName));
6373 /******************************************************************************
6374 * DeletePrintProcessorW (WINSPOOL.@)
6376 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6378 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6379 debugstr_w(pPrintProcessorName));
6383 /******************************************************************************
6384 * DeletePrintProvidorA (WINSPOOL.@)
6386 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6388 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6389 debugstr_a(pPrintProviderName));
6393 /******************************************************************************
6394 * DeletePrintProvidorW (WINSPOOL.@)
6396 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6398 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6399 debugstr_w(pPrintProviderName));
6403 /******************************************************************************
6404 * EnumFormsA (WINSPOOL.@)
6406 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6407 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6409 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6410 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6414 /******************************************************************************
6415 * EnumFormsW (WINSPOOL.@)
6417 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6418 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6420 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6421 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6425 /*****************************************************************************
6426 * EnumMonitorsA [WINSPOOL.@]
6428 * See EnumMonitorsW.
6431 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6432 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6435 LPBYTE bufferW = NULL;
6436 LPWSTR nameW = NULL;
6438 DWORD numentries = 0;
6441 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6442 cbBuf, pcbNeeded, pcReturned);
6444 /* convert servername to unicode */
6446 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6447 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6448 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6450 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6451 needed = cbBuf * sizeof(WCHAR);
6452 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6453 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6455 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6456 if (pcbNeeded) needed = *pcbNeeded;
6457 /* HeapReAlloc return NULL, when bufferW was NULL */
6458 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6459 HeapAlloc(GetProcessHeap(), 0, needed);
6461 /* Try again with the large Buffer */
6462 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6464 numentries = pcReturned ? *pcReturned : 0;
6467 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6468 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6471 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6472 DWORD entrysize = 0;
6475 LPMONITOR_INFO_2W mi2w;
6476 LPMONITOR_INFO_2A mi2a;
6478 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6479 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6481 /* First pass: calculate the size for all Entries */
6482 mi2w = (LPMONITOR_INFO_2W) bufferW;
6483 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6485 while (index < numentries) {
6487 needed += entrysize; /* MONITOR_INFO_?A */
6488 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6490 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6491 NULL, 0, NULL, NULL);
6493 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6494 NULL, 0, NULL, NULL);
6495 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6496 NULL, 0, NULL, NULL);
6498 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6499 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6500 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6503 /* check for errors and quit on failure */
6504 if (cbBuf < needed) {
6505 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6509 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6510 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6511 cbBuf -= len ; /* free Bytes in the user-Buffer */
6512 mi2w = (LPMONITOR_INFO_2W) bufferW;
6513 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6515 /* Second Pass: Fill the User Buffer (if we have one) */
6516 while ((index < numentries) && pMonitors) {
6518 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6520 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6521 ptr, cbBuf , NULL, NULL);
6525 mi2a->pEnvironment = ptr;
6526 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6527 ptr, cbBuf, NULL, NULL);
6531 mi2a->pDLLName = ptr;
6532 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6533 ptr, cbBuf, NULL, NULL);
6537 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6538 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6539 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6543 if (pcbNeeded) *pcbNeeded = needed;
6544 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6546 HeapFree(GetProcessHeap(), 0, nameW);
6547 HeapFree(GetProcessHeap(), 0, bufferW);
6549 TRACE("returning %d with %d (%d byte for %d entries)\n",
6550 (res), GetLastError(), needed, numentries);
6556 /*****************************************************************************
6557 * EnumMonitorsW [WINSPOOL.@]
6559 * Enumerate available Port-Monitors
6562 * pName [I] Servername or NULL (local Computer)
6563 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6564 * pMonitors [O] PTR to Buffer that receives the Result
6565 * cbBuf [I] Size of Buffer at pMonitors
6566 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6567 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6571 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6574 * Windows reads the Registry once and cache the Results.
6576 *| Language-Monitors are also installed in the same Registry-Location but
6577 *| they are filtered in Windows (not returned by EnumMonitors).
6578 *| We do no filtering to simplify our Code.
6581 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6582 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6585 DWORD numentries = 0;
6588 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6589 cbBuf, pcbNeeded, pcReturned);
6591 if (pName && (lstrlenW(pName))) {
6592 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6593 SetLastError(ERROR_ACCESS_DENIED);
6597 /* Level is not checked in win9x */
6598 if (!Level || (Level > 2)) {
6599 WARN("level (%d) is ignored in win9x\n", Level);
6600 SetLastError(ERROR_INVALID_LEVEL);
6604 SetLastError(RPC_X_NULL_REF_POINTER);
6608 /* Scan all Monitor-Keys */
6610 needed = get_local_monitors(Level, NULL, 0, &numentries);
6612 /* we calculated the needed buffersize. now do the error-checks */
6613 if (cbBuf < needed) {
6614 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6617 else if (!pMonitors || !pcReturned) {
6618 SetLastError(RPC_X_NULL_REF_POINTER);
6622 /* fill the Buffer with the Monitor-Keys */
6623 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6627 if (pcbNeeded) *pcbNeeded = needed;
6628 if (pcReturned) *pcReturned = numentries;
6630 TRACE("returning %d with %d (%d byte for %d entries)\n",
6631 res, GetLastError(), needed, numentries);
6636 /******************************************************************************
6637 * XcvDataW (WINSPOOL.@)
6639 * Execute commands in the Printmonitor DLL
6642 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6643 * pszDataName [i] Name of the command to execute
6644 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6645 * cbInputData [i] Size in Bytes of Buffer at pInputData
6646 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6647 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6648 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6649 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6656 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6657 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6659 * Minimal List of commands, that a Printmonitor DLL should support:
6661 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6662 *| "AddPort" : Add a Port
6663 *| "DeletePort": Delete a Port
6665 * Many Printmonitors support additional commands. Examples for localspl.dll:
6666 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6667 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6670 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6671 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6672 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6674 opened_printer_t *printer;
6676 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6677 pInputData, cbInputData, pOutputData,
6678 cbOutputData, pcbOutputNeeded, pdwStatus);
6680 printer = get_opened_printer(hXcv);
6681 if (!printer || (!printer->hXcv)) {
6682 SetLastError(ERROR_INVALID_HANDLE);
6686 if (!pcbOutputNeeded) {
6687 SetLastError(ERROR_INVALID_PARAMETER);
6691 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6692 SetLastError(RPC_X_NULL_REF_POINTER);
6696 *pcbOutputNeeded = 0;
6698 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6699 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6704 /*****************************************************************************
6705 * EnumPrinterDataA [WINSPOOL.@]
6708 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6709 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6710 DWORD cbData, LPDWORD pcbData )
6712 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6713 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6714 return ERROR_NO_MORE_ITEMS;
6717 /*****************************************************************************
6718 * EnumPrinterDataW [WINSPOOL.@]
6721 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6722 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6723 DWORD cbData, LPDWORD pcbData )
6725 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6726 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6727 return ERROR_NO_MORE_ITEMS;
6730 /*****************************************************************************
6731 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6734 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6735 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6736 LPDWORD pcbNeeded, LPDWORD pcReturned)
6738 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6739 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6740 pcbNeeded, pcReturned);
6744 /*****************************************************************************
6745 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6748 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6749 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6750 LPDWORD pcbNeeded, LPDWORD pcReturned)
6752 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6753 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6754 pcbNeeded, pcReturned);
6758 /*****************************************************************************
6759 * EnumPrintProcessorsA [WINSPOOL.@]
6762 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6763 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6765 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6766 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6770 /*****************************************************************************
6771 * EnumPrintProcessorsW [WINSPOOL.@]
6774 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6775 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6777 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6778 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6779 cbBuf, pcbNeeded, pcbReturned);
6783 /*****************************************************************************
6784 * ExtDeviceMode [WINSPOOL.@]
6787 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6788 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6791 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6792 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6793 debugstr_a(pProfile), fMode);
6797 /*****************************************************************************
6798 * FindClosePrinterChangeNotification [WINSPOOL.@]
6801 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6803 FIXME("Stub: %p\n", hChange);
6807 /*****************************************************************************
6808 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6811 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6812 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6814 FIXME("Stub: %p %x %x %p\n",
6815 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6816 return INVALID_HANDLE_VALUE;
6819 /*****************************************************************************
6820 * FindNextPrinterChangeNotification [WINSPOOL.@]
6823 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6824 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6826 FIXME("Stub: %p %p %p %p\n",
6827 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6831 /*****************************************************************************
6832 * FreePrinterNotifyInfo [WINSPOOL.@]
6835 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6837 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6841 /*****************************************************************************
6844 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6845 * ansi depending on the unicode parameter.
6847 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6857 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6860 memcpy(ptr, str, *size);
6867 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6870 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6877 /*****************************************************************************
6880 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6881 LPDWORD pcbNeeded, BOOL unicode)
6883 DWORD size, left = cbBuf;
6884 BOOL space = (cbBuf > 0);
6891 ji1->JobId = job->job_id;
6894 string_to_buf(job->document_title, ptr, left, &size, unicode);
6895 if(space && size <= left)
6897 ji1->pDocument = (LPWSTR)ptr;
6908 /*****************************************************************************
6911 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6912 LPDWORD pcbNeeded, BOOL unicode)
6914 DWORD size, left = cbBuf;
6915 BOOL space = (cbBuf > 0);
6922 ji2->JobId = job->job_id;
6925 string_to_buf(job->document_title, ptr, left, &size, unicode);
6926 if(space && size <= left)
6928 ji2->pDocument = (LPWSTR)ptr;
6939 /*****************************************************************************
6942 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6943 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6946 DWORD needed = 0, size;
6950 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6952 EnterCriticalSection(&printer_handles_cs);
6953 job = get_job(hPrinter, JobId);
6960 size = sizeof(JOB_INFO_1W);
6965 memset(pJob, 0, size);
6969 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6974 size = sizeof(JOB_INFO_2W);
6979 memset(pJob, 0, size);
6983 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6988 size = sizeof(JOB_INFO_3);
6992 memset(pJob, 0, size);
7001 SetLastError(ERROR_INVALID_LEVEL);
7005 *pcbNeeded = needed;
7007 LeaveCriticalSection(&printer_handles_cs);
7011 /*****************************************************************************
7012 * GetJobA [WINSPOOL.@]
7015 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7016 DWORD cbBuf, LPDWORD pcbNeeded)
7018 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7021 /*****************************************************************************
7022 * GetJobW [WINSPOOL.@]
7025 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7026 DWORD cbBuf, LPDWORD pcbNeeded)
7028 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7031 /*****************************************************************************
7034 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7036 char *unixname, *queue, *cmd;
7037 char fmt[] = "lpr -P%s %s";
7040 if(!(unixname = wine_get_unix_file_name(filename)))
7043 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7044 queue = HeapAlloc(GetProcessHeap(), 0, len);
7045 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7047 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7048 sprintf(cmd, fmt, queue, unixname);
7050 TRACE("printing with: %s\n", cmd);
7053 HeapFree(GetProcessHeap(), 0, cmd);
7054 HeapFree(GetProcessHeap(), 0, queue);
7055 HeapFree(GetProcessHeap(), 0, unixname);
7059 /*****************************************************************************
7062 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7064 #if HAVE_CUPS_CUPS_H
7067 char *unixname, *queue, *doc_titleA;
7071 if(!(unixname = wine_get_unix_file_name(filename)))
7074 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7075 queue = HeapAlloc(GetProcessHeap(), 0, len);
7076 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7078 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7079 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7080 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7082 TRACE("printing via cups\n");
7083 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7084 HeapFree(GetProcessHeap(), 0, doc_titleA);
7085 HeapFree(GetProcessHeap(), 0, queue);
7086 HeapFree(GetProcessHeap(), 0, unixname);
7092 return schedule_lpr(printer_name, filename);
7096 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7103 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7107 if(HIWORD(wparam) == BN_CLICKED)
7109 if(LOWORD(wparam) == IDOK)
7112 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7115 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7116 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7118 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7120 WCHAR caption[200], message[200];
7123 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7124 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7125 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7126 if(mb_ret == IDCANCEL)
7128 HeapFree(GetProcessHeap(), 0, filename);
7132 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7133 if(hf == INVALID_HANDLE_VALUE)
7135 WCHAR caption[200], message[200];
7137 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7138 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7139 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7140 HeapFree(GetProcessHeap(), 0, filename);
7144 DeleteFileW(filename);
7145 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7147 EndDialog(hwnd, IDOK);
7150 if(LOWORD(wparam) == IDCANCEL)
7152 EndDialog(hwnd, IDCANCEL);
7161 /*****************************************************************************
7164 static BOOL get_filename(LPWSTR *filename)
7166 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7167 file_dlg_proc, (LPARAM)filename) == IDOK;
7170 /*****************************************************************************
7173 static BOOL schedule_file(LPCWSTR filename)
7175 LPWSTR output = NULL;
7177 if(get_filename(&output))
7179 TRACE("copy to %s\n", debugstr_w(output));
7180 CopyFileW(filename, output, FALSE);
7181 HeapFree(GetProcessHeap(), 0, output);
7187 /*****************************************************************************
7190 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7193 char *unixname, *cmdA;
7195 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7199 if(!(unixname = wine_get_unix_file_name(filename)))
7202 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7203 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7204 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7206 TRACE("printing with: %s\n", cmdA);
7208 if((file_fd = open(unixname, O_RDONLY)) == -1)
7213 ERR("pipe() failed!\n");
7223 /* reset signals that we previously set to SIG_IGN */
7224 signal(SIGPIPE, SIG_DFL);
7225 signal(SIGCHLD, SIG_DFL);
7227 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7231 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7232 write(fds[1], buf, no_read);
7237 if(file_fd != -1) close(file_fd);
7238 if(fds[0] != -1) close(fds[0]);
7239 if(fds[1] != -1) close(fds[1]);
7241 HeapFree(GetProcessHeap(), 0, cmdA);
7242 HeapFree(GetProcessHeap(), 0, unixname);
7249 /*****************************************************************************
7252 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7254 int in_fd, out_fd, no_read;
7257 char *unixname, *outputA;
7260 if(!(unixname = wine_get_unix_file_name(filename)))
7263 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7264 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7265 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7267 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7268 in_fd = open(unixname, O_RDONLY);
7269 if(out_fd == -1 || in_fd == -1)
7272 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7273 write(out_fd, buf, no_read);
7277 if(in_fd != -1) close(in_fd);
7278 if(out_fd != -1) close(out_fd);
7279 HeapFree(GetProcessHeap(), 0, outputA);
7280 HeapFree(GetProcessHeap(), 0, unixname);
7284 /*****************************************************************************
7285 * ScheduleJob [WINSPOOL.@]
7288 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7290 opened_printer_t *printer;
7292 struct list *cursor, *cursor2;
7294 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7295 EnterCriticalSection(&printer_handles_cs);
7296 printer = get_opened_printer(hPrinter);
7300 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7302 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7305 if(job->job_id != dwJobID) continue;
7307 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7308 if(hf != INVALID_HANDLE_VALUE)
7310 PRINTER_INFO_5W *pi5;
7314 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7315 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7317 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7318 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7319 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7320 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7321 debugstr_w(pi5->pPortName));
7325 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7326 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7328 DWORD type, count = sizeof(output);
7329 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7332 if(output[0] == '|')
7334 schedule_pipe(output + 1, job->filename);
7338 schedule_unixfile(output, job->filename);
7340 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7342 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7344 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7346 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7348 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7350 schedule_file(job->filename);
7354 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7356 HeapFree(GetProcessHeap(), 0, pi5);
7358 DeleteFileW(job->filename);
7360 list_remove(cursor);
7361 HeapFree(GetProcessHeap(), 0, job->document_title);
7362 HeapFree(GetProcessHeap(), 0, job->filename);
7363 HeapFree(GetProcessHeap(), 0, job);
7368 LeaveCriticalSection(&printer_handles_cs);
7372 /*****************************************************************************
7373 * StartDocDlgA [WINSPOOL.@]
7375 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7377 UNICODE_STRING usBuffer;
7380 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7383 docW.cbSize = sizeof(docW);
7384 if (doc->lpszDocName)
7386 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7387 if (!(docW.lpszDocName = docnameW)) return NULL;
7389 if (doc->lpszOutput)
7391 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7392 if (!(docW.lpszOutput = outputW)) return NULL;
7394 if (doc->lpszDatatype)
7396 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7397 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7399 docW.fwType = doc->fwType;
7401 retW = StartDocDlgW(hPrinter, &docW);
7405 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7406 ret = HeapAlloc(GetProcessHeap(), 0, len);
7407 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7408 HeapFree(GetProcessHeap(), 0, retW);
7411 HeapFree(GetProcessHeap(), 0, datatypeW);
7412 HeapFree(GetProcessHeap(), 0, outputW);
7413 HeapFree(GetProcessHeap(), 0, docnameW);
7418 /*****************************************************************************
7419 * StartDocDlgW [WINSPOOL.@]
7421 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7422 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7423 * port is "FILE:". Also returns the full path if passed a relative path.
7425 * The caller should free the returned string from the process heap.
7427 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7432 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7434 PRINTER_INFO_5W *pi5;
7435 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7436 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7438 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7439 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7440 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7442 HeapFree(GetProcessHeap(), 0, pi5);
7445 HeapFree(GetProcessHeap(), 0, pi5);
7448 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7452 if (get_filename(&name))
7454 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7456 HeapFree(GetProcessHeap(), 0, name);
7459 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7460 GetFullPathNameW(name, len, ret, NULL);
7461 HeapFree(GetProcessHeap(), 0, name);
7466 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7469 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7470 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7472 attr = GetFileAttributesW(ret);
7473 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7475 HeapFree(GetProcessHeap(), 0, ret);