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};
252 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
253 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
254 DWORD Level, LPBYTE pDriverInfo,
255 DWORD cbBuf, LPDWORD pcbNeeded,
257 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
258 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
260 /******************************************************************
261 * validate the user-supplied printing-environment [internal]
264 * env [I] PTR to Environment-String or NULL
268 * Success: PTR to printenv_t
271 * An empty string is handled the same way as NULL.
272 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
276 static const printenv_t * validate_envW(LPCWSTR env)
278 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
279 3, Version3_RegPathW, Version3_SubdirW};
280 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
281 0, emptyStringW, emptyStringW};
282 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
284 const printenv_t *result = NULL;
287 TRACE("testing %s\n", debugstr_w(env));
290 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
292 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
294 result = all_printenv[i];
299 if (result == NULL) {
300 FIXME("unsupported Environment: %s\n", debugstr_w(env));
301 SetLastError(ERROR_INVALID_ENVIRONMENT);
303 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
307 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
309 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
315 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
316 if passed a NULL string. This returns NULLs to the result.
318 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
322 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
323 return usBufferPtr->Buffer;
325 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
329 static LPWSTR strdupW(LPCWSTR p)
335 len = (strlenW(p) + 1) * sizeof(WCHAR);
336 ret = HeapAlloc(GetProcessHeap(), 0, len);
341 static LPSTR strdupWtoA( LPCWSTR str )
346 if (!str) return NULL;
347 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
348 ret = HeapAlloc( GetProcessHeap(), 0, len );
349 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
353 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
354 The result includes all \0s (specifically the last two). */
355 static int multi_sz_lenA(const char *str)
357 const char *ptr = str;
361 ptr += lstrlenA(ptr) + 1;
364 return ptr - str + 1;
368 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
371 /* If forcing, or no profile string entry for device yet, set the entry
373 * The always change entry if not WINEPS yet is discussable.
376 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
378 !strstr(qbuf,"WINEPS.DRV")
380 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
383 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
384 WriteProfileStringA("windows","device",buf);
385 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
386 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
389 HeapFree(GetProcessHeap(),0,buf);
393 static BOOL add_printer_driver(char *name)
397 static char driver_path[] = "wineps16",
398 data_file[] = "<datafile?>",
399 config_file[] = "wineps16",
400 help_file[] = "<helpfile?>",
401 dep_file[] = "<dependent files?>\0",
402 monitor_name[] = "<monitor name?>",
403 default_data_type[] = "RAW";
405 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
406 di3a.pName = (char *)name;
407 di3a.pEnvironment = NULL; /* NULL means auto */
408 di3a.pDriverPath = driver_path;
409 di3a.pDataFile = data_file;
410 di3a.pConfigFile = config_file;
411 di3a.pHelpFile = help_file;
412 di3a.pDependentFiles = dep_file;
413 di3a.pMonitorName = monitor_name;
414 di3a.pDefaultDataType = default_data_type;
416 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
418 ERR("Failed adding driver (%d)\n", GetLastError());
424 #ifdef HAVE_CUPS_CUPS_H
425 static typeof(cupsGetDests) *pcupsGetDests;
426 static typeof(cupsGetPPD) *pcupsGetPPD;
427 static typeof(cupsPrintFile) *pcupsPrintFile;
428 static void *cupshandle;
430 static BOOL CUPS_LoadPrinters(void)
433 BOOL hadprinter = FALSE;
435 PRINTER_INFO_2A pinfo2a;
437 HKEY hkeyPrinter, hkeyPrinters, hkey;
439 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
442 TRACE("loaded %s\n", SONAME_LIBCUPS);
445 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
446 if (!p##x) return FALSE;
449 DYNCUPS(cupsGetDests);
450 DYNCUPS(cupsPrintFile);
453 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
455 ERR("Can't create Printers key\n");
459 nrofdests = pcupsGetDests(&dests);
460 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
461 for (i=0;i<nrofdests;i++) {
462 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
463 sprintf(port,"LPR:%s",dests[i].name);
464 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
465 sprintf(devline,"WINEPS.DRV,%s",port);
466 WriteProfileStringA("devices",dests[i].name,devline);
467 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
468 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
471 HeapFree(GetProcessHeap(),0,devline);
473 TRACE("Printer %d: %s\n", i, dests[i].name);
474 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
475 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
477 TRACE("Printer already exists\n");
478 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
479 RegCloseKey(hkeyPrinter);
481 static CHAR data_type[] = "RAW",
482 print_proc[] = "WinPrint",
483 comment[] = "WINEPS Printer using CUPS",
484 location[] = "<physical location of printer>",
485 params[] = "<parameters?>",
486 share_name[] = "<share name?>",
487 sep_file[] = "<sep file?>";
489 add_printer_driver(dests[i].name);
491 memset(&pinfo2a,0,sizeof(pinfo2a));
492 pinfo2a.pPrinterName = dests[i].name;
493 pinfo2a.pDatatype = data_type;
494 pinfo2a.pPrintProcessor = print_proc;
495 pinfo2a.pDriverName = dests[i].name;
496 pinfo2a.pComment = comment;
497 pinfo2a.pLocation = location;
498 pinfo2a.pPortName = port;
499 pinfo2a.pParameters = params;
500 pinfo2a.pShareName = share_name;
501 pinfo2a.pSepFile = sep_file;
503 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
504 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
505 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
508 HeapFree(GetProcessHeap(),0,port);
511 if (dests[i].is_default)
512 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
514 RegCloseKey(hkeyPrinters);
520 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
521 PRINTER_INFO_2A pinfo2a;
522 char *e,*s,*name,*prettyname,*devname;
523 BOOL ret = FALSE, set_default = FALSE;
524 char *port,*devline,*env_default;
525 HKEY hkeyPrinter, hkeyPrinters, hkey;
527 while (isspace(*pent)) pent++;
528 s = strchr(pent,':');
530 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
538 TRACE("name=%s entry=%s\n",name, pent);
540 if(ispunct(*name)) { /* a tc entry, not a real printer */
541 TRACE("skipping tc entry\n");
545 if(strstr(pent,":server")) { /* server only version so skip */
546 TRACE("skipping server entry\n");
550 /* Determine whether this is a postscript printer. */
553 env_default = getenv("PRINTER");
555 /* Get longest name, usually the one at the right for later display. */
556 while((s=strchr(prettyname,'|'))) {
559 while(isspace(*--e)) *e = '\0';
560 TRACE("\t%s\n", debugstr_a(prettyname));
561 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
562 for(prettyname = s+1; isspace(*prettyname); prettyname++)
565 e = prettyname + strlen(prettyname);
566 while(isspace(*--e)) *e = '\0';
567 TRACE("\t%s\n", debugstr_a(prettyname));
568 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
570 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
571 * if it is too long, we use it as comment below. */
572 devname = prettyname;
573 if (strlen(devname)>=CCHDEVICENAME-1)
575 if (strlen(devname)>=CCHDEVICENAME-1) {
580 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
581 sprintf(port,"LPR:%s",name);
583 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
584 sprintf(devline,"WINEPS.DRV,%s",port);
585 WriteProfileStringA("devices",devname,devline);
586 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
587 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
590 HeapFree(GetProcessHeap(),0,devline);
592 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
594 ERR("Can't create Printers key\n");
598 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
599 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
601 TRACE("Printer already exists\n");
602 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
603 RegCloseKey(hkeyPrinter);
605 static CHAR data_type[] = "RAW",
606 print_proc[] = "WinPrint",
607 comment[] = "WINEPS Printer using LPR",
608 params[] = "<parameters?>",
609 share_name[] = "<share name?>",
610 sep_file[] = "<sep file?>";
612 add_printer_driver(devname);
614 memset(&pinfo2a,0,sizeof(pinfo2a));
615 pinfo2a.pPrinterName = devname;
616 pinfo2a.pDatatype = data_type;
617 pinfo2a.pPrintProcessor = print_proc;
618 pinfo2a.pDriverName = devname;
619 pinfo2a.pComment = comment;
620 pinfo2a.pLocation = prettyname;
621 pinfo2a.pPortName = port;
622 pinfo2a.pParameters = params;
623 pinfo2a.pShareName = share_name;
624 pinfo2a.pSepFile = sep_file;
626 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
627 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
628 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
631 RegCloseKey(hkeyPrinters);
633 if (isfirst || set_default)
634 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
636 HeapFree(GetProcessHeap(), 0, port);
638 HeapFree(GetProcessHeap(), 0, name);
643 PRINTCAP_LoadPrinters(void) {
644 BOOL hadprinter = FALSE;
648 BOOL had_bash = FALSE;
650 f = fopen("/etc/printcap","r");
654 while(fgets(buf,sizeof(buf),f)) {
657 end=strchr(buf,'\n');
661 while(isspace(*start)) start++;
662 if(*start == '#' || *start == '\0')
665 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
666 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
667 HeapFree(GetProcessHeap(),0,pent);
671 if (end && *--end == '\\') {
678 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
681 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
687 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
688 HeapFree(GetProcessHeap(),0,pent);
694 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
697 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
698 (lstrlenW(value) + 1) * sizeof(WCHAR));
700 return ERROR_FILE_NOT_FOUND;
703 void WINSPOOL_LoadSystemPrinters(void)
705 HKEY hkey, hkeyPrinters;
707 DWORD needed, num, i;
708 WCHAR PrinterName[256];
711 /* This ensures that all printer entries have a valid Name value. If causes
712 problems later if they don't. If one is found to be missed we create one
713 and set it equal to the name of the key */
714 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
715 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
716 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
717 for(i = 0; i < num; i++) {
718 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
719 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
720 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
721 set_reg_szW(hkey, NameW, PrinterName);
728 RegCloseKey(hkeyPrinters);
731 /* We want to avoid calling AddPrinter on printers as much as
732 possible, because on cups printers this will (eventually) lead
733 to a call to cupsGetPPD which takes forever, even with non-cups
734 printers AddPrinter takes a while. So we'll tag all printers that
735 were automatically added last time around, if they still exist
736 we'll leave them be otherwise we'll delete them. */
737 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
739 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
740 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
741 for(i = 0; i < num; i++) {
742 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
743 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
744 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
746 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
754 HeapFree(GetProcessHeap(), 0, pi);
758 #ifdef HAVE_CUPS_CUPS_H
759 done = CUPS_LoadPrinters();
762 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
763 /* Check for [ppd] section in config file before parsing /etc/printcap */
764 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
765 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
766 &hkey) == ERROR_SUCCESS) {
768 PRINTCAP_LoadPrinters();
772 /* Now enumerate the list again and delete any printers that a still tagged */
773 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
775 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
776 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
777 for(i = 0; i < num; i++) {
778 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
779 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
780 BOOL delete_driver = FALSE;
781 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
782 DWORD dw, type, size = sizeof(dw);
783 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
784 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
786 delete_driver = TRUE;
792 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
797 HeapFree(GetProcessHeap(), 0, pi);
804 /*****************************************************************************
805 * enumerate the local monitors (INTERNAL)
807 * returns the needed size (in bytes) for pMonitors
808 * and *lpreturned is set to number of entries returned in pMonitors
811 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
816 LPMONITOR_INFO_2W mi;
817 WCHAR buffer[MAX_PATH];
818 WCHAR dllname[MAX_PATH];
826 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
828 numentries = *lpreturned; /* this is 0, when we scan the registry */
829 len = entrysize * numentries;
830 ptr = (LPWSTR) &pMonitors[len];
833 len = sizeof(buffer);
836 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
837 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
838 /* Scan all Monitor-Registry-Keys */
839 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
840 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
841 dllsize = sizeof(dllname);
844 /* The Monitor must have a Driver-DLL */
845 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
846 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
847 /* We found a valid DLL for this Monitor. */
848 TRACE("using Driver: %s\n", debugstr_w(dllname));
853 /* Windows returns only Port-Monitors here, but to simplify our code,
854 we do no filtering for Language-Monitors */
858 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
860 /* we install and return only monitors for "Windows NT x86" */
861 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
865 /* required size is calculated. Now fill the user-buffer */
866 if (pMonitors && (cbBuf >= needed)){
867 mi = (LPMONITOR_INFO_2W) pMonitors;
868 pMonitors += entrysize;
870 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
872 lstrcpyW(ptr, buffer); /* Name of the Monitor */
873 ptr += (len+1); /* len is lstrlenW(monitorname) */
875 mi->pEnvironment = ptr;
876 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
877 ptr += (lstrlenW(envname_x86W)+1);
880 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
881 ptr += (dllsize / sizeof(WCHAR));
886 len = sizeof(buffer);
891 *lpreturned = numentries;
892 TRACE("need %d byte for %d entries\n", needed, numentries);
896 /******************************************************************
897 * monitor_flush [internal]
899 * flush the cached PORT_INFO_2W - data
902 void monitor_flush(monitor_t * pm)
906 EnterCriticalSection(&monitor_handles_cs);
908 TRACE("%p (%s) cache: %p (%d, %d)\n", pm, debugstr_w(pm->name), pm->cache, pm->pi1_needed, pm->pi2_needed);
910 HeapFree(GetProcessHeap(), 0, pm->cache);
915 LeaveCriticalSection(&monitor_handles_cs);
918 /******************************************************************
919 * monitor_unload [internal]
921 * release a printmonitor and unload it from memory, when needed
924 static void monitor_unload(monitor_t * pm)
926 if (pm == NULL) return;
927 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
929 EnterCriticalSection(&monitor_handles_cs);
931 if (pm->refcount) pm->refcount--;
933 if (pm->refcount == 0) {
934 list_remove(&pm->entry);
935 FreeLibrary(pm->hdll);
936 HeapFree(GetProcessHeap(), 0, pm->name);
937 HeapFree(GetProcessHeap(), 0, pm->dllname);
938 HeapFree(GetProcessHeap(), 0, pm);
940 LeaveCriticalSection(&monitor_handles_cs);
943 /******************************************************************
944 * monitor_unloadall [internal]
946 * release all printmonitors and unload them from memory, when needed
949 static void monitor_unloadall(void)
954 EnterCriticalSection(&monitor_handles_cs);
955 /* iterate through the list, with safety against removal */
956 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
960 LeaveCriticalSection(&monitor_handles_cs);
963 /******************************************************************
964 * monitor_load [internal]
966 * load a printmonitor, get the dllname from the registry, when needed
967 * initialize the monitor and dump found function-pointers
969 * On failure, SetLastError() is called and NULL is returned
972 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
974 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
975 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
976 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
977 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
978 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
980 monitor_t * pm = NULL;
982 LPWSTR regroot = NULL;
983 LPWSTR driver = dllname;
985 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
986 /* Is the Monitor already loaded? */
987 EnterCriticalSection(&monitor_handles_cs);
990 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
992 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
1000 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
1001 if (pm == NULL) goto cleanup;
1002 list_add_tail(&monitor_handles, &pm->entry);
1006 if (pm->name == NULL) {
1007 /* Load the monitor */
1008 LPMONITOREX pmonitorEx;
1012 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
1013 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1017 lstrcpyW(regroot, MonitorsW);
1018 lstrcatW(regroot, name);
1019 /* Get the Driver from the Registry */
1020 if (driver == NULL) {
1023 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
1024 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
1025 &namesize) == ERROR_SUCCESS) {
1026 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
1027 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
1034 pm->name = strdupW(name);
1035 pm->dllname = strdupW(driver);
1037 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
1039 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1044 pm->hdll = LoadLibraryW(driver);
1045 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
1047 if (pm->hdll == NULL) {
1049 SetLastError(ERROR_MOD_NOT_FOUND);
1054 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
1055 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1056 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1057 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1058 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1061 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1062 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1063 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1064 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1065 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1067 if (pInitializePrintMonitorUI != NULL) {
1068 pm->monitorUI = pInitializePrintMonitorUI();
1069 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1070 if (pm->monitorUI) {
1071 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1072 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1077 if (pInitializePrintMonitor && regroot) {
1078 pmonitorEx = pInitializePrintMonitor(regroot);
1079 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1080 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1083 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1084 pm->monitor = &(pmonitorEx->Monitor);
1089 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1093 if (!pm->monitor && regroot) {
1094 if (pInitializePrintMonitor2 != NULL) {
1095 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1097 if (pInitializeMonitorEx != NULL) {
1098 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1100 if (pInitializeMonitor != NULL) {
1101 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1104 if (!pm->monitor && !pm->monitorUI) {
1106 SetLastError(ERROR_PROC_NOT_FOUND);
1111 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1115 LeaveCriticalSection(&monitor_handles_cs);
1116 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1117 HeapFree(GetProcessHeap(), 0, regroot);
1118 TRACE("=> %p\n", pm);
1122 /******************************************************************
1123 * monitor_loadall [internal]
1125 * Load all registered monitors
1128 static DWORD monitor_loadall(void)
1131 DWORD registered = 0;
1134 WCHAR buffer[MAX_PATH];
1137 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1138 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1139 NULL, NULL, NULL, NULL, NULL);
1141 TRACE("%d monitors registered\n", registered);
1143 EnterCriticalSection(&monitor_handles_cs);
1144 while (id < registered) {
1146 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1147 pm = monitor_load(buffer, NULL);
1151 LeaveCriticalSection(&monitor_handles_cs);
1152 RegCloseKey(hmonitors);
1154 TRACE("%d monitors loaded\n", loaded);
1158 /******************************************************************
1159 * monitor_loadui [internal]
1161 * load the userinterface-dll for a given portmonitor
1163 * On failure, NULL is returned
1166 static monitor_t * monitor_loadui(monitor_t * pm)
1168 monitor_t * pui = NULL;
1169 LPWSTR buffer[MAX_PATH];
1174 if (pm == NULL) return NULL;
1175 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1177 /* Try the Portmonitor first; works for many monitors */
1178 if (pm->monitorUI) {
1179 EnterCriticalSection(&monitor_handles_cs);
1181 LeaveCriticalSection(&monitor_handles_cs);
1185 /* query the userinterface-dllname from the Portmonitor */
1186 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1187 /* building (",XcvMonitor %s",pm->name) not needed yet */
1188 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1189 TRACE("got %u with %p\n", res, hXcv);
1191 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1192 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1193 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1194 pm->monitor->pfnXcvClosePort(hXcv);
1201 /******************************************************************
1202 * monitor_load_by_port [internal]
1204 * load a printmonitor for a given port
1206 * On failure, NULL is returned
1209 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1214 monitor_t * pm = NULL;
1215 DWORD registered = 0;
1219 TRACE("(%s)\n", debugstr_w(portname));
1221 /* Try the Local Monitor first */
1222 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1223 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1224 /* found the portname */
1226 return monitor_load(LocalPortW, NULL);
1231 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1232 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1233 if (buffer == NULL) return NULL;
1235 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1236 EnterCriticalSection(&monitor_handles_cs);
1237 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1239 while ((pm == NULL) && (id < registered)) {
1241 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1242 TRACE("testing %s\n", debugstr_w(buffer));
1243 len = lstrlenW(buffer);
1244 lstrcatW(buffer, bs_Ports_bsW);
1245 lstrcatW(buffer, portname);
1246 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1248 buffer[len] = '\0'; /* use only the Monitor-Name */
1249 pm = monitor_load(buffer, NULL);
1253 LeaveCriticalSection(&monitor_handles_cs);
1256 HeapFree(GetProcessHeap(), 0, buffer);
1260 /******************************************************************
1261 * enumerate the local Ports from all loaded monitors (internal)
1263 * returns the needed size (in bytes) for pPorts
1264 * and *lpreturned is set to number of entries returned in pPorts
1267 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1271 LPPORT_INFO_2W cache;
1281 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1282 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1284 numentries = *lpreturned; /* this is 0, when we scan the registry */
1285 needed = entrysize * numentries;
1286 ptr = (LPWSTR) &pPorts[needed];
1291 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1293 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1294 if (pm->cache == NULL) {
1295 res = pm->monitor->pfnEnumPorts(NULL, 2, NULL, 0, &(pm->pi2_needed), &(pm->returned));
1296 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1297 pm->cache = HeapAlloc(GetProcessHeap(), 0, (pm->pi2_needed));
1298 res = pm->monitor->pfnEnumPorts(NULL, 2, (LPBYTE) pm->cache, pm->pi2_needed, &(pm->pi2_needed), &(pm->returned));
1300 TRACE("(%s) got %d with %d (cache need %d byte for %d entries)\n",
1301 debugstr_w(pm->name), res, GetLastError(), pm->pi2_needed, pm->returned);
1304 if (pm->cache && (level == 1) && (pm->pi1_needed == 0) && (pm->returned > 0)) {
1307 while (cacheindex < (pm->returned)) {
1308 pm->pi1_needed += sizeof(PORT_INFO_1W);
1309 pm->pi1_needed += (lstrlenW(cache->pPortName) + 1) * sizeof(WCHAR);
1313 TRACE("%d byte for %d cached PORT_INFO_1W entries (%s)\n",
1314 pm->pi1_needed, cacheindex, debugstr_w(pm->name));
1316 numentries += pm->returned;
1317 needed += (level == 1) ? pm->pi1_needed : pm->pi2_needed;
1319 /* fill the buffer, if we have one */
1320 if (pPorts && (cbBuf >= needed )) {
1323 while (cacheindex < pm->returned) {
1324 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1325 out->pPortName = ptr;
1326 lstrcpyW(ptr, cache->pPortName);
1327 ptr += (lstrlenW(ptr)+1);
1329 out->pMonitorName = ptr;
1330 lstrcpyW(ptr, cache->pMonitorName);
1331 ptr += (lstrlenW(ptr)+1);
1333 out->pDescription = ptr;
1334 lstrcpyW(ptr, cache->pDescription);
1335 ptr += (lstrlenW(ptr)+1);
1336 out->fPortType = cache->fPortType;
1337 out->Reserved = cache->Reserved;
1347 *lpreturned = numentries;
1348 TRACE("need %d byte for %d entries\n", needed, numentries);
1352 /******************************************************************
1353 * get_servername_from_name (internal)
1355 * for an external server, a copy of the serverpart from the full name is returned
1358 static LPWSTR get_servername_from_name(LPCWSTR name)
1362 WCHAR buffer[MAX_PATH];
1365 if (name == NULL) return NULL;
1366 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1368 server = strdupW(&name[2]); /* skip over both backslash */
1369 if (server == NULL) return NULL;
1371 /* strip '\' and the printername */
1372 ptr = strchrW(server, '\\');
1373 if (ptr) ptr[0] = '\0';
1375 TRACE("found %s\n", debugstr_w(server));
1377 len = sizeof(buffer)/sizeof(buffer[0]);
1378 if (GetComputerNameW(buffer, &len)) {
1379 if (lstrcmpW(buffer, server) == 0) {
1380 /* The requested Servername is our computername */
1381 HeapFree(GetProcessHeap(), 0, server);
1388 /******************************************************************
1389 * get_basename_from_name (internal)
1391 * skip over the serverpart from the full name
1394 static LPCWSTR get_basename_from_name(LPCWSTR name)
1396 if (name == NULL) return NULL;
1397 if ((name[0] == '\\') && (name[1] == '\\')) {
1398 /* skip over the servername and search for the following '\' */
1399 name = strchrW(&name[2], '\\');
1400 if ((name) && (name[1])) {
1401 /* found a seperator ('\') followed by a name:
1402 skip over the seperator and return the rest */
1407 /* no basename present (we found only a servername) */
1414 /******************************************************************
1415 * get_opened_printer_entry
1416 * Get the first place empty in the opened printer table
1419 * - pDefault is ignored
1421 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1423 UINT_PTR handle = nb_printer_handles, i;
1424 jobqueue_t *queue = NULL;
1425 opened_printer_t *printer = NULL;
1427 LPCWSTR printername;
1432 servername = get_servername_from_name(name);
1434 FIXME("server %s not supported\n", debugstr_w(servername));
1435 HeapFree(GetProcessHeap(), 0, servername);
1436 SetLastError(ERROR_INVALID_PRINTER_NAME);
1440 printername = get_basename_from_name(name);
1441 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1443 /* an empty printername is invalid */
1444 if (printername && (!printername[0])) {
1445 SetLastError(ERROR_INVALID_PARAMETER);
1449 EnterCriticalSection(&printer_handles_cs);
1451 for (i = 0; i < nb_printer_handles; i++)
1453 if (!printer_handles[i])
1455 if(handle == nb_printer_handles)
1460 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1461 queue = printer_handles[i]->queue;
1465 if (handle >= nb_printer_handles)
1467 opened_printer_t **new_array;
1468 if (printer_handles)
1469 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1470 (nb_printer_handles + 16) * sizeof(*new_array) );
1472 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1473 (nb_printer_handles + 16) * sizeof(*new_array) );
1480 printer_handles = new_array;
1481 nb_printer_handles += 16;
1484 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1491 /* clone the base name. This is NULL for the printserver */
1492 printer->printername = strdupW(printername);
1494 /* clone the full name */
1495 printer->name = strdupW(name);
1496 if (name && (!printer->name)) {
1502 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1503 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1504 /* OpenPrinter(",XcvMonitor " detected */
1505 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1506 printer->pm = monitor_load(&printername[len], NULL);
1507 if (printer->pm == NULL) {
1508 SetLastError(ERROR_INVALID_PARAMETER);
1515 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1516 if (strncmpW( printername, XcvPortW, len) == 0) {
1517 /* OpenPrinter(",XcvPort " detected */
1518 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1519 printer->pm = monitor_load_by_port(&printername[len]);
1520 if (printer->pm == NULL) {
1521 SetLastError(ERROR_INVALID_PARAMETER);
1529 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1530 printer->pm->monitor->pfnXcvOpenPort(&printername[len], pDefault->DesiredAccess, &printer->hXcv);
1532 if (printer->hXcv == NULL) {
1533 SetLastError(ERROR_INVALID_PARAMETER);
1540 /* Does the Printer exist? */
1541 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1542 ERR("Can't create Printers key\n");
1546 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1547 WARN("Printer not found in Registry: '%s'\n", debugstr_w(printername));
1548 RegCloseKey(hkeyPrinters);
1549 SetLastError(ERROR_INVALID_PRINTER_NAME);
1553 RegCloseKey(hkeyPrinter);
1554 RegCloseKey(hkeyPrinters);
1559 TRACE("using the local printserver\n");
1563 printer->queue = queue;
1566 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1567 if (!printer->queue) {
1571 list_init(&printer->queue->jobs);
1572 printer->queue->ref = 0;
1574 InterlockedIncrement(&printer->queue->ref);
1576 printer_handles[handle] = printer;
1579 LeaveCriticalSection(&printer_handles_cs);
1580 if (!handle && printer) {
1581 /* Something failed: Free all resources */
1582 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1583 monitor_unload(printer->pm);
1584 HeapFree(GetProcessHeap(), 0, printer->printername);
1585 HeapFree(GetProcessHeap(), 0, printer->name);
1586 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1587 HeapFree(GetProcessHeap(), 0, printer);
1590 return (HANDLE)handle;
1593 /******************************************************************
1594 * get_opened_printer
1595 * Get the pointer to the opened printer referred by the handle
1597 static opened_printer_t *get_opened_printer(HANDLE hprn)
1599 UINT_PTR idx = (UINT_PTR)hprn;
1600 opened_printer_t *ret = NULL;
1602 EnterCriticalSection(&printer_handles_cs);
1604 if ((idx <= 0) || (idx > nb_printer_handles))
1607 ret = printer_handles[idx - 1];
1609 LeaveCriticalSection(&printer_handles_cs);
1613 /******************************************************************
1614 * get_opened_printer_name
1615 * Get the pointer to the opened printer name referred by the handle
1617 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1619 opened_printer_t *printer = get_opened_printer(hprn);
1620 if(!printer) return NULL;
1621 return printer->name;
1624 /******************************************************************
1625 * WINSPOOL_GetOpenedPrinterRegKey
1628 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1630 LPCWSTR name = get_opened_printer_name(hPrinter);
1634 if(!name) return ERROR_INVALID_HANDLE;
1636 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1640 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1642 ERR("Can't find opened printer %s in registry\n",
1644 RegCloseKey(hkeyPrinters);
1645 return ERROR_INVALID_PRINTER_NAME; /* ? */
1647 RegCloseKey(hkeyPrinters);
1648 return ERROR_SUCCESS;
1651 /******************************************************************
1654 * Get the pointer to the specified job.
1655 * Should hold the printer_handles_cs before calling.
1657 static job_t *get_job(HANDLE hprn, DWORD JobId)
1659 opened_printer_t *printer = get_opened_printer(hprn);
1662 if(!printer) return NULL;
1663 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1665 if(job->job_id == JobId)
1671 /***********************************************************
1674 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1677 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1680 Formname = (dmA->dmSize > off_formname);
1681 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1682 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1683 dmW->dmDeviceName, CCHDEVICENAME);
1685 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1686 dmA->dmSize - CCHDEVICENAME);
1688 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1689 off_formname - CCHDEVICENAME);
1690 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1691 dmW->dmFormName, CCHFORMNAME);
1692 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1693 (off_formname + CCHFORMNAME));
1696 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1697 dmA->dmDriverExtra);
1701 /***********************************************************
1703 * Creates an ascii copy of supplied devmode on heap
1705 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1710 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1712 if(!dmW) return NULL;
1713 Formname = (dmW->dmSize > off_formname);
1714 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1715 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1716 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1717 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1719 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1720 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1722 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1723 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1724 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1725 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1726 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1727 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1730 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1731 dmW->dmDriverExtra);
1735 /***********************************************************
1736 * PRINTER_INFO_2AtoW
1737 * Creates a unicode copy of PRINTER_INFO_2A on heap
1739 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1741 LPPRINTER_INFO_2W piW;
1742 UNICODE_STRING usBuffer;
1744 if(!piA) return NULL;
1745 piW = HeapAlloc(heap, 0, sizeof(*piW));
1746 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1748 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1749 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1750 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1751 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1752 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1753 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1754 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1755 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1756 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1757 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1758 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1759 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1763 /***********************************************************
1764 * FREE_PRINTER_INFO_2W
1765 * Free PRINTER_INFO_2W and all strings
1767 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1771 HeapFree(heap,0,piW->pServerName);
1772 HeapFree(heap,0,piW->pPrinterName);
1773 HeapFree(heap,0,piW->pShareName);
1774 HeapFree(heap,0,piW->pPortName);
1775 HeapFree(heap,0,piW->pDriverName);
1776 HeapFree(heap,0,piW->pComment);
1777 HeapFree(heap,0,piW->pLocation);
1778 HeapFree(heap,0,piW->pDevMode);
1779 HeapFree(heap,0,piW->pSepFile);
1780 HeapFree(heap,0,piW->pPrintProcessor);
1781 HeapFree(heap,0,piW->pDatatype);
1782 HeapFree(heap,0,piW->pParameters);
1783 HeapFree(heap,0,piW);
1787 /******************************************************************
1788 * DeviceCapabilities [WINSPOOL.@]
1789 * DeviceCapabilitiesA [WINSPOOL.@]
1792 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1793 LPSTR pOutput, LPDEVMODEA lpdm)
1797 if (!GDI_CallDeviceCapabilities16)
1799 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1801 if (!GDI_CallDeviceCapabilities16) return -1;
1803 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1805 /* If DC_PAPERSIZE map POINT16s to POINTs */
1806 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1807 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1808 POINT *pt = (POINT *)pOutput;
1810 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1811 for(i = 0; i < ret; i++, pt++)
1816 HeapFree( GetProcessHeap(), 0, tmp );
1822 /*****************************************************************************
1823 * DeviceCapabilitiesW [WINSPOOL.@]
1825 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1828 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1829 WORD fwCapability, LPWSTR pOutput,
1830 const DEVMODEW *pDevMode)
1832 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1833 LPSTR pDeviceA = strdupWtoA(pDevice);
1834 LPSTR pPortA = strdupWtoA(pPort);
1837 if(pOutput && (fwCapability == DC_BINNAMES ||
1838 fwCapability == DC_FILEDEPENDENCIES ||
1839 fwCapability == DC_PAPERNAMES)) {
1840 /* These need A -> W translation */
1843 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1847 switch(fwCapability) {
1852 case DC_FILEDEPENDENCIES:
1856 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1857 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1859 for(i = 0; i < ret; i++)
1860 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1861 pOutput + (i * size), size);
1862 HeapFree(GetProcessHeap(), 0, pOutputA);
1864 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1865 (LPSTR)pOutput, dmA);
1867 HeapFree(GetProcessHeap(),0,pPortA);
1868 HeapFree(GetProcessHeap(),0,pDeviceA);
1869 HeapFree(GetProcessHeap(),0,dmA);
1873 /******************************************************************
1874 * DocumentPropertiesA [WINSPOOL.@]
1876 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1878 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1879 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1880 LPDEVMODEA pDevModeInput,DWORD fMode )
1882 LPSTR lpName = pDeviceName;
1883 static CHAR port[] = "LPT1:";
1886 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1887 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1891 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1893 ERR("no name from hPrinter?\n");
1894 SetLastError(ERROR_INVALID_HANDLE);
1897 lpName = strdupWtoA(lpNameW);
1900 if (!GDI_CallExtDeviceMode16)
1902 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1904 if (!GDI_CallExtDeviceMode16) {
1905 ERR("No CallExtDeviceMode16?\n");
1909 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1910 pDevModeInput, NULL, fMode);
1913 HeapFree(GetProcessHeap(),0,lpName);
1918 /*****************************************************************************
1919 * DocumentPropertiesW (WINSPOOL.@)
1921 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1923 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1925 LPDEVMODEW pDevModeOutput,
1926 LPDEVMODEW pDevModeInput, DWORD fMode)
1929 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1930 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1931 LPDEVMODEA pDevModeOutputA = NULL;
1934 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1935 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1937 if(pDevModeOutput) {
1938 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1939 if(ret < 0) return ret;
1940 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1942 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1943 pDevModeInputA, fMode);
1944 if(pDevModeOutput) {
1945 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1946 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1948 if(fMode == 0 && ret > 0)
1949 ret += (CCHDEVICENAME + CCHFORMNAME);
1950 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1951 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1955 /******************************************************************
1956 * OpenPrinterA [WINSPOOL.@]
1961 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1962 LPPRINTER_DEFAULTSA pDefault)
1964 UNICODE_STRING lpPrinterNameW;
1965 UNICODE_STRING usBuffer;
1966 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1967 PWSTR pwstrPrinterNameW;
1970 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1973 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1974 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1975 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1976 pDefaultW = &DefaultW;
1978 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1980 RtlFreeUnicodeString(&usBuffer);
1981 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1983 RtlFreeUnicodeString(&lpPrinterNameW);
1987 /******************************************************************
1988 * OpenPrinterW [WINSPOOL.@]
1990 * Open a Printer / Printserver or a Printer-Object
1993 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1994 * phPrinter [O] The resulting Handle is stored here
1995 * pDefault [I] PTR to Default Printer Settings or NULL
2002 * lpPrinterName is one of:
2003 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2004 *| Printer: "PrinterName"
2005 *| Printer-Object: "PrinterName,Job xxx"
2006 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2007 *| XcvPort: "Servername,XcvPort PortName"
2010 *| Printer-Object not supported
2011 *| pDefaults is ignored
2014 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2017 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2019 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2020 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2024 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2025 SetLastError(ERROR_INVALID_PARAMETER);
2029 /* Get the unique handle of the printer or Printserver */
2030 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2031 TRACE("returning %d with 0x%x and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2032 return (*phPrinter != 0);
2035 /******************************************************************
2036 * AddMonitorA [WINSPOOL.@]
2041 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2043 LPWSTR nameW = NULL;
2046 LPMONITOR_INFO_2A mi2a;
2047 MONITOR_INFO_2W mi2w;
2049 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2050 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2051 mi2a ? debugstr_a(mi2a->pName) : NULL,
2052 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2053 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2056 SetLastError(ERROR_INVALID_LEVEL);
2060 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2066 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2067 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2068 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2071 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2073 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2074 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2075 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2077 if (mi2a->pEnvironment) {
2078 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2079 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2080 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2082 if (mi2a->pDLLName) {
2083 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2084 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2085 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2088 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2090 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2091 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2092 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2094 HeapFree(GetProcessHeap(), 0, nameW);
2098 /******************************************************************************
2099 * AddMonitorW [WINSPOOL.@]
2101 * Install a Printmonitor
2104 * pName [I] Servername or NULL (local Computer)
2105 * Level [I] Structure-Level (Must be 2)
2106 * pMonitors [I] PTR to MONITOR_INFO_2
2113 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2116 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2118 monitor_t * pm = NULL;
2119 LPMONITOR_INFO_2W mi2w;
2125 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2126 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2127 mi2w ? debugstr_w(mi2w->pName) : NULL,
2128 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2129 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2132 SetLastError(ERROR_INVALID_LEVEL);
2136 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2141 if (pName && (pName[0])) {
2142 FIXME("for server %s not implemented\n", debugstr_w(pName));
2143 SetLastError(ERROR_ACCESS_DENIED);
2148 if (!mi2w->pName || (! mi2w->pName[0])) {
2149 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2150 SetLastError(ERROR_INVALID_PARAMETER);
2153 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2154 WARN("Environment %s requested (we support only %s)\n",
2155 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2156 SetLastError(ERROR_INVALID_ENVIRONMENT);
2160 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2161 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2162 SetLastError(ERROR_INVALID_PARAMETER);
2166 /* Load and initialize the monitor. SetLastError() is called on failure */
2167 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2172 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2173 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2177 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2178 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2179 &disposition) == ERROR_SUCCESS) {
2181 /* Some installers set options for the port before calling AddMonitor.
2182 We query the "Driver" entry to verify that the monitor is installed,
2183 before we return an error.
2184 When a user installs two print monitors at the same time with the
2185 same name but with a different driver DLL and a task switch comes
2186 between RegQueryValueExW and RegSetValueExW, a race condition
2187 is possible but silently ignored. */
2191 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2192 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2193 &namesize) == ERROR_SUCCESS)) {
2194 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2195 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2196 9x: ERROR_ALREADY_EXISTS (183) */
2197 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2202 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2203 res = (RegSetValueExW(hentry, DriverW, 0,
2204 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2206 RegCloseKey(hentry);
2213 /******************************************************************
2214 * DeletePrinterDriverA [WINSPOOL.@]
2217 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2219 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2222 /******************************************************************
2223 * DeletePrinterDriverW [WINSPOOL.@]
2226 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2228 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2231 /******************************************************************
2232 * DeleteMonitorA [WINSPOOL.@]
2234 * See DeleteMonitorW.
2237 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2239 LPWSTR nameW = NULL;
2240 LPWSTR EnvironmentW = NULL;
2241 LPWSTR MonitorNameW = NULL;
2246 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2247 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2248 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2252 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2253 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2254 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2257 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2258 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2259 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2262 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2264 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2265 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2266 HeapFree(GetProcessHeap(), 0, nameW);
2270 /******************************************************************
2271 * DeleteMonitorW [WINSPOOL.@]
2273 * Delete a specific Printmonitor from a Printing-Environment
2276 * pName [I] Servername or NULL (local Computer)
2277 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2278 * pMonitorName [I] Name of the Monitor, that should be deleted
2285 * pEnvironment is ignored in Windows for the local Computer.
2289 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2293 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2294 debugstr_w(pMonitorName));
2296 if (pName && (pName[0])) {
2297 FIXME("for server %s not implemented\n", debugstr_w(pName));
2298 SetLastError(ERROR_ACCESS_DENIED);
2302 /* pEnvironment is ignored in Windows for the local Computer */
2304 if (!pMonitorName || !pMonitorName[0]) {
2305 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2306 SetLastError(ERROR_INVALID_PARAMETER);
2310 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2311 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2315 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2316 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2317 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2322 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
2325 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2326 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2330 /******************************************************************
2331 * DeletePortA [WINSPOOL.@]
2336 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2338 LPWSTR nameW = NULL;
2339 LPWSTR portW = NULL;
2343 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2345 /* convert servername to unicode */
2347 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2348 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2349 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2352 /* convert portname to unicode */
2354 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2355 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2356 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2359 res = DeletePortW(nameW, hWnd, portW);
2360 HeapFree(GetProcessHeap(), 0, nameW);
2361 HeapFree(GetProcessHeap(), 0, portW);
2365 /******************************************************************
2366 * DeletePortW [WINSPOOL.@]
2368 * Delete a specific Port
2371 * pName [I] Servername or NULL (local Computer)
2372 * hWnd [I] Handle to parent Window for the Dialog-Box
2373 * pPortName [I] Name of the Port, that should be deleted
2380 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2383 DWORD res = ROUTER_UNKNOWN;
2385 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2387 if (pName && pName[0]) {
2388 SetLastError(ERROR_INVALID_PARAMETER);
2393 SetLastError(RPC_X_NULL_REF_POINTER);
2397 /* an empty Portname is Invalid */
2398 if (!pPortName[0]) goto cleanup;
2400 pm = monitor_load_by_port(pPortName);
2401 if (pm && pm->monitor) {
2402 if (pm->monitor->pfnDeletePort != NULL) {
2403 TRACE("Using %s for %s:\n", debugstr_w(pm->name), debugstr_w(pPortName));
2404 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2405 TRACE("got %d with %d\n", res, GetLastError());
2407 else if (pm->monitor->pfnXcvOpenPort)
2409 FIXME("XcvOpenPort not implemented (dwMonitorSize: %d)\n", pm->dwMonitorSize);
2411 /* invalidate cached PORT_INFO_2W */
2412 if (res == ROUTER_SUCCESS) monitor_flush(pm);
2417 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2418 if (res == ROUTER_UNKNOWN) SetLastError(ERROR_NOT_SUPPORTED);
2419 TRACE("returning %d with %d\n", (res == ROUTER_SUCCESS), GetLastError());
2420 return (res == ROUTER_SUCCESS);
2423 /******************************************************************************
2424 * SetPrinterW [WINSPOOL.@]
2426 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2428 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2429 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2433 /******************************************************************************
2434 * WritePrinter [WINSPOOL.@]
2436 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2438 opened_printer_t *printer;
2441 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2443 EnterCriticalSection(&printer_handles_cs);
2444 printer = get_opened_printer(hPrinter);
2447 SetLastError(ERROR_INVALID_HANDLE);
2453 SetLastError(ERROR_SPL_NO_STARTDOC);
2457 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2459 LeaveCriticalSection(&printer_handles_cs);
2463 /*****************************************************************************
2464 * AddFormA [WINSPOOL.@]
2466 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2468 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2472 /*****************************************************************************
2473 * AddFormW [WINSPOOL.@]
2475 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2477 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2481 /*****************************************************************************
2482 * AddJobA [WINSPOOL.@]
2484 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2487 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2491 SetLastError(ERROR_INVALID_LEVEL);
2495 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2498 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2499 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2500 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2501 if(*pcbNeeded > cbBuf) {
2502 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2505 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2506 addjobA->JobId = addjobW->JobId;
2507 addjobA->Path = (char *)(addjobA + 1);
2508 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2514 /*****************************************************************************
2515 * AddJobW [WINSPOOL.@]
2517 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2519 opened_printer_t *printer;
2522 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2523 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2524 WCHAR path[MAX_PATH], filename[MAX_PATH];
2526 ADDJOB_INFO_1W *addjob;
2528 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2530 EnterCriticalSection(&printer_handles_cs);
2532 printer = get_opened_printer(hPrinter);
2535 SetLastError(ERROR_INVALID_HANDLE);
2540 SetLastError(ERROR_INVALID_LEVEL);
2544 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2548 job->job_id = InterlockedIncrement(&next_job_id);
2550 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2551 if(path[len - 1] != '\\')
2553 memcpy(path + len, spool_path, sizeof(spool_path));
2554 sprintfW(filename, fmtW, path, job->job_id);
2556 len = strlenW(filename);
2557 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2558 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2559 job->document_title = strdupW(default_doc_title);
2560 list_add_tail(&printer->queue->jobs, &job->entry);
2562 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2563 if(*pcbNeeded <= cbBuf) {
2564 addjob = (ADDJOB_INFO_1W*)pData;
2565 addjob->JobId = job->job_id;
2566 addjob->Path = (WCHAR *)(addjob + 1);
2567 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2570 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2573 LeaveCriticalSection(&printer_handles_cs);
2577 /*****************************************************************************
2578 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2580 * Return the PATH for the Print-Processors
2582 * See GetPrintProcessorDirectoryW.
2586 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2587 DWORD level, LPBYTE Info,
2588 DWORD cbBuf, LPDWORD pcbNeeded)
2590 LPWSTR serverW = NULL;
2595 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2596 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2600 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2601 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2602 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2606 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2607 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2608 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2611 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2612 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2614 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2617 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2618 cbBuf, NULL, NULL) > 0;
2621 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2622 HeapFree(GetProcessHeap(), 0, envW);
2623 HeapFree(GetProcessHeap(), 0, serverW);
2627 /*****************************************************************************
2628 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2630 * Return the PATH for the Print-Processors
2633 * server [I] Servername (NT only) or NULL (local Computer)
2634 * env [I] Printing-Environment (see below) or NULL (Default)
2635 * level [I] Structure-Level (must be 1)
2636 * Info [O] PTR to Buffer that receives the Result
2637 * cbBuf [I] Size of Buffer at "Info"
2638 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2639 * required for the Buffer at "Info"
2642 * Success: TRUE and in pcbNeeded the Bytes used in Info
2643 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2644 * if cbBuf is too small
2646 * Native Values returned in Info on Success:
2647 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2648 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2649 *| win9x(Windows 4.0): "%winsysdir%"
2651 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2654 * Only NULL or "" is supported for server
2657 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2658 DWORD level, LPBYTE Info,
2659 DWORD cbBuf, LPDWORD pcbNeeded)
2662 const printenv_t * env_t;
2664 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2665 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2667 if(server != NULL && server[0]) {
2668 FIXME("server not supported: %s\n", debugstr_w(server));
2669 SetLastError(ERROR_INVALID_PARAMETER);
2673 env_t = validate_envW(env);
2674 if(!env_t) return FALSE; /* environment invalid or unsupported */
2677 WARN("(Level: %d) is ignored in win9x\n", level);
2678 SetLastError(ERROR_INVALID_LEVEL);
2682 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2683 needed = GetSystemDirectoryW(NULL, 0);
2684 /* add the Size for the Subdirectories */
2685 needed += lstrlenW(spoolprtprocsW);
2686 needed += lstrlenW(env_t->subdir);
2687 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2689 if(pcbNeeded) *pcbNeeded = needed;
2690 TRACE ("required: 0x%x/%d\n", needed, needed);
2691 if (needed > cbBuf) {
2692 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2695 if(pcbNeeded == NULL) {
2696 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2697 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2698 SetLastError(RPC_X_NULL_REF_POINTER);
2702 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2703 SetLastError(RPC_X_NULL_REF_POINTER);
2707 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2708 /* add the Subdirectories */
2709 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2710 lstrcatW((LPWSTR) Info, env_t->subdir);
2711 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2715 /*****************************************************************************
2716 * WINSPOOL_OpenDriverReg [internal]
2718 * opens the registry for the printer drivers depending on the given input
2719 * variable pEnvironment
2722 * the opened hkey on success
2725 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2729 const printenv_t * env;
2732 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2734 if (!pEnvironment || unicode) {
2735 /* pEnvironment was NULL or an Unicode-String: use it direct */
2736 env = validate_envW(pEnvironment);
2740 /* pEnvironment was an ANSI-String: convert to unicode first */
2742 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2743 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2744 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2745 env = validate_envW(buffer);
2746 HeapFree(GetProcessHeap(), 0, buffer);
2748 if (!env) return NULL;
2750 buffer = HeapAlloc( GetProcessHeap(), 0,
2751 (strlenW(DriversW) + strlenW(env->envname) +
2752 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2754 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2755 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2756 HeapFree(GetProcessHeap(), 0, buffer);
2761 /*****************************************************************************
2762 * AddPrinterW [WINSPOOL.@]
2764 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2766 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2770 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2773 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2776 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2777 SetLastError(ERROR_INVALID_PARAMETER);
2781 ERR("Level = %d, unsupported!\n", Level);
2782 SetLastError(ERROR_INVALID_LEVEL);
2786 SetLastError(ERROR_INVALID_PARAMETER);
2789 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2791 ERR("Can't create Printers key\n");
2794 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2795 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2796 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2797 RegCloseKey(hkeyPrinter);
2798 RegCloseKey(hkeyPrinters);
2801 RegCloseKey(hkeyPrinter);
2803 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2805 ERR("Can't create Drivers key\n");
2806 RegCloseKey(hkeyPrinters);
2809 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2811 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2812 RegCloseKey(hkeyPrinters);
2813 RegCloseKey(hkeyDrivers);
2814 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2817 RegCloseKey(hkeyDriver);
2818 RegCloseKey(hkeyDrivers);
2820 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2821 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2822 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2823 RegCloseKey(hkeyPrinters);
2827 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2829 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2830 SetLastError(ERROR_INVALID_PRINTER_NAME);
2831 RegCloseKey(hkeyPrinters);
2834 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2835 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2836 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2838 /* See if we can load the driver. We may need the devmode structure anyway
2841 * Note that DocumentPropertiesW will briefly try to open the printer we
2842 * just create to find a DEVMODEA struct (it will use the WINEPS default
2843 * one in case it is not there, so we are ok).
2845 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2848 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2849 size = sizeof(DEVMODEW);
2855 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2856 ZeroMemory(dmW,size);
2858 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2860 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2861 HeapFree(GetProcessHeap(),0,dmW);
2866 /* set devmode to printer name */
2867 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2871 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2872 and we support these drivers. NT writes DEVMODEW so somehow
2873 we'll need to distinguish between these when we support NT
2877 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2878 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2879 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2880 HeapFree(GetProcessHeap(), 0, dmA);
2882 HeapFree(GetProcessHeap(), 0, dmW);
2884 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2885 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2886 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2887 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2889 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2890 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2891 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2892 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2893 (LPBYTE)&pi->Priority, sizeof(DWORD));
2894 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2895 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2896 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2897 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2898 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2899 (LPBYTE)&pi->Status, sizeof(DWORD));
2900 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2901 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2903 RegCloseKey(hkeyPrinter);
2904 RegCloseKey(hkeyPrinters);
2905 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2906 ERR("OpenPrinter failing\n");
2912 /*****************************************************************************
2913 * AddPrinterA [WINSPOOL.@]
2915 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2917 UNICODE_STRING pNameW;
2919 PRINTER_INFO_2W *piW;
2920 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2923 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2925 ERR("Level = %d, unsupported!\n", Level);
2926 SetLastError(ERROR_INVALID_LEVEL);
2929 pwstrNameW = asciitounicode(&pNameW,pName);
2930 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2932 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2934 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2935 RtlFreeUnicodeString(&pNameW);
2940 /*****************************************************************************
2941 * ClosePrinter [WINSPOOL.@]
2943 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2945 UINT_PTR i = (UINT_PTR)hPrinter;
2946 opened_printer_t *printer = NULL;
2949 TRACE("Handle %p\n", hPrinter);
2951 EnterCriticalSection(&printer_handles_cs);
2953 if ((i > 0) && (i <= nb_printer_handles))
2954 printer = printer_handles[i - 1];
2958 struct list *cursor, *cursor2;
2961 EndDocPrinter(hPrinter);
2963 if(InterlockedDecrement(&printer->queue->ref) == 0)
2965 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2967 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2968 ScheduleJob(hPrinter, job->job_id);
2970 HeapFree(GetProcessHeap(), 0, printer->queue);
2972 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2973 monitor_unload(printer->pm);
2974 HeapFree(GetProcessHeap(), 0, printer->printername);
2975 HeapFree(GetProcessHeap(), 0, printer->name);
2976 HeapFree(GetProcessHeap(), 0, printer);
2977 printer_handles[i - 1] = NULL;
2980 LeaveCriticalSection(&printer_handles_cs);
2984 /*****************************************************************************
2985 * DeleteFormA [WINSPOOL.@]
2987 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2989 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2993 /*****************************************************************************
2994 * DeleteFormW [WINSPOOL.@]
2996 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2998 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3002 /*****************************************************************************
3003 * WINSPOOL_SHRegDeleteKey
3005 * Recursively delete subkeys.
3006 * Cut & paste from shlwapi.
3009 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
3011 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
3012 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
3015 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
3018 /* Find how many subkeys there are */
3019 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
3020 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
3024 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
3025 /* Name too big: alloc a buffer for it */
3026 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
3029 dwRet = ERROR_NOT_ENOUGH_MEMORY;
3032 /* Recursively delete all the subkeys */
3033 for(i = 0; i < dwKeyCount && !dwRet; i++)
3035 dwSize = dwMaxSubkeyLen;
3036 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
3038 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
3041 if (lpszName != szNameBuf)
3042 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
3046 RegCloseKey(hSubKey);
3048 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
3053 /*****************************************************************************
3054 * DeletePrinter [WINSPOOL.@]
3056 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3058 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3059 HKEY hkeyPrinters, hkey;
3062 SetLastError(ERROR_INVALID_HANDLE);
3065 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3066 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
3067 RegCloseKey(hkeyPrinters);
3069 WriteProfileStringW(devicesW, lpNameW, NULL);
3070 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3071 RegDeleteValueW(hkey, lpNameW);
3077 /*****************************************************************************
3078 * SetPrinterA [WINSPOOL.@]
3080 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3083 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3087 /*****************************************************************************
3088 * SetJobA [WINSPOOL.@]
3090 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3091 LPBYTE pJob, DWORD Command)
3095 UNICODE_STRING usBuffer;
3097 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3099 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3100 are all ignored by SetJob, so we don't bother copying them */
3108 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3109 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3111 JobW = (LPBYTE)info1W;
3112 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3113 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3114 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3115 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3116 info1W->Status = info1A->Status;
3117 info1W->Priority = info1A->Priority;
3118 info1W->Position = info1A->Position;
3119 info1W->PagesPrinted = info1A->PagesPrinted;
3124 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3125 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3127 JobW = (LPBYTE)info2W;
3128 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3129 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3130 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3131 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3132 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3133 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3134 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3135 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3136 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3137 info2W->Status = info2A->Status;
3138 info2W->Priority = info2A->Priority;
3139 info2W->Position = info2A->Position;
3140 info2W->StartTime = info2A->StartTime;
3141 info2W->UntilTime = info2A->UntilTime;
3142 info2W->PagesPrinted = info2A->PagesPrinted;
3146 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3147 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3150 SetLastError(ERROR_INVALID_LEVEL);
3154 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3160 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3161 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3162 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3163 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3164 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3169 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3170 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3171 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3172 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3173 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3174 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3175 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3176 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3177 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3181 HeapFree(GetProcessHeap(), 0, JobW);
3186 /*****************************************************************************
3187 * SetJobW [WINSPOOL.@]
3189 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3190 LPBYTE pJob, DWORD Command)
3195 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3196 FIXME("Ignoring everything other than document title\n");
3198 EnterCriticalSection(&printer_handles_cs);
3199 job = get_job(hPrinter, JobId);
3209 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3210 HeapFree(GetProcessHeap(), 0, job->document_title);
3211 job->document_title = strdupW(info1->pDocument);
3216 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3217 HeapFree(GetProcessHeap(), 0, job->document_title);
3218 job->document_title = strdupW(info2->pDocument);
3224 SetLastError(ERROR_INVALID_LEVEL);
3229 LeaveCriticalSection(&printer_handles_cs);
3233 /*****************************************************************************
3234 * EndDocPrinter [WINSPOOL.@]
3236 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3238 opened_printer_t *printer;
3240 TRACE("(%p)\n", hPrinter);
3242 EnterCriticalSection(&printer_handles_cs);
3244 printer = get_opened_printer(hPrinter);
3247 SetLastError(ERROR_INVALID_HANDLE);
3253 SetLastError(ERROR_SPL_NO_STARTDOC);
3257 CloseHandle(printer->doc->hf);
3258 ScheduleJob(hPrinter, printer->doc->job_id);
3259 HeapFree(GetProcessHeap(), 0, printer->doc);
3260 printer->doc = NULL;
3263 LeaveCriticalSection(&printer_handles_cs);
3267 /*****************************************************************************
3268 * EndPagePrinter [WINSPOOL.@]
3270 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3272 FIXME("(%p): stub\n", hPrinter);
3276 /*****************************************************************************
3277 * StartDocPrinterA [WINSPOOL.@]
3279 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3281 UNICODE_STRING usBuffer;
3283 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3286 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3287 or one (DOC_INFO_3) extra DWORDs */
3291 doc2W.JobId = doc2->JobId;
3294 doc2W.dwMode = doc2->dwMode;
3297 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3298 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3299 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3303 SetLastError(ERROR_INVALID_LEVEL);
3307 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3309 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3310 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3311 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3316 /*****************************************************************************
3317 * StartDocPrinterW [WINSPOOL.@]
3319 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3321 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3322 opened_printer_t *printer;
3323 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3324 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3325 JOB_INFO_1W job_info;
3326 DWORD needed, ret = 0;
3330 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3331 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3332 debugstr_w(doc->pDatatype));
3334 if(Level < 1 || Level > 3)
3336 SetLastError(ERROR_INVALID_LEVEL);
3340 EnterCriticalSection(&printer_handles_cs);
3341 printer = get_opened_printer(hPrinter);
3344 SetLastError(ERROR_INVALID_HANDLE);
3350 SetLastError(ERROR_INVALID_PRINTER_STATE);
3354 /* Even if we're printing to a file we still add a print job, we'll
3355 just ignore the spool file name */
3357 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3359 ERR("AddJob failed gle %08x\n", GetLastError());
3363 if(doc->pOutputFile)
3364 filename = doc->pOutputFile;
3366 filename = addjob->Path;
3368 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3369 if(hf == INVALID_HANDLE_VALUE)
3372 memset(&job_info, 0, sizeof(job_info));
3373 job_info.pDocument = doc->pDocName;
3374 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3376 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3377 printer->doc->hf = hf;
3378 ret = printer->doc->job_id = addjob->JobId;
3380 LeaveCriticalSection(&printer_handles_cs);
3385 /*****************************************************************************
3386 * StartPagePrinter [WINSPOOL.@]
3388 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3390 FIXME("(%p): stub\n", hPrinter);
3394 /*****************************************************************************
3395 * GetFormA [WINSPOOL.@]
3397 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3398 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3400 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3401 Level,pForm,cbBuf,pcbNeeded);
3405 /*****************************************************************************
3406 * GetFormW [WINSPOOL.@]
3408 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3409 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3411 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3412 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3416 /*****************************************************************************
3417 * SetFormA [WINSPOOL.@]
3419 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3422 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3426 /*****************************************************************************
3427 * SetFormW [WINSPOOL.@]
3429 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3432 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3436 /*****************************************************************************
3437 * ReadPrinter [WINSPOOL.@]
3439 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3440 LPDWORD pNoBytesRead)
3442 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3446 /*****************************************************************************
3447 * ResetPrinterA [WINSPOOL.@]
3449 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3451 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3455 /*****************************************************************************
3456 * ResetPrinterW [WINSPOOL.@]
3458 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3460 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3464 /*****************************************************************************
3465 * WINSPOOL_GetDWORDFromReg
3467 * Return DWORD associated with ValueName from hkey.
3469 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3471 DWORD sz = sizeof(DWORD), type, value = 0;
3474 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3476 if(ret != ERROR_SUCCESS) {
3477 WARN("Got ret = %d on name %s\n", ret, ValueName);
3480 if(type != REG_DWORD) {
3481 ERR("Got type %d\n", type);
3487 /*****************************************************************************
3488 * WINSPOOL_GetStringFromReg
3490 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3491 * String is stored either as unicode or ascii.
3492 * Bit of a hack here to get the ValueName if we want ascii.
3494 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3495 DWORD buflen, DWORD *needed,
3498 DWORD sz = buflen, type;
3502 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3504 LPSTR ValueNameA = strdupWtoA(ValueName);
3505 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3506 HeapFree(GetProcessHeap(),0,ValueNameA);
3508 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3509 WARN("Got ret = %d\n", ret);
3513 /* add space for terminating '\0' */
3514 sz += unicode ? sizeof(WCHAR) : 1;
3518 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3523 /*****************************************************************************
3524 * WINSPOOL_GetDefaultDevMode
3526 * Get a default DevMode values for wineps.
3530 static void WINSPOOL_GetDefaultDevMode(
3532 DWORD buflen, DWORD *needed,
3536 static const char szwps[] = "wineps.drv";
3538 /* fill default DEVMODE - should be read from ppd... */
3539 ZeroMemory( &dm, sizeof(dm) );
3540 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3541 dm.dmSpecVersion = DM_SPECVERSION;
3542 dm.dmDriverVersion = 1;
3543 dm.dmSize = sizeof(DEVMODEA);
3544 dm.dmDriverExtra = 0;
3546 DM_ORIENTATION | DM_PAPERSIZE |
3547 DM_PAPERLENGTH | DM_PAPERWIDTH |
3550 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3551 DM_YRESOLUTION | DM_TTOPTION;
3553 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3554 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3555 dm.u1.s1.dmPaperLength = 2970;
3556 dm.u1.s1.dmPaperWidth = 2100;
3560 dm.dmDefaultSource = DMBIN_AUTO;
3561 dm.dmPrintQuality = DMRES_MEDIUM;
3564 dm.dmYResolution = 300; /* 300dpi */
3565 dm.dmTTOption = DMTT_BITMAP;
3568 /* dm.dmLogPixels */
3569 /* dm.dmBitsPerPel */
3570 /* dm.dmPelsWidth */
3571 /* dm.dmPelsHeight */
3572 /* dm.dmDisplayFlags */
3573 /* dm.dmDisplayFrequency */
3574 /* dm.dmICMMethod */
3575 /* dm.dmICMIntent */
3576 /* dm.dmMediaType */
3577 /* dm.dmDitherType */
3578 /* dm.dmReserved1 */
3579 /* dm.dmReserved2 */
3580 /* dm.dmPanningWidth */
3581 /* dm.dmPanningHeight */
3584 if(buflen >= sizeof(DEVMODEW)) {
3585 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3586 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3587 HeapFree(GetProcessHeap(),0,pdmW);
3589 *needed = sizeof(DEVMODEW);
3593 if(buflen >= sizeof(DEVMODEA)) {
3594 memcpy(ptr, &dm, sizeof(DEVMODEA));
3596 *needed = sizeof(DEVMODEA);
3600 /*****************************************************************************
3601 * WINSPOOL_GetDevModeFromReg
3603 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3604 * DevMode is stored either as unicode or ascii.
3606 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3608 DWORD buflen, DWORD *needed,
3611 DWORD sz = buflen, type;
3614 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3615 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3616 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3617 if (sz < sizeof(DEVMODEA))
3619 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3622 /* ensures that dmSize is not erratically bogus if registry is invalid */
3623 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3624 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3626 sz += (CCHDEVICENAME + CCHFORMNAME);
3628 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3629 memcpy(ptr, dmW, sz);
3630 HeapFree(GetProcessHeap(),0,dmW);
3637 /*********************************************************************
3638 * WINSPOOL_GetPrinter_2
3640 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3641 * The strings are either stored as unicode or ascii.
3643 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3644 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3647 DWORD size, left = cbBuf;
3648 BOOL space = (cbBuf > 0);
3653 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3655 if(space && size <= left) {
3656 pi2->pPrinterName = (LPWSTR)ptr;
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3665 if(space && size <= left) {
3666 pi2->pShareName = (LPWSTR)ptr;
3673 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3675 if(space && size <= left) {
3676 pi2->pPortName = (LPWSTR)ptr;
3683 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3685 if(space && size <= left) {
3686 pi2->pDriverName = (LPWSTR)ptr;
3693 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3695 if(space && size <= left) {
3696 pi2->pComment = (LPWSTR)ptr;
3703 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3705 if(space && size <= left) {
3706 pi2->pLocation = (LPWSTR)ptr;
3713 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3715 if(space && size <= left) {
3716 pi2->pDevMode = (LPDEVMODEW)ptr;
3725 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3726 if(space && size <= left) {
3727 pi2->pDevMode = (LPDEVMODEW)ptr;
3734 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3736 if(space && size <= left) {
3737 pi2->pSepFile = (LPWSTR)ptr;
3744 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3746 if(space && size <= left) {
3747 pi2->pPrintProcessor = (LPWSTR)ptr;
3754 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3756 if(space && size <= left) {
3757 pi2->pDatatype = (LPWSTR)ptr;
3764 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3766 if(space && size <= left) {
3767 pi2->pParameters = (LPWSTR)ptr;
3775 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3776 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3777 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3778 "Default Priority");
3779 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3780 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3783 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3784 memset(pi2, 0, sizeof(*pi2));
3789 /*********************************************************************
3790 * WINSPOOL_GetPrinter_4
3792 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3794 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3795 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3798 DWORD size, left = cbBuf;
3799 BOOL space = (cbBuf > 0);
3804 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3806 if(space && size <= left) {
3807 pi4->pPrinterName = (LPWSTR)ptr;
3815 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3818 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3819 memset(pi4, 0, sizeof(*pi4));
3824 /*********************************************************************
3825 * WINSPOOL_GetPrinter_5
3827 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3829 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3830 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3833 DWORD size, left = cbBuf;
3834 BOOL space = (cbBuf > 0);
3839 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3841 if(space && size <= left) {
3842 pi5->pPrinterName = (LPWSTR)ptr;
3849 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3851 if(space && size <= left) {
3852 pi5->pPortName = (LPWSTR)ptr;
3860 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3861 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3863 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3867 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3868 memset(pi5, 0, sizeof(*pi5));
3873 /*****************************************************************************
3874 * WINSPOOL_GetPrinter
3876 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3877 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3878 * just a collection of pointers to strings.
3880 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3881 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3884 DWORD size, needed = 0;
3886 HKEY hkeyPrinter, hkeyPrinters;
3889 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3891 if (!(name = get_opened_printer_name(hPrinter))) {
3892 SetLastError(ERROR_INVALID_HANDLE);
3896 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3898 ERR("Can't create Printers key\n");
3901 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3903 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3904 RegCloseKey(hkeyPrinters);
3905 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3912 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3914 size = sizeof(PRINTER_INFO_2W);
3916 ptr = pPrinter + size;
3918 memset(pPrinter, 0, size);
3923 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3931 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3933 size = sizeof(PRINTER_INFO_4W);
3935 ptr = pPrinter + size;
3937 memset(pPrinter, 0, size);
3942 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3951 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3953 size = sizeof(PRINTER_INFO_5W);
3955 ptr = pPrinter + size;
3957 memset(pPrinter, 0, size);
3963 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3970 FIXME("Unimplemented level %d\n", Level);
3971 SetLastError(ERROR_INVALID_LEVEL);
3972 RegCloseKey(hkeyPrinters);
3973 RegCloseKey(hkeyPrinter);
3977 RegCloseKey(hkeyPrinter);
3978 RegCloseKey(hkeyPrinters);
3980 TRACE("returning %d needed = %d\n", ret, needed);
3981 if(pcbNeeded) *pcbNeeded = needed;
3983 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3987 /*****************************************************************************
3988 * GetPrinterW [WINSPOOL.@]
3990 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3991 DWORD cbBuf, LPDWORD pcbNeeded)
3993 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3997 /*****************************************************************************
3998 * GetPrinterA [WINSPOOL.@]
4000 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4001 DWORD cbBuf, LPDWORD pcbNeeded)
4003 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4007 /*****************************************************************************
4008 * WINSPOOL_EnumPrinters
4010 * Implementation of EnumPrintersA|W
4012 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4013 DWORD dwLevel, LPBYTE lpbPrinters,
4014 DWORD cbBuf, LPDWORD lpdwNeeded,
4015 LPDWORD lpdwReturned, BOOL unicode)
4018 HKEY hkeyPrinters, hkeyPrinter;
4019 WCHAR PrinterName[255];
4020 DWORD needed = 0, number = 0;
4021 DWORD used, i, left;
4025 memset(lpbPrinters, 0, cbBuf);
4031 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4032 if(dwType == PRINTER_ENUM_DEFAULT)
4035 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4036 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4037 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4038 if(!dwType) return TRUE;
4041 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4042 FIXME("dwType = %08x\n", dwType);
4043 SetLastError(ERROR_INVALID_FLAGS);
4047 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4049 ERR("Can't create Printers key\n");
4053 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4054 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4055 RegCloseKey(hkeyPrinters);
4056 ERR("Can't query Printers key\n");
4059 TRACE("Found %d printers\n", number);
4063 RegCloseKey(hkeyPrinters);
4065 *lpdwReturned = number;
4069 used = number * sizeof(PRINTER_INFO_2W);
4072 used = number * sizeof(PRINTER_INFO_4W);
4075 used = number * sizeof(PRINTER_INFO_5W);
4079 SetLastError(ERROR_INVALID_LEVEL);
4080 RegCloseKey(hkeyPrinters);
4083 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4085 for(i = 0; i < number; i++) {
4086 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4088 ERR("Can't enum key number %d\n", i);
4089 RegCloseKey(hkeyPrinters);
4092 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4093 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4095 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4096 RegCloseKey(hkeyPrinters);
4101 buf = lpbPrinters + used;
4102 left = cbBuf - used;
4110 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4111 left, &needed, unicode);
4113 if(pi) pi += sizeof(PRINTER_INFO_2W);
4116 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4117 left, &needed, unicode);
4119 if(pi) pi += sizeof(PRINTER_INFO_4W);
4122 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4123 left, &needed, unicode);
4125 if(pi) pi += sizeof(PRINTER_INFO_5W);
4128 ERR("Shouldn't be here!\n");
4129 RegCloseKey(hkeyPrinter);
4130 RegCloseKey(hkeyPrinters);
4133 RegCloseKey(hkeyPrinter);
4135 RegCloseKey(hkeyPrinters);
4142 memset(lpbPrinters, 0, cbBuf);
4143 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4147 *lpdwReturned = number;
4148 SetLastError(ERROR_SUCCESS);
4153 /******************************************************************
4154 * EnumPrintersW [WINSPOOL.@]
4156 * Enumerates the available printers, print servers and print
4157 * providers, depending on the specified flags, name and level.
4161 * If level is set to 1:
4162 * Not implemented yet!
4163 * Returns TRUE with an empty list.
4165 * If level is set to 2:
4166 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4167 * Returns an array of PRINTER_INFO_2 data structures in the
4168 * lpbPrinters buffer. Note that according to MSDN also an
4169 * OpenPrinter should be performed on every remote printer.
4171 * If level is set to 4 (officially WinNT only):
4172 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4173 * Fast: Only the registry is queried to retrieve printer names,
4174 * no connection to the driver is made.
4175 * Returns an array of PRINTER_INFO_4 data structures in the
4176 * lpbPrinters buffer.
4178 * If level is set to 5 (officially WinNT4/Win9x only):
4179 * Fast: Only the registry is queried to retrieve printer names,
4180 * no connection to the driver is made.
4181 * Returns an array of PRINTER_INFO_5 data structures in the
4182 * lpbPrinters buffer.
4184 * If level set to 3 or 6+:
4185 * returns zero (failure!)
4187 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4191 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4192 * - Only levels 2, 4 and 5 are implemented at the moment.
4193 * - 16-bit printer drivers are not enumerated.
4194 * - Returned amount of bytes used/needed does not match the real Windoze
4195 * implementation (as in this implementation, all strings are part
4196 * of the buffer, whereas Win32 keeps them somewhere else)
4197 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4200 * - In a regular Wine installation, no registry settings for printers
4201 * exist, which makes this function return an empty list.
4203 BOOL WINAPI EnumPrintersW(
4204 DWORD dwType, /* [in] Types of print objects to enumerate */
4205 LPWSTR lpszName, /* [in] name of objects to enumerate */
4206 DWORD dwLevel, /* [in] type of printer info structure */
4207 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4208 DWORD cbBuf, /* [in] max size of buffer in bytes */
4209 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4210 LPDWORD lpdwReturned /* [out] number of entries returned */
4213 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4214 lpdwNeeded, lpdwReturned, TRUE);
4217 /******************************************************************
4218 * EnumPrintersA [WINSPOOL.@]
4221 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4222 DWORD dwLevel, LPBYTE lpbPrinters,
4223 DWORD cbBuf, LPDWORD lpdwNeeded,
4224 LPDWORD lpdwReturned)
4226 BOOL ret, unicode = FALSE;
4227 UNICODE_STRING lpszNameW;
4230 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4231 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4232 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4233 lpdwNeeded, lpdwReturned, unicode);
4234 RtlFreeUnicodeString(&lpszNameW);
4238 /*****************************************************************************
4239 * WINSPOOL_GetDriverInfoFromReg [internal]
4241 * Enters the information from the registry into the DRIVER_INFO struct
4244 * zero if the printer driver does not exist in the registry
4245 * (only if Level > 1) otherwise nonzero
4247 static BOOL WINSPOOL_GetDriverInfoFromReg(
4250 LPCWSTR pEnvironment,
4252 LPBYTE ptr, /* DRIVER_INFO */
4253 LPBYTE pDriverStrings, /* strings buffer */
4254 DWORD cbBuf, /* size of string buffer */
4255 LPDWORD pcbNeeded, /* space needed for str. */
4256 BOOL unicode) /* type of strings */
4260 LPBYTE strPtr = pDriverStrings;
4262 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4263 debugstr_w(DriverName), debugstr_w(pEnvironment),
4264 Level, ptr, pDriverStrings, cbBuf, unicode);
4267 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4268 if (*pcbNeeded <= cbBuf)
4269 strcpyW((LPWSTR)strPtr, DriverName);
4271 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4273 if(*pcbNeeded <= cbBuf)
4274 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4275 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4279 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4283 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4284 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4287 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4288 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
4289 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4294 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4297 pEnvironment = DefaultEnvironmentW;
4299 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4301 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4304 if(*pcbNeeded <= cbBuf) {
4306 strcpyW((LPWSTR)strPtr, pEnvironment);
4308 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4309 (LPSTR)strPtr, size, NULL, NULL);
4311 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4312 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4315 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4318 if(*pcbNeeded <= cbBuf)
4319 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4322 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4323 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4326 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4329 if(*pcbNeeded <= cbBuf)
4330 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4333 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4334 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4337 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4338 0, &size, unicode)) {
4340 if(*pcbNeeded <= cbBuf)
4341 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4342 size, &tmp, unicode);
4344 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4345 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4349 RegCloseKey(hkeyDriver);
4350 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4354 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4357 if(*pcbNeeded <= cbBuf)
4358 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4359 size, &tmp, unicode);
4361 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4362 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4365 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4368 if(*pcbNeeded <= cbBuf)
4369 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4370 size, &tmp, unicode);
4372 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4373 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4376 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4379 if(*pcbNeeded <= cbBuf)
4380 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4381 size, &tmp, unicode);
4383 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4384 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4387 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4390 if(*pcbNeeded <= cbBuf)
4391 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4392 size, &tmp, unicode);
4394 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4395 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4398 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4399 RegCloseKey(hkeyDriver);
4403 /*****************************************************************************
4404 * WINSPOOL_GetPrinterDriver
4406 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
4407 DWORD Level, LPBYTE pDriverInfo,
4408 DWORD cbBuf, LPDWORD pcbNeeded,
4412 WCHAR DriverName[100];
4413 DWORD ret, type, size, needed = 0;
4415 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4417 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4418 Level,pDriverInfo,cbBuf, pcbNeeded);
4420 ZeroMemory(pDriverInfo, cbBuf);
4422 if (!(name = get_opened_printer_name(hPrinter))) {
4423 SetLastError(ERROR_INVALID_HANDLE);
4426 if(Level < 1 || Level > 6) {
4427 SetLastError(ERROR_INVALID_LEVEL);
4430 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4432 ERR("Can't create Printers key\n");
4435 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4437 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4438 RegCloseKey(hkeyPrinters);
4439 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4442 size = sizeof(DriverName);
4444 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4445 (LPBYTE)DriverName, &size);
4446 RegCloseKey(hkeyPrinter);
4447 RegCloseKey(hkeyPrinters);
4448 if(ret != ERROR_SUCCESS) {
4449 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4453 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4455 ERR("Can't create Drivers key\n");
4461 size = sizeof(DRIVER_INFO_1W);
4464 size = sizeof(DRIVER_INFO_2W);
4467 size = sizeof(DRIVER_INFO_3W);
4470 size = sizeof(DRIVER_INFO_4W);
4473 size = sizeof(DRIVER_INFO_5W);
4476 size = sizeof(DRIVER_INFO_6W);
4479 ERR("Invalid level\n");
4484 ptr = pDriverInfo + size;
4486 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4487 pEnvironment, Level, pDriverInfo,
4488 (cbBuf < size) ? NULL : ptr,
4489 (cbBuf < size) ? 0 : cbBuf - size,
4490 &needed, unicode)) {
4491 RegCloseKey(hkeyDrivers);
4495 RegCloseKey(hkeyDrivers);
4497 if(pcbNeeded) *pcbNeeded = size + needed;
4498 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4499 if(cbBuf >= needed) return TRUE;
4500 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4504 /*****************************************************************************
4505 * GetPrinterDriverA [WINSPOOL.@]
4507 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4508 DWORD Level, LPBYTE pDriverInfo,
4509 DWORD cbBuf, LPDWORD pcbNeeded)
4512 UNICODE_STRING pEnvW;
4515 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4516 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4517 cbBuf, pcbNeeded, FALSE);
4518 RtlFreeUnicodeString(&pEnvW);
4521 /*****************************************************************************
4522 * GetPrinterDriverW [WINSPOOL.@]
4524 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4525 DWORD Level, LPBYTE pDriverInfo,
4526 DWORD cbBuf, LPDWORD pcbNeeded)
4528 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4529 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4532 /*****************************************************************************
4533 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4535 * Return the PATH for the Printer-Drivers (UNICODE)
4538 * pName [I] Servername (NT only) or NULL (local Computer)
4539 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4540 * Level [I] Structure-Level (must be 1)
4541 * pDriverDirectory [O] PTR to Buffer that receives the Result
4542 * cbBuf [I] Size of Buffer at pDriverDirectory
4543 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4544 * required for pDriverDirectory
4547 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4548 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4549 * if cbBuf is too small
4551 * Native Values returned in pDriverDirectory on Success:
4552 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4553 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4554 *| win9x(Windows 4.0): "%winsysdir%"
4556 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4559 *- Only NULL or "" is supported for pName
4562 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4563 DWORD Level, LPBYTE pDriverDirectory,
4564 DWORD cbBuf, LPDWORD pcbNeeded)
4567 const printenv_t * env;
4569 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4570 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4571 if(pName != NULL && pName[0]) {
4572 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4573 SetLastError(ERROR_INVALID_PARAMETER);
4577 env = validate_envW(pEnvironment);
4578 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4581 WARN("(Level: %d) is ignored in win9x\n", Level);
4582 SetLastError(ERROR_INVALID_LEVEL);
4586 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4587 needed = GetSystemDirectoryW(NULL, 0);
4588 /* add the Size for the Subdirectories */
4589 needed += lstrlenW(spooldriversW);
4590 needed += lstrlenW(env->subdir);
4591 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4594 *pcbNeeded = needed;
4595 TRACE("required: 0x%x/%d\n", needed, needed);
4596 if(needed > cbBuf) {
4597 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4600 if(pcbNeeded == NULL) {
4601 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4602 SetLastError(RPC_X_NULL_REF_POINTER);
4605 if(pDriverDirectory == NULL) {
4606 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4607 SetLastError(ERROR_INVALID_USER_BUFFER);
4611 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4612 /* add the Subdirectories */
4613 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4614 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4615 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4620 /*****************************************************************************
4621 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4623 * Return the PATH for the Printer-Drivers (ANSI)
4625 * See GetPrinterDriverDirectoryW.
4628 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4631 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4632 DWORD Level, LPBYTE pDriverDirectory,
4633 DWORD cbBuf, LPDWORD pcbNeeded)
4635 UNICODE_STRING nameW, environmentW;
4638 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4639 WCHAR *driverDirectoryW = NULL;
4641 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4642 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4644 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4646 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4647 else nameW.Buffer = NULL;
4648 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4649 else environmentW.Buffer = NULL;
4651 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4652 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4655 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4656 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4658 *pcbNeeded = needed;
4659 ret = (needed <= cbBuf) ? TRUE : FALSE;
4661 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4663 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4665 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4666 RtlFreeUnicodeString(&environmentW);
4667 RtlFreeUnicodeString(&nameW);
4672 /*****************************************************************************
4673 * AddPrinterDriverA [WINSPOOL.@]
4675 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4678 HKEY hkeyDrivers, hkeyName;
4679 static CHAR empty[] = "",
4682 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4684 if(level != 2 && level != 3) {
4685 SetLastError(ERROR_INVALID_LEVEL);
4688 if ((pName) && (pName[0])) {
4689 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4690 SetLastError(ERROR_INVALID_PARAMETER);
4694 WARN("pDriverInfo == NULL\n");
4695 SetLastError(ERROR_INVALID_PARAMETER);
4700 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4702 memset(&di3, 0, sizeof(di3));
4703 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4706 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4708 SetLastError(ERROR_INVALID_PARAMETER);
4712 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4713 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4714 if(!di3.pHelpFile) di3.pHelpFile = empty;
4715 if(!di3.pMonitorName) di3.pMonitorName = empty;
4717 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4720 ERR("Can't create Drivers key\n");
4724 if(level == 2) { /* apparently can't overwrite with level2 */
4725 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4726 RegCloseKey(hkeyName);
4727 RegCloseKey(hkeyDrivers);
4728 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4729 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4733 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4734 RegCloseKey(hkeyDrivers);
4735 ERR("Can't create Name key\n");
4738 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4739 lstrlenA(di3.pConfigFile) + 1);
4740 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4741 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4742 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4744 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4745 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4746 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4747 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4748 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4749 RegCloseKey(hkeyName);
4750 RegCloseKey(hkeyDrivers);
4755 /*****************************************************************************
4756 * AddPrinterDriverW [WINSPOOL.@]
4758 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4761 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4766 /*****************************************************************************
4767 * AddPrintProcessorA [WINSPOOL.@]
4769 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4770 LPSTR pPrintProcessorName)
4772 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4773 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4777 /*****************************************************************************
4778 * AddPrintProcessorW [WINSPOOL.@]
4780 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4781 LPWSTR pPrintProcessorName)
4783 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4784 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4788 /*****************************************************************************
4789 * AddPrintProvidorA [WINSPOOL.@]
4791 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4793 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4797 /*****************************************************************************
4798 * AddPrintProvidorW [WINSPOOL.@]
4800 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4802 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4806 /*****************************************************************************
4807 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4809 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4810 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4812 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4813 pDevModeOutput, pDevModeInput);
4817 /*****************************************************************************
4818 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4820 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4821 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4823 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4824 pDevModeOutput, pDevModeInput);
4828 /*****************************************************************************
4829 * PrinterProperties [WINSPOOL.@]
4831 * Displays a dialog to set the properties of the printer.
4834 * nonzero on success or zero on failure
4837 * implemented as stub only
4839 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4840 HANDLE hPrinter /* [in] handle to printer object */
4842 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4843 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4847 /*****************************************************************************
4848 * EnumJobsA [WINSPOOL.@]
4851 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4852 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4855 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4856 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4858 if(pcbNeeded) *pcbNeeded = 0;
4859 if(pcReturned) *pcReturned = 0;
4864 /*****************************************************************************
4865 * EnumJobsW [WINSPOOL.@]
4868 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4869 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4872 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4873 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4875 if(pcbNeeded) *pcbNeeded = 0;
4876 if(pcReturned) *pcReturned = 0;
4880 /*****************************************************************************
4881 * WINSPOOL_EnumPrinterDrivers [internal]
4883 * Delivers information about all printer drivers installed on the
4884 * localhost or a given server
4887 * nonzero on success or zero on failure. If the buffer for the returned
4888 * information is too small the function will return an error
4891 * - only implemented for localhost, foreign hosts will return an error
4893 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4894 DWORD Level, LPBYTE pDriverInfo,
4895 DWORD cbBuf, LPDWORD pcbNeeded,
4896 LPDWORD pcReturned, BOOL unicode)
4899 DWORD i, needed, number = 0, size = 0;
4900 WCHAR DriverNameW[255];
4903 TRACE("%s,%s,%d,%p,%d,%d\n",
4904 debugstr_w(pName), debugstr_w(pEnvironment),
4905 Level, pDriverInfo, cbBuf, unicode);
4907 /* check for local drivers */
4908 if((pName) && (pName[0])) {
4909 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4910 SetLastError(ERROR_ACCESS_DENIED);
4914 /* check input parameter */
4915 if((Level < 1) || (Level > 3)) {
4916 ERR("unsupported level %d\n", Level);
4917 SetLastError(ERROR_INVALID_LEVEL);
4921 /* initialize return values */
4923 memset( pDriverInfo, 0, cbBuf);
4927 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4929 ERR("Can't open Drivers key\n");
4933 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4934 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4935 RegCloseKey(hkeyDrivers);
4936 ERR("Can't query Drivers key\n");
4939 TRACE("Found %d Drivers\n", number);
4941 /* get size of single struct
4942 * unicode and ascii structure have the same size
4946 size = sizeof(DRIVER_INFO_1A);
4949 size = sizeof(DRIVER_INFO_2A);
4952 size = sizeof(DRIVER_INFO_3A);
4956 /* calculate required buffer size */
4957 *pcbNeeded = size * number;
4959 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4961 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4962 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4964 ERR("Can't enum key number %d\n", i);
4965 RegCloseKey(hkeyDrivers);
4968 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4969 pEnvironment, Level, ptr,
4970 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4971 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4972 &needed, unicode)) {
4973 RegCloseKey(hkeyDrivers);
4976 (*pcbNeeded) += needed;
4979 RegCloseKey(hkeyDrivers);
4981 if(cbBuf < *pcbNeeded){
4982 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4986 *pcReturned = number;
4990 /*****************************************************************************
4991 * EnumPrinterDriversW [WINSPOOL.@]
4993 * see function EnumPrinterDrivers for RETURNS, BUGS
4995 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4996 LPBYTE pDriverInfo, DWORD cbBuf,
4997 LPDWORD pcbNeeded, LPDWORD pcReturned)
4999 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5000 cbBuf, pcbNeeded, pcReturned, TRUE);
5003 /*****************************************************************************
5004 * EnumPrinterDriversA [WINSPOOL.@]
5006 * see function EnumPrinterDrivers for RETURNS, BUGS
5008 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5009 LPBYTE pDriverInfo, DWORD cbBuf,
5010 LPDWORD pcbNeeded, LPDWORD pcReturned)
5012 UNICODE_STRING pNameW, pEnvironmentW;
5013 PWSTR pwstrNameW, pwstrEnvironmentW;
5015 pwstrNameW = asciitounicode(&pNameW, pName);
5016 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5018 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5019 Level, pDriverInfo, cbBuf, pcbNeeded,
5021 RtlFreeUnicodeString(&pNameW);
5022 RtlFreeUnicodeString(&pEnvironmentW);
5027 /******************************************************************************
5028 * EnumPortsA (WINSPOOL.@)
5033 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5034 LPDWORD pcbNeeded, LPDWORD pcReturned)
5037 LPBYTE bufferW = NULL;
5038 LPWSTR nameW = NULL;
5040 DWORD numentries = 0;
5043 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5044 cbBuf, pcbNeeded, pcReturned);
5046 /* convert servername to unicode */
5048 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5049 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5050 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5052 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5053 needed = cbBuf * sizeof(WCHAR);
5054 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5055 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5057 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5058 if (pcbNeeded) needed = *pcbNeeded;
5059 /* HeapReAlloc return NULL, when bufferW was NULL */
5060 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5061 HeapAlloc(GetProcessHeap(), 0, needed);
5063 /* Try again with the large Buffer */
5064 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5066 needed = pcbNeeded ? *pcbNeeded : 0;
5067 numentries = pcReturned ? *pcReturned : 0;
5070 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5071 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5074 /* EnumPortsW collected all Data. Parse them to caclulate ANSI-Size */
5075 DWORD entrysize = 0;
5078 LPPORT_INFO_2W pi2w;
5079 LPPORT_INFO_2A pi2a;
5082 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5084 /* First pass: calculate the size for all Entries */
5085 pi2w = (LPPORT_INFO_2W) bufferW;
5086 pi2a = (LPPORT_INFO_2A) pPorts;
5088 while (index < numentries) {
5090 needed += entrysize; /* PORT_INFO_?A */
5091 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5093 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5094 NULL, 0, NULL, NULL);
5096 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5097 NULL, 0, NULL, NULL);
5098 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5099 NULL, 0, NULL, NULL);
5101 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5102 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5103 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5106 /* check for errors and quit on failure */
5107 if (cbBuf < needed) {
5108 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5112 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5113 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5114 cbBuf -= len ; /* free Bytes in the user-Buffer */
5115 pi2w = (LPPORT_INFO_2W) bufferW;
5116 pi2a = (LPPORT_INFO_2A) pPorts;
5118 /* Second Pass: Fill the User Buffer (if we have one) */
5119 while ((index < numentries) && pPorts) {
5121 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5122 pi2a->pPortName = ptr;
5123 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5124 ptr, cbBuf , NULL, NULL);
5128 pi2a->pMonitorName = ptr;
5129 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5130 ptr, cbBuf, NULL, NULL);
5134 pi2a->pDescription = ptr;
5135 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5136 ptr, cbBuf, NULL, NULL);
5140 pi2a->fPortType = pi2w->fPortType;
5141 pi2a->Reserved = 0; /* documented: "must be zero" */
5144 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5145 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5146 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5151 if (pcbNeeded) *pcbNeeded = needed;
5152 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5154 HeapFree(GetProcessHeap(), 0, nameW);
5155 HeapFree(GetProcessHeap(), 0, bufferW);
5157 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5158 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5164 /******************************************************************************
5165 * EnumPortsW (WINSPOOL.@)
5167 * Enumerate available Ports
5170 * name [I] Servername or NULL (local Computer)
5171 * level [I] Structure-Level (1 or 2)
5172 * buffer [O] PTR to Buffer that receives the Result
5173 * bufsize [I] Size of Buffer at buffer
5174 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5175 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5179 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5183 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5186 DWORD numentries = 0;
5189 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5190 cbBuf, pcbNeeded, pcReturned);
5192 if (pName && (pName[0])) {
5193 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5194 SetLastError(ERROR_ACCESS_DENIED);
5198 /* Level is not checked in win9x */
5199 if (!Level || (Level > 2)) {
5200 WARN("level (%d) is ignored in win9x\n", Level);
5201 SetLastError(ERROR_INVALID_LEVEL);
5205 SetLastError(RPC_X_NULL_REF_POINTER);
5209 EnterCriticalSection(&monitor_handles_cs);
5212 /* Scan all local Ports */
5214 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5216 /* we calculated the needed buffersize. now do the error-checks */
5217 if (cbBuf < needed) {
5218 monitor_unloadall();
5219 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5220 goto emP_cleanup_cs;
5222 else if (!pPorts || !pcReturned) {
5223 monitor_unloadall();
5224 SetLastError(RPC_X_NULL_REF_POINTER);
5225 goto emP_cleanup_cs;
5228 /* Fill the Buffer */
5229 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5231 monitor_unloadall();
5234 LeaveCriticalSection(&monitor_handles_cs);
5237 if (pcbNeeded) *pcbNeeded = needed;
5238 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5240 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5241 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5246 /******************************************************************************
5247 * GetDefaultPrinterW (WINSPOOL.@)
5250 * This function must read the value from data 'device' of key
5251 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5253 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5257 WCHAR *buffer, *ptr;
5261 SetLastError(ERROR_INVALID_PARAMETER);
5265 /* make the buffer big enough for the stuff from the profile/registry,
5266 * the content must fit into the local buffer to compute the correct
5267 * size even if the extern buffer is too small or not given.
5268 * (20 for ,driver,port) */
5270 len = max(100, (insize + 20));
5271 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5273 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5275 SetLastError (ERROR_FILE_NOT_FOUND);
5279 TRACE("%s\n", debugstr_w(buffer));
5281 if ((ptr = strchrW(buffer, ',')) == NULL)
5283 SetLastError(ERROR_INVALID_NAME);
5289 *namesize = strlenW(buffer) + 1;
5290 if(!name || (*namesize > insize))
5292 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5296 strcpyW(name, buffer);
5299 HeapFree( GetProcessHeap(), 0, buffer);
5304 /******************************************************************************
5305 * GetDefaultPrinterA (WINSPOOL.@)
5307 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5311 WCHAR *bufferW = NULL;
5315 SetLastError(ERROR_INVALID_PARAMETER);
5319 if(name && *namesize) {
5321 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5324 if(!GetDefaultPrinterW( bufferW, namesize)) {
5329 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5333 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5336 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5339 HeapFree( GetProcessHeap(), 0, bufferW);
5344 /******************************************************************************
5345 * SetDefaultPrinterW (WINSPOOL.204)
5347 * Set the Name of the Default Printer
5350 * pszPrinter [I] Name of the Printer or NULL
5357 * When the Parameter is NULL or points to an Empty String and
5358 * a Default Printer was already present, then this Function changes nothing.
5359 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5360 * the First enumerated local Printer is used.
5363 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5366 TRACE("(%s)\n", debugstr_w(pszPrinter));
5368 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5372 /******************************************************************************
5373 * SetDefaultPrinterA (WINSPOOL.202)
5375 * See SetDefaultPrinterW.
5378 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5381 TRACE("(%s)\n", debugstr_a(pszPrinter));
5383 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5388 /******************************************************************************
5389 * SetPrinterDataExA (WINSPOOL.@)
5391 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5392 LPCSTR pValueName, DWORD Type,
5393 LPBYTE pData, DWORD cbData)
5395 HKEY hkeyPrinter, hkeySubkey;
5398 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5399 debugstr_a(pValueName), Type, pData, cbData);
5401 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5405 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5407 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5408 RegCloseKey(hkeyPrinter);
5411 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5412 RegCloseKey(hkeySubkey);
5413 RegCloseKey(hkeyPrinter);
5417 /******************************************************************************
5418 * SetPrinterDataExW (WINSPOOL.@)
5420 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5421 LPCWSTR pValueName, DWORD Type,
5422 LPBYTE pData, DWORD cbData)
5424 HKEY hkeyPrinter, hkeySubkey;
5427 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5428 debugstr_w(pValueName), Type, pData, cbData);
5430 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5434 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5436 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5437 RegCloseKey(hkeyPrinter);
5440 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5441 RegCloseKey(hkeySubkey);
5442 RegCloseKey(hkeyPrinter);
5446 /******************************************************************************
5447 * SetPrinterDataA (WINSPOOL.@)
5449 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5450 LPBYTE pData, DWORD cbData)
5452 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5456 /******************************************************************************
5457 * SetPrinterDataW (WINSPOOL.@)
5459 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5460 LPBYTE pData, DWORD cbData)
5462 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5466 /******************************************************************************
5467 * GetPrinterDataExA (WINSPOOL.@)
5469 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5470 LPCSTR pValueName, LPDWORD pType,
5471 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5473 HKEY hkeyPrinter, hkeySubkey;
5476 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5477 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5480 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5484 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5486 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5487 RegCloseKey(hkeyPrinter);
5491 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5492 RegCloseKey(hkeySubkey);
5493 RegCloseKey(hkeyPrinter);
5497 /******************************************************************************
5498 * GetPrinterDataExW (WINSPOOL.@)
5500 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5501 LPCWSTR pValueName, LPDWORD pType,
5502 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5504 HKEY hkeyPrinter, hkeySubkey;
5507 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5508 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5511 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5515 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5517 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5518 RegCloseKey(hkeyPrinter);
5522 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5523 RegCloseKey(hkeySubkey);
5524 RegCloseKey(hkeyPrinter);
5528 /******************************************************************************
5529 * GetPrinterDataA (WINSPOOL.@)
5531 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5532 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5534 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5535 pData, nSize, pcbNeeded);
5538 /******************************************************************************
5539 * GetPrinterDataW (WINSPOOL.@)
5541 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5542 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5544 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5545 pData, nSize, pcbNeeded);
5548 /*******************************************************************************
5549 * EnumPrinterDataExW [WINSPOOL.@]
5551 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5552 LPBYTE pEnumValues, DWORD cbEnumValues,
5553 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5555 HKEY hkPrinter, hkSubKey;
5556 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5557 cbValueNameLen, cbMaxValueLen, cbValueLen,
5562 PPRINTER_ENUM_VALUESW ppev;
5564 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5566 if (pKeyName == NULL || *pKeyName == 0)
5567 return ERROR_INVALID_PARAMETER;
5569 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5570 if (ret != ERROR_SUCCESS)
5572 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5577 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5578 if (ret != ERROR_SUCCESS)
5580 r = RegCloseKey (hkPrinter);
5581 if (r != ERROR_SUCCESS)
5582 WARN ("RegCloseKey returned %i\n", r);
5583 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5584 debugstr_w (pKeyName), ret);
5588 ret = RegCloseKey (hkPrinter);
5589 if (ret != ERROR_SUCCESS)
5591 ERR ("RegCloseKey returned %i\n", ret);
5592 r = RegCloseKey (hkSubKey);
5593 if (r != ERROR_SUCCESS)
5594 WARN ("RegCloseKey returned %i\n", r);
5598 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5599 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5600 if (ret != ERROR_SUCCESS)
5602 r = RegCloseKey (hkSubKey);
5603 if (r != ERROR_SUCCESS)
5604 WARN ("RegCloseKey returned %i\n", r);
5605 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5609 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5610 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5612 if (cValues == 0) /* empty key */
5614 r = RegCloseKey (hkSubKey);
5615 if (r != ERROR_SUCCESS)
5616 WARN ("RegCloseKey returned %i\n", r);
5617 *pcbEnumValues = *pnEnumValues = 0;
5618 return ERROR_SUCCESS;
5621 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5623 hHeap = GetProcessHeap ();
5626 ERR ("GetProcessHeap failed\n");
5627 r = RegCloseKey (hkSubKey);
5628 if (r != ERROR_SUCCESS)
5629 WARN ("RegCloseKey returned %i\n", r);
5630 return ERROR_OUTOFMEMORY;
5633 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5634 if (lpValueName == NULL)
5636 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5637 r = RegCloseKey (hkSubKey);
5638 if (r != ERROR_SUCCESS)
5639 WARN ("RegCloseKey returned %i\n", r);
5640 return ERROR_OUTOFMEMORY;
5643 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5644 if (lpValue == NULL)
5646 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5647 if (HeapFree (hHeap, 0, lpValueName) == 0)
5648 WARN ("HeapFree failed with code %i\n", GetLastError ());
5649 r = RegCloseKey (hkSubKey);
5650 if (r != ERROR_SUCCESS)
5651 WARN ("RegCloseKey returned %i\n", r);
5652 return ERROR_OUTOFMEMORY;
5655 TRACE ("pass 1: calculating buffer required for all names and values\n");
5657 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5659 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5661 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5663 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5664 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5665 NULL, NULL, lpValue, &cbValueLen);
5666 if (ret != ERROR_SUCCESS)
5668 if (HeapFree (hHeap, 0, lpValue) == 0)
5669 WARN ("HeapFree failed with code %i\n", GetLastError ());
5670 if (HeapFree (hHeap, 0, lpValueName) == 0)
5671 WARN ("HeapFree failed with code %i\n", GetLastError ());
5672 r = RegCloseKey (hkSubKey);
5673 if (r != ERROR_SUCCESS)
5674 WARN ("RegCloseKey returned %i\n", r);
5675 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5679 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5680 debugstr_w (lpValueName), dwIndex,
5681 cbValueNameLen + 1, cbValueLen);
5683 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5684 cbBufSize += cbValueLen;
5687 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5689 *pcbEnumValues = cbBufSize;
5690 *pnEnumValues = cValues;
5692 if (cbEnumValues < cbBufSize) /* buffer too small */
5694 if (HeapFree (hHeap, 0, lpValue) == 0)
5695 WARN ("HeapFree failed with code %i\n", GetLastError ());
5696 if (HeapFree (hHeap, 0, lpValueName) == 0)
5697 WARN ("HeapFree failed with code %i\n", GetLastError ());
5698 r = RegCloseKey (hkSubKey);
5699 if (r != ERROR_SUCCESS)
5700 WARN ("RegCloseKey returned %i\n", r);
5701 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5702 return ERROR_MORE_DATA;
5705 TRACE ("pass 2: copying all names and values to buffer\n");
5707 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5708 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5710 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5712 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5713 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5714 NULL, &dwType, lpValue, &cbValueLen);
5715 if (ret != ERROR_SUCCESS)
5717 if (HeapFree (hHeap, 0, lpValue) == 0)
5718 WARN ("HeapFree failed with code %i\n", GetLastError ());
5719 if (HeapFree (hHeap, 0, lpValueName) == 0)
5720 WARN ("HeapFree failed with code %i\n", GetLastError ());
5721 r = RegCloseKey (hkSubKey);
5722 if (r != ERROR_SUCCESS)
5723 WARN ("RegCloseKey returned %i\n", r);
5724 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5728 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5729 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5730 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5731 pEnumValues += cbValueNameLen;
5733 /* return # of *bytes* (including trailing \0), not # of chars */
5734 ppev[dwIndex].cbValueName = cbValueNameLen;
5736 ppev[dwIndex].dwType = dwType;
5738 memcpy (pEnumValues, lpValue, cbValueLen);
5739 ppev[dwIndex].pData = pEnumValues;
5740 pEnumValues += cbValueLen;
5742 ppev[dwIndex].cbData = cbValueLen;
5744 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5745 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5748 if (HeapFree (hHeap, 0, lpValue) == 0)
5750 ret = GetLastError ();
5751 ERR ("HeapFree failed with code %i\n", ret);
5752 if (HeapFree (hHeap, 0, lpValueName) == 0)
5753 WARN ("HeapFree failed with code %i\n", GetLastError ());
5754 r = RegCloseKey (hkSubKey);
5755 if (r != ERROR_SUCCESS)
5756 WARN ("RegCloseKey returned %i\n", r);
5760 if (HeapFree (hHeap, 0, lpValueName) == 0)
5762 ret = GetLastError ();
5763 ERR ("HeapFree failed with code %i\n", ret);
5764 r = RegCloseKey (hkSubKey);
5765 if (r != ERROR_SUCCESS)
5766 WARN ("RegCloseKey returned %i\n", r);
5770 ret = RegCloseKey (hkSubKey);
5771 if (ret != ERROR_SUCCESS)
5773 ERR ("RegCloseKey returned %i\n", ret);
5777 return ERROR_SUCCESS;
5780 /*******************************************************************************
5781 * EnumPrinterDataExA [WINSPOOL.@]
5783 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5784 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5785 * what Windows 2000 SP1 does.
5788 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5789 LPBYTE pEnumValues, DWORD cbEnumValues,
5790 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5794 DWORD ret, dwIndex, dwBufSize;
5798 TRACE ("%p %s\n", hPrinter, pKeyName);
5800 if (pKeyName == NULL || *pKeyName == 0)
5801 return ERROR_INVALID_PARAMETER;
5803 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5806 ret = GetLastError ();
5807 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5811 hHeap = GetProcessHeap ();
5814 ERR ("GetProcessHeap failed\n");
5815 return ERROR_OUTOFMEMORY;
5818 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5819 if (pKeyNameW == NULL)
5821 ERR ("Failed to allocate %i bytes from process heap\n",
5822 (LONG)(len * sizeof (WCHAR)));
5823 return ERROR_OUTOFMEMORY;
5826 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5828 ret = GetLastError ();
5829 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5830 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5831 WARN ("HeapFree failed with code %i\n", GetLastError ());
5835 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5836 pcbEnumValues, pnEnumValues);
5837 if (ret != ERROR_SUCCESS)
5839 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5840 WARN ("HeapFree failed with code %i\n", GetLastError ());
5841 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5845 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5847 ret = GetLastError ();
5848 ERR ("HeapFree failed with code %i\n", ret);
5852 if (*pnEnumValues == 0) /* empty key */
5853 return ERROR_SUCCESS;
5856 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5858 PPRINTER_ENUM_VALUESW ppev =
5859 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5861 if (dwBufSize < ppev->cbValueName)
5862 dwBufSize = ppev->cbValueName;
5864 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5865 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5866 dwBufSize = ppev->cbData;
5869 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5871 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5872 if (pBuffer == NULL)
5874 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5875 return ERROR_OUTOFMEMORY;
5878 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5880 PPRINTER_ENUM_VALUESW ppev =
5881 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5883 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5884 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5888 ret = GetLastError ();
5889 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5890 if (HeapFree (hHeap, 0, pBuffer) == 0)
5891 WARN ("HeapFree failed with code %i\n", GetLastError ());
5895 memcpy (ppev->pValueName, pBuffer, len);
5897 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5899 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5900 ppev->dwType != REG_MULTI_SZ)
5903 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5904 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5907 ret = GetLastError ();
5908 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5909 if (HeapFree (hHeap, 0, pBuffer) == 0)
5910 WARN ("HeapFree failed with code %i\n", GetLastError ());
5914 memcpy (ppev->pData, pBuffer, len);
5916 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5917 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5920 if (HeapFree (hHeap, 0, pBuffer) == 0)
5922 ret = GetLastError ();
5923 ERR ("HeapFree failed with code %i\n", ret);
5927 return ERROR_SUCCESS;
5930 /******************************************************************************
5931 * AbortPrinter (WINSPOOL.@)
5933 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5935 FIXME("(%p), stub!\n", hPrinter);
5939 /******************************************************************************
5940 * AddPortA (WINSPOOL.@)
5945 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5947 LPWSTR nameW = NULL;
5948 LPWSTR monitorW = NULL;
5952 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5955 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5956 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5957 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5961 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5962 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5963 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5965 res = AddPortW(nameW, hWnd, monitorW);
5966 HeapFree(GetProcessHeap(), 0, nameW);
5967 HeapFree(GetProcessHeap(), 0, monitorW);
5971 /******************************************************************************
5972 * AddPortW (WINSPOOL.@)
5974 * Add a Port for a specific Monitor
5977 * pName [I] Servername or NULL (local Computer)
5978 * hWnd [I] Handle to parent Window for the Dialog-Box
5979 * pMonitorName [I] Name of the Monitor that manage the Port
5986 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5989 DWORD res = ROUTER_UNKNOWN;
5991 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5993 if (pName && pName[0]) {
5994 SetLastError(ERROR_INVALID_PARAMETER);
5998 if (!pMonitorName) {
5999 SetLastError(RPC_X_NULL_REF_POINTER);
6003 /* an empty Monitorname is Invalid */
6004 if (!pMonitorName[0]) goto cleanup;
6006 pm = monitor_load(pMonitorName, NULL);
6007 if (pm && pm->monitor) {
6008 if (pm->monitor->pfnAddPort != NULL) {
6009 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6010 TRACE("got %d with %d\n", res, GetLastError());
6012 else if (pm->monitor->pfnXcvOpenPort != NULL)
6014 FIXME("XcvOpenPort not implemented (dwMonitorSize: %d)\n", pm->dwMonitorSize);
6016 /* invalidate cached PORT_INFO_2W */
6017 if (res == ROUTER_SUCCESS) monitor_flush(pm);
6022 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6023 if (res == ROUTER_UNKNOWN) SetLastError(ERROR_NOT_SUPPORTED);
6024 TRACE("returning %d with %d\n", (res == ROUTER_SUCCESS), GetLastError());
6025 return (res == ROUTER_SUCCESS);
6028 /******************************************************************************
6029 * AddPortExA (WINSPOOL.@)
6034 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
6036 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
6037 lpBuffer, debugstr_a(lpMonitorName));
6041 /******************************************************************************
6042 * AddPortExW (WINSPOOL.@)
6044 * Add a Port for a specific Monitor, without presenting a user interface
6047 * hMonitor [I] Handle from InitializePrintMonitor2()
6048 * pName [I] Servername or NULL (local Computer)
6049 * Level [I] Structure-Level (1 or 2) for lpBuffer
6050 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6051 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
6061 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
6063 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
6064 lpBuffer, debugstr_w(lpMonitorName));
6068 /******************************************************************************
6069 * AddPrinterConnectionA (WINSPOOL.@)
6071 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6073 FIXME("%s\n", debugstr_a(pName));
6077 /******************************************************************************
6078 * AddPrinterConnectionW (WINSPOOL.@)
6080 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6082 FIXME("%s\n", debugstr_w(pName));
6086 /******************************************************************************
6087 * AddPrinterDriverExW (WINSPOOL.@)
6089 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6090 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6092 FIXME("%s %d %p %d\n", debugstr_w(pName),
6093 Level, pDriverInfo, dwFileCopyFlags);
6094 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6098 /******************************************************************************
6099 * AddPrinterDriverExA (WINSPOOL.@)
6101 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6102 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6104 FIXME("%s %d %p %d\n", debugstr_a(pName),
6105 Level, pDriverInfo, dwFileCopyFlags);
6106 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6110 /******************************************************************************
6111 * ConfigurePortA (WINSPOOL.@)
6113 * See ConfigurePortW.
6116 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6118 LPWSTR nameW = NULL;
6119 LPWSTR portW = NULL;
6123 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6125 /* convert servername to unicode */
6127 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6128 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6129 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6132 /* convert portname to unicode */
6134 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6135 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6136 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6139 res = ConfigurePortW(nameW, hWnd, portW);
6140 HeapFree(GetProcessHeap(), 0, nameW);
6141 HeapFree(GetProcessHeap(), 0, portW);
6145 /******************************************************************************
6146 * ConfigurePortW (WINSPOOL.@)
6148 * Display the Configuration-Dialog for a specific Port
6151 * pName [I] Servername or NULL (local Computer)
6152 * hWnd [I] Handle to parent Window for the Dialog-Box
6153 * pPortName [I] Name of the Port, that should be configured
6160 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6166 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6168 if (pName && pName[0]) {
6169 SetLastError(ERROR_INVALID_PARAMETER);
6174 SetLastError(RPC_X_NULL_REF_POINTER);
6178 /* an empty Portname is Invalid, but can popup a Dialog */
6179 if (!pPortName[0]) {
6180 SetLastError(ERROR_NOT_SUPPORTED);
6184 pm = monitor_load_by_port(pPortName);
6185 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6186 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6187 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6188 TRACE("got %d with %u\n", res, GetLastError());
6192 pui = monitor_loadui(pm);
6193 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6194 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6195 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6196 TRACE("got %d with %u\n", res, GetLastError());
6200 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6201 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6203 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6204 SetLastError(ERROR_NOT_SUPPORTED);
6207 monitor_unload(pui);
6211 TRACE("returning %d with %u\n", res, GetLastError());
6215 /******************************************************************************
6216 * ConnectToPrinterDlg (WINSPOOL.@)
6218 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6220 FIXME("%p %x\n", hWnd, Flags);
6224 /******************************************************************************
6225 * DeletePrinterConnectionA (WINSPOOL.@)
6227 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6229 FIXME("%s\n", debugstr_a(pName));
6233 /******************************************************************************
6234 * DeletePrinterConnectionW (WINSPOOL.@)
6236 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6238 FIXME("%s\n", debugstr_w(pName));
6242 /******************************************************************************
6243 * DeletePrinterDriverExW (WINSPOOL.@)
6245 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6246 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6251 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6252 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6254 if(pName && pName[0])
6256 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6257 SetLastError(ERROR_INVALID_PARAMETER);
6263 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6264 SetLastError(ERROR_INVALID_PARAMETER);
6268 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6272 ERR("Can't open drivers key\n");
6276 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6279 RegCloseKey(hkey_drivers);
6284 /******************************************************************************
6285 * DeletePrinterDriverExA (WINSPOOL.@)
6287 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6288 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6290 UNICODE_STRING NameW, EnvW, DriverW;
6293 asciitounicode(&NameW, pName);
6294 asciitounicode(&EnvW, pEnvironment);
6295 asciitounicode(&DriverW, pDriverName);
6297 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6299 RtlFreeUnicodeString(&DriverW);
6300 RtlFreeUnicodeString(&EnvW);
6301 RtlFreeUnicodeString(&NameW);
6306 /******************************************************************************
6307 * DeletePrinterDataExW (WINSPOOL.@)
6309 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6312 FIXME("%p %s %s\n", hPrinter,
6313 debugstr_w(pKeyName), debugstr_w(pValueName));
6314 return ERROR_INVALID_PARAMETER;
6317 /******************************************************************************
6318 * DeletePrinterDataExA (WINSPOOL.@)
6320 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6323 FIXME("%p %s %s\n", hPrinter,
6324 debugstr_a(pKeyName), debugstr_a(pValueName));
6325 return ERROR_INVALID_PARAMETER;
6328 /******************************************************************************
6329 * DeletePrintProcessorA (WINSPOOL.@)
6331 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6333 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6334 debugstr_a(pPrintProcessorName));
6338 /******************************************************************************
6339 * DeletePrintProcessorW (WINSPOOL.@)
6341 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6343 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6344 debugstr_w(pPrintProcessorName));
6348 /******************************************************************************
6349 * DeletePrintProvidorA (WINSPOOL.@)
6351 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6353 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6354 debugstr_a(pPrintProviderName));
6358 /******************************************************************************
6359 * DeletePrintProvidorW (WINSPOOL.@)
6361 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6363 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6364 debugstr_w(pPrintProviderName));
6368 /******************************************************************************
6369 * EnumFormsA (WINSPOOL.@)
6371 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6372 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6374 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6375 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6379 /******************************************************************************
6380 * EnumFormsW (WINSPOOL.@)
6382 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6383 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6385 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6386 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6390 /*****************************************************************************
6391 * EnumMonitorsA [WINSPOOL.@]
6393 * See EnumMonitorsW.
6396 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6397 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6400 LPBYTE bufferW = NULL;
6401 LPWSTR nameW = NULL;
6403 DWORD numentries = 0;
6406 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6407 cbBuf, pcbNeeded, pcReturned);
6409 /* convert servername to unicode */
6411 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6412 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6413 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6415 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6416 needed = cbBuf * sizeof(WCHAR);
6417 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6418 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6420 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6421 if (pcbNeeded) needed = *pcbNeeded;
6422 /* HeapReAlloc return NULL, when bufferW was NULL */
6423 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6424 HeapAlloc(GetProcessHeap(), 0, needed);
6426 /* Try again with the large Buffer */
6427 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6429 numentries = pcReturned ? *pcReturned : 0;
6432 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6433 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6436 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
6437 DWORD entrysize = 0;
6440 LPMONITOR_INFO_2W mi2w;
6441 LPMONITOR_INFO_2A mi2a;
6443 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6444 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6446 /* First pass: calculate the size for all Entries */
6447 mi2w = (LPMONITOR_INFO_2W) bufferW;
6448 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6450 while (index < numentries) {
6452 needed += entrysize; /* MONITOR_INFO_?A */
6453 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6455 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6456 NULL, 0, NULL, NULL);
6458 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6459 NULL, 0, NULL, NULL);
6460 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6461 NULL, 0, NULL, NULL);
6463 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6464 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6465 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6468 /* check for errors and quit on failure */
6469 if (cbBuf < needed) {
6470 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6474 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6475 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6476 cbBuf -= len ; /* free Bytes in the user-Buffer */
6477 mi2w = (LPMONITOR_INFO_2W) bufferW;
6478 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6480 /* Second Pass: Fill the User Buffer (if we have one) */
6481 while ((index < numentries) && pMonitors) {
6483 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6485 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6486 ptr, cbBuf , NULL, NULL);
6490 mi2a->pEnvironment = ptr;
6491 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6492 ptr, cbBuf, NULL, NULL);
6496 mi2a->pDLLName = ptr;
6497 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6498 ptr, cbBuf, NULL, NULL);
6502 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6503 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6504 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6508 if (pcbNeeded) *pcbNeeded = needed;
6509 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6511 HeapFree(GetProcessHeap(), 0, nameW);
6512 HeapFree(GetProcessHeap(), 0, bufferW);
6514 TRACE("returning %d with %d (%d byte for %d entries)\n",
6515 (res), GetLastError(), needed, numentries);
6521 /*****************************************************************************
6522 * EnumMonitorsW [WINSPOOL.@]
6524 * Enumerate available Port-Monitors
6527 * pName [I] Servername or NULL (local Computer)
6528 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6529 * pMonitors [O] PTR to Buffer that receives the Result
6530 * cbBuf [I] Size of Buffer at pMonitors
6531 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6532 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6536 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6539 * Windows reads the Registry once and cache the Results.
6541 *| Language-Monitors are also installed in the same Registry-Location but
6542 *| they are filtered in Windows (not returned by EnumMonitors).
6543 *| We do no filtering to simplify our Code.
6546 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6547 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6550 DWORD numentries = 0;
6553 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6554 cbBuf, pcbNeeded, pcReturned);
6556 if (pName && (lstrlenW(pName))) {
6557 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6558 SetLastError(ERROR_ACCESS_DENIED);
6562 /* Level is not checked in win9x */
6563 if (!Level || (Level > 2)) {
6564 WARN("level (%d) is ignored in win9x\n", Level);
6565 SetLastError(ERROR_INVALID_LEVEL);
6569 SetLastError(RPC_X_NULL_REF_POINTER);
6573 /* Scan all Monitor-Keys */
6575 needed = get_local_monitors(Level, NULL, 0, &numentries);
6577 /* we calculated the needed buffersize. now do the error-checks */
6578 if (cbBuf < needed) {
6579 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6582 else if (!pMonitors || !pcReturned) {
6583 SetLastError(RPC_X_NULL_REF_POINTER);
6587 /* fill the Buffer with the Monitor-Keys */
6588 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6592 if (pcbNeeded) *pcbNeeded = needed;
6593 if (pcReturned) *pcReturned = numentries;
6595 TRACE("returning %d with %d (%d byte for %d entries)\n",
6596 res, GetLastError(), needed, numentries);
6601 /******************************************************************************
6602 * XcvDataW (WINSPOOL.@)
6604 * Execute commands in the Printmonitor DLL
6607 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6608 * pszDataName [i] Name of the command to execute
6609 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6610 * cbInputData [i] Size in Bytes of Buffer at pInputData
6611 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6612 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6613 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6614 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6621 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6622 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6624 * Minimal List of commands, that a Printmonitor DLL should support:
6626 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6627 *| "AddPort" : Add a Port
6628 *| "DeletePort": Delete a Port
6630 * Many Printmonitors support additional commands. Examples for localspl.dll:
6631 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6632 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6635 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6636 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6637 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6639 opened_printer_t *printer;
6641 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6642 pInputData, cbInputData, pOutputData,
6643 cbOutputData, pcbOutputNeeded, pdwStatus);
6645 printer = get_opened_printer(hXcv);
6646 if (!printer || (!printer->hXcv)) {
6647 SetLastError(ERROR_INVALID_HANDLE);
6651 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6652 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6657 /*****************************************************************************
6658 * EnumPrinterDataA [WINSPOOL.@]
6661 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6662 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6663 DWORD cbData, LPDWORD pcbData )
6665 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6666 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6667 return ERROR_NO_MORE_ITEMS;
6670 /*****************************************************************************
6671 * EnumPrinterDataW [WINSPOOL.@]
6674 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6675 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6676 DWORD cbData, LPDWORD pcbData )
6678 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6679 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6680 return ERROR_NO_MORE_ITEMS;
6683 /*****************************************************************************
6684 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6687 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6688 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6689 LPDWORD pcbNeeded, LPDWORD pcReturned)
6691 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6692 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6693 pcbNeeded, pcReturned);
6697 /*****************************************************************************
6698 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6701 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6702 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6703 LPDWORD pcbNeeded, LPDWORD pcReturned)
6705 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6706 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6707 pcbNeeded, pcReturned);
6711 /*****************************************************************************
6712 * EnumPrintProcessorsA [WINSPOOL.@]
6715 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6716 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6718 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6719 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6723 /*****************************************************************************
6724 * EnumPrintProcessorsW [WINSPOOL.@]
6727 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6728 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6730 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6731 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6732 cbBuf, pcbNeeded, pcbReturned);
6736 /*****************************************************************************
6737 * ExtDeviceMode [WINSPOOL.@]
6740 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6741 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6744 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6745 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6746 debugstr_a(pProfile), fMode);
6750 /*****************************************************************************
6751 * FindClosePrinterChangeNotification [WINSPOOL.@]
6754 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6756 FIXME("Stub: %p\n", hChange);
6760 /*****************************************************************************
6761 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6764 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6765 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6767 FIXME("Stub: %p %x %x %p\n",
6768 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6769 return INVALID_HANDLE_VALUE;
6772 /*****************************************************************************
6773 * FindNextPrinterChangeNotification [WINSPOOL.@]
6776 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6777 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6779 FIXME("Stub: %p %p %p %p\n",
6780 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6784 /*****************************************************************************
6785 * FreePrinterNotifyInfo [WINSPOOL.@]
6788 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6790 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6794 /*****************************************************************************
6797 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6798 * ansi depending on the unicode parameter.
6800 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6810 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6813 memcpy(ptr, str, *size);
6820 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6823 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6830 /*****************************************************************************
6833 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6834 LPDWORD pcbNeeded, BOOL unicode)
6836 DWORD size, left = cbBuf;
6837 BOOL space = (cbBuf > 0);
6844 ji1->JobId = job->job_id;
6847 string_to_buf(job->document_title, ptr, left, &size, unicode);
6848 if(space && size <= left)
6850 ji1->pDocument = (LPWSTR)ptr;
6861 /*****************************************************************************
6864 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6865 LPDWORD pcbNeeded, BOOL unicode)
6867 DWORD size, left = cbBuf;
6868 BOOL space = (cbBuf > 0);
6875 ji2->JobId = job->job_id;
6878 string_to_buf(job->document_title, ptr, left, &size, unicode);
6879 if(space && size <= left)
6881 ji2->pDocument = (LPWSTR)ptr;
6892 /*****************************************************************************
6895 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6896 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6899 DWORD needed = 0, size;
6903 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6905 EnterCriticalSection(&printer_handles_cs);
6906 job = get_job(hPrinter, JobId);
6913 size = sizeof(JOB_INFO_1W);
6918 memset(pJob, 0, size);
6922 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6927 size = sizeof(JOB_INFO_2W);
6932 memset(pJob, 0, size);
6936 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6941 size = sizeof(JOB_INFO_3);
6945 memset(pJob, 0, size);
6954 SetLastError(ERROR_INVALID_LEVEL);
6958 *pcbNeeded = needed;
6960 LeaveCriticalSection(&printer_handles_cs);
6964 /*****************************************************************************
6965 * GetJobA [WINSPOOL.@]
6968 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6969 DWORD cbBuf, LPDWORD pcbNeeded)
6971 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6974 /*****************************************************************************
6975 * GetJobW [WINSPOOL.@]
6978 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6979 DWORD cbBuf, LPDWORD pcbNeeded)
6981 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6984 /*****************************************************************************
6987 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6989 char *unixname, *queue, *cmd;
6990 char fmt[] = "lpr -P%s %s";
6993 if(!(unixname = wine_get_unix_file_name(filename)))
6996 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6997 queue = HeapAlloc(GetProcessHeap(), 0, len);
6998 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7000 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7001 sprintf(cmd, fmt, queue, unixname);
7003 TRACE("printing with: %s\n", cmd);
7006 HeapFree(GetProcessHeap(), 0, cmd);
7007 HeapFree(GetProcessHeap(), 0, queue);
7008 HeapFree(GetProcessHeap(), 0, unixname);
7012 /*****************************************************************************
7015 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7017 #if HAVE_CUPS_CUPS_H
7020 char *unixname, *queue, *doc_titleA;
7024 if(!(unixname = wine_get_unix_file_name(filename)))
7027 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7028 queue = HeapAlloc(GetProcessHeap(), 0, len);
7029 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7031 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7032 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7033 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7035 TRACE("printing via cups\n");
7036 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7037 HeapFree(GetProcessHeap(), 0, doc_titleA);
7038 HeapFree(GetProcessHeap(), 0, queue);
7039 HeapFree(GetProcessHeap(), 0, unixname);
7045 return schedule_lpr(printer_name, filename);
7049 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7056 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7060 if(HIWORD(wparam) == BN_CLICKED)
7062 if(LOWORD(wparam) == IDOK)
7065 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7068 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7069 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7071 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7073 WCHAR caption[200], message[200];
7076 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7077 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7078 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7079 if(mb_ret == IDCANCEL)
7081 HeapFree(GetProcessHeap(), 0, filename);
7085 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7086 if(hf == INVALID_HANDLE_VALUE)
7088 WCHAR caption[200], message[200];
7090 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7091 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7092 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7093 HeapFree(GetProcessHeap(), 0, filename);
7097 DeleteFileW(filename);
7098 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7100 EndDialog(hwnd, IDOK);
7103 if(LOWORD(wparam) == IDCANCEL)
7105 EndDialog(hwnd, IDCANCEL);
7114 /*****************************************************************************
7117 static BOOL get_filename(LPWSTR *filename)
7119 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7120 file_dlg_proc, (LPARAM)filename) == IDOK;
7123 /*****************************************************************************
7126 static BOOL schedule_file(LPCWSTR filename)
7128 LPWSTR output = NULL;
7130 if(get_filename(&output))
7132 TRACE("copy to %s\n", debugstr_w(output));
7133 CopyFileW(filename, output, FALSE);
7134 HeapFree(GetProcessHeap(), 0, output);
7140 /*****************************************************************************
7143 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7146 char *unixname, *cmdA;
7148 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7152 if(!(unixname = wine_get_unix_file_name(filename)))
7155 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7156 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7157 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7159 TRACE("printing with: %s\n", cmdA);
7161 if((file_fd = open(unixname, O_RDONLY)) == -1)
7166 ERR("pipe() failed!\n");
7176 /* reset signals that we previously set to SIG_IGN */
7177 signal(SIGPIPE, SIG_DFL);
7178 signal(SIGCHLD, SIG_DFL);
7184 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7185 write(fds[1], buf, no_read);
7190 if(file_fd != -1) close(file_fd);
7191 if(fds[0] != -1) close(fds[0]);
7192 if(fds[1] != -1) close(fds[1]);
7194 HeapFree(GetProcessHeap(), 0, cmdA);
7195 HeapFree(GetProcessHeap(), 0, unixname);
7202 /*****************************************************************************
7205 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7207 int in_fd, out_fd, no_read;
7210 char *unixname, *outputA;
7213 if(!(unixname = wine_get_unix_file_name(filename)))
7216 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7217 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7218 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7220 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7221 in_fd = open(unixname, O_RDONLY);
7222 if(out_fd == -1 || in_fd == -1)
7225 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7226 write(out_fd, buf, no_read);
7230 if(in_fd != -1) close(in_fd);
7231 if(out_fd != -1) close(out_fd);
7232 HeapFree(GetProcessHeap(), 0, outputA);
7233 HeapFree(GetProcessHeap(), 0, unixname);
7237 /*****************************************************************************
7238 * ScheduleJob [WINSPOOL.@]
7241 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7243 opened_printer_t *printer;
7245 struct list *cursor, *cursor2;
7247 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7248 EnterCriticalSection(&printer_handles_cs);
7249 printer = get_opened_printer(hPrinter);
7253 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7255 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7258 if(job->job_id != dwJobID) continue;
7260 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7261 if(hf != INVALID_HANDLE_VALUE)
7263 PRINTER_INFO_5W *pi5;
7267 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7268 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7270 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7271 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7272 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7273 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7274 debugstr_w(pi5->pPortName));
7278 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7279 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7281 DWORD type, count = sizeof(output);
7282 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7285 if(output[0] == '|')
7287 schedule_pipe(output + 1, job->filename);
7291 schedule_unixfile(output, job->filename);
7293 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7295 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7297 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7299 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7301 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7303 schedule_file(job->filename);
7307 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7309 HeapFree(GetProcessHeap(), 0, pi5);
7311 DeleteFileW(job->filename);
7313 list_remove(cursor);
7314 HeapFree(GetProcessHeap(), 0, job->document_title);
7315 HeapFree(GetProcessHeap(), 0, job->filename);
7316 HeapFree(GetProcessHeap(), 0, job);
7321 LeaveCriticalSection(&printer_handles_cs);
7325 /*****************************************************************************
7326 * StartDocDlgA [WINSPOOL.@]
7328 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7330 UNICODE_STRING usBuffer;
7333 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7336 docW.cbSize = sizeof(docW);
7337 if (doc->lpszDocName)
7339 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7340 if (!(docW.lpszDocName = docnameW)) return NULL;
7342 if (doc->lpszOutput)
7344 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7345 if (!(docW.lpszOutput = outputW)) return NULL;
7347 if (doc->lpszDatatype)
7349 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7350 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7352 docW.fwType = doc->fwType;
7354 retW = StartDocDlgW(hPrinter, &docW);
7358 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7359 ret = HeapAlloc(GetProcessHeap(), 0, len);
7360 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7361 HeapFree(GetProcessHeap(), 0, retW);
7364 HeapFree(GetProcessHeap(), 0, datatypeW);
7365 HeapFree(GetProcessHeap(), 0, outputW);
7366 HeapFree(GetProcessHeap(), 0, docnameW);
7371 /*****************************************************************************
7372 * StartDocDlgW [WINSPOOL.@]
7374 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7375 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7376 * port is "FILE:". Also returns the full path if passed a relative path.
7378 * The caller should free the returned string from the process heap.
7380 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7385 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7387 PRINTER_INFO_5W *pi5;
7388 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7389 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7391 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7392 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7393 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7395 HeapFree(GetProcessHeap(), 0, pi5);
7398 HeapFree(GetProcessHeap(), 0, pi5);
7401 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7405 if (get_filename(&name))
7407 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7409 HeapFree(GetProcessHeap(), 0, name);
7412 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7413 GetFullPathNameW(name, len, ret, NULL);
7414 HeapFree(GetProcessHeap(), 0, name);
7419 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7422 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7423 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7425 attr = GetFileAttributesW(ret);
7426 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7428 HeapFree(GetProcessHeap(), 0, ret);