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(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 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 )) {
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 /* Check for [ppd] section in config file before parsing /etc/printcap */
1656 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
1657 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
1658 &hkey) == ERROR_SUCCESS) {
1660 PRINTCAP_LoadPrinters();
1664 /* Now enumerate the list again and delete any printers that a still tagged */
1665 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1667 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1668 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1669 for(i = 0; i < num; i++) {
1670 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1671 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1672 BOOL delete_driver = FALSE;
1673 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1674 DWORD dw, type, size = sizeof(dw);
1675 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1676 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1677 DeletePrinter(hprn);
1678 delete_driver = TRUE;
1684 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1689 HeapFree(GetProcessHeap(), 0, pi);
1696 /******************************************************************
1699 * Get the pointer to the specified job.
1700 * Should hold the printer_handles_cs before calling.
1702 static job_t *get_job(HANDLE hprn, DWORD JobId)
1704 opened_printer_t *printer = get_opened_printer(hprn);
1707 if(!printer) return NULL;
1708 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1710 if(job->job_id == JobId)
1716 /***********************************************************
1719 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1722 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1725 Formname = (dmA->dmSize > off_formname);
1726 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1727 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1728 dmW->dmDeviceName, CCHDEVICENAME);
1730 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1731 dmA->dmSize - CCHDEVICENAME);
1733 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1734 off_formname - CCHDEVICENAME);
1735 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1736 dmW->dmFormName, CCHFORMNAME);
1737 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1738 (off_formname + CCHFORMNAME));
1741 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1742 dmA->dmDriverExtra);
1746 /***********************************************************
1748 * Creates an ascii copy of supplied devmode on heap
1750 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1755 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1757 if(!dmW) return NULL;
1758 Formname = (dmW->dmSize > off_formname);
1759 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1760 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1761 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1762 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1764 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1765 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1767 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1768 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1769 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1770 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1771 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1772 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1775 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1776 dmW->dmDriverExtra);
1780 /***********************************************************
1781 * PRINTER_INFO_2AtoW
1782 * Creates a unicode copy of PRINTER_INFO_2A on heap
1784 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1786 LPPRINTER_INFO_2W piW;
1787 UNICODE_STRING usBuffer;
1789 if(!piA) return NULL;
1790 piW = HeapAlloc(heap, 0, sizeof(*piW));
1791 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1793 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1794 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1795 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1796 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1797 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1798 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1799 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1800 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1801 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1802 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1803 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1804 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1808 /***********************************************************
1809 * FREE_PRINTER_INFO_2W
1810 * Free PRINTER_INFO_2W and all strings
1812 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1816 HeapFree(heap,0,piW->pServerName);
1817 HeapFree(heap,0,piW->pPrinterName);
1818 HeapFree(heap,0,piW->pShareName);
1819 HeapFree(heap,0,piW->pPortName);
1820 HeapFree(heap,0,piW->pDriverName);
1821 HeapFree(heap,0,piW->pComment);
1822 HeapFree(heap,0,piW->pLocation);
1823 HeapFree(heap,0,piW->pDevMode);
1824 HeapFree(heap,0,piW->pSepFile);
1825 HeapFree(heap,0,piW->pPrintProcessor);
1826 HeapFree(heap,0,piW->pDatatype);
1827 HeapFree(heap,0,piW->pParameters);
1828 HeapFree(heap,0,piW);
1832 /******************************************************************
1833 * DeviceCapabilities [WINSPOOL.@]
1834 * DeviceCapabilitiesA [WINSPOOL.@]
1837 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1838 LPSTR pOutput, LPDEVMODEA lpdm)
1842 if (!GDI_CallDeviceCapabilities16)
1844 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1846 if (!GDI_CallDeviceCapabilities16) return -1;
1848 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1850 /* If DC_PAPERSIZE map POINT16s to POINTs */
1851 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1852 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1853 POINT *pt = (POINT *)pOutput;
1855 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1856 for(i = 0; i < ret; i++, pt++)
1861 HeapFree( GetProcessHeap(), 0, tmp );
1867 /*****************************************************************************
1868 * DeviceCapabilitiesW [WINSPOOL.@]
1870 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1873 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1874 WORD fwCapability, LPWSTR pOutput,
1875 const DEVMODEW *pDevMode)
1877 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1878 LPSTR pDeviceA = strdupWtoA(pDevice);
1879 LPSTR pPortA = strdupWtoA(pPort);
1882 if(pOutput && (fwCapability == DC_BINNAMES ||
1883 fwCapability == DC_FILEDEPENDENCIES ||
1884 fwCapability == DC_PAPERNAMES)) {
1885 /* These need A -> W translation */
1888 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1892 switch(fwCapability) {
1897 case DC_FILEDEPENDENCIES:
1901 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1902 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1904 for(i = 0; i < ret; i++)
1905 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1906 pOutput + (i * size), size);
1907 HeapFree(GetProcessHeap(), 0, pOutputA);
1909 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1910 (LPSTR)pOutput, dmA);
1912 HeapFree(GetProcessHeap(),0,pPortA);
1913 HeapFree(GetProcessHeap(),0,pDeviceA);
1914 HeapFree(GetProcessHeap(),0,dmA);
1918 /******************************************************************
1919 * DocumentPropertiesA [WINSPOOL.@]
1921 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1923 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1924 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1925 LPDEVMODEA pDevModeInput,DWORD fMode )
1927 LPSTR lpName = pDeviceName;
1928 static CHAR port[] = "LPT1:";
1931 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1932 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1936 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1938 ERR("no name from hPrinter?\n");
1939 SetLastError(ERROR_INVALID_HANDLE);
1942 lpName = strdupWtoA(lpNameW);
1945 if (!GDI_CallExtDeviceMode16)
1947 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1949 if (!GDI_CallExtDeviceMode16) {
1950 ERR("No CallExtDeviceMode16?\n");
1954 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1955 pDevModeInput, NULL, fMode);
1958 HeapFree(GetProcessHeap(),0,lpName);
1963 /*****************************************************************************
1964 * DocumentPropertiesW (WINSPOOL.@)
1966 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1968 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1970 LPDEVMODEW pDevModeOutput,
1971 LPDEVMODEW pDevModeInput, DWORD fMode)
1974 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1975 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1976 LPDEVMODEA pDevModeOutputA = NULL;
1979 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1980 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1982 if(pDevModeOutput) {
1983 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1984 if(ret < 0) return ret;
1985 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1987 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1988 pDevModeInputA, fMode);
1989 if(pDevModeOutput) {
1990 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1991 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1993 if(fMode == 0 && ret > 0)
1994 ret += (CCHDEVICENAME + CCHFORMNAME);
1995 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1996 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2000 /******************************************************************
2001 * OpenPrinterA [WINSPOOL.@]
2006 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2007 LPPRINTER_DEFAULTSA pDefault)
2009 UNICODE_STRING lpPrinterNameW;
2010 UNICODE_STRING usBuffer;
2011 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2012 PWSTR pwstrPrinterNameW;
2015 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2018 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2019 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2020 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2021 pDefaultW = &DefaultW;
2023 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2025 RtlFreeUnicodeString(&usBuffer);
2026 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2028 RtlFreeUnicodeString(&lpPrinterNameW);
2032 /******************************************************************
2033 * OpenPrinterW [WINSPOOL.@]
2035 * Open a Printer / Printserver or a Printer-Object
2038 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2039 * phPrinter [O] The resulting Handle is stored here
2040 * pDefault [I] PTR to Default Printer Settings or NULL
2047 * lpPrinterName is one of:
2048 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2049 *| Printer: "PrinterName"
2050 *| Printer-Object: "PrinterName,Job xxx"
2051 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2052 *| XcvPort: "Servername,XcvPort PortName"
2055 *| Printer-Object not supported
2056 *| pDefaults is ignored
2059 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2062 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2064 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2065 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2069 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2070 SetLastError(ERROR_INVALID_PARAMETER);
2074 /* Get the unique handle of the printer or Printserver */
2075 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2076 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2077 return (*phPrinter != 0);
2080 /******************************************************************
2081 * AddMonitorA [WINSPOOL.@]
2086 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2088 LPWSTR nameW = NULL;
2091 LPMONITOR_INFO_2A mi2a;
2092 MONITOR_INFO_2W mi2w;
2094 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2095 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2096 mi2a ? debugstr_a(mi2a->pName) : NULL,
2097 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2098 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2101 SetLastError(ERROR_INVALID_LEVEL);
2105 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2111 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2112 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2113 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2116 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2118 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2119 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2120 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2122 if (mi2a->pEnvironment) {
2123 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2124 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2125 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2127 if (mi2a->pDLLName) {
2128 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2129 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2130 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2133 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2135 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2136 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2137 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2139 HeapFree(GetProcessHeap(), 0, nameW);
2143 /******************************************************************************
2144 * AddMonitorW [WINSPOOL.@]
2146 * Install a Printmonitor
2149 * pName [I] Servername or NULL (local Computer)
2150 * Level [I] Structure-Level (Must be 2)
2151 * pMonitors [I] PTR to MONITOR_INFO_2
2158 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2161 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2163 monitor_t * pm = NULL;
2164 LPMONITOR_INFO_2W mi2w;
2170 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2171 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2172 mi2w ? debugstr_w(mi2w->pName) : NULL,
2173 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2174 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2177 SetLastError(ERROR_INVALID_LEVEL);
2181 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2186 if (pName && (pName[0])) {
2187 FIXME("for server %s not implemented\n", debugstr_w(pName));
2188 SetLastError(ERROR_ACCESS_DENIED);
2193 if (!mi2w->pName || (! mi2w->pName[0])) {
2194 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2195 SetLastError(ERROR_INVALID_PARAMETER);
2198 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2199 WARN("Environment %s requested (we support only %s)\n",
2200 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2201 SetLastError(ERROR_INVALID_ENVIRONMENT);
2205 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2206 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2207 SetLastError(ERROR_INVALID_PARAMETER);
2211 /* Load and initialize the monitor. SetLastError() is called on failure */
2212 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2217 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2218 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2222 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2223 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2224 &disposition) == ERROR_SUCCESS) {
2226 /* Some installers set options for the port before calling AddMonitor.
2227 We query the "Driver" entry to verify that the monitor is installed,
2228 before we return an error.
2229 When a user installs two print monitors at the same time with the
2230 same name but with a different driver DLL and a task switch comes
2231 between RegQueryValueExW and RegSetValueExW, a race condition
2232 is possible but silently ignored. */
2236 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2237 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2238 &namesize) == ERROR_SUCCESS)) {
2239 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2240 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2241 9x: ERROR_ALREADY_EXISTS (183) */
2242 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2247 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2248 res = (RegSetValueExW(hentry, DriverW, 0,
2249 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2251 RegCloseKey(hentry);
2258 /******************************************************************
2259 * DeletePrinterDriverA [WINSPOOL.@]
2262 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2264 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2267 /******************************************************************
2268 * DeletePrinterDriverW [WINSPOOL.@]
2271 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2273 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2276 /******************************************************************
2277 * DeleteMonitorA [WINSPOOL.@]
2279 * See DeleteMonitorW.
2282 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2284 LPWSTR nameW = NULL;
2285 LPWSTR EnvironmentW = NULL;
2286 LPWSTR MonitorNameW = NULL;
2291 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2292 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2293 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2297 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2298 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2299 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2302 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2303 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2304 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2307 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2309 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2310 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2311 HeapFree(GetProcessHeap(), 0, nameW);
2315 /******************************************************************
2316 * DeleteMonitorW [WINSPOOL.@]
2318 * Delete a specific Printmonitor from a Printing-Environment
2321 * pName [I] Servername or NULL (local Computer)
2322 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2323 * pMonitorName [I] Name of the Monitor, that should be deleted
2330 * pEnvironment is ignored in Windows for the local Computer.
2334 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2338 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2339 debugstr_w(pMonitorName));
2341 if (pName && (pName[0])) {
2342 FIXME("for server %s not implemented\n", debugstr_w(pName));
2343 SetLastError(ERROR_ACCESS_DENIED);
2347 /* pEnvironment is ignored in Windows for the local Computer */
2349 if (!pMonitorName || !pMonitorName[0]) {
2350 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2351 SetLastError(ERROR_INVALID_PARAMETER);
2355 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2356 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2360 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2361 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2362 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2367 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2370 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2371 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2375 /******************************************************************
2376 * DeletePortA [WINSPOOL.@]
2381 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2383 LPWSTR nameW = NULL;
2384 LPWSTR portW = NULL;
2388 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2390 /* convert servername to unicode */
2392 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2393 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2394 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2397 /* convert portname to unicode */
2399 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2400 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2401 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2404 res = DeletePortW(nameW, hWnd, portW);
2405 HeapFree(GetProcessHeap(), 0, nameW);
2406 HeapFree(GetProcessHeap(), 0, portW);
2410 /******************************************************************
2411 * DeletePortW [WINSPOOL.@]
2413 * Delete a specific Port
2416 * pName [I] Servername or NULL (local Computer)
2417 * hWnd [I] Handle to parent Window for the Dialog-Box
2418 * pPortName [I] Name of the Port, that should be deleted
2425 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2431 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2433 if (pName && pName[0]) {
2434 SetLastError(ERROR_INVALID_PARAMETER);
2439 SetLastError(RPC_X_NULL_REF_POINTER);
2443 /* an empty Portname is Invalid */
2444 if (!pPortName[0]) {
2445 SetLastError(ERROR_NOT_SUPPORTED);
2449 pm = monitor_load_by_port(pPortName);
2450 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2451 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2452 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2453 TRACE("got %d with %u\n", res, GetLastError());
2457 pui = monitor_loadui(pm);
2458 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2459 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2460 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2461 TRACE("got %d with %u\n", res, GetLastError());
2465 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2466 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2468 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2469 SetLastError(ERROR_NOT_SUPPORTED);
2472 monitor_unload(pui);
2474 /* always invalidate cached PORT_INFO_2W */
2479 TRACE("returning %d with %u\n", res, GetLastError());
2483 /******************************************************************************
2484 * SetPrinterW [WINSPOOL.@]
2486 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2488 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2489 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2493 /******************************************************************************
2494 * WritePrinter [WINSPOOL.@]
2496 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2498 opened_printer_t *printer;
2501 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2503 EnterCriticalSection(&printer_handles_cs);
2504 printer = get_opened_printer(hPrinter);
2507 SetLastError(ERROR_INVALID_HANDLE);
2513 SetLastError(ERROR_SPL_NO_STARTDOC);
2517 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2519 LeaveCriticalSection(&printer_handles_cs);
2523 /*****************************************************************************
2524 * AddFormA [WINSPOOL.@]
2526 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2528 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2532 /*****************************************************************************
2533 * AddFormW [WINSPOOL.@]
2535 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2537 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2541 /*****************************************************************************
2542 * AddJobA [WINSPOOL.@]
2544 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2547 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2551 SetLastError(ERROR_INVALID_LEVEL);
2555 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2558 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2559 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2560 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2561 if(*pcbNeeded > cbBuf) {
2562 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2565 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2566 addjobA->JobId = addjobW->JobId;
2567 addjobA->Path = (char *)(addjobA + 1);
2568 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2574 /*****************************************************************************
2575 * AddJobW [WINSPOOL.@]
2577 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2579 opened_printer_t *printer;
2582 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2583 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2584 WCHAR path[MAX_PATH], filename[MAX_PATH];
2586 ADDJOB_INFO_1W *addjob;
2588 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2590 EnterCriticalSection(&printer_handles_cs);
2592 printer = get_opened_printer(hPrinter);
2595 SetLastError(ERROR_INVALID_HANDLE);
2600 SetLastError(ERROR_INVALID_LEVEL);
2604 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2608 job->job_id = InterlockedIncrement(&next_job_id);
2610 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2611 if(path[len - 1] != '\\')
2613 memcpy(path + len, spool_path, sizeof(spool_path));
2614 sprintfW(filename, fmtW, path, job->job_id);
2616 len = strlenW(filename);
2617 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2618 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2619 job->document_title = strdupW(default_doc_title);
2620 list_add_tail(&printer->queue->jobs, &job->entry);
2622 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2623 if(*pcbNeeded <= cbBuf) {
2624 addjob = (ADDJOB_INFO_1W*)pData;
2625 addjob->JobId = job->job_id;
2626 addjob->Path = (WCHAR *)(addjob + 1);
2627 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2630 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2633 LeaveCriticalSection(&printer_handles_cs);
2637 /*****************************************************************************
2638 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2640 * Return the PATH for the Print-Processors
2642 * See GetPrintProcessorDirectoryW.
2646 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2647 DWORD level, LPBYTE Info,
2648 DWORD cbBuf, LPDWORD pcbNeeded)
2650 LPWSTR serverW = NULL;
2655 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2656 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2660 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2661 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2662 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2666 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2667 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2668 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2671 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2672 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2674 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2677 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2678 cbBuf, NULL, NULL) > 0;
2681 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2682 HeapFree(GetProcessHeap(), 0, envW);
2683 HeapFree(GetProcessHeap(), 0, serverW);
2687 /*****************************************************************************
2688 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2690 * Return the PATH for the Print-Processors
2693 * server [I] Servername (NT only) or NULL (local Computer)
2694 * env [I] Printing-Environment (see below) or NULL (Default)
2695 * level [I] Structure-Level (must be 1)
2696 * Info [O] PTR to Buffer that receives the Result
2697 * cbBuf [I] Size of Buffer at "Info"
2698 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2699 * required for the Buffer at "Info"
2702 * Success: TRUE and in pcbNeeded the Bytes used in Info
2703 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2704 * if cbBuf is too small
2706 * Native Values returned in Info on Success:
2707 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2708 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2709 *| win9x(Windows 4.0): "%winsysdir%"
2711 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2714 * Only NULL or "" is supported for server
2717 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2718 DWORD level, LPBYTE Info,
2719 DWORD cbBuf, LPDWORD pcbNeeded)
2722 const printenv_t * env_t;
2724 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2725 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2727 if(server != NULL && server[0]) {
2728 FIXME("server not supported: %s\n", debugstr_w(server));
2729 SetLastError(ERROR_INVALID_PARAMETER);
2733 env_t = validate_envW(env);
2734 if(!env_t) return FALSE; /* environment invalid or unsupported */
2737 WARN("(Level: %d) is ignored in win9x\n", level);
2738 SetLastError(ERROR_INVALID_LEVEL);
2742 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2743 needed = GetSystemDirectoryW(NULL, 0);
2744 /* add the Size for the Subdirectories */
2745 needed += lstrlenW(spoolprtprocsW);
2746 needed += lstrlenW(env_t->subdir);
2747 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2749 if(pcbNeeded) *pcbNeeded = needed;
2750 TRACE ("required: 0x%x/%d\n", needed, needed);
2751 if (needed > cbBuf) {
2752 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2755 if(pcbNeeded == NULL) {
2756 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2757 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2758 SetLastError(RPC_X_NULL_REF_POINTER);
2762 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2763 SetLastError(RPC_X_NULL_REF_POINTER);
2767 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2768 /* add the Subdirectories */
2769 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2770 lstrcatW((LPWSTR) Info, env_t->subdir);
2771 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2775 /*****************************************************************************
2776 * WINSPOOL_OpenDriverReg [internal]
2778 * opens the registry for the printer drivers depending on the given input
2779 * variable pEnvironment
2782 * the opened hkey on success
2785 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2789 const printenv_t * env;
2792 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2794 if (!pEnvironment || unicode) {
2795 /* pEnvironment was NULL or an Unicode-String: use it direct */
2796 env = validate_envW(pEnvironment);
2800 /* pEnvironment was an ANSI-String: convert to unicode first */
2802 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2803 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2804 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2805 env = validate_envW(buffer);
2806 HeapFree(GetProcessHeap(), 0, buffer);
2808 if (!env) return NULL;
2810 buffer = HeapAlloc( GetProcessHeap(), 0,
2811 (strlenW(DriversW) + strlenW(env->envname) +
2812 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2814 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2815 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2816 HeapFree(GetProcessHeap(), 0, buffer);
2821 /*****************************************************************************
2822 * AddPrinterW [WINSPOOL.@]
2824 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2826 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2830 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2833 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2836 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2837 SetLastError(ERROR_INVALID_PARAMETER);
2841 ERR("Level = %d, unsupported!\n", Level);
2842 SetLastError(ERROR_INVALID_LEVEL);
2846 SetLastError(ERROR_INVALID_PARAMETER);
2849 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2851 ERR("Can't create Printers key\n");
2854 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2855 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2856 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2857 RegCloseKey(hkeyPrinter);
2858 RegCloseKey(hkeyPrinters);
2861 RegCloseKey(hkeyPrinter);
2863 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2865 ERR("Can't create Drivers key\n");
2866 RegCloseKey(hkeyPrinters);
2869 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2871 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2872 RegCloseKey(hkeyPrinters);
2873 RegCloseKey(hkeyDrivers);
2874 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2877 RegCloseKey(hkeyDriver);
2878 RegCloseKey(hkeyDrivers);
2880 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2881 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2882 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2883 RegCloseKey(hkeyPrinters);
2887 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2889 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2890 SetLastError(ERROR_INVALID_PRINTER_NAME);
2891 RegCloseKey(hkeyPrinters);
2894 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2895 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2896 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2898 /* See if we can load the driver. We may need the devmode structure anyway
2901 * Note that DocumentPropertiesW will briefly try to open the printer we
2902 * just create to find a DEVMODEA struct (it will use the WINEPS default
2903 * one in case it is not there, so we are ok).
2905 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2908 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2909 size = sizeof(DEVMODEW);
2915 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2916 ZeroMemory(dmW,size);
2918 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2920 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2921 HeapFree(GetProcessHeap(),0,dmW);
2926 /* set devmode to printer name */
2927 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2931 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2932 and we support these drivers. NT writes DEVMODEW so somehow
2933 we'll need to distinguish between these when we support NT
2937 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2938 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2939 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2940 HeapFree(GetProcessHeap(), 0, dmA);
2942 HeapFree(GetProcessHeap(), 0, dmW);
2944 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2945 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2946 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2947 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2949 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2950 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2951 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2952 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2953 (LPBYTE)&pi->Priority, sizeof(DWORD));
2954 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2955 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2956 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2957 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2958 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2959 (LPBYTE)&pi->Status, sizeof(DWORD));
2960 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2961 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2963 RegCloseKey(hkeyPrinter);
2964 RegCloseKey(hkeyPrinters);
2965 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2966 ERR("OpenPrinter failing\n");
2972 /*****************************************************************************
2973 * AddPrinterA [WINSPOOL.@]
2975 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2977 UNICODE_STRING pNameW;
2979 PRINTER_INFO_2W *piW;
2980 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2983 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2985 ERR("Level = %d, unsupported!\n", Level);
2986 SetLastError(ERROR_INVALID_LEVEL);
2989 pwstrNameW = asciitounicode(&pNameW,pName);
2990 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2992 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2994 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2995 RtlFreeUnicodeString(&pNameW);
3000 /*****************************************************************************
3001 * ClosePrinter [WINSPOOL.@]
3003 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3005 UINT_PTR i = (UINT_PTR)hPrinter;
3006 opened_printer_t *printer = NULL;
3009 TRACE("(%p)\n", hPrinter);
3011 EnterCriticalSection(&printer_handles_cs);
3013 if ((i > 0) && (i <= nb_printer_handles))
3014 printer = printer_handles[i - 1];
3019 struct list *cursor, *cursor2;
3021 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3022 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3023 printer->hXcv, debugstr_w(printer->name), printer->doc );
3026 EndDocPrinter(hPrinter);
3028 if(InterlockedDecrement(&printer->queue->ref) == 0)
3030 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3032 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3033 ScheduleJob(hPrinter, job->job_id);
3035 HeapFree(GetProcessHeap(), 0, printer->queue);
3037 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3038 monitor_unload(printer->pm);
3039 HeapFree(GetProcessHeap(), 0, printer->printername);
3040 HeapFree(GetProcessHeap(), 0, printer->name);
3041 HeapFree(GetProcessHeap(), 0, printer);
3042 printer_handles[i - 1] = NULL;
3045 LeaveCriticalSection(&printer_handles_cs);
3049 /*****************************************************************************
3050 * DeleteFormA [WINSPOOL.@]
3052 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3054 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3058 /*****************************************************************************
3059 * DeleteFormW [WINSPOOL.@]
3061 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3063 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3067 /*****************************************************************************
3068 * DeletePrinter [WINSPOOL.@]
3070 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3072 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3073 HKEY hkeyPrinters, hkey;
3076 SetLastError(ERROR_INVALID_HANDLE);
3079 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3080 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
3081 RegCloseKey(hkeyPrinters);
3083 WriteProfileStringW(devicesW, lpNameW, NULL);
3084 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3085 RegDeleteValueW(hkey, lpNameW);
3091 /*****************************************************************************
3092 * SetPrinterA [WINSPOOL.@]
3094 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3097 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3101 /*****************************************************************************
3102 * SetJobA [WINSPOOL.@]
3104 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3105 LPBYTE pJob, DWORD Command)
3109 UNICODE_STRING usBuffer;
3111 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3113 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3114 are all ignored by SetJob, so we don't bother copying them */
3122 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3123 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3125 JobW = (LPBYTE)info1W;
3126 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3127 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3128 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3129 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3130 info1W->Status = info1A->Status;
3131 info1W->Priority = info1A->Priority;
3132 info1W->Position = info1A->Position;
3133 info1W->PagesPrinted = info1A->PagesPrinted;
3138 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3139 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3141 JobW = (LPBYTE)info2W;
3142 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3143 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3144 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3145 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3146 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3147 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3148 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3149 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3150 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3151 info2W->Status = info2A->Status;
3152 info2W->Priority = info2A->Priority;
3153 info2W->Position = info2A->Position;
3154 info2W->StartTime = info2A->StartTime;
3155 info2W->UntilTime = info2A->UntilTime;
3156 info2W->PagesPrinted = info2A->PagesPrinted;
3160 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3161 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3164 SetLastError(ERROR_INVALID_LEVEL);
3168 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3174 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3175 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3176 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3177 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3178 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3183 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3184 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3185 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3186 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3187 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3188 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3189 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3190 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3191 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3195 HeapFree(GetProcessHeap(), 0, JobW);
3200 /*****************************************************************************
3201 * SetJobW [WINSPOOL.@]
3203 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3204 LPBYTE pJob, DWORD Command)
3209 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3210 FIXME("Ignoring everything other than document title\n");
3212 EnterCriticalSection(&printer_handles_cs);
3213 job = get_job(hPrinter, JobId);
3223 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3224 HeapFree(GetProcessHeap(), 0, job->document_title);
3225 job->document_title = strdupW(info1->pDocument);
3230 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3231 HeapFree(GetProcessHeap(), 0, job->document_title);
3232 job->document_title = strdupW(info2->pDocument);
3238 SetLastError(ERROR_INVALID_LEVEL);
3243 LeaveCriticalSection(&printer_handles_cs);
3247 /*****************************************************************************
3248 * EndDocPrinter [WINSPOOL.@]
3250 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3252 opened_printer_t *printer;
3254 TRACE("(%p)\n", hPrinter);
3256 EnterCriticalSection(&printer_handles_cs);
3258 printer = get_opened_printer(hPrinter);
3261 SetLastError(ERROR_INVALID_HANDLE);
3267 SetLastError(ERROR_SPL_NO_STARTDOC);
3271 CloseHandle(printer->doc->hf);
3272 ScheduleJob(hPrinter, printer->doc->job_id);
3273 HeapFree(GetProcessHeap(), 0, printer->doc);
3274 printer->doc = NULL;
3277 LeaveCriticalSection(&printer_handles_cs);
3281 /*****************************************************************************
3282 * EndPagePrinter [WINSPOOL.@]
3284 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3286 FIXME("(%p): stub\n", hPrinter);
3290 /*****************************************************************************
3291 * StartDocPrinterA [WINSPOOL.@]
3293 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3295 UNICODE_STRING usBuffer;
3297 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3300 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3301 or one (DOC_INFO_3) extra DWORDs */
3305 doc2W.JobId = doc2->JobId;
3308 doc2W.dwMode = doc2->dwMode;
3311 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3312 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3313 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3317 SetLastError(ERROR_INVALID_LEVEL);
3321 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3323 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3324 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3325 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3330 /*****************************************************************************
3331 * StartDocPrinterW [WINSPOOL.@]
3333 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3335 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3336 opened_printer_t *printer;
3337 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3338 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3339 JOB_INFO_1W job_info;
3340 DWORD needed, ret = 0;
3344 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3345 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3346 debugstr_w(doc->pDatatype));
3348 if(Level < 1 || Level > 3)
3350 SetLastError(ERROR_INVALID_LEVEL);
3354 EnterCriticalSection(&printer_handles_cs);
3355 printer = get_opened_printer(hPrinter);
3358 SetLastError(ERROR_INVALID_HANDLE);
3364 SetLastError(ERROR_INVALID_PRINTER_STATE);
3368 /* Even if we're printing to a file we still add a print job, we'll
3369 just ignore the spool file name */
3371 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3373 ERR("AddJob failed gle %u\n", GetLastError());
3377 if(doc->pOutputFile)
3378 filename = doc->pOutputFile;
3380 filename = addjob->Path;
3382 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3383 if(hf == INVALID_HANDLE_VALUE)
3386 memset(&job_info, 0, sizeof(job_info));
3387 job_info.pDocument = doc->pDocName;
3388 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3390 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3391 printer->doc->hf = hf;
3392 ret = printer->doc->job_id = addjob->JobId;
3394 LeaveCriticalSection(&printer_handles_cs);
3399 /*****************************************************************************
3400 * StartPagePrinter [WINSPOOL.@]
3402 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3404 FIXME("(%p): stub\n", hPrinter);
3408 /*****************************************************************************
3409 * GetFormA [WINSPOOL.@]
3411 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3412 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3414 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3415 Level,pForm,cbBuf,pcbNeeded);
3419 /*****************************************************************************
3420 * GetFormW [WINSPOOL.@]
3422 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3423 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3425 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3426 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3430 /*****************************************************************************
3431 * SetFormA [WINSPOOL.@]
3433 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3436 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3440 /*****************************************************************************
3441 * SetFormW [WINSPOOL.@]
3443 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3446 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3450 /*****************************************************************************
3451 * ReadPrinter [WINSPOOL.@]
3453 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3454 LPDWORD pNoBytesRead)
3456 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3460 /*****************************************************************************
3461 * ResetPrinterA [WINSPOOL.@]
3463 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3465 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3469 /*****************************************************************************
3470 * ResetPrinterW [WINSPOOL.@]
3472 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3474 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3478 /*****************************************************************************
3479 * WINSPOOL_GetDWORDFromReg
3481 * Return DWORD associated with ValueName from hkey.
3483 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3485 DWORD sz = sizeof(DWORD), type, value = 0;
3488 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3490 if(ret != ERROR_SUCCESS) {
3491 WARN("Got ret = %d on name %s\n", ret, ValueName);
3494 if(type != REG_DWORD) {
3495 ERR("Got type %d\n", type);
3501 /*****************************************************************************
3502 * WINSPOOL_GetStringFromReg
3504 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3505 * String is stored either as unicode or ascii.
3506 * Bit of a hack here to get the ValueName if we want ascii.
3508 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3509 DWORD buflen, DWORD *needed,
3512 DWORD sz = buflen, type;
3516 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3518 LPSTR ValueNameA = strdupWtoA(ValueName);
3519 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3520 HeapFree(GetProcessHeap(),0,ValueNameA);
3522 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3523 WARN("Got ret = %d\n", ret);
3527 /* add space for terminating '\0' */
3528 sz += unicode ? sizeof(WCHAR) : 1;
3532 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3537 /*****************************************************************************
3538 * WINSPOOL_GetDefaultDevMode
3540 * Get a default DevMode values for wineps.
3544 static void WINSPOOL_GetDefaultDevMode(
3546 DWORD buflen, DWORD *needed,
3550 static const char szwps[] = "wineps.drv";
3552 /* fill default DEVMODE - should be read from ppd... */
3553 ZeroMemory( &dm, sizeof(dm) );
3554 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3555 dm.dmSpecVersion = DM_SPECVERSION;
3556 dm.dmDriverVersion = 1;
3557 dm.dmSize = sizeof(DEVMODEA);
3558 dm.dmDriverExtra = 0;
3560 DM_ORIENTATION | DM_PAPERSIZE |
3561 DM_PAPERLENGTH | DM_PAPERWIDTH |
3564 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3565 DM_YRESOLUTION | DM_TTOPTION;
3567 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3568 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3569 dm.u1.s1.dmPaperLength = 2970;
3570 dm.u1.s1.dmPaperWidth = 2100;
3574 dm.dmDefaultSource = DMBIN_AUTO;
3575 dm.dmPrintQuality = DMRES_MEDIUM;
3578 dm.dmYResolution = 300; /* 300dpi */
3579 dm.dmTTOption = DMTT_BITMAP;
3582 /* dm.dmLogPixels */
3583 /* dm.dmBitsPerPel */
3584 /* dm.dmPelsWidth */
3585 /* dm.dmPelsHeight */
3586 /* dm.dmDisplayFlags */
3587 /* dm.dmDisplayFrequency */
3588 /* dm.dmICMMethod */
3589 /* dm.dmICMIntent */
3590 /* dm.dmMediaType */
3591 /* dm.dmDitherType */
3592 /* dm.dmReserved1 */
3593 /* dm.dmReserved2 */
3594 /* dm.dmPanningWidth */
3595 /* dm.dmPanningHeight */
3598 if(buflen >= sizeof(DEVMODEW)) {
3599 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3600 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3601 HeapFree(GetProcessHeap(),0,pdmW);
3603 *needed = sizeof(DEVMODEW);
3607 if(buflen >= sizeof(DEVMODEA)) {
3608 memcpy(ptr, &dm, sizeof(DEVMODEA));
3610 *needed = sizeof(DEVMODEA);
3614 /*****************************************************************************
3615 * WINSPOOL_GetDevModeFromReg
3617 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3618 * DevMode is stored either as unicode or ascii.
3620 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3622 DWORD buflen, DWORD *needed,
3625 DWORD sz = buflen, type;
3628 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3629 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3630 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3631 if (sz < sizeof(DEVMODEA))
3633 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3636 /* ensures that dmSize is not erratically bogus if registry is invalid */
3637 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3638 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3640 sz += (CCHDEVICENAME + CCHFORMNAME);
3642 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3643 memcpy(ptr, dmW, sz);
3644 HeapFree(GetProcessHeap(),0,dmW);
3651 /*********************************************************************
3652 * WINSPOOL_GetPrinter_2
3654 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3655 * The strings are either stored as unicode or ascii.
3657 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3658 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3661 DWORD size, left = cbBuf;
3662 BOOL space = (cbBuf > 0);
3667 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3669 if(space && size <= left) {
3670 pi2->pPrinterName = (LPWSTR)ptr;
3677 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3679 if(space && size <= left) {
3680 pi2->pShareName = (LPWSTR)ptr;
3687 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3689 if(space && size <= left) {
3690 pi2->pPortName = (LPWSTR)ptr;
3697 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3699 if(space && size <= left) {
3700 pi2->pDriverName = (LPWSTR)ptr;
3707 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3709 if(space && size <= left) {
3710 pi2->pComment = (LPWSTR)ptr;
3717 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3719 if(space && size <= left) {
3720 pi2->pLocation = (LPWSTR)ptr;
3727 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3729 if(space && size <= left) {
3730 pi2->pDevMode = (LPDEVMODEW)ptr;
3739 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3740 if(space && size <= left) {
3741 pi2->pDevMode = (LPDEVMODEW)ptr;
3748 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3750 if(space && size <= left) {
3751 pi2->pSepFile = (LPWSTR)ptr;
3758 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3760 if(space && size <= left) {
3761 pi2->pPrintProcessor = (LPWSTR)ptr;
3768 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3770 if(space && size <= left) {
3771 pi2->pDatatype = (LPWSTR)ptr;
3778 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3780 if(space && size <= left) {
3781 pi2->pParameters = (LPWSTR)ptr;
3789 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3790 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3791 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3792 "Default Priority");
3793 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3794 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3797 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3798 memset(pi2, 0, sizeof(*pi2));
3803 /*********************************************************************
3804 * WINSPOOL_GetPrinter_4
3806 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3808 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3809 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3812 DWORD size, left = cbBuf;
3813 BOOL space = (cbBuf > 0);
3818 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3820 if(space && size <= left) {
3821 pi4->pPrinterName = (LPWSTR)ptr;
3829 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3832 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3833 memset(pi4, 0, sizeof(*pi4));
3838 /*********************************************************************
3839 * WINSPOOL_GetPrinter_5
3841 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3843 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3844 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3847 DWORD size, left = cbBuf;
3848 BOOL space = (cbBuf > 0);
3853 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3855 if(space && size <= left) {
3856 pi5->pPrinterName = (LPWSTR)ptr;
3863 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3865 if(space && size <= left) {
3866 pi5->pPortName = (LPWSTR)ptr;
3874 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3875 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3877 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3881 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3882 memset(pi5, 0, sizeof(*pi5));
3887 /*****************************************************************************
3888 * WINSPOOL_GetPrinter
3890 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3891 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3892 * just a collection of pointers to strings.
3894 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3895 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3898 DWORD size, needed = 0;
3900 HKEY hkeyPrinter, hkeyPrinters;
3903 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3905 if (!(name = get_opened_printer_name(hPrinter))) {
3906 SetLastError(ERROR_INVALID_HANDLE);
3910 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3912 ERR("Can't create Printers key\n");
3915 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3917 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3918 RegCloseKey(hkeyPrinters);
3919 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3926 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3928 size = sizeof(PRINTER_INFO_2W);
3930 ptr = pPrinter + size;
3932 memset(pPrinter, 0, size);
3937 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3945 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3947 size = sizeof(PRINTER_INFO_4W);
3949 ptr = pPrinter + size;
3951 memset(pPrinter, 0, size);
3956 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3965 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3967 size = sizeof(PRINTER_INFO_5W);
3969 ptr = pPrinter + size;
3971 memset(pPrinter, 0, size);
3977 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3984 FIXME("Unimplemented level %d\n", Level);
3985 SetLastError(ERROR_INVALID_LEVEL);
3986 RegCloseKey(hkeyPrinters);
3987 RegCloseKey(hkeyPrinter);
3991 RegCloseKey(hkeyPrinter);
3992 RegCloseKey(hkeyPrinters);
3994 TRACE("returning %d needed = %d\n", ret, needed);
3995 if(pcbNeeded) *pcbNeeded = needed;
3997 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4001 /*****************************************************************************
4002 * GetPrinterW [WINSPOOL.@]
4004 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4005 DWORD cbBuf, LPDWORD pcbNeeded)
4007 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4011 /*****************************************************************************
4012 * GetPrinterA [WINSPOOL.@]
4014 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4015 DWORD cbBuf, LPDWORD pcbNeeded)
4017 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4021 /*****************************************************************************
4022 * WINSPOOL_EnumPrinters
4024 * Implementation of EnumPrintersA|W
4026 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4027 DWORD dwLevel, LPBYTE lpbPrinters,
4028 DWORD cbBuf, LPDWORD lpdwNeeded,
4029 LPDWORD lpdwReturned, BOOL unicode)
4032 HKEY hkeyPrinters, hkeyPrinter;
4033 WCHAR PrinterName[255];
4034 DWORD needed = 0, number = 0;
4035 DWORD used, i, left;
4039 memset(lpbPrinters, 0, cbBuf);
4045 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4046 if(dwType == PRINTER_ENUM_DEFAULT)
4049 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4050 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4051 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4053 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4061 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4062 FIXME("dwType = %08x\n", dwType);
4063 SetLastError(ERROR_INVALID_FLAGS);
4067 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4069 ERR("Can't create Printers key\n");
4073 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4074 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4075 RegCloseKey(hkeyPrinters);
4076 ERR("Can't query Printers key\n");
4079 TRACE("Found %d printers\n", number);
4083 RegCloseKey(hkeyPrinters);
4085 *lpdwReturned = number;
4089 used = number * sizeof(PRINTER_INFO_2W);
4092 used = number * sizeof(PRINTER_INFO_4W);
4095 used = number * sizeof(PRINTER_INFO_5W);
4099 SetLastError(ERROR_INVALID_LEVEL);
4100 RegCloseKey(hkeyPrinters);
4103 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4105 for(i = 0; i < number; i++) {
4106 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4108 ERR("Can't enum key number %d\n", i);
4109 RegCloseKey(hkeyPrinters);
4112 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4113 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4115 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4116 RegCloseKey(hkeyPrinters);
4121 buf = lpbPrinters + used;
4122 left = cbBuf - used;
4130 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4131 left, &needed, unicode);
4133 if(pi) pi += sizeof(PRINTER_INFO_2W);
4136 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4137 left, &needed, unicode);
4139 if(pi) pi += sizeof(PRINTER_INFO_4W);
4142 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4143 left, &needed, unicode);
4145 if(pi) pi += sizeof(PRINTER_INFO_5W);
4148 ERR("Shouldn't be here!\n");
4149 RegCloseKey(hkeyPrinter);
4150 RegCloseKey(hkeyPrinters);
4153 RegCloseKey(hkeyPrinter);
4155 RegCloseKey(hkeyPrinters);
4162 memset(lpbPrinters, 0, cbBuf);
4163 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4167 *lpdwReturned = number;
4168 SetLastError(ERROR_SUCCESS);
4173 /******************************************************************
4174 * EnumPrintersW [WINSPOOL.@]
4176 * Enumerates the available printers, print servers and print
4177 * providers, depending on the specified flags, name and level.
4181 * If level is set to 1:
4182 * Not implemented yet!
4183 * Returns TRUE with an empty list.
4185 * If level is set to 2:
4186 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4187 * Returns an array of PRINTER_INFO_2 data structures in the
4188 * lpbPrinters buffer. Note that according to MSDN also an
4189 * OpenPrinter should be performed on every remote printer.
4191 * If level is set to 4 (officially WinNT only):
4192 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4193 * Fast: Only the registry is queried to retrieve printer names,
4194 * no connection to the driver is made.
4195 * Returns an array of PRINTER_INFO_4 data structures in the
4196 * lpbPrinters buffer.
4198 * If level is set to 5 (officially WinNT4/Win9x only):
4199 * Fast: Only the registry is queried to retrieve printer names,
4200 * no connection to the driver is made.
4201 * Returns an array of PRINTER_INFO_5 data structures in the
4202 * lpbPrinters buffer.
4204 * If level set to 3 or 6+:
4205 * returns zero (failure!)
4207 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4211 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4212 * - Only levels 2, 4 and 5 are implemented at the moment.
4213 * - 16-bit printer drivers are not enumerated.
4214 * - Returned amount of bytes used/needed does not match the real Windoze
4215 * implementation (as in this implementation, all strings are part
4216 * of the buffer, whereas Win32 keeps them somewhere else)
4217 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4220 * - In a regular Wine installation, no registry settings for printers
4221 * exist, which makes this function return an empty list.
4223 BOOL WINAPI EnumPrintersW(
4224 DWORD dwType, /* [in] Types of print objects to enumerate */
4225 LPWSTR lpszName, /* [in] name of objects to enumerate */
4226 DWORD dwLevel, /* [in] type of printer info structure */
4227 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4228 DWORD cbBuf, /* [in] max size of buffer in bytes */
4229 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4230 LPDWORD lpdwReturned /* [out] number of entries returned */
4233 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4234 lpdwNeeded, lpdwReturned, TRUE);
4237 /******************************************************************
4238 * EnumPrintersA [WINSPOOL.@]
4241 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4242 DWORD dwLevel, LPBYTE lpbPrinters,
4243 DWORD cbBuf, LPDWORD lpdwNeeded,
4244 LPDWORD lpdwReturned)
4246 BOOL ret, unicode = FALSE;
4247 UNICODE_STRING lpszNameW;
4250 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4251 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4252 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4253 lpdwNeeded, lpdwReturned, unicode);
4254 RtlFreeUnicodeString(&lpszNameW);
4258 /*****************************************************************************
4259 * WINSPOOL_GetDriverInfoFromReg [internal]
4261 * Enters the information from the registry into the DRIVER_INFO struct
4264 * zero if the printer driver does not exist in the registry
4265 * (only if Level > 1) otherwise nonzero
4267 static BOOL WINSPOOL_GetDriverInfoFromReg(
4270 LPCWSTR pEnvironment,
4272 LPBYTE ptr, /* DRIVER_INFO */
4273 LPBYTE pDriverStrings, /* strings buffer */
4274 DWORD cbBuf, /* size of string buffer */
4275 LPDWORD pcbNeeded, /* space needed for str. */
4276 BOOL unicode) /* type of strings */
4280 LPBYTE strPtr = pDriverStrings;
4282 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4283 debugstr_w(DriverName), debugstr_w(pEnvironment),
4284 Level, ptr, pDriverStrings, cbBuf, unicode);
4287 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4288 if (*pcbNeeded <= cbBuf)
4289 strcpyW((LPWSTR)strPtr, DriverName);
4291 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4293 if(*pcbNeeded <= cbBuf)
4294 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4295 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4299 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4303 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4304 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4307 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4308 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4309 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4314 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4317 pEnvironment = DefaultEnvironmentW;
4319 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4321 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4324 if(*pcbNeeded <= cbBuf) {
4326 strcpyW((LPWSTR)strPtr, pEnvironment);
4328 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4329 (LPSTR)strPtr, size, NULL, NULL);
4331 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4332 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4335 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4338 if(*pcbNeeded <= cbBuf)
4339 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4342 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4343 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4346 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4349 if(*pcbNeeded <= cbBuf)
4350 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4353 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4354 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4357 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4358 0, &size, unicode)) {
4360 if(*pcbNeeded <= cbBuf)
4361 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4362 size, &tmp, unicode);
4364 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4365 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4369 RegCloseKey(hkeyDriver);
4370 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4374 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4377 if(*pcbNeeded <= cbBuf)
4378 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4379 size, &tmp, unicode);
4381 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4382 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4385 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4388 if(*pcbNeeded <= cbBuf)
4389 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4390 size, &tmp, unicode);
4392 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4393 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4396 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4399 if(*pcbNeeded <= cbBuf)
4400 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4401 size, &tmp, unicode);
4403 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4404 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4407 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4410 if(*pcbNeeded <= cbBuf)
4411 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4412 size, &tmp, unicode);
4414 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4415 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4418 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4419 RegCloseKey(hkeyDriver);
4423 /*****************************************************************************
4424 * WINSPOOL_GetPrinterDriver
4426 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
4427 DWORD Level, LPBYTE pDriverInfo,
4428 DWORD cbBuf, LPDWORD pcbNeeded,
4432 WCHAR DriverName[100];
4433 DWORD ret, type, size, needed = 0;
4435 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4437 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4438 Level,pDriverInfo,cbBuf, pcbNeeded);
4440 ZeroMemory(pDriverInfo, cbBuf);
4442 if (!(name = get_opened_printer_name(hPrinter))) {
4443 SetLastError(ERROR_INVALID_HANDLE);
4446 if(Level < 1 || Level > 6) {
4447 SetLastError(ERROR_INVALID_LEVEL);
4450 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4452 ERR("Can't create Printers key\n");
4455 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4457 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4458 RegCloseKey(hkeyPrinters);
4459 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4462 size = sizeof(DriverName);
4464 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4465 (LPBYTE)DriverName, &size);
4466 RegCloseKey(hkeyPrinter);
4467 RegCloseKey(hkeyPrinters);
4468 if(ret != ERROR_SUCCESS) {
4469 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4473 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4475 ERR("Can't create Drivers key\n");
4481 size = sizeof(DRIVER_INFO_1W);
4484 size = sizeof(DRIVER_INFO_2W);
4487 size = sizeof(DRIVER_INFO_3W);
4490 size = sizeof(DRIVER_INFO_4W);
4493 size = sizeof(DRIVER_INFO_5W);
4496 size = sizeof(DRIVER_INFO_6W);
4499 ERR("Invalid level\n");
4504 ptr = pDriverInfo + size;
4506 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4507 pEnvironment, Level, pDriverInfo,
4508 (cbBuf < size) ? NULL : ptr,
4509 (cbBuf < size) ? 0 : cbBuf - size,
4510 &needed, unicode)) {
4511 RegCloseKey(hkeyDrivers);
4515 RegCloseKey(hkeyDrivers);
4517 if(pcbNeeded) *pcbNeeded = size + needed;
4518 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4519 if(cbBuf >= needed) return TRUE;
4520 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4524 /*****************************************************************************
4525 * GetPrinterDriverA [WINSPOOL.@]
4527 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4528 DWORD Level, LPBYTE pDriverInfo,
4529 DWORD cbBuf, LPDWORD pcbNeeded)
4532 UNICODE_STRING pEnvW;
4535 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4536 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4537 cbBuf, pcbNeeded, FALSE);
4538 RtlFreeUnicodeString(&pEnvW);
4541 /*****************************************************************************
4542 * GetPrinterDriverW [WINSPOOL.@]
4544 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4545 DWORD Level, LPBYTE pDriverInfo,
4546 DWORD cbBuf, LPDWORD pcbNeeded)
4548 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4549 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4552 /*****************************************************************************
4553 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4555 * Return the PATH for the Printer-Drivers (UNICODE)
4558 * pName [I] Servername (NT only) or NULL (local Computer)
4559 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4560 * Level [I] Structure-Level (must be 1)
4561 * pDriverDirectory [O] PTR to Buffer that receives the Result
4562 * cbBuf [I] Size of Buffer at pDriverDirectory
4563 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4564 * required for pDriverDirectory
4567 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4568 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4569 * if cbBuf is too small
4571 * Native Values returned in pDriverDirectory on Success:
4572 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4573 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4574 *| win9x(Windows 4.0): "%winsysdir%"
4576 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4579 *- Only NULL or "" is supported for pName
4582 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4583 DWORD Level, LPBYTE pDriverDirectory,
4584 DWORD cbBuf, LPDWORD pcbNeeded)
4587 const printenv_t * env;
4589 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4590 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4591 if(pName != NULL && pName[0]) {
4592 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4593 SetLastError(ERROR_INVALID_PARAMETER);
4597 env = validate_envW(pEnvironment);
4598 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4601 WARN("(Level: %d) is ignored in win9x\n", Level);
4602 SetLastError(ERROR_INVALID_LEVEL);
4606 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4607 needed = GetSystemDirectoryW(NULL, 0);
4608 /* add the Size for the Subdirectories */
4609 needed += lstrlenW(spooldriversW);
4610 needed += lstrlenW(env->subdir);
4611 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4614 *pcbNeeded = needed;
4615 TRACE("required: 0x%x/%d\n", needed, needed);
4616 if(needed > cbBuf) {
4617 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4620 if(pcbNeeded == NULL) {
4621 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4622 SetLastError(RPC_X_NULL_REF_POINTER);
4625 if(pDriverDirectory == NULL) {
4626 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4627 SetLastError(ERROR_INVALID_USER_BUFFER);
4631 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4632 /* add the Subdirectories */
4633 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4634 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4635 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4640 /*****************************************************************************
4641 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4643 * Return the PATH for the Printer-Drivers (ANSI)
4645 * See GetPrinterDriverDirectoryW.
4648 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4651 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4652 DWORD Level, LPBYTE pDriverDirectory,
4653 DWORD cbBuf, LPDWORD pcbNeeded)
4655 UNICODE_STRING nameW, environmentW;
4658 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4659 WCHAR *driverDirectoryW = NULL;
4661 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4662 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4664 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4666 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4667 else nameW.Buffer = NULL;
4668 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4669 else environmentW.Buffer = NULL;
4671 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4672 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4675 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4676 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4678 *pcbNeeded = needed;
4679 ret = (needed <= cbBuf) ? TRUE : FALSE;
4681 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4683 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4685 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4686 RtlFreeUnicodeString(&environmentW);
4687 RtlFreeUnicodeString(&nameW);
4692 /*****************************************************************************
4693 * AddPrinterDriverA [WINSPOOL.@]
4695 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4698 HKEY hkeyDrivers, hkeyName;
4699 static CHAR empty[] = "",
4702 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4704 if(level != 2 && level != 3) {
4705 SetLastError(ERROR_INVALID_LEVEL);
4708 if ((pName) && (pName[0])) {
4709 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4710 SetLastError(ERROR_INVALID_PARAMETER);
4714 WARN("pDriverInfo == NULL\n");
4715 SetLastError(ERROR_INVALID_PARAMETER);
4720 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4722 memset(&di3, 0, sizeof(di3));
4723 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4726 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4728 SetLastError(ERROR_INVALID_PARAMETER);
4732 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4733 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4734 if(!di3.pHelpFile) di3.pHelpFile = empty;
4735 if(!di3.pMonitorName) di3.pMonitorName = empty;
4737 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4740 ERR("Can't create Drivers key\n");
4744 if(level == 2) { /* apparently can't overwrite with level2 */
4745 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4746 RegCloseKey(hkeyName);
4747 RegCloseKey(hkeyDrivers);
4748 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4749 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4753 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4754 RegCloseKey(hkeyDrivers);
4755 ERR("Can't create Name key\n");
4758 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4759 lstrlenA(di3.pConfigFile) + 1);
4760 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4761 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4762 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4764 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4765 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4766 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4767 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4768 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4769 RegCloseKey(hkeyName);
4770 RegCloseKey(hkeyDrivers);
4775 /*****************************************************************************
4776 * AddPrinterDriverW [WINSPOOL.@]
4778 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4781 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4786 /*****************************************************************************
4787 * AddPrintProcessorA [WINSPOOL.@]
4789 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4790 LPSTR pPrintProcessorName)
4792 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4793 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4797 /*****************************************************************************
4798 * AddPrintProcessorW [WINSPOOL.@]
4800 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4801 LPWSTR pPrintProcessorName)
4803 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4804 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4808 /*****************************************************************************
4809 * AddPrintProvidorA [WINSPOOL.@]
4811 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4813 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4817 /*****************************************************************************
4818 * AddPrintProvidorW [WINSPOOL.@]
4820 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4822 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4826 /*****************************************************************************
4827 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4829 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4830 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4832 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4833 pDevModeOutput, pDevModeInput);
4837 /*****************************************************************************
4838 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4840 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4841 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4843 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4844 pDevModeOutput, pDevModeInput);
4848 /*****************************************************************************
4849 * PrinterProperties [WINSPOOL.@]
4851 * Displays a dialog to set the properties of the printer.
4854 * nonzero on success or zero on failure
4857 * implemented as stub only
4859 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4860 HANDLE hPrinter /* [in] handle to printer object */
4862 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4863 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4867 /*****************************************************************************
4868 * EnumJobsA [WINSPOOL.@]
4871 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4872 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4875 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4876 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4878 if(pcbNeeded) *pcbNeeded = 0;
4879 if(pcReturned) *pcReturned = 0;
4884 /*****************************************************************************
4885 * EnumJobsW [WINSPOOL.@]
4888 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4889 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4892 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4893 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4895 if(pcbNeeded) *pcbNeeded = 0;
4896 if(pcReturned) *pcReturned = 0;
4900 /*****************************************************************************
4901 * WINSPOOL_EnumPrinterDrivers [internal]
4903 * Delivers information about all printer drivers installed on the
4904 * localhost or a given server
4907 * nonzero on success or zero on failure. If the buffer for the returned
4908 * information is too small the function will return an error
4911 * - only implemented for localhost, foreign hosts will return an error
4913 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4914 DWORD Level, LPBYTE pDriverInfo,
4915 DWORD cbBuf, LPDWORD pcbNeeded,
4916 LPDWORD pcReturned, BOOL unicode)
4919 DWORD i, needed, number = 0, size = 0;
4920 WCHAR DriverNameW[255];
4923 TRACE("%s,%s,%d,%p,%d,%d\n",
4924 debugstr_w(pName), debugstr_w(pEnvironment),
4925 Level, pDriverInfo, cbBuf, unicode);
4927 /* check for local drivers */
4928 if((pName) && (pName[0])) {
4929 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4930 SetLastError(ERROR_ACCESS_DENIED);
4934 /* check input parameter */
4935 if((Level < 1) || (Level > 3)) {
4936 ERR("unsupported level %d\n", Level);
4937 SetLastError(ERROR_INVALID_LEVEL);
4941 /* initialize return values */
4943 memset( pDriverInfo, 0, cbBuf);
4947 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4949 ERR("Can't open Drivers key\n");
4953 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4954 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4955 RegCloseKey(hkeyDrivers);
4956 ERR("Can't query Drivers key\n");
4959 TRACE("Found %d Drivers\n", number);
4961 /* get size of single struct
4962 * unicode and ascii structure have the same size
4966 size = sizeof(DRIVER_INFO_1A);
4969 size = sizeof(DRIVER_INFO_2A);
4972 size = sizeof(DRIVER_INFO_3A);
4976 /* calculate required buffer size */
4977 *pcbNeeded = size * number;
4979 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4981 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4982 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4984 ERR("Can't enum key number %d\n", i);
4985 RegCloseKey(hkeyDrivers);
4988 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4989 pEnvironment, Level, ptr,
4990 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4991 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4992 &needed, unicode)) {
4993 RegCloseKey(hkeyDrivers);
4996 (*pcbNeeded) += needed;
4999 RegCloseKey(hkeyDrivers);
5001 if(cbBuf < *pcbNeeded){
5002 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5006 *pcReturned = number;
5010 /*****************************************************************************
5011 * EnumPrinterDriversW [WINSPOOL.@]
5013 * see function EnumPrinterDrivers for RETURNS, BUGS
5015 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5016 LPBYTE pDriverInfo, DWORD cbBuf,
5017 LPDWORD pcbNeeded, LPDWORD pcReturned)
5019 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5020 cbBuf, pcbNeeded, pcReturned, TRUE);
5023 /*****************************************************************************
5024 * EnumPrinterDriversA [WINSPOOL.@]
5026 * see function EnumPrinterDrivers for RETURNS, BUGS
5028 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5029 LPBYTE pDriverInfo, DWORD cbBuf,
5030 LPDWORD pcbNeeded, LPDWORD pcReturned)
5032 UNICODE_STRING pNameW, pEnvironmentW;
5033 PWSTR pwstrNameW, pwstrEnvironmentW;
5035 pwstrNameW = asciitounicode(&pNameW, pName);
5036 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5038 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5039 Level, pDriverInfo, cbBuf, pcbNeeded,
5041 RtlFreeUnicodeString(&pNameW);
5042 RtlFreeUnicodeString(&pEnvironmentW);
5047 /******************************************************************************
5048 * EnumPortsA (WINSPOOL.@)
5053 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5054 LPDWORD pcbNeeded, LPDWORD pcReturned)
5057 LPBYTE bufferW = NULL;
5058 LPWSTR nameW = NULL;
5060 DWORD numentries = 0;
5063 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5064 cbBuf, pcbNeeded, pcReturned);
5066 /* convert servername to unicode */
5068 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5069 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5070 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5072 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5073 needed = cbBuf * sizeof(WCHAR);
5074 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5075 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5077 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5078 if (pcbNeeded) needed = *pcbNeeded;
5079 /* HeapReAlloc return NULL, when bufferW was NULL */
5080 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5081 HeapAlloc(GetProcessHeap(), 0, needed);
5083 /* Try again with the large Buffer */
5084 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5086 needed = pcbNeeded ? *pcbNeeded : 0;
5087 numentries = pcReturned ? *pcReturned : 0;
5090 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5091 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5094 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5095 DWORD entrysize = 0;
5098 LPPORT_INFO_2W pi2w;
5099 LPPORT_INFO_2A pi2a;
5102 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5104 /* First pass: calculate the size for all Entries */
5105 pi2w = (LPPORT_INFO_2W) bufferW;
5106 pi2a = (LPPORT_INFO_2A) pPorts;
5108 while (index < numentries) {
5110 needed += entrysize; /* PORT_INFO_?A */
5111 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5113 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5114 NULL, 0, NULL, NULL);
5116 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5117 NULL, 0, NULL, NULL);
5118 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5119 NULL, 0, NULL, NULL);
5121 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5122 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5123 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5126 /* check for errors and quit on failure */
5127 if (cbBuf < needed) {
5128 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5132 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5133 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5134 cbBuf -= len ; /* free Bytes in the user-Buffer */
5135 pi2w = (LPPORT_INFO_2W) bufferW;
5136 pi2a = (LPPORT_INFO_2A) pPorts;
5138 /* Second Pass: Fill the User Buffer (if we have one) */
5139 while ((index < numentries) && pPorts) {
5141 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5142 pi2a->pPortName = ptr;
5143 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5144 ptr, cbBuf , NULL, NULL);
5148 pi2a->pMonitorName = ptr;
5149 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5150 ptr, cbBuf, NULL, NULL);
5154 pi2a->pDescription = ptr;
5155 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5156 ptr, cbBuf, NULL, NULL);
5160 pi2a->fPortType = pi2w->fPortType;
5161 pi2a->Reserved = 0; /* documented: "must be zero" */
5164 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5165 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5166 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5171 if (pcbNeeded) *pcbNeeded = needed;
5172 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5174 HeapFree(GetProcessHeap(), 0, nameW);
5175 HeapFree(GetProcessHeap(), 0, bufferW);
5177 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5178 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5184 /******************************************************************************
5185 * EnumPortsW (WINSPOOL.@)
5187 * Enumerate available Ports
5190 * name [I] Servername or NULL (local Computer)
5191 * level [I] Structure-Level (1 or 2)
5192 * buffer [O] PTR to Buffer that receives the Result
5193 * bufsize [I] Size of Buffer at buffer
5194 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5195 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5199 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5203 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5206 DWORD numentries = 0;
5209 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5210 cbBuf, pcbNeeded, pcReturned);
5212 if (pName && (pName[0])) {
5213 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5214 SetLastError(ERROR_ACCESS_DENIED);
5218 /* Level is not checked in win9x */
5219 if (!Level || (Level > 2)) {
5220 WARN("level (%d) is ignored in win9x\n", Level);
5221 SetLastError(ERROR_INVALID_LEVEL);
5225 SetLastError(RPC_X_NULL_REF_POINTER);
5229 EnterCriticalSection(&monitor_handles_cs);
5232 /* Scan all local Ports */
5234 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5236 /* we calculated the needed buffersize. now do the error-checks */
5237 if (cbBuf < needed) {
5238 monitor_unloadall();
5239 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5240 goto emP_cleanup_cs;
5242 else if (!pPorts || !pcReturned) {
5243 monitor_unloadall();
5244 SetLastError(RPC_X_NULL_REF_POINTER);
5245 goto emP_cleanup_cs;
5248 /* Fill the Buffer */
5249 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5251 monitor_unloadall();
5254 LeaveCriticalSection(&monitor_handles_cs);
5257 if (pcbNeeded) *pcbNeeded = needed;
5258 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5260 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5261 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5266 /******************************************************************************
5267 * GetDefaultPrinterW (WINSPOOL.@)
5270 * This function must read the value from data 'device' of key
5271 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5273 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5277 WCHAR *buffer, *ptr;
5281 SetLastError(ERROR_INVALID_PARAMETER);
5285 /* make the buffer big enough for the stuff from the profile/registry,
5286 * the content must fit into the local buffer to compute the correct
5287 * size even if the extern buffer is too small or not given.
5288 * (20 for ,driver,port) */
5290 len = max(100, (insize + 20));
5291 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5293 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5295 SetLastError (ERROR_FILE_NOT_FOUND);
5299 TRACE("%s\n", debugstr_w(buffer));
5301 if ((ptr = strchrW(buffer, ',')) == NULL)
5303 SetLastError(ERROR_INVALID_NAME);
5309 *namesize = strlenW(buffer) + 1;
5310 if(!name || (*namesize > insize))
5312 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5316 strcpyW(name, buffer);
5319 HeapFree( GetProcessHeap(), 0, buffer);
5324 /******************************************************************************
5325 * GetDefaultPrinterA (WINSPOOL.@)
5327 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5331 WCHAR *bufferW = NULL;
5335 SetLastError(ERROR_INVALID_PARAMETER);
5339 if(name && *namesize) {
5341 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5344 if(!GetDefaultPrinterW( bufferW, namesize)) {
5349 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5353 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5356 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5359 HeapFree( GetProcessHeap(), 0, bufferW);
5364 /******************************************************************************
5365 * SetDefaultPrinterW (WINSPOOL.204)
5367 * Set the Name of the Default Printer
5370 * pszPrinter [I] Name of the Printer or NULL
5377 * When the Parameter is NULL or points to an Empty String and
5378 * a Default Printer was already present, then this Function changes nothing.
5379 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5380 * the First enumerated local Printer is used.
5383 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5386 TRACE("(%s)\n", debugstr_w(pszPrinter));
5388 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5392 /******************************************************************************
5393 * SetDefaultPrinterA (WINSPOOL.202)
5395 * See SetDefaultPrinterW.
5398 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5401 TRACE("(%s)\n", debugstr_a(pszPrinter));
5403 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5408 /******************************************************************************
5409 * SetPrinterDataExA (WINSPOOL.@)
5411 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5412 LPCSTR pValueName, DWORD Type,
5413 LPBYTE pData, DWORD cbData)
5415 HKEY hkeyPrinter, hkeySubkey;
5418 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5419 debugstr_a(pValueName), Type, pData, cbData);
5421 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5425 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5427 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5428 RegCloseKey(hkeyPrinter);
5431 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5432 RegCloseKey(hkeySubkey);
5433 RegCloseKey(hkeyPrinter);
5437 /******************************************************************************
5438 * SetPrinterDataExW (WINSPOOL.@)
5440 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5441 LPCWSTR pValueName, DWORD Type,
5442 LPBYTE pData, DWORD cbData)
5444 HKEY hkeyPrinter, hkeySubkey;
5447 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5448 debugstr_w(pValueName), Type, pData, cbData);
5450 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5454 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5456 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5457 RegCloseKey(hkeyPrinter);
5460 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5461 RegCloseKey(hkeySubkey);
5462 RegCloseKey(hkeyPrinter);
5466 /******************************************************************************
5467 * SetPrinterDataA (WINSPOOL.@)
5469 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5470 LPBYTE pData, DWORD cbData)
5472 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5476 /******************************************************************************
5477 * SetPrinterDataW (WINSPOOL.@)
5479 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5480 LPBYTE pData, DWORD cbData)
5482 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5486 /******************************************************************************
5487 * GetPrinterDataExA (WINSPOOL.@)
5489 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5490 LPCSTR pValueName, LPDWORD pType,
5491 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5493 HKEY hkeyPrinter, hkeySubkey;
5496 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5497 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5500 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5504 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5506 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5507 RegCloseKey(hkeyPrinter);
5511 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5512 RegCloseKey(hkeySubkey);
5513 RegCloseKey(hkeyPrinter);
5517 /******************************************************************************
5518 * GetPrinterDataExW (WINSPOOL.@)
5520 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5521 LPCWSTR pValueName, LPDWORD pType,
5522 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5524 HKEY hkeyPrinter, hkeySubkey;
5527 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5528 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5531 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5535 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5537 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5538 RegCloseKey(hkeyPrinter);
5542 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5543 RegCloseKey(hkeySubkey);
5544 RegCloseKey(hkeyPrinter);
5548 /******************************************************************************
5549 * GetPrinterDataA (WINSPOOL.@)
5551 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5552 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5554 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5555 pData, nSize, pcbNeeded);
5558 /******************************************************************************
5559 * GetPrinterDataW (WINSPOOL.@)
5561 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5562 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5564 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5565 pData, nSize, pcbNeeded);
5568 /*******************************************************************************
5569 * EnumPrinterDataExW [WINSPOOL.@]
5571 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5572 LPBYTE pEnumValues, DWORD cbEnumValues,
5573 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5575 HKEY hkPrinter, hkSubKey;
5576 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5577 cbValueNameLen, cbMaxValueLen, cbValueLen,
5582 PPRINTER_ENUM_VALUESW ppev;
5584 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5586 if (pKeyName == NULL || *pKeyName == 0)
5587 return ERROR_INVALID_PARAMETER;
5589 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5590 if (ret != ERROR_SUCCESS)
5592 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5597 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5598 if (ret != ERROR_SUCCESS)
5600 r = RegCloseKey (hkPrinter);
5601 if (r != ERROR_SUCCESS)
5602 WARN ("RegCloseKey returned %i\n", r);
5603 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5604 debugstr_w (pKeyName), ret);
5608 ret = RegCloseKey (hkPrinter);
5609 if (ret != ERROR_SUCCESS)
5611 ERR ("RegCloseKey returned %i\n", ret);
5612 r = RegCloseKey (hkSubKey);
5613 if (r != ERROR_SUCCESS)
5614 WARN ("RegCloseKey returned %i\n", r);
5618 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5619 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5620 if (ret != ERROR_SUCCESS)
5622 r = RegCloseKey (hkSubKey);
5623 if (r != ERROR_SUCCESS)
5624 WARN ("RegCloseKey returned %i\n", r);
5625 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5629 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5630 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5632 if (cValues == 0) /* empty key */
5634 r = RegCloseKey (hkSubKey);
5635 if (r != ERROR_SUCCESS)
5636 WARN ("RegCloseKey returned %i\n", r);
5637 *pcbEnumValues = *pnEnumValues = 0;
5638 return ERROR_SUCCESS;
5641 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5643 hHeap = GetProcessHeap ();
5646 ERR ("GetProcessHeap failed\n");
5647 r = RegCloseKey (hkSubKey);
5648 if (r != ERROR_SUCCESS)
5649 WARN ("RegCloseKey returned %i\n", r);
5650 return ERROR_OUTOFMEMORY;
5653 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5654 if (lpValueName == NULL)
5656 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5657 r = RegCloseKey (hkSubKey);
5658 if (r != ERROR_SUCCESS)
5659 WARN ("RegCloseKey returned %i\n", r);
5660 return ERROR_OUTOFMEMORY;
5663 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5664 if (lpValue == NULL)
5666 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5667 if (HeapFree (hHeap, 0, lpValueName) == 0)
5668 WARN ("HeapFree failed with code %i\n", GetLastError ());
5669 r = RegCloseKey (hkSubKey);
5670 if (r != ERROR_SUCCESS)
5671 WARN ("RegCloseKey returned %i\n", r);
5672 return ERROR_OUTOFMEMORY;
5675 TRACE ("pass 1: calculating buffer required for all names and values\n");
5677 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5679 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5681 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5683 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5684 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5685 NULL, NULL, lpValue, &cbValueLen);
5686 if (ret != ERROR_SUCCESS)
5688 if (HeapFree (hHeap, 0, lpValue) == 0)
5689 WARN ("HeapFree failed with code %i\n", GetLastError ());
5690 if (HeapFree (hHeap, 0, lpValueName) == 0)
5691 WARN ("HeapFree failed with code %i\n", GetLastError ());
5692 r = RegCloseKey (hkSubKey);
5693 if (r != ERROR_SUCCESS)
5694 WARN ("RegCloseKey returned %i\n", r);
5695 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5699 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5700 debugstr_w (lpValueName), dwIndex,
5701 cbValueNameLen + 1, cbValueLen);
5703 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5704 cbBufSize += cbValueLen;
5707 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5709 *pcbEnumValues = cbBufSize;
5710 *pnEnumValues = cValues;
5712 if (cbEnumValues < cbBufSize) /* buffer too small */
5714 if (HeapFree (hHeap, 0, lpValue) == 0)
5715 WARN ("HeapFree failed with code %i\n", GetLastError ());
5716 if (HeapFree (hHeap, 0, lpValueName) == 0)
5717 WARN ("HeapFree failed with code %i\n", GetLastError ());
5718 r = RegCloseKey (hkSubKey);
5719 if (r != ERROR_SUCCESS)
5720 WARN ("RegCloseKey returned %i\n", r);
5721 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5722 return ERROR_MORE_DATA;
5725 TRACE ("pass 2: copying all names and values to buffer\n");
5727 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5728 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5730 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5732 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5733 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5734 NULL, &dwType, lpValue, &cbValueLen);
5735 if (ret != ERROR_SUCCESS)
5737 if (HeapFree (hHeap, 0, lpValue) == 0)
5738 WARN ("HeapFree failed with code %i\n", GetLastError ());
5739 if (HeapFree (hHeap, 0, lpValueName) == 0)
5740 WARN ("HeapFree failed with code %i\n", GetLastError ());
5741 r = RegCloseKey (hkSubKey);
5742 if (r != ERROR_SUCCESS)
5743 WARN ("RegCloseKey returned %i\n", r);
5744 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5748 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5749 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5750 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5751 pEnumValues += cbValueNameLen;
5753 /* return # of *bytes* (including trailing \0), not # of chars */
5754 ppev[dwIndex].cbValueName = cbValueNameLen;
5756 ppev[dwIndex].dwType = dwType;
5758 memcpy (pEnumValues, lpValue, cbValueLen);
5759 ppev[dwIndex].pData = pEnumValues;
5760 pEnumValues += cbValueLen;
5762 ppev[dwIndex].cbData = cbValueLen;
5764 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5765 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5768 if (HeapFree (hHeap, 0, lpValue) == 0)
5770 ret = GetLastError ();
5771 ERR ("HeapFree failed with code %i\n", ret);
5772 if (HeapFree (hHeap, 0, lpValueName) == 0)
5773 WARN ("HeapFree failed with code %i\n", GetLastError ());
5774 r = RegCloseKey (hkSubKey);
5775 if (r != ERROR_SUCCESS)
5776 WARN ("RegCloseKey returned %i\n", r);
5780 if (HeapFree (hHeap, 0, lpValueName) == 0)
5782 ret = GetLastError ();
5783 ERR ("HeapFree failed with code %i\n", ret);
5784 r = RegCloseKey (hkSubKey);
5785 if (r != ERROR_SUCCESS)
5786 WARN ("RegCloseKey returned %i\n", r);
5790 ret = RegCloseKey (hkSubKey);
5791 if (ret != ERROR_SUCCESS)
5793 ERR ("RegCloseKey returned %i\n", ret);
5797 return ERROR_SUCCESS;
5800 /*******************************************************************************
5801 * EnumPrinterDataExA [WINSPOOL.@]
5803 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5804 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5805 * what Windows 2000 SP1 does.
5808 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5809 LPBYTE pEnumValues, DWORD cbEnumValues,
5810 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5814 DWORD ret, dwIndex, dwBufSize;
5818 TRACE ("%p %s\n", hPrinter, pKeyName);
5820 if (pKeyName == NULL || *pKeyName == 0)
5821 return ERROR_INVALID_PARAMETER;
5823 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5826 ret = GetLastError ();
5827 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5831 hHeap = GetProcessHeap ();
5834 ERR ("GetProcessHeap failed\n");
5835 return ERROR_OUTOFMEMORY;
5838 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5839 if (pKeyNameW == NULL)
5841 ERR ("Failed to allocate %i bytes from process heap\n",
5842 (LONG)(len * sizeof (WCHAR)));
5843 return ERROR_OUTOFMEMORY;
5846 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5848 ret = GetLastError ();
5849 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5850 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5855 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5856 pcbEnumValues, pnEnumValues);
5857 if (ret != ERROR_SUCCESS)
5859 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5860 WARN ("HeapFree failed with code %i\n", GetLastError ());
5861 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5865 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5867 ret = GetLastError ();
5868 ERR ("HeapFree failed with code %i\n", ret);
5872 if (*pnEnumValues == 0) /* empty key */
5873 return ERROR_SUCCESS;
5876 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5878 PPRINTER_ENUM_VALUESW ppev =
5879 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5881 if (dwBufSize < ppev->cbValueName)
5882 dwBufSize = ppev->cbValueName;
5884 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5885 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5886 dwBufSize = ppev->cbData;
5889 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5891 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5892 if (pBuffer == NULL)
5894 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5895 return ERROR_OUTOFMEMORY;
5898 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5900 PPRINTER_ENUM_VALUESW ppev =
5901 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5903 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5904 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5908 ret = GetLastError ();
5909 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5910 if (HeapFree (hHeap, 0, pBuffer) == 0)
5911 WARN ("HeapFree failed with code %i\n", GetLastError ());
5915 memcpy (ppev->pValueName, pBuffer, len);
5917 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5919 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5920 ppev->dwType != REG_MULTI_SZ)
5923 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5924 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5927 ret = GetLastError ();
5928 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5929 if (HeapFree (hHeap, 0, pBuffer) == 0)
5930 WARN ("HeapFree failed with code %i\n", GetLastError ());
5934 memcpy (ppev->pData, pBuffer, len);
5936 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5937 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5940 if (HeapFree (hHeap, 0, pBuffer) == 0)
5942 ret = GetLastError ();
5943 ERR ("HeapFree failed with code %i\n", ret);
5947 return ERROR_SUCCESS;
5950 /******************************************************************************
5951 * AbortPrinter (WINSPOOL.@)
5953 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5955 FIXME("(%p), stub!\n", hPrinter);
5959 /******************************************************************************
5960 * AddPortA (WINSPOOL.@)
5965 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5967 LPWSTR nameW = NULL;
5968 LPWSTR monitorW = NULL;
5972 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5975 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5976 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5977 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5981 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5982 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5983 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5985 res = AddPortW(nameW, hWnd, monitorW);
5986 HeapFree(GetProcessHeap(), 0, nameW);
5987 HeapFree(GetProcessHeap(), 0, monitorW);
5991 /******************************************************************************
5992 * AddPortW (WINSPOOL.@)
5994 * Add a Port for a specific Monitor
5997 * pName [I] Servername or NULL (local Computer)
5998 * hWnd [I] Handle to parent Window for the Dialog-Box
5999 * pMonitorName [I] Name of the Monitor that manage the Port
6006 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6012 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6014 if (pName && pName[0]) {
6015 SetLastError(ERROR_INVALID_PARAMETER);
6019 if (!pMonitorName) {
6020 SetLastError(RPC_X_NULL_REF_POINTER);
6024 /* an empty Monitorname is Invalid */
6025 if (!pMonitorName[0]) {
6026 SetLastError(ERROR_NOT_SUPPORTED);
6030 pm = monitor_load(pMonitorName, NULL);
6031 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6032 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6033 TRACE("got %d with %u\n", res, GetLastError());
6038 pui = monitor_loadui(pm);
6039 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6040 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6041 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6042 TRACE("got %d with %u\n", res, GetLastError());
6047 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6048 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6050 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6051 SetLastError(ERROR_NOT_SUPPORTED);
6054 monitor_unload(pui);
6056 /* invalidate cached PORT_INFO_2W */
6060 TRACE("returning %d with %u\n", res, GetLastError());
6064 /******************************************************************************
6065 * AddPortExA (WINSPOOL.@)
6070 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
6072 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
6073 lpBuffer, debugstr_a(lpMonitorName));
6077 /******************************************************************************
6078 * AddPortExW (WINSPOOL.@)
6080 * Add a Port for a specific Monitor, without presenting a user interface
6083 * hMonitor [I] Handle from InitializePrintMonitor2()
6084 * pName [I] Servername or NULL (local Computer)
6085 * Level [I] Structure-Level (1 or 2) for lpBuffer
6086 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6087 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
6097 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
6099 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
6100 lpBuffer, debugstr_w(lpMonitorName));
6104 /******************************************************************************
6105 * AddPrinterConnectionA (WINSPOOL.@)
6107 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6109 FIXME("%s\n", debugstr_a(pName));
6113 /******************************************************************************
6114 * AddPrinterConnectionW (WINSPOOL.@)
6116 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6118 FIXME("%s\n", debugstr_w(pName));
6122 /******************************************************************************
6123 * AddPrinterDriverExW (WINSPOOL.@)
6125 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6126 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6128 FIXME("%s %d %p %d\n", debugstr_w(pName),
6129 Level, pDriverInfo, dwFileCopyFlags);
6130 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6134 /******************************************************************************
6135 * AddPrinterDriverExA (WINSPOOL.@)
6137 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6138 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6140 FIXME("%s %d %p %d\n", debugstr_a(pName),
6141 Level, pDriverInfo, dwFileCopyFlags);
6142 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6146 /******************************************************************************
6147 * ConfigurePortA (WINSPOOL.@)
6149 * See ConfigurePortW.
6152 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6154 LPWSTR nameW = NULL;
6155 LPWSTR portW = NULL;
6159 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6161 /* convert servername to unicode */
6163 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6164 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6165 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6168 /* convert portname to unicode */
6170 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6171 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6172 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6175 res = ConfigurePortW(nameW, hWnd, portW);
6176 HeapFree(GetProcessHeap(), 0, nameW);
6177 HeapFree(GetProcessHeap(), 0, portW);
6181 /******************************************************************************
6182 * ConfigurePortW (WINSPOOL.@)
6184 * Display the Configuration-Dialog for a specific Port
6187 * pName [I] Servername or NULL (local Computer)
6188 * hWnd [I] Handle to parent Window for the Dialog-Box
6189 * pPortName [I] Name of the Port, that should be configured
6196 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6202 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6204 if (pName && pName[0]) {
6205 SetLastError(ERROR_INVALID_PARAMETER);
6210 SetLastError(RPC_X_NULL_REF_POINTER);
6214 /* an empty Portname is Invalid, but can popup a Dialog */
6215 if (!pPortName[0]) {
6216 SetLastError(ERROR_NOT_SUPPORTED);
6220 pm = monitor_load_by_port(pPortName);
6221 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6222 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6223 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6224 TRACE("got %d with %u\n", res, GetLastError());
6228 pui = monitor_loadui(pm);
6229 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6230 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6231 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6232 TRACE("got %d with %u\n", res, GetLastError());
6236 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6237 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6239 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6240 SetLastError(ERROR_NOT_SUPPORTED);
6243 monitor_unload(pui);
6247 TRACE("returning %d with %u\n", res, GetLastError());
6251 /******************************************************************************
6252 * ConnectToPrinterDlg (WINSPOOL.@)
6254 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6256 FIXME("%p %x\n", hWnd, Flags);
6260 /******************************************************************************
6261 * DeletePrinterConnectionA (WINSPOOL.@)
6263 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6265 FIXME("%s\n", debugstr_a(pName));
6269 /******************************************************************************
6270 * DeletePrinterConnectionW (WINSPOOL.@)
6272 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6274 FIXME("%s\n", debugstr_w(pName));
6278 /******************************************************************************
6279 * DeletePrinterDriverExW (WINSPOOL.@)
6281 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6282 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6287 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6288 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6290 if(pName && pName[0])
6292 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6293 SetLastError(ERROR_INVALID_PARAMETER);
6299 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6300 SetLastError(ERROR_INVALID_PARAMETER);
6304 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6308 ERR("Can't open drivers key\n");
6312 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6315 RegCloseKey(hkey_drivers);
6320 /******************************************************************************
6321 * DeletePrinterDriverExA (WINSPOOL.@)
6323 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6324 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6326 UNICODE_STRING NameW, EnvW, DriverW;
6329 asciitounicode(&NameW, pName);
6330 asciitounicode(&EnvW, pEnvironment);
6331 asciitounicode(&DriverW, pDriverName);
6333 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6335 RtlFreeUnicodeString(&DriverW);
6336 RtlFreeUnicodeString(&EnvW);
6337 RtlFreeUnicodeString(&NameW);
6342 /******************************************************************************
6343 * DeletePrinterDataExW (WINSPOOL.@)
6345 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6348 FIXME("%p %s %s\n", hPrinter,
6349 debugstr_w(pKeyName), debugstr_w(pValueName));
6350 return ERROR_INVALID_PARAMETER;
6353 /******************************************************************************
6354 * DeletePrinterDataExA (WINSPOOL.@)
6356 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6359 FIXME("%p %s %s\n", hPrinter,
6360 debugstr_a(pKeyName), debugstr_a(pValueName));
6361 return ERROR_INVALID_PARAMETER;
6364 /******************************************************************************
6365 * DeletePrintProcessorA (WINSPOOL.@)
6367 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6369 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6370 debugstr_a(pPrintProcessorName));
6374 /******************************************************************************
6375 * DeletePrintProcessorW (WINSPOOL.@)
6377 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6379 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6380 debugstr_w(pPrintProcessorName));
6384 /******************************************************************************
6385 * DeletePrintProvidorA (WINSPOOL.@)
6387 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6389 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6390 debugstr_a(pPrintProviderName));
6394 /******************************************************************************
6395 * DeletePrintProvidorW (WINSPOOL.@)
6397 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6399 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6400 debugstr_w(pPrintProviderName));
6404 /******************************************************************************
6405 * EnumFormsA (WINSPOOL.@)
6407 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6408 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6410 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6411 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6415 /******************************************************************************
6416 * EnumFormsW (WINSPOOL.@)
6418 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6419 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6421 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6422 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6426 /*****************************************************************************
6427 * EnumMonitorsA [WINSPOOL.@]
6429 * See EnumMonitorsW.
6432 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6433 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6436 LPBYTE bufferW = NULL;
6437 LPWSTR nameW = NULL;
6439 DWORD numentries = 0;
6442 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6443 cbBuf, pcbNeeded, pcReturned);
6445 /* convert servername to unicode */
6447 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6448 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6449 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6451 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6452 needed = cbBuf * sizeof(WCHAR);
6453 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6454 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6456 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6457 if (pcbNeeded) needed = *pcbNeeded;
6458 /* HeapReAlloc return NULL, when bufferW was NULL */
6459 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6460 HeapAlloc(GetProcessHeap(), 0, needed);
6462 /* Try again with the large Buffer */
6463 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6465 numentries = pcReturned ? *pcReturned : 0;
6468 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6469 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6472 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6473 DWORD entrysize = 0;
6476 LPMONITOR_INFO_2W mi2w;
6477 LPMONITOR_INFO_2A mi2a;
6479 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6480 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6482 /* First pass: calculate the size for all Entries */
6483 mi2w = (LPMONITOR_INFO_2W) bufferW;
6484 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6486 while (index < numentries) {
6488 needed += entrysize; /* MONITOR_INFO_?A */
6489 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6491 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6492 NULL, 0, NULL, NULL);
6494 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6495 NULL, 0, NULL, NULL);
6496 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6497 NULL, 0, NULL, NULL);
6499 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6500 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6501 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6504 /* check for errors and quit on failure */
6505 if (cbBuf < needed) {
6506 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6510 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6511 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6512 cbBuf -= len ; /* free Bytes in the user-Buffer */
6513 mi2w = (LPMONITOR_INFO_2W) bufferW;
6514 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6516 /* Second Pass: Fill the User Buffer (if we have one) */
6517 while ((index < numentries) && pMonitors) {
6519 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6521 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6522 ptr, cbBuf , NULL, NULL);
6526 mi2a->pEnvironment = ptr;
6527 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6528 ptr, cbBuf, NULL, NULL);
6532 mi2a->pDLLName = ptr;
6533 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6534 ptr, cbBuf, NULL, NULL);
6538 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6539 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6540 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6544 if (pcbNeeded) *pcbNeeded = needed;
6545 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6547 HeapFree(GetProcessHeap(), 0, nameW);
6548 HeapFree(GetProcessHeap(), 0, bufferW);
6550 TRACE("returning %d with %d (%d byte for %d entries)\n",
6551 (res), GetLastError(), needed, numentries);
6557 /*****************************************************************************
6558 * EnumMonitorsW [WINSPOOL.@]
6560 * Enumerate available Port-Monitors
6563 * pName [I] Servername or NULL (local Computer)
6564 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6565 * pMonitors [O] PTR to Buffer that receives the Result
6566 * cbBuf [I] Size of Buffer at pMonitors
6567 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6568 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6572 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6575 * Windows reads the Registry once and cache the Results.
6577 *| Language-Monitors are also installed in the same Registry-Location but
6578 *| they are filtered in Windows (not returned by EnumMonitors).
6579 *| We do no filtering to simplify our Code.
6582 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6583 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6586 DWORD numentries = 0;
6589 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6590 cbBuf, pcbNeeded, pcReturned);
6592 if (pName && (lstrlenW(pName))) {
6593 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6594 SetLastError(ERROR_ACCESS_DENIED);
6598 /* Level is not checked in win9x */
6599 if (!Level || (Level > 2)) {
6600 WARN("level (%d) is ignored in win9x\n", Level);
6601 SetLastError(ERROR_INVALID_LEVEL);
6605 SetLastError(RPC_X_NULL_REF_POINTER);
6609 /* Scan all Monitor-Keys */
6611 needed = get_local_monitors(Level, NULL, 0, &numentries);
6613 /* we calculated the needed buffersize. now do the error-checks */
6614 if (cbBuf < needed) {
6615 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6618 else if (!pMonitors || !pcReturned) {
6619 SetLastError(RPC_X_NULL_REF_POINTER);
6623 /* fill the Buffer with the Monitor-Keys */
6624 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6628 if (pcbNeeded) *pcbNeeded = needed;
6629 if (pcReturned) *pcReturned = numentries;
6631 TRACE("returning %d with %d (%d byte for %d entries)\n",
6632 res, GetLastError(), needed, numentries);
6637 /******************************************************************************
6638 * XcvDataW (WINSPOOL.@)
6640 * Execute commands in the Printmonitor DLL
6643 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6644 * pszDataName [i] Name of the command to execute
6645 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6646 * cbInputData [i] Size in Bytes of Buffer at pInputData
6647 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6648 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6649 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6650 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6657 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6658 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6660 * Minimal List of commands, that a Printmonitor DLL should support:
6662 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6663 *| "AddPort" : Add a Port
6664 *| "DeletePort": Delete a Port
6666 * Many Printmonitors support additional commands. Examples for localspl.dll:
6667 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6668 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6671 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6672 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6673 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6675 opened_printer_t *printer;
6677 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6678 pInputData, cbInputData, pOutputData,
6679 cbOutputData, pcbOutputNeeded, pdwStatus);
6681 printer = get_opened_printer(hXcv);
6682 if (!printer || (!printer->hXcv)) {
6683 SetLastError(ERROR_INVALID_HANDLE);
6687 if (!pcbOutputNeeded) {
6688 SetLastError(ERROR_INVALID_PARAMETER);
6692 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6693 SetLastError(RPC_X_NULL_REF_POINTER);
6697 *pcbOutputNeeded = 0;
6699 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6700 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6705 /*****************************************************************************
6706 * EnumPrinterDataA [WINSPOOL.@]
6709 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6710 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6711 DWORD cbData, LPDWORD pcbData )
6713 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6714 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6715 return ERROR_NO_MORE_ITEMS;
6718 /*****************************************************************************
6719 * EnumPrinterDataW [WINSPOOL.@]
6722 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6723 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6724 DWORD cbData, LPDWORD pcbData )
6726 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6727 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6728 return ERROR_NO_MORE_ITEMS;
6731 /*****************************************************************************
6732 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6735 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6736 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6737 LPDWORD pcbNeeded, LPDWORD pcReturned)
6739 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6740 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6741 pcbNeeded, pcReturned);
6745 /*****************************************************************************
6746 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6749 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6750 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6751 LPDWORD pcbNeeded, LPDWORD pcReturned)
6753 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6754 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6755 pcbNeeded, pcReturned);
6759 /*****************************************************************************
6760 * EnumPrintProcessorsA [WINSPOOL.@]
6763 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6764 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6766 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6767 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6771 /*****************************************************************************
6772 * EnumPrintProcessorsW [WINSPOOL.@]
6775 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6776 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6778 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6779 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6780 cbBuf, pcbNeeded, pcbReturned);
6784 /*****************************************************************************
6785 * ExtDeviceMode [WINSPOOL.@]
6788 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6789 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6792 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6793 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6794 debugstr_a(pProfile), fMode);
6798 /*****************************************************************************
6799 * FindClosePrinterChangeNotification [WINSPOOL.@]
6802 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6804 FIXME("Stub: %p\n", hChange);
6808 /*****************************************************************************
6809 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6812 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6813 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6815 FIXME("Stub: %p %x %x %p\n",
6816 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6817 return INVALID_HANDLE_VALUE;
6820 /*****************************************************************************
6821 * FindNextPrinterChangeNotification [WINSPOOL.@]
6824 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6825 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6827 FIXME("Stub: %p %p %p %p\n",
6828 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6832 /*****************************************************************************
6833 * FreePrinterNotifyInfo [WINSPOOL.@]
6836 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6838 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6842 /*****************************************************************************
6845 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6846 * ansi depending on the unicode parameter.
6848 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6858 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6861 memcpy(ptr, str, *size);
6868 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6871 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6878 /*****************************************************************************
6881 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6882 LPDWORD pcbNeeded, BOOL unicode)
6884 DWORD size, left = cbBuf;
6885 BOOL space = (cbBuf > 0);
6892 ji1->JobId = job->job_id;
6895 string_to_buf(job->document_title, ptr, left, &size, unicode);
6896 if(space && size <= left)
6898 ji1->pDocument = (LPWSTR)ptr;
6909 /*****************************************************************************
6912 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6913 LPDWORD pcbNeeded, BOOL unicode)
6915 DWORD size, left = cbBuf;
6916 BOOL space = (cbBuf > 0);
6923 ji2->JobId = job->job_id;
6926 string_to_buf(job->document_title, ptr, left, &size, unicode);
6927 if(space && size <= left)
6929 ji2->pDocument = (LPWSTR)ptr;
6940 /*****************************************************************************
6943 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6944 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6947 DWORD needed = 0, size;
6951 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6953 EnterCriticalSection(&printer_handles_cs);
6954 job = get_job(hPrinter, JobId);
6961 size = sizeof(JOB_INFO_1W);
6966 memset(pJob, 0, size);
6970 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6975 size = sizeof(JOB_INFO_2W);
6980 memset(pJob, 0, size);
6984 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6989 size = sizeof(JOB_INFO_3);
6993 memset(pJob, 0, size);
7002 SetLastError(ERROR_INVALID_LEVEL);
7006 *pcbNeeded = needed;
7008 LeaveCriticalSection(&printer_handles_cs);
7012 /*****************************************************************************
7013 * GetJobA [WINSPOOL.@]
7016 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7017 DWORD cbBuf, LPDWORD pcbNeeded)
7019 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7022 /*****************************************************************************
7023 * GetJobW [WINSPOOL.@]
7026 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7027 DWORD cbBuf, LPDWORD pcbNeeded)
7029 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7032 /*****************************************************************************
7035 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7037 char *unixname, *queue, *cmd;
7038 char fmt[] = "lpr -P%s %s";
7041 if(!(unixname = wine_get_unix_file_name(filename)))
7044 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7045 queue = HeapAlloc(GetProcessHeap(), 0, len);
7046 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7048 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7049 sprintf(cmd, fmt, queue, unixname);
7051 TRACE("printing with: %s\n", cmd);
7054 HeapFree(GetProcessHeap(), 0, cmd);
7055 HeapFree(GetProcessHeap(), 0, queue);
7056 HeapFree(GetProcessHeap(), 0, unixname);
7060 /*****************************************************************************
7063 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7065 #if HAVE_CUPS_CUPS_H
7068 char *unixname, *queue, *doc_titleA;
7072 if(!(unixname = wine_get_unix_file_name(filename)))
7075 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7076 queue = HeapAlloc(GetProcessHeap(), 0, len);
7077 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7079 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7080 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7081 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7083 TRACE("printing via cups\n");
7084 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7085 HeapFree(GetProcessHeap(), 0, doc_titleA);
7086 HeapFree(GetProcessHeap(), 0, queue);
7087 HeapFree(GetProcessHeap(), 0, unixname);
7093 return schedule_lpr(printer_name, filename);
7097 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7104 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7108 if(HIWORD(wparam) == BN_CLICKED)
7110 if(LOWORD(wparam) == IDOK)
7113 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7116 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7117 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7119 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7121 WCHAR caption[200], message[200];
7124 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7125 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7126 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7127 if(mb_ret == IDCANCEL)
7129 HeapFree(GetProcessHeap(), 0, filename);
7133 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7134 if(hf == INVALID_HANDLE_VALUE)
7136 WCHAR caption[200], message[200];
7138 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7139 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7140 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7141 HeapFree(GetProcessHeap(), 0, filename);
7145 DeleteFileW(filename);
7146 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7148 EndDialog(hwnd, IDOK);
7151 if(LOWORD(wparam) == IDCANCEL)
7153 EndDialog(hwnd, IDCANCEL);
7162 /*****************************************************************************
7165 static BOOL get_filename(LPWSTR *filename)
7167 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7168 file_dlg_proc, (LPARAM)filename) == IDOK;
7171 /*****************************************************************************
7174 static BOOL schedule_file(LPCWSTR filename)
7176 LPWSTR output = NULL;
7178 if(get_filename(&output))
7180 TRACE("copy to %s\n", debugstr_w(output));
7181 CopyFileW(filename, output, FALSE);
7182 HeapFree(GetProcessHeap(), 0, output);
7188 /*****************************************************************************
7191 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7194 char *unixname, *cmdA;
7196 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7200 if(!(unixname = wine_get_unix_file_name(filename)))
7203 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7204 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7205 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7207 TRACE("printing with: %s\n", cmdA);
7209 if((file_fd = open(unixname, O_RDONLY)) == -1)
7214 ERR("pipe() failed!\n");
7224 /* reset signals that we previously set to SIG_IGN */
7225 signal(SIGPIPE, SIG_DFL);
7226 signal(SIGCHLD, SIG_DFL);
7232 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7233 write(fds[1], buf, no_read);
7238 if(file_fd != -1) close(file_fd);
7239 if(fds[0] != -1) close(fds[0]);
7240 if(fds[1] != -1) close(fds[1]);
7242 HeapFree(GetProcessHeap(), 0, cmdA);
7243 HeapFree(GetProcessHeap(), 0, unixname);
7250 /*****************************************************************************
7253 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7255 int in_fd, out_fd, no_read;
7258 char *unixname, *outputA;
7261 if(!(unixname = wine_get_unix_file_name(filename)))
7264 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7265 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7266 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7268 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7269 in_fd = open(unixname, O_RDONLY);
7270 if(out_fd == -1 || in_fd == -1)
7273 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7274 write(out_fd, buf, no_read);
7278 if(in_fd != -1) close(in_fd);
7279 if(out_fd != -1) close(out_fd);
7280 HeapFree(GetProcessHeap(), 0, outputA);
7281 HeapFree(GetProcessHeap(), 0, unixname);
7285 /*****************************************************************************
7286 * ScheduleJob [WINSPOOL.@]
7289 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7291 opened_printer_t *printer;
7293 struct list *cursor, *cursor2;
7295 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7296 EnterCriticalSection(&printer_handles_cs);
7297 printer = get_opened_printer(hPrinter);
7301 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7303 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7306 if(job->job_id != dwJobID) continue;
7308 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7309 if(hf != INVALID_HANDLE_VALUE)
7311 PRINTER_INFO_5W *pi5;
7315 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7316 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7318 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7319 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7320 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7321 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7322 debugstr_w(pi5->pPortName));
7326 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7327 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7329 DWORD type, count = sizeof(output);
7330 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7333 if(output[0] == '|')
7335 schedule_pipe(output + 1, job->filename);
7339 schedule_unixfile(output, job->filename);
7341 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7343 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7345 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7347 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7349 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7351 schedule_file(job->filename);
7355 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7357 HeapFree(GetProcessHeap(), 0, pi5);
7359 DeleteFileW(job->filename);
7361 list_remove(cursor);
7362 HeapFree(GetProcessHeap(), 0, job->document_title);
7363 HeapFree(GetProcessHeap(), 0, job->filename);
7364 HeapFree(GetProcessHeap(), 0, job);
7369 LeaveCriticalSection(&printer_handles_cs);
7373 /*****************************************************************************
7374 * StartDocDlgA [WINSPOOL.@]
7376 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7378 UNICODE_STRING usBuffer;
7381 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7384 docW.cbSize = sizeof(docW);
7385 if (doc->lpszDocName)
7387 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7388 if (!(docW.lpszDocName = docnameW)) return NULL;
7390 if (doc->lpszOutput)
7392 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7393 if (!(docW.lpszOutput = outputW)) return NULL;
7395 if (doc->lpszDatatype)
7397 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7398 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7400 docW.fwType = doc->fwType;
7402 retW = StartDocDlgW(hPrinter, &docW);
7406 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7407 ret = HeapAlloc(GetProcessHeap(), 0, len);
7408 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7409 HeapFree(GetProcessHeap(), 0, retW);
7412 HeapFree(GetProcessHeap(), 0, datatypeW);
7413 HeapFree(GetProcessHeap(), 0, outputW);
7414 HeapFree(GetProcessHeap(), 0, docnameW);
7419 /*****************************************************************************
7420 * StartDocDlgW [WINSPOOL.@]
7422 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7423 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7424 * port is "FILE:". Also returns the full path if passed a relative path.
7426 * The caller should free the returned string from the process heap.
7428 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7433 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7435 PRINTER_INFO_5W *pi5;
7436 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7437 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7439 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7440 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7441 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7443 HeapFree(GetProcessHeap(), 0, pi5);
7446 HeapFree(GetProcessHeap(), 0, pi5);
7449 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7453 if (get_filename(&name))
7455 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7457 HeapFree(GetProcessHeap(), 0, name);
7460 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7461 GetFullPathNameW(name, len, ret, NULL);
7462 HeapFree(GetProcessHeap(), 0, name);
7467 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7470 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7471 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7473 attr = GetFileAttributesW(ret);
7474 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7476 HeapFree(GetProcessHeap(), 0, ret);