4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
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 */
126 WCHAR *document_title;
134 LPCWSTR versionregpath;
135 LPCWSTR versionsubdir;
138 /* ############################### */
140 static struct list monitor_handles = LIST_INIT( monitor_handles );
141 static monitor_t * pm_localport;
143 static opened_printer_t **printer_handles;
144 static int nb_printer_handles;
145 static LONG next_job_id = 1;
147 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
148 WORD fwCapability, LPSTR lpszOutput,
150 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
151 LPSTR lpszDevice, LPSTR lpszPort,
152 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
155 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
156 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
157 'c','o','n','t','r','o','l','\\',
158 'P','r','i','n','t','\\',
159 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
160 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
162 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
163 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
164 'C','o','n','t','r','o','l','\\',
165 'P','r','i','n','t','\\',
166 'M','o','n','i','t','o','r','s','\\',0};
168 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
169 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
170 'C','o','n','t','r','o','l','\\',
171 'P','r','i','n','t','\\',
172 'P','r','i','n','t','e','r','s',0};
174 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
176 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
177 'M','i','c','r','o','s','o','f','t','\\',
178 'W','i','n','d','o','w','s',' ','N','T','\\',
179 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
180 'W','i','n','d','o','w','s',0};
182 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
183 'M','i','c','r','o','s','o','f','t','\\',
184 'W','i','n','d','o','w','s',' ','N','T','\\',
185 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
186 'D','e','v','i','c','e','s',0};
188 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
189 'M','i','c','r','o','s','o','f','t','\\',
190 'W','i','n','d','o','w','s',' ','N','T','\\',
191 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
192 'P','o','r','t','s',0};
194 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
195 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
196 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
197 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
198 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
199 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
200 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
202 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
203 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
205 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
206 'i','o','n',' ','F','i','l','e',0};
207 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
208 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
209 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
211 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
213 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
214 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
215 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
216 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
217 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
218 static const WCHAR NameW[] = {'N','a','m','e',0};
219 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
220 static const WCHAR PortW[] = {'P','o','r','t',0};
221 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
222 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
224 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
226 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
227 'v','e','r','D','a','t','a',0};
228 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
230 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
232 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
233 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
234 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
235 static const WCHAR emptyStringW[] = {0};
237 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
239 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
240 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
241 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
243 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
244 'D','o','c','u','m','e','n','t',0};
246 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
247 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
248 DWORD Level, LPBYTE pDriverInfo,
249 DWORD cbBuf, LPDWORD pcbNeeded,
251 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
252 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
254 /******************************************************************
255 * validate the user-supplied printing-environment [internal]
258 * env [I] PTR to Environment-String or NULL
262 * Success: PTR to printenv_t
265 * An empty string is handled the same way as NULL.
266 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
270 static const printenv_t * validate_envW(LPCWSTR env)
272 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
273 3, Version3_RegPathW, Version3_SubdirW};
274 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
275 0, emptyStringW, emptyStringW};
276 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
278 const printenv_t *result = NULL;
281 TRACE("testing %s\n", debugstr_w(env));
284 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
286 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
288 result = all_printenv[i];
293 if (result == NULL) {
294 FIXME("unsupported Environment: %s\n", debugstr_w(env));
295 SetLastError(ERROR_INVALID_ENVIRONMENT);
297 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
301 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
303 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
309 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
310 if passed a NULL string. This returns NULLs to the result.
312 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
316 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
317 return usBufferPtr->Buffer;
319 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
323 static LPWSTR strdupW(LPCWSTR p)
329 len = (strlenW(p) + 1) * sizeof(WCHAR);
330 ret = HeapAlloc(GetProcessHeap(), 0, len);
335 static LPSTR strdupWtoA( LPCWSTR str )
340 if (!str) return NULL;
341 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
342 ret = HeapAlloc( GetProcessHeap(), 0, len );
343 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
347 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
348 The result includes all \0s (specifically the last two). */
349 static int multi_sz_lenA(const char *str)
351 const char *ptr = str;
355 ptr += lstrlenA(ptr) + 1;
358 return ptr - str + 1;
362 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
365 /* If forcing, or no profile string entry for device yet, set the entry
367 * The always change entry if not WINEPS yet is discussable.
370 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
372 !strstr(qbuf,"WINEPS.DRV")
374 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
377 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
378 WriteProfileStringA("windows","device",buf);
379 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
380 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
383 HeapFree(GetProcessHeap(),0,buf);
387 static BOOL add_printer_driver(char *name)
391 static char driver_path[] = "wineps16",
392 data_file[] = "<datafile?>",
393 config_file[] = "wineps16",
394 help_file[] = "<helpfile?>",
395 dep_file[] = "<dependent files?>\0",
396 monitor_name[] = "<monitor name?>",
397 default_data_type[] = "RAW";
399 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
400 di3a.pName = (char *)name;
401 di3a.pEnvironment = NULL; /* NULL means auto */
402 di3a.pDriverPath = driver_path;
403 di3a.pDataFile = data_file;
404 di3a.pConfigFile = config_file;
405 di3a.pHelpFile = help_file;
406 di3a.pDependentFiles = dep_file;
407 di3a.pMonitorName = monitor_name;
408 di3a.pDefaultDataType = default_data_type;
410 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
412 ERR("Failed adding driver (%d)\n", GetLastError());
418 #ifdef HAVE_CUPS_CUPS_H
419 static typeof(cupsGetDests) *pcupsGetDests;
420 static typeof(cupsGetPPD) *pcupsGetPPD;
421 static typeof(cupsPrintFile) *pcupsPrintFile;
422 static void *cupshandle;
424 static BOOL CUPS_LoadPrinters(void)
427 BOOL hadprinter = FALSE;
429 PRINTER_INFO_2A pinfo2a;
431 HKEY hkeyPrinter, hkeyPrinters, hkey;
433 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
436 TRACE("loaded %s\n", SONAME_LIBCUPS);
439 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
440 if (!p##x) return FALSE;
443 DYNCUPS(cupsGetDests);
444 DYNCUPS(cupsPrintFile);
447 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
449 ERR("Can't create Printers key\n");
453 nrofdests = pcupsGetDests(&dests);
454 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
455 for (i=0;i<nrofdests;i++) {
456 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
457 sprintf(port,"LPR:%s",dests[i].name);
458 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
459 sprintf(devline,"WINEPS.DRV,%s",port);
460 WriteProfileStringA("devices",dests[i].name,devline);
461 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
462 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
465 HeapFree(GetProcessHeap(),0,devline);
467 TRACE("Printer %d: %s\n", i, dests[i].name);
468 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
469 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
471 TRACE("Printer already exists\n");
472 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
473 RegCloseKey(hkeyPrinter);
475 static CHAR data_type[] = "RAW",
476 print_proc[] = "WinPrint",
477 comment[] = "WINEPS Printer using CUPS",
478 location[] = "<physical location of printer>",
479 params[] = "<parameters?>",
480 share_name[] = "<share name?>",
481 sep_file[] = "<sep file?>";
483 add_printer_driver(dests[i].name);
485 memset(&pinfo2a,0,sizeof(pinfo2a));
486 pinfo2a.pPrinterName = dests[i].name;
487 pinfo2a.pDatatype = data_type;
488 pinfo2a.pPrintProcessor = print_proc;
489 pinfo2a.pDriverName = dests[i].name;
490 pinfo2a.pComment = comment;
491 pinfo2a.pLocation = location;
492 pinfo2a.pPortName = port;
493 pinfo2a.pParameters = params;
494 pinfo2a.pShareName = share_name;
495 pinfo2a.pSepFile = sep_file;
497 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
498 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
499 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
502 HeapFree(GetProcessHeap(),0,port);
505 if (dests[i].is_default)
506 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
508 RegCloseKey(hkeyPrinters);
514 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
515 PRINTER_INFO_2A pinfo2a;
516 char *e,*s,*name,*prettyname,*devname;
517 BOOL ret = FALSE, set_default = FALSE;
518 char *port,*devline,*env_default;
519 HKEY hkeyPrinter, hkeyPrinters, hkey;
521 while (isspace(*pent)) pent++;
522 s = strchr(pent,':');
524 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
532 TRACE("name=%s entry=%s\n",name, pent);
534 if(ispunct(*name)) { /* a tc entry, not a real printer */
535 TRACE("skipping tc entry\n");
539 if(strstr(pent,":server")) { /* server only version so skip */
540 TRACE("skipping server entry\n");
544 /* Determine whether this is a postscript printer. */
547 env_default = getenv("PRINTER");
549 /* Get longest name, usually the one at the right for later display. */
550 while((s=strchr(prettyname,'|'))) {
553 while(isspace(*--e)) *e = '\0';
554 TRACE("\t%s\n", debugstr_a(prettyname));
555 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
556 for(prettyname = s+1; isspace(*prettyname); prettyname++)
559 e = prettyname + strlen(prettyname);
560 while(isspace(*--e)) *e = '\0';
561 TRACE("\t%s\n", debugstr_a(prettyname));
562 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
564 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
565 * if it is too long, we use it as comment below. */
566 devname = prettyname;
567 if (strlen(devname)>=CCHDEVICENAME-1)
569 if (strlen(devname)>=CCHDEVICENAME-1) {
574 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
575 sprintf(port,"LPR:%s",name);
577 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
578 sprintf(devline,"WINEPS.DRV,%s",port);
579 WriteProfileStringA("devices",devname,devline);
580 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
581 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
584 HeapFree(GetProcessHeap(),0,devline);
586 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
588 ERR("Can't create Printers key\n");
592 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
593 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
595 TRACE("Printer already exists\n");
596 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
597 RegCloseKey(hkeyPrinter);
599 static CHAR data_type[] = "RAW",
600 print_proc[] = "WinPrint",
601 comment[] = "WINEPS Printer using LPR",
602 params[] = "<parameters?>",
603 share_name[] = "<share name?>",
604 sep_file[] = "<sep file?>";
606 add_printer_driver(devname);
608 memset(&pinfo2a,0,sizeof(pinfo2a));
609 pinfo2a.pPrinterName = devname;
610 pinfo2a.pDatatype = data_type;
611 pinfo2a.pPrintProcessor = print_proc;
612 pinfo2a.pDriverName = devname;
613 pinfo2a.pComment = comment;
614 pinfo2a.pLocation = prettyname;
615 pinfo2a.pPortName = port;
616 pinfo2a.pParameters = params;
617 pinfo2a.pShareName = share_name;
618 pinfo2a.pSepFile = sep_file;
620 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
621 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
622 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
625 RegCloseKey(hkeyPrinters);
627 if (isfirst || set_default)
628 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
630 HeapFree(GetProcessHeap(), 0, port);
632 HeapFree(GetProcessHeap(), 0, name);
637 PRINTCAP_LoadPrinters(void) {
638 BOOL hadprinter = FALSE;
642 BOOL had_bash = FALSE;
644 f = fopen("/etc/printcap","r");
648 while(fgets(buf,sizeof(buf),f)) {
651 end=strchr(buf,'\n');
655 while(isspace(*start)) start++;
656 if(*start == '#' || *start == '\0')
659 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
660 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
661 HeapFree(GetProcessHeap(),0,pent);
665 if (end && *--end == '\\') {
672 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
675 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
681 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
682 HeapFree(GetProcessHeap(),0,pent);
688 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
691 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
692 (lstrlenW(value) + 1) * sizeof(WCHAR));
694 return ERROR_FILE_NOT_FOUND;
697 void WINSPOOL_LoadSystemPrinters(void)
699 HKEY hkey, hkeyPrinters;
701 DWORD needed, num, i;
702 WCHAR PrinterName[256];
705 /* This ensures that all printer entries have a valid Name value. If causes
706 problems later if they don't. If one is found to be missed we create one
707 and set it equal to the name of the key */
708 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
709 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
710 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
711 for(i = 0; i < num; i++) {
712 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
713 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
714 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
715 set_reg_szW(hkey, NameW, PrinterName);
722 RegCloseKey(hkeyPrinters);
725 /* We want to avoid calling AddPrinter on printers as much as
726 possible, because on cups printers this will (eventually) lead
727 to a call to cupsGetPPD which takes forever, even with non-cups
728 printers AddPrinter takes a while. So we'll tag all printers that
729 were automatically added last time around, if they still exist
730 we'll leave them be otherwise we'll delete them. */
731 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
733 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
734 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
735 for(i = 0; i < num; i++) {
736 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
737 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
738 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
740 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
748 HeapFree(GetProcessHeap(), 0, pi);
752 #ifdef HAVE_CUPS_CUPS_H
753 done = CUPS_LoadPrinters();
756 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
757 /* Check for [ppd] section in config file before parsing /etc/printcap */
758 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
759 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
760 &hkey) == ERROR_SUCCESS) {
762 PRINTCAP_LoadPrinters();
766 /* Now enumerate the list again and delete any printers that a still tagged */
767 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
769 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
770 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
771 for(i = 0; i < num; i++) {
772 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
773 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
774 BOOL delete_driver = FALSE;
775 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
776 DWORD dw, type, size = sizeof(dw);
777 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
778 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
780 delete_driver = TRUE;
786 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
791 HeapFree(GetProcessHeap(), 0, pi);
798 /*****************************************************************************
799 * enumerate the local monitors (INTERNAL)
801 * returns the needed size (in bytes) for pMonitors
802 * and *lpreturned is set to number of entries returned in pMonitors
805 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
810 LPMONITOR_INFO_2W mi;
811 WCHAR buffer[MAX_PATH];
812 WCHAR dllname[MAX_PATH];
820 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
822 numentries = *lpreturned; /* this is 0, when we scan the registry */
823 len = entrysize * numentries;
824 ptr = (LPWSTR) &pMonitors[len];
827 len = sizeof(buffer);
830 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
831 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
832 /* Scan all Monitor-Registry-Keys */
833 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
834 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
835 dllsize = sizeof(dllname);
838 /* The Monitor must have a Driver-DLL */
839 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
840 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
841 /* We found a valid DLL for this Monitor. */
842 TRACE("using Driver: %s\n", debugstr_w(dllname));
847 /* Windows returns only Port-Monitors here, but to simplify our code,
848 we do no filtering for Language-Monitors */
852 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
854 /* we install and return only monitors for "Windows NT x86" */
855 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
859 /* required size is calculated. Now fill the user-buffer */
860 if (pMonitors && (cbBuf >= needed)){
861 mi = (LPMONITOR_INFO_2W) pMonitors;
862 pMonitors += entrysize;
864 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
866 lstrcpyW(ptr, buffer); /* Name of the Monitor */
867 ptr += (len+1); /* len is lstrlenW(monitorname) */
869 mi->pEnvironment = ptr;
870 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
871 ptr += (lstrlenW(envname_x86W)+1);
874 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
875 ptr += (dllsize / sizeof(WCHAR));
880 len = sizeof(buffer);
885 *lpreturned = numentries;
886 TRACE("need %d byte for %d entries\n", needed, numentries);
890 /******************************************************************
891 * monitor_flush [internal]
893 * flush the cached PORT_INFO_2W - data
896 void monitor_flush(monitor_t * pm)
900 EnterCriticalSection(&monitor_handles_cs);
902 TRACE("%p (%s) cache: %p (%d, %d)\n", pm, debugstr_w(pm->name), pm->cache, pm->pi1_needed, pm->pi2_needed);
904 HeapFree(GetProcessHeap(), 0, pm->cache);
909 LeaveCriticalSection(&monitor_handles_cs);
912 /******************************************************************
913 * monitor_unload [internal]
915 * release a printmonitor and unload it from memory, when needed
918 static void monitor_unload(monitor_t * pm)
920 if (pm == NULL) return;
921 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
923 EnterCriticalSection(&monitor_handles_cs);
925 if (pm->refcount) pm->refcount--;
927 if (pm->refcount == 0) {
928 list_remove(&pm->entry);
929 FreeLibrary(pm->hdll);
930 HeapFree(GetProcessHeap(), 0, pm->name);
931 HeapFree(GetProcessHeap(), 0, pm->dllname);
932 HeapFree(GetProcessHeap(), 0, pm);
934 LeaveCriticalSection(&monitor_handles_cs);
937 /******************************************************************
938 * monitor_unloadall [internal]
940 * release all printmonitors and unload them from memory, when needed
943 static void monitor_unloadall(void)
948 EnterCriticalSection(&monitor_handles_cs);
949 /* iterate through the list, with safety against removal */
950 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
954 LeaveCriticalSection(&monitor_handles_cs);
957 /******************************************************************
958 * monitor_load [internal]
960 * load a printmonitor, get the dllname from the registry, when needed
961 * initialize the monitor and dump found function-pointers
963 * On failure, SetLastError() is called and NULL is returned
966 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
968 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
969 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
970 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
971 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
972 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
974 monitor_t * pm = NULL;
976 LPWSTR regroot = NULL;
977 LPWSTR driver = dllname;
979 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
980 /* Is the Monitor already loaded? */
981 EnterCriticalSection(&monitor_handles_cs);
983 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
985 if (lstrcmpW(name, cursor->name) == 0) {
992 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
993 if (pm == NULL) goto cleanup;
994 list_add_tail(&monitor_handles, &pm->entry);
998 if (pm->name == NULL) {
999 /* Load the monitor */
1000 LPMONITOREX pmonitorEx;
1003 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
1004 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1007 lstrcpyW(regroot, MonitorsW);
1008 lstrcatW(regroot, name);
1009 /* Get the Driver from the Registry */
1010 if (driver == NULL) {
1013 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
1014 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
1015 &namesize) == ERROR_SUCCESS) {
1016 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
1017 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
1024 pm->name = strdupW(name);
1025 pm->dllname = strdupW(driver);
1027 if (!regroot || !pm->name || !pm->dllname) {
1029 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1034 pm->hdll = LoadLibraryW(driver);
1035 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
1037 if (pm->hdll == NULL) {
1039 SetLastError(ERROR_MOD_NOT_FOUND);
1044 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
1045 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1046 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1047 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1048 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1051 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1052 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1053 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1054 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1055 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1057 if (pInitializePrintMonitorUI != NULL) {
1058 pm->monitorUI = pInitializePrintMonitorUI();
1059 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1060 if (pm->monitorUI) {
1061 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1062 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1067 if (pInitializePrintMonitor != NULL) {
1068 pmonitorEx = pInitializePrintMonitor(regroot);
1069 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1070 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1073 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1074 pm->monitor = &(pmonitorEx->Monitor);
1079 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1084 if (pInitializePrintMonitor2 != NULL) {
1085 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1087 if (pInitializeMonitorEx != NULL) {
1088 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1090 if (pInitializeMonitor != NULL) {
1091 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1094 if (!pm->monitor && !pm->monitorUI) {
1096 SetLastError(ERROR_PROC_NOT_FOUND);
1101 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1105 LeaveCriticalSection(&monitor_handles_cs);
1106 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1107 HeapFree(GetProcessHeap(), 0, regroot);
1108 TRACE("=> %p\n", pm);
1112 /******************************************************************
1113 * monitor_loadall [internal]
1115 * Load all registered monitors
1118 static DWORD monitor_loadall(void)
1121 DWORD registered = 0;
1124 WCHAR buffer[MAX_PATH];
1127 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1128 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1129 NULL, NULL, NULL, NULL, NULL);
1131 TRACE("%d monitors registered\n", registered);
1133 EnterCriticalSection(&monitor_handles_cs);
1134 while (id < registered) {
1136 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1137 pm = monitor_load(buffer, NULL);
1141 LeaveCriticalSection(&monitor_handles_cs);
1142 RegCloseKey(hmonitors);
1144 TRACE("%d monitors loaded\n", loaded);
1148 /******************************************************************
1149 * monitor_load_by_port [internal]
1151 * load a printmonitor for a given port
1153 * On failure, NULL is returned
1156 static monitor_t * monitor_load_by_port(LPWSTR portname)
1161 monitor_t * pm = NULL;
1162 DWORD registered = 0;
1166 TRACE("(%s)\n", debugstr_w(portname));
1168 /* Try the Local Monitor first */
1169 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1170 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1171 /* found the portname */
1173 return monitor_load(LocalPortW, NULL);
1178 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1179 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1180 if (buffer == NULL) return NULL;
1182 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1183 EnterCriticalSection(&monitor_handles_cs);
1184 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1186 while ((pm == NULL) && (id < registered)) {
1188 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1189 TRACE("testing %s\n", debugstr_w(buffer));
1190 len = lstrlenW(buffer);
1191 lstrcatW(buffer, bs_Ports_bsW);
1192 lstrcatW(buffer, portname);
1193 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1195 buffer[len] = '\0'; /* use only the Monitor-Name */
1196 pm = monitor_load(buffer, NULL);
1200 LeaveCriticalSection(&monitor_handles_cs);
1203 HeapFree(GetProcessHeap(), 0, buffer);
1207 /******************************************************************
1208 * enumerate the local Ports from all loaded monitors (internal)
1210 * returns the needed size (in bytes) for pPorts
1211 * and *lpreturned is set to number of entries returned in pPorts
1214 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1218 LPPORT_INFO_2W cache;
1228 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1229 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1231 numentries = *lpreturned; /* this is 0, when we scan the registry */
1232 needed = entrysize * numentries;
1233 ptr = (LPWSTR) &pPorts[needed];
1238 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1240 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1241 if (pm->cache == NULL) {
1242 res = pm->monitor->pfnEnumPorts(NULL, 2, NULL, 0, &(pm->pi2_needed), &(pm->returned));
1243 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1244 pm->cache = HeapAlloc(GetProcessHeap(), 0, (pm->pi2_needed));
1245 res = pm->monitor->pfnEnumPorts(NULL, 2, (LPBYTE) pm->cache, pm->pi2_needed, &(pm->pi2_needed), &(pm->returned));
1247 TRACE("(%s) got %d with %d (cache need %d byte for %d entries)\n",
1248 debugstr_w(pm->name), res, GetLastError(), pm->pi2_needed, pm->returned);
1251 if (pm->cache && (level == 1) && (pm->pi1_needed == 0) && (pm->returned > 0)) {
1254 while (cacheindex < (pm->returned)) {
1255 pm->pi1_needed += sizeof(PORT_INFO_1W);
1256 pm->pi1_needed += (lstrlenW(cache->pPortName) + 1) * sizeof(WCHAR);
1260 TRACE("%d byte for %d cached PORT_INFO_1W entries (%s)\n",
1261 pm->pi1_needed, cacheindex, debugstr_w(pm->name));
1263 numentries += pm->returned;
1264 needed += (level == 1) ? pm->pi1_needed : pm->pi2_needed;
1266 /* fill the buffer, if we have one */
1267 if (pPorts && (cbBuf >= needed )) {
1270 while (cacheindex < pm->returned) {
1271 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1272 out->pPortName = ptr;
1273 lstrcpyW(ptr, cache->pPortName);
1274 ptr += (lstrlenW(ptr)+1);
1276 out->pMonitorName = ptr;
1277 lstrcpyW(ptr, cache->pMonitorName);
1278 ptr += (lstrlenW(ptr)+1);
1280 out->pDescription = ptr;
1281 lstrcpyW(ptr, cache->pDescription);
1282 ptr += (lstrlenW(ptr)+1);
1283 out->fPortType = cache->fPortType;
1284 out->Reserved = cache->Reserved;
1294 *lpreturned = numentries;
1295 TRACE("need %d byte for %d entries\n", needed, numentries);
1299 /******************************************************************
1300 * get_opened_printer_entry
1301 * Get the first place empty in the opened printer table
1304 * - pDefault is ignored
1306 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1308 UINT_PTR handle = nb_printer_handles, i;
1309 jobqueue_t *queue = NULL;
1310 opened_printer_t *printer = NULL;
1312 EnterCriticalSection(&printer_handles_cs);
1314 for (i = 0; i < nb_printer_handles; i++)
1316 if (!printer_handles[i])
1318 if(handle == nb_printer_handles)
1323 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1324 queue = printer_handles[i]->queue;
1328 if (handle >= nb_printer_handles)
1330 opened_printer_t **new_array;
1331 if (printer_handles)
1332 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1333 (nb_printer_handles + 16) * sizeof(*new_array) );
1335 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1336 (nb_printer_handles + 16) * sizeof(*new_array) );
1343 printer_handles = new_array;
1344 nb_printer_handles += 16;
1347 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1354 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
1355 if (!printer->name) {
1359 strcpyW(printer->name, name);
1363 printer->queue = queue;
1366 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1367 if (!printer->queue) {
1371 list_init(&printer->queue->jobs);
1372 printer->queue->ref = 0;
1374 InterlockedIncrement(&printer->queue->ref);
1376 printer_handles[handle] = printer;
1379 LeaveCriticalSection(&printer_handles_cs);
1380 if (!handle && printer) {
1381 /* Something Failed: Free the Buffers */
1382 HeapFree(GetProcessHeap(), 0, printer->name);
1383 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1384 HeapFree(GetProcessHeap(), 0, printer);
1387 return (HANDLE)handle;
1390 /******************************************************************
1391 * get_opened_printer
1392 * Get the pointer to the opened printer referred by the handle
1394 static opened_printer_t *get_opened_printer(HANDLE hprn)
1396 UINT_PTR idx = (UINT_PTR)hprn;
1397 opened_printer_t *ret = NULL;
1399 EnterCriticalSection(&printer_handles_cs);
1401 if ((idx <= 0) || (idx > nb_printer_handles))
1404 ret = printer_handles[idx - 1];
1406 LeaveCriticalSection(&printer_handles_cs);
1410 /******************************************************************
1411 * get_opened_printer_name
1412 * Get the pointer to the opened printer name referred by the handle
1414 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1416 opened_printer_t *printer = get_opened_printer(hprn);
1417 if(!printer) return NULL;
1418 return printer->name;
1421 /******************************************************************
1422 * WINSPOOL_GetOpenedPrinterRegKey
1425 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1427 LPCWSTR name = get_opened_printer_name(hPrinter);
1431 if(!name) return ERROR_INVALID_HANDLE;
1433 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1437 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1439 ERR("Can't find opened printer %s in registry\n",
1441 RegCloseKey(hkeyPrinters);
1442 return ERROR_INVALID_PRINTER_NAME; /* ? */
1444 RegCloseKey(hkeyPrinters);
1445 return ERROR_SUCCESS;
1448 /******************************************************************
1451 * Get the pointer to the specified job.
1452 * Should hold the printer_handles_cs before calling.
1454 static job_t *get_job(HANDLE hprn, DWORD JobId)
1456 opened_printer_t *printer = get_opened_printer(hprn);
1459 if(!printer) return NULL;
1460 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1462 if(job->job_id == JobId)
1468 /***********************************************************
1471 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1474 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1477 Formname = (dmA->dmSize > off_formname);
1478 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1479 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1480 dmW->dmDeviceName, CCHDEVICENAME);
1482 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1483 dmA->dmSize - CCHDEVICENAME);
1485 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1486 off_formname - CCHDEVICENAME);
1487 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1488 dmW->dmFormName, CCHFORMNAME);
1489 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1490 (off_formname + CCHFORMNAME));
1493 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1494 dmA->dmDriverExtra);
1498 /***********************************************************
1500 * Creates an ascii copy of supplied devmode on heap
1502 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1507 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1509 if(!dmW) return NULL;
1510 Formname = (dmW->dmSize > off_formname);
1511 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1512 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1513 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1514 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1516 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1517 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1519 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1520 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1521 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1522 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1523 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1524 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1527 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1528 dmW->dmDriverExtra);
1532 /***********************************************************
1533 * PRINTER_INFO_2AtoW
1534 * Creates a unicode copy of PRINTER_INFO_2A on heap
1536 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1538 LPPRINTER_INFO_2W piW;
1539 UNICODE_STRING usBuffer;
1541 if(!piA) return NULL;
1542 piW = HeapAlloc(heap, 0, sizeof(*piW));
1543 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1545 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1546 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1547 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1548 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1549 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1550 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1551 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1552 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1553 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1554 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1555 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1556 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1560 /***********************************************************
1561 * FREE_PRINTER_INFO_2W
1562 * Free PRINTER_INFO_2W and all strings
1564 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1568 HeapFree(heap,0,piW->pServerName);
1569 HeapFree(heap,0,piW->pPrinterName);
1570 HeapFree(heap,0,piW->pShareName);
1571 HeapFree(heap,0,piW->pPortName);
1572 HeapFree(heap,0,piW->pDriverName);
1573 HeapFree(heap,0,piW->pComment);
1574 HeapFree(heap,0,piW->pLocation);
1575 HeapFree(heap,0,piW->pDevMode);
1576 HeapFree(heap,0,piW->pSepFile);
1577 HeapFree(heap,0,piW->pPrintProcessor);
1578 HeapFree(heap,0,piW->pDatatype);
1579 HeapFree(heap,0,piW->pParameters);
1580 HeapFree(heap,0,piW);
1584 /******************************************************************
1585 * DeviceCapabilities [WINSPOOL.@]
1586 * DeviceCapabilitiesA [WINSPOOL.@]
1589 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1590 LPSTR pOutput, LPDEVMODEA lpdm)
1594 if (!GDI_CallDeviceCapabilities16)
1596 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1598 if (!GDI_CallDeviceCapabilities16) return -1;
1600 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1602 /* If DC_PAPERSIZE map POINT16s to POINTs */
1603 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1604 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1605 POINT *pt = (POINT *)pOutput;
1607 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1608 for(i = 0; i < ret; i++, pt++)
1613 HeapFree( GetProcessHeap(), 0, tmp );
1619 /*****************************************************************************
1620 * DeviceCapabilitiesW [WINSPOOL.@]
1622 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1625 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1626 WORD fwCapability, LPWSTR pOutput,
1627 const DEVMODEW *pDevMode)
1629 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1630 LPSTR pDeviceA = strdupWtoA(pDevice);
1631 LPSTR pPortA = strdupWtoA(pPort);
1634 if(pOutput && (fwCapability == DC_BINNAMES ||
1635 fwCapability == DC_FILEDEPENDENCIES ||
1636 fwCapability == DC_PAPERNAMES)) {
1637 /* These need A -> W translation */
1640 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1644 switch(fwCapability) {
1649 case DC_FILEDEPENDENCIES:
1653 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1654 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1656 for(i = 0; i < ret; i++)
1657 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1658 pOutput + (i * size), size);
1659 HeapFree(GetProcessHeap(), 0, pOutputA);
1661 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1662 (LPSTR)pOutput, dmA);
1664 HeapFree(GetProcessHeap(),0,pPortA);
1665 HeapFree(GetProcessHeap(),0,pDeviceA);
1666 HeapFree(GetProcessHeap(),0,dmA);
1670 /******************************************************************
1671 * DocumentPropertiesA [WINSPOOL.@]
1673 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1675 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1676 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1677 LPDEVMODEA pDevModeInput,DWORD fMode )
1679 LPSTR lpName = pDeviceName;
1680 static CHAR port[] = "LPT1:";
1683 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1684 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1688 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1690 ERR("no name from hPrinter?\n");
1691 SetLastError(ERROR_INVALID_HANDLE);
1694 lpName = strdupWtoA(lpNameW);
1697 if (!GDI_CallExtDeviceMode16)
1699 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1701 if (!GDI_CallExtDeviceMode16) {
1702 ERR("No CallExtDeviceMode16?\n");
1706 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1707 pDevModeInput, NULL, fMode);
1710 HeapFree(GetProcessHeap(),0,lpName);
1715 /*****************************************************************************
1716 * DocumentPropertiesW (WINSPOOL.@)
1718 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1720 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1722 LPDEVMODEW pDevModeOutput,
1723 LPDEVMODEW pDevModeInput, DWORD fMode)
1726 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1727 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1728 LPDEVMODEA pDevModeOutputA = NULL;
1731 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1732 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1734 if(pDevModeOutput) {
1735 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1736 if(ret < 0) return ret;
1737 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1739 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1740 pDevModeInputA, fMode);
1741 if(pDevModeOutput) {
1742 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1743 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1745 if(fMode == 0 && ret > 0)
1746 ret += (CCHDEVICENAME + CCHFORMNAME);
1747 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1748 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1752 /******************************************************************
1753 * OpenPrinterA [WINSPOOL.@]
1758 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1759 LPPRINTER_DEFAULTSA pDefault)
1761 UNICODE_STRING lpPrinterNameW;
1762 UNICODE_STRING usBuffer;
1763 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1764 PWSTR pwstrPrinterNameW;
1767 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1770 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1771 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1772 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1773 pDefaultW = &DefaultW;
1775 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1777 RtlFreeUnicodeString(&usBuffer);
1778 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1780 RtlFreeUnicodeString(&lpPrinterNameW);
1784 /******************************************************************
1785 * OpenPrinterW [WINSPOOL.@]
1787 * Open a Printer / Printserver or a Printer-Object
1790 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1791 * phPrinter [O] The resulting Handle is stored here
1792 * pDefault [I] PTR to Default Printer Settings or NULL
1799 * lpPrinterName is one of:
1800 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1801 *| Printer: "PrinterName"
1802 *| Printer-Object: "PrinterName,Job xxx"
1803 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1804 *| XcvPort: "Servername,XcvPort PortName"
1807 *| Printer-Object not supported
1808 *| XcvMonitor not supported
1809 *| XcvPort not supported
1810 *| pDefaults is ignored
1813 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1815 HKEY hkeyPrinters = NULL;
1816 HKEY hkeyPrinter = NULL;
1818 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1820 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1821 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1824 if(lpPrinterName != NULL)
1826 /* Check any Printer exists */
1827 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1828 ERR("Can't create Printers key\n");
1829 SetLastError(ERROR_FILE_NOT_FOUND);
1832 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1833 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1835 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1836 RegCloseKey(hkeyPrinters);
1837 SetLastError(ERROR_INVALID_PRINTER_NAME);
1840 RegCloseKey(hkeyPrinter);
1841 RegCloseKey(hkeyPrinters);
1844 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1845 SetLastError(ERROR_INVALID_PARAMETER);
1849 /* Get the unique handle of the printer or Printserver */
1850 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1851 return (*phPrinter != 0);
1854 /******************************************************************
1855 * AddMonitorA [WINSPOOL.@]
1860 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1862 LPWSTR nameW = NULL;
1865 LPMONITOR_INFO_2A mi2a;
1866 MONITOR_INFO_2W mi2w;
1868 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1869 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1870 mi2a ? debugstr_a(mi2a->pName) : NULL,
1871 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1872 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1875 SetLastError(ERROR_INVALID_LEVEL);
1879 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1885 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1886 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1887 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1890 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1892 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1893 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1894 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1896 if (mi2a->pEnvironment) {
1897 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1898 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1899 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1901 if (mi2a->pDLLName) {
1902 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1903 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1904 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1907 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1909 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1910 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1911 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1913 HeapFree(GetProcessHeap(), 0, nameW);
1917 /******************************************************************************
1918 * AddMonitorW [WINSPOOL.@]
1920 * Install a Printmonitor
1923 * pName [I] Servername or NULL (local Computer)
1924 * Level [I] Structure-Level (Must be 2)
1925 * pMonitors [I] PTR to MONITOR_INFO_2
1932 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1935 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1937 monitor_t * pm = NULL;
1938 LPMONITOR_INFO_2W mi2w;
1944 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1945 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1946 mi2w ? debugstr_w(mi2w->pName) : NULL,
1947 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1948 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1951 SetLastError(ERROR_INVALID_LEVEL);
1955 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1960 if (pName && (pName[0])) {
1961 FIXME("for server %s not implemented\n", debugstr_w(pName));
1962 SetLastError(ERROR_ACCESS_DENIED);
1967 if (!mi2w->pName || (! mi2w->pName[0])) {
1968 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1969 SetLastError(ERROR_INVALID_PARAMETER);
1972 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1973 WARN("Environment %s requested (we support only %s)\n",
1974 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1975 SetLastError(ERROR_INVALID_ENVIRONMENT);
1979 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1980 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1981 SetLastError(ERROR_INVALID_PARAMETER);
1985 /* Load and initialize the monitor. SetLastError() is called on failure */
1986 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1991 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1992 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1996 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1997 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1998 &disposition) == ERROR_SUCCESS) {
2000 /* Some installers set options for the port before calling AddMonitor.
2001 We query the "Driver" entry to verify that the monitor is installed,
2002 before we return an error.
2003 When a user installs two print monitors at the same time with the
2004 same name but with a different driver DLL and a task switch comes
2005 between RegQueryValueExW and RegSetValueExW, a race condition
2006 is possible but silently ignored. */
2010 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2011 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2012 &namesize) == ERROR_SUCCESS)) {
2013 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2014 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2015 9x: ERROR_ALREADY_EXISTS (183) */
2016 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2021 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2022 res = (RegSetValueExW(hentry, DriverW, 0,
2023 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2025 RegCloseKey(hentry);
2032 /******************************************************************
2033 * DeletePrinterDriverA [WINSPOOL.@]
2036 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2038 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2041 /******************************************************************
2042 * DeletePrinterDriverW [WINSPOOL.@]
2045 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2047 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2050 /******************************************************************
2051 * DeleteMonitorA [WINSPOOL.@]
2053 * See DeleteMonitorW.
2056 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2058 LPWSTR nameW = NULL;
2059 LPWSTR EnvironmentW = NULL;
2060 LPWSTR MonitorNameW = NULL;
2065 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2066 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2067 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2071 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2072 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2073 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2076 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2077 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2078 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2081 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2083 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2084 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2085 HeapFree(GetProcessHeap(), 0, nameW);
2089 /******************************************************************
2090 * DeleteMonitorW [WINSPOOL.@]
2092 * Delete a specific Printmonitor from a Printing-Environment
2095 * pName [I] Servername or NULL (local Computer)
2096 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2097 * pMonitorName [I] Name of the Monitor, that should be deleted
2104 * pEnvironment is ignored in Windows for the local Computer.
2108 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2112 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2113 debugstr_w(pMonitorName));
2115 if (pName && (pName[0])) {
2116 FIXME("for server %s not implemented\n", debugstr_w(pName));
2117 SetLastError(ERROR_ACCESS_DENIED);
2121 /* pEnvironment is ignored in Windows for the local Computer */
2123 if (!pMonitorName || !pMonitorName[0]) {
2124 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2125 SetLastError(ERROR_INVALID_PARAMETER);
2129 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2130 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2134 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2135 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2136 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2141 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
2144 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2145 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2149 /******************************************************************
2150 * DeletePortA [WINSPOOL.@]
2155 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2157 LPWSTR nameW = NULL;
2158 LPWSTR portW = NULL;
2162 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2164 /* convert servername to unicode */
2166 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2167 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2168 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2171 /* convert portname to unicode */
2173 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2174 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2175 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2178 res = DeletePortW(nameW, hWnd, portW);
2179 HeapFree(GetProcessHeap(), 0, nameW);
2180 HeapFree(GetProcessHeap(), 0, portW);
2184 /******************************************************************
2185 * DeletePortW [WINSPOOL.@]
2187 * Delete a specific Port
2190 * pName [I] Servername or NULL (local Computer)
2191 * hWnd [I] Handle to parent Window for the Dialog-Box
2192 * pPortName [I] Name of the Port, that should be deleted
2199 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2202 DWORD res = ROUTER_UNKNOWN;
2204 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2206 if (pName && pName[0]) {
2207 SetLastError(ERROR_INVALID_PARAMETER);
2212 SetLastError(RPC_X_NULL_REF_POINTER);
2216 /* an empty Portname is Invalid */
2217 if (!pPortName[0]) goto cleanup;
2219 pm = monitor_load_by_port(pPortName);
2220 if (pm && pm->monitor) {
2221 if (pm->monitor->pfnDeletePort != NULL) {
2222 TRACE("Using %s for %s:\n", debugstr_w(pm->name), debugstr_w(pPortName));
2223 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2224 TRACE("got %d with %d\n", res, GetLastError());
2226 else if (pm->monitor->pfnXcvOpenPort)
2228 FIXME("XcvOpenPort not implemented (dwMonitorSize: %d)\n", pm->dwMonitorSize);
2230 /* invalidate cached PORT_INFO_2W */
2231 if (res == ROUTER_SUCCESS) monitor_flush(pm);
2236 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2237 if (res == ROUTER_UNKNOWN) SetLastError(ERROR_NOT_SUPPORTED);
2238 TRACE("returning %d with %d\n", (res == ROUTER_SUCCESS), GetLastError());
2239 return (res == ROUTER_SUCCESS);
2242 /******************************************************************************
2243 * SetPrinterW [WINSPOOL.@]
2245 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2247 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2248 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2252 /******************************************************************************
2253 * WritePrinter [WINSPOOL.@]
2255 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2257 opened_printer_t *printer;
2260 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2262 EnterCriticalSection(&printer_handles_cs);
2263 printer = get_opened_printer(hPrinter);
2266 SetLastError(ERROR_INVALID_HANDLE);
2272 SetLastError(ERROR_SPL_NO_STARTDOC);
2276 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2278 LeaveCriticalSection(&printer_handles_cs);
2282 /*****************************************************************************
2283 * AddFormA [WINSPOOL.@]
2285 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2287 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2291 /*****************************************************************************
2292 * AddFormW [WINSPOOL.@]
2294 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2296 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2300 /*****************************************************************************
2301 * AddJobA [WINSPOOL.@]
2303 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2306 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2310 SetLastError(ERROR_INVALID_LEVEL);
2314 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2317 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2318 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2319 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2320 if(*pcbNeeded > cbBuf) {
2321 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2324 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2325 addjobA->JobId = addjobW->JobId;
2326 addjobA->Path = (char *)(addjobA + 1);
2327 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2333 /*****************************************************************************
2334 * AddJobW [WINSPOOL.@]
2336 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2338 opened_printer_t *printer;
2341 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2342 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2343 WCHAR path[MAX_PATH], filename[MAX_PATH];
2345 ADDJOB_INFO_1W *addjob;
2347 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2349 EnterCriticalSection(&printer_handles_cs);
2351 printer = get_opened_printer(hPrinter);
2354 SetLastError(ERROR_INVALID_HANDLE);
2359 SetLastError(ERROR_INVALID_LEVEL);
2363 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2367 job->job_id = InterlockedIncrement(&next_job_id);
2369 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2370 if(path[len - 1] != '\\')
2372 memcpy(path + len, spool_path, sizeof(spool_path));
2373 sprintfW(filename, fmtW, path, job->job_id);
2375 len = strlenW(filename);
2376 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2377 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2378 job->document_title = strdupW(default_doc_title);
2379 list_add_tail(&printer->queue->jobs, &job->entry);
2381 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2382 if(*pcbNeeded <= cbBuf) {
2383 addjob = (ADDJOB_INFO_1W*)pData;
2384 addjob->JobId = job->job_id;
2385 addjob->Path = (WCHAR *)(addjob + 1);
2386 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2389 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2392 LeaveCriticalSection(&printer_handles_cs);
2396 /*****************************************************************************
2397 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2399 * Return the PATH for the Print-Processors
2401 * See GetPrintProcessorDirectoryW.
2405 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2406 DWORD level, LPBYTE Info,
2407 DWORD cbBuf, LPDWORD pcbNeeded)
2409 LPWSTR serverW = NULL;
2414 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2415 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2419 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2420 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2421 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2425 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2426 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2427 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2430 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2431 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2433 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2436 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2437 cbBuf, NULL, NULL) > 0;
2440 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2441 HeapFree(GetProcessHeap(), 0, envW);
2442 HeapFree(GetProcessHeap(), 0, serverW);
2446 /*****************************************************************************
2447 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2449 * Return the PATH for the Print-Processors
2452 * server [I] Servername (NT only) or NULL (local Computer)
2453 * env [I] Printing-Environment (see below) or NULL (Default)
2454 * level [I] Structure-Level (must be 1)
2455 * Info [O] PTR to Buffer that receives the Result
2456 * cbBuf [I] Size of Buffer at "Info"
2457 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2458 * required for the Buffer at "Info"
2461 * Success: TRUE and in pcbNeeded the Bytes used in Info
2462 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2463 * if cbBuf is too small
2465 * Native Values returned in Info on Success:
2466 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2467 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2468 *| win9x(Windows 4.0): "%winsysdir%"
2470 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2473 * Only NULL or "" is supported for server
2476 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2477 DWORD level, LPBYTE Info,
2478 DWORD cbBuf, LPDWORD pcbNeeded)
2481 const printenv_t * env_t;
2483 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2484 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2486 if(server != NULL && server[0]) {
2487 FIXME("server not supported: %s\n", debugstr_w(server));
2488 SetLastError(ERROR_INVALID_PARAMETER);
2492 env_t = validate_envW(env);
2493 if(!env_t) return FALSE; /* environment invalid or unsupported */
2496 WARN("(Level: %d) is ignored in win9x\n", level);
2497 SetLastError(ERROR_INVALID_LEVEL);
2501 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2502 needed = GetSystemDirectoryW(NULL, 0);
2503 /* add the Size for the Subdirectories */
2504 needed += lstrlenW(spoolprtprocsW);
2505 needed += lstrlenW(env_t->subdir);
2506 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2508 if(pcbNeeded) *pcbNeeded = needed;
2509 TRACE ("required: 0x%x/%d\n", needed, needed);
2510 if (needed > cbBuf) {
2511 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2514 if(pcbNeeded == NULL) {
2515 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2516 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2517 SetLastError(RPC_X_NULL_REF_POINTER);
2521 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2522 SetLastError(RPC_X_NULL_REF_POINTER);
2526 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2527 /* add the Subdirectories */
2528 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2529 lstrcatW((LPWSTR) Info, env_t->subdir);
2530 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2534 /*****************************************************************************
2535 * WINSPOOL_OpenDriverReg [internal]
2537 * opens the registry for the printer drivers depending on the given input
2538 * variable pEnvironment
2541 * the opened hkey on success
2544 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2548 const printenv_t * env;
2551 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2553 if (!pEnvironment || unicode) {
2554 /* pEnvironment was NULL or an Unicode-String: use it direct */
2555 env = validate_envW(pEnvironment);
2559 /* pEnvironment was an ANSI-String: convert to unicode first */
2561 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2562 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2563 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2564 env = validate_envW(buffer);
2565 HeapFree(GetProcessHeap(), 0, buffer);
2567 if (!env) return NULL;
2569 buffer = HeapAlloc( GetProcessHeap(), 0,
2570 (strlenW(DriversW) + strlenW(env->envname) +
2571 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2573 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2574 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2575 HeapFree(GetProcessHeap(), 0, buffer);
2580 /*****************************************************************************
2581 * AddPrinterW [WINSPOOL.@]
2583 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2585 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2589 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2592 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2595 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2596 SetLastError(ERROR_INVALID_PARAMETER);
2600 ERR("Level = %d, unsupported!\n", Level);
2601 SetLastError(ERROR_INVALID_LEVEL);
2605 SetLastError(ERROR_INVALID_PARAMETER);
2608 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2610 ERR("Can't create Printers key\n");
2613 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2614 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2615 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2616 RegCloseKey(hkeyPrinter);
2617 RegCloseKey(hkeyPrinters);
2620 RegCloseKey(hkeyPrinter);
2622 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2624 ERR("Can't create Drivers key\n");
2625 RegCloseKey(hkeyPrinters);
2628 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2630 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2631 RegCloseKey(hkeyPrinters);
2632 RegCloseKey(hkeyDrivers);
2633 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2636 RegCloseKey(hkeyDriver);
2637 RegCloseKey(hkeyDrivers);
2639 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2640 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2641 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2642 RegCloseKey(hkeyPrinters);
2646 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2648 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2649 SetLastError(ERROR_INVALID_PRINTER_NAME);
2650 RegCloseKey(hkeyPrinters);
2653 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2654 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2655 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2657 /* See if we can load the driver. We may need the devmode structure anyway
2660 * Note that DocumentPropertiesW will briefly try to open the printer we
2661 * just create to find a DEVMODEA struct (it will use the WINEPS default
2662 * one in case it is not there, so we are ok).
2664 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2667 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2668 size = sizeof(DEVMODEW);
2674 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2675 ZeroMemory(dmW,size);
2677 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2679 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2680 HeapFree(GetProcessHeap(),0,dmW);
2685 /* set devmode to printer name */
2686 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2690 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2691 and we support these drivers. NT writes DEVMODEW so somehow
2692 we'll need to distinguish between these when we support NT
2696 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2697 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2698 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2699 HeapFree(GetProcessHeap(), 0, dmA);
2701 HeapFree(GetProcessHeap(), 0, dmW);
2703 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2704 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2705 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2706 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2708 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2709 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2710 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2711 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2712 (LPBYTE)&pi->Priority, sizeof(DWORD));
2713 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2714 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2715 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2716 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2717 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2718 (LPBYTE)&pi->Status, sizeof(DWORD));
2719 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2720 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2722 RegCloseKey(hkeyPrinter);
2723 RegCloseKey(hkeyPrinters);
2724 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2725 ERR("OpenPrinter failing\n");
2731 /*****************************************************************************
2732 * AddPrinterA [WINSPOOL.@]
2734 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2736 UNICODE_STRING pNameW;
2738 PRINTER_INFO_2W *piW;
2739 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2742 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2744 ERR("Level = %d, unsupported!\n", Level);
2745 SetLastError(ERROR_INVALID_LEVEL);
2748 pwstrNameW = asciitounicode(&pNameW,pName);
2749 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2751 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2753 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2754 RtlFreeUnicodeString(&pNameW);
2759 /*****************************************************************************
2760 * ClosePrinter [WINSPOOL.@]
2762 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2764 UINT_PTR i = (UINT_PTR)hPrinter;
2765 opened_printer_t *printer = NULL;
2768 TRACE("Handle %p\n", hPrinter);
2770 EnterCriticalSection(&printer_handles_cs);
2772 if ((i > 0) && (i <= nb_printer_handles))
2773 printer = printer_handles[i - 1];
2777 struct list *cursor, *cursor2;
2780 EndDocPrinter(hPrinter);
2782 if(InterlockedDecrement(&printer->queue->ref) == 0)
2784 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2786 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2787 ScheduleJob(hPrinter, job->job_id);
2789 HeapFree(GetProcessHeap(), 0, printer->queue);
2791 HeapFree(GetProcessHeap(), 0, printer->name);
2792 HeapFree(GetProcessHeap(), 0, printer);
2793 printer_handles[i - 1] = NULL;
2796 LeaveCriticalSection(&printer_handles_cs);
2800 /*****************************************************************************
2801 * DeleteFormA [WINSPOOL.@]
2803 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2805 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2809 /*****************************************************************************
2810 * DeleteFormW [WINSPOOL.@]
2812 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2814 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2818 /*****************************************************************************
2819 * WINSPOOL_SHRegDeleteKey
2821 * Recursively delete subkeys.
2822 * Cut & paste from shlwapi.
2825 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2827 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2828 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2831 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2834 /* Find how many subkeys there are */
2835 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2836 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2840 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2841 /* Name too big: alloc a buffer for it */
2842 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2845 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2848 /* Recursively delete all the subkeys */
2849 for(i = 0; i < dwKeyCount && !dwRet; i++)
2851 dwSize = dwMaxSubkeyLen;
2852 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2854 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2857 if (lpszName != szNameBuf)
2858 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2862 RegCloseKey(hSubKey);
2864 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2869 /*****************************************************************************
2870 * DeletePrinter [WINSPOOL.@]
2872 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2874 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2875 HKEY hkeyPrinters, hkey;
2878 SetLastError(ERROR_INVALID_HANDLE);
2881 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2882 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2883 RegCloseKey(hkeyPrinters);
2885 WriteProfileStringW(devicesW, lpNameW, NULL);
2886 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2887 RegDeleteValueW(hkey, lpNameW);
2893 /*****************************************************************************
2894 * SetPrinterA [WINSPOOL.@]
2896 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2899 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2903 /*****************************************************************************
2904 * SetJobA [WINSPOOL.@]
2906 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2907 LPBYTE pJob, DWORD Command)
2911 UNICODE_STRING usBuffer;
2913 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2915 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2916 are all ignored by SetJob, so we don't bother copying them */
2924 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2925 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2927 JobW = (LPBYTE)info1W;
2928 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2929 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2930 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2931 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2932 info1W->Status = info1A->Status;
2933 info1W->Priority = info1A->Priority;
2934 info1W->Position = info1A->Position;
2935 info1W->PagesPrinted = info1A->PagesPrinted;
2940 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2941 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2943 JobW = (LPBYTE)info2W;
2944 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2945 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2946 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2947 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2948 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2949 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2950 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2951 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2952 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2953 info2W->Status = info2A->Status;
2954 info2W->Priority = info2A->Priority;
2955 info2W->Position = info2A->Position;
2956 info2W->StartTime = info2A->StartTime;
2957 info2W->UntilTime = info2A->UntilTime;
2958 info2W->PagesPrinted = info2A->PagesPrinted;
2962 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2963 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2966 SetLastError(ERROR_INVALID_LEVEL);
2970 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2976 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2977 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2978 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2979 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2980 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2985 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2986 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2987 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2988 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2989 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2990 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2991 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2992 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2993 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2997 HeapFree(GetProcessHeap(), 0, JobW);
3002 /*****************************************************************************
3003 * SetJobW [WINSPOOL.@]
3005 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3006 LPBYTE pJob, DWORD Command)
3011 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3012 FIXME("Ignoring everything other than document title\n");
3014 EnterCriticalSection(&printer_handles_cs);
3015 job = get_job(hPrinter, JobId);
3025 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3026 HeapFree(GetProcessHeap(), 0, job->document_title);
3027 job->document_title = strdupW(info1->pDocument);
3032 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3033 HeapFree(GetProcessHeap(), 0, job->document_title);
3034 job->document_title = strdupW(info2->pDocument);
3040 SetLastError(ERROR_INVALID_LEVEL);
3045 LeaveCriticalSection(&printer_handles_cs);
3049 /*****************************************************************************
3050 * EndDocPrinter [WINSPOOL.@]
3052 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3054 opened_printer_t *printer;
3056 TRACE("(%p)\n", hPrinter);
3058 EnterCriticalSection(&printer_handles_cs);
3060 printer = get_opened_printer(hPrinter);
3063 SetLastError(ERROR_INVALID_HANDLE);
3069 SetLastError(ERROR_SPL_NO_STARTDOC);
3073 CloseHandle(printer->doc->hf);
3074 ScheduleJob(hPrinter, printer->doc->job_id);
3075 HeapFree(GetProcessHeap(), 0, printer->doc);
3076 printer->doc = NULL;
3079 LeaveCriticalSection(&printer_handles_cs);
3083 /*****************************************************************************
3084 * EndPagePrinter [WINSPOOL.@]
3086 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3088 FIXME("(%p): stub\n", hPrinter);
3092 /*****************************************************************************
3093 * StartDocPrinterA [WINSPOOL.@]
3095 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3097 UNICODE_STRING usBuffer;
3099 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3102 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3103 or one (DOC_INFO_3) extra DWORDs */
3107 doc2W.JobId = doc2->JobId;
3110 doc2W.dwMode = doc2->dwMode;
3113 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3114 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3115 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3119 SetLastError(ERROR_INVALID_LEVEL);
3123 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3125 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3126 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3127 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3132 /*****************************************************************************
3133 * StartDocPrinterW [WINSPOOL.@]
3135 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3137 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3138 opened_printer_t *printer;
3139 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3140 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3141 JOB_INFO_1W job_info;
3142 DWORD needed, ret = 0;
3146 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3147 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3148 debugstr_w(doc->pDatatype));
3150 if(Level < 1 || Level > 3)
3152 SetLastError(ERROR_INVALID_LEVEL);
3156 EnterCriticalSection(&printer_handles_cs);
3157 printer = get_opened_printer(hPrinter);
3160 SetLastError(ERROR_INVALID_HANDLE);
3166 SetLastError(ERROR_INVALID_PRINTER_STATE);
3170 /* Even if we're printing to a file we still add a print job, we'll
3171 just ignore the spool file name */
3173 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3175 ERR("AddJob failed gle %08x\n", GetLastError());
3179 if(doc->pOutputFile)
3180 filename = doc->pOutputFile;
3182 filename = addjob->Path;
3184 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3185 if(hf == INVALID_HANDLE_VALUE)
3188 memset(&job_info, 0, sizeof(job_info));
3189 job_info.pDocument = doc->pDocName;
3190 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3192 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3193 printer->doc->hf = hf;
3194 ret = printer->doc->job_id = addjob->JobId;
3196 LeaveCriticalSection(&printer_handles_cs);
3201 /*****************************************************************************
3202 * StartPagePrinter [WINSPOOL.@]
3204 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3206 FIXME("(%p): stub\n", hPrinter);
3210 /*****************************************************************************
3211 * GetFormA [WINSPOOL.@]
3213 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3214 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3216 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3217 Level,pForm,cbBuf,pcbNeeded);
3221 /*****************************************************************************
3222 * GetFormW [WINSPOOL.@]
3224 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3225 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3227 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3228 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3232 /*****************************************************************************
3233 * SetFormA [WINSPOOL.@]
3235 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3238 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3242 /*****************************************************************************
3243 * SetFormW [WINSPOOL.@]
3245 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3248 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3252 /*****************************************************************************
3253 * ReadPrinter [WINSPOOL.@]
3255 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3256 LPDWORD pNoBytesRead)
3258 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3262 /*****************************************************************************
3263 * ResetPrinterA [WINSPOOL.@]
3265 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3267 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3271 /*****************************************************************************
3272 * ResetPrinterW [WINSPOOL.@]
3274 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3276 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3280 /*****************************************************************************
3281 * WINSPOOL_GetDWORDFromReg
3283 * Return DWORD associated with ValueName from hkey.
3285 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3287 DWORD sz = sizeof(DWORD), type, value = 0;
3290 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3292 if(ret != ERROR_SUCCESS) {
3293 WARN("Got ret = %d on name %s\n", ret, ValueName);
3296 if(type != REG_DWORD) {
3297 ERR("Got type %d\n", type);
3303 /*****************************************************************************
3304 * WINSPOOL_GetStringFromReg
3306 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3307 * String is stored either as unicode or ascii.
3308 * Bit of a hack here to get the ValueName if we want ascii.
3310 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3311 DWORD buflen, DWORD *needed,
3314 DWORD sz = buflen, type;
3318 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3320 LPSTR ValueNameA = strdupWtoA(ValueName);
3321 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3322 HeapFree(GetProcessHeap(),0,ValueNameA);
3324 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3325 WARN("Got ret = %d\n", ret);
3329 /* add space for terminating '\0' */
3330 sz += unicode ? sizeof(WCHAR) : 1;
3334 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3339 /*****************************************************************************
3340 * WINSPOOL_GetDefaultDevMode
3342 * Get a default DevMode values for wineps.
3346 static void WINSPOOL_GetDefaultDevMode(
3348 DWORD buflen, DWORD *needed,
3352 static const char szwps[] = "wineps.drv";
3354 /* fill default DEVMODE - should be read from ppd... */
3355 ZeroMemory( &dm, sizeof(dm) );
3356 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3357 dm.dmSpecVersion = DM_SPECVERSION;
3358 dm.dmDriverVersion = 1;
3359 dm.dmSize = sizeof(DEVMODEA);
3360 dm.dmDriverExtra = 0;
3362 DM_ORIENTATION | DM_PAPERSIZE |
3363 DM_PAPERLENGTH | DM_PAPERWIDTH |
3366 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3367 DM_YRESOLUTION | DM_TTOPTION;
3369 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3370 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3371 dm.u1.s1.dmPaperLength = 2970;
3372 dm.u1.s1.dmPaperWidth = 2100;
3376 dm.dmDefaultSource = DMBIN_AUTO;
3377 dm.dmPrintQuality = DMRES_MEDIUM;
3380 dm.dmYResolution = 300; /* 300dpi */
3381 dm.dmTTOption = DMTT_BITMAP;
3384 /* dm.dmLogPixels */
3385 /* dm.dmBitsPerPel */
3386 /* dm.dmPelsWidth */
3387 /* dm.dmPelsHeight */
3388 /* dm.dmDisplayFlags */
3389 /* dm.dmDisplayFrequency */
3390 /* dm.dmICMMethod */
3391 /* dm.dmICMIntent */
3392 /* dm.dmMediaType */
3393 /* dm.dmDitherType */
3394 /* dm.dmReserved1 */
3395 /* dm.dmReserved2 */
3396 /* dm.dmPanningWidth */
3397 /* dm.dmPanningHeight */
3400 if(buflen >= sizeof(DEVMODEW)) {
3401 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3402 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3403 HeapFree(GetProcessHeap(),0,pdmW);
3405 *needed = sizeof(DEVMODEW);
3409 if(buflen >= sizeof(DEVMODEA)) {
3410 memcpy(ptr, &dm, sizeof(DEVMODEA));
3412 *needed = sizeof(DEVMODEA);
3416 /*****************************************************************************
3417 * WINSPOOL_GetDevModeFromReg
3419 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3420 * DevMode is stored either as unicode or ascii.
3422 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3424 DWORD buflen, DWORD *needed,
3427 DWORD sz = buflen, type;
3430 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3431 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3432 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3433 if (sz < sizeof(DEVMODEA))
3435 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3438 /* ensures that dmSize is not erratically bogus if registry is invalid */
3439 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3440 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3442 sz += (CCHDEVICENAME + CCHFORMNAME);
3444 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3445 memcpy(ptr, dmW, sz);
3446 HeapFree(GetProcessHeap(),0,dmW);
3453 /*********************************************************************
3454 * WINSPOOL_GetPrinter_2
3456 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3457 * The strings are either stored as unicode or ascii.
3459 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3460 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3463 DWORD size, left = cbBuf;
3464 BOOL space = (cbBuf > 0);
3469 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3471 if(space && size <= left) {
3472 pi2->pPrinterName = (LPWSTR)ptr;
3479 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3481 if(space && size <= left) {
3482 pi2->pShareName = (LPWSTR)ptr;
3489 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3491 if(space && size <= left) {
3492 pi2->pPortName = (LPWSTR)ptr;
3499 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3501 if(space && size <= left) {
3502 pi2->pDriverName = (LPWSTR)ptr;
3509 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3511 if(space && size <= left) {
3512 pi2->pComment = (LPWSTR)ptr;
3519 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3521 if(space && size <= left) {
3522 pi2->pLocation = (LPWSTR)ptr;
3529 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3531 if(space && size <= left) {
3532 pi2->pDevMode = (LPDEVMODEW)ptr;
3541 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3542 if(space && size <= left) {
3543 pi2->pDevMode = (LPDEVMODEW)ptr;
3550 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3552 if(space && size <= left) {
3553 pi2->pSepFile = (LPWSTR)ptr;
3560 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3562 if(space && size <= left) {
3563 pi2->pPrintProcessor = (LPWSTR)ptr;
3570 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3572 if(space && size <= left) {
3573 pi2->pDatatype = (LPWSTR)ptr;
3580 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3582 if(space && size <= left) {
3583 pi2->pParameters = (LPWSTR)ptr;
3591 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3592 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3593 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3594 "Default Priority");
3595 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3596 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3599 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3600 memset(pi2, 0, sizeof(*pi2));
3605 /*********************************************************************
3606 * WINSPOOL_GetPrinter_4
3608 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3610 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3611 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3614 DWORD size, left = cbBuf;
3615 BOOL space = (cbBuf > 0);
3620 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3622 if(space && size <= left) {
3623 pi4->pPrinterName = (LPWSTR)ptr;
3631 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3634 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3635 memset(pi4, 0, sizeof(*pi4));
3640 /*********************************************************************
3641 * WINSPOOL_GetPrinter_5
3643 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3645 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3646 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3649 DWORD size, left = cbBuf;
3650 BOOL space = (cbBuf > 0);
3655 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3657 if(space && size <= left) {
3658 pi5->pPrinterName = (LPWSTR)ptr;
3665 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3667 if(space && size <= left) {
3668 pi5->pPortName = (LPWSTR)ptr;
3676 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3677 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3679 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3683 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3684 memset(pi5, 0, sizeof(*pi5));
3689 /*****************************************************************************
3690 * WINSPOOL_GetPrinter
3692 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3693 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3694 * just a collection of pointers to strings.
3696 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3697 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3700 DWORD size, needed = 0;
3702 HKEY hkeyPrinter, hkeyPrinters;
3705 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3707 if (!(name = get_opened_printer_name(hPrinter))) {
3708 SetLastError(ERROR_INVALID_HANDLE);
3712 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3714 ERR("Can't create Printers key\n");
3717 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3719 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3720 RegCloseKey(hkeyPrinters);
3721 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3728 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3730 size = sizeof(PRINTER_INFO_2W);
3732 ptr = pPrinter + size;
3734 memset(pPrinter, 0, size);
3739 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3747 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3749 size = sizeof(PRINTER_INFO_4W);
3751 ptr = pPrinter + size;
3753 memset(pPrinter, 0, size);
3758 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3767 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3769 size = sizeof(PRINTER_INFO_5W);
3771 ptr = pPrinter + size;
3773 memset(pPrinter, 0, size);
3779 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3786 FIXME("Unimplemented level %d\n", Level);
3787 SetLastError(ERROR_INVALID_LEVEL);
3788 RegCloseKey(hkeyPrinters);
3789 RegCloseKey(hkeyPrinter);
3793 RegCloseKey(hkeyPrinter);
3794 RegCloseKey(hkeyPrinters);
3796 TRACE("returning %d needed = %d\n", ret, needed);
3797 if(pcbNeeded) *pcbNeeded = needed;
3799 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3803 /*****************************************************************************
3804 * GetPrinterW [WINSPOOL.@]
3806 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3807 DWORD cbBuf, LPDWORD pcbNeeded)
3809 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3813 /*****************************************************************************
3814 * GetPrinterA [WINSPOOL.@]
3816 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3817 DWORD cbBuf, LPDWORD pcbNeeded)
3819 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3823 /*****************************************************************************
3824 * WINSPOOL_EnumPrinters
3826 * Implementation of EnumPrintersA|W
3828 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3829 DWORD dwLevel, LPBYTE lpbPrinters,
3830 DWORD cbBuf, LPDWORD lpdwNeeded,
3831 LPDWORD lpdwReturned, BOOL unicode)
3834 HKEY hkeyPrinters, hkeyPrinter;
3835 WCHAR PrinterName[255];
3836 DWORD needed = 0, number = 0;
3837 DWORD used, i, left;
3841 memset(lpbPrinters, 0, cbBuf);
3847 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3848 if(dwType == PRINTER_ENUM_DEFAULT)
3851 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3852 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3853 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3854 if(!dwType) return TRUE;
3857 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3858 FIXME("dwType = %08x\n", dwType);
3859 SetLastError(ERROR_INVALID_FLAGS);
3863 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3865 ERR("Can't create Printers key\n");
3869 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3870 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3871 RegCloseKey(hkeyPrinters);
3872 ERR("Can't query Printers key\n");
3875 TRACE("Found %d printers\n", number);
3879 RegCloseKey(hkeyPrinters);
3881 *lpdwReturned = number;
3885 used = number * sizeof(PRINTER_INFO_2W);
3888 used = number * sizeof(PRINTER_INFO_4W);
3891 used = number * sizeof(PRINTER_INFO_5W);
3895 SetLastError(ERROR_INVALID_LEVEL);
3896 RegCloseKey(hkeyPrinters);
3899 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3901 for(i = 0; i < number; i++) {
3902 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3904 ERR("Can't enum key number %d\n", i);
3905 RegCloseKey(hkeyPrinters);
3908 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3909 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3911 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3912 RegCloseKey(hkeyPrinters);
3917 buf = lpbPrinters + used;
3918 left = cbBuf - used;
3926 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3927 left, &needed, unicode);
3929 if(pi) pi += sizeof(PRINTER_INFO_2W);
3932 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3933 left, &needed, unicode);
3935 if(pi) pi += sizeof(PRINTER_INFO_4W);
3938 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3939 left, &needed, unicode);
3941 if(pi) pi += sizeof(PRINTER_INFO_5W);
3944 ERR("Shouldn't be here!\n");
3945 RegCloseKey(hkeyPrinter);
3946 RegCloseKey(hkeyPrinters);
3949 RegCloseKey(hkeyPrinter);
3951 RegCloseKey(hkeyPrinters);
3958 memset(lpbPrinters, 0, cbBuf);
3959 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3963 *lpdwReturned = number;
3964 SetLastError(ERROR_SUCCESS);
3969 /******************************************************************
3970 * EnumPrintersW [WINSPOOL.@]
3972 * Enumerates the available printers, print servers and print
3973 * providers, depending on the specified flags, name and level.
3977 * If level is set to 1:
3978 * Not implemented yet!
3979 * Returns TRUE with an empty list.
3981 * If level is set to 2:
3982 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3983 * Returns an array of PRINTER_INFO_2 data structures in the
3984 * lpbPrinters buffer. Note that according to MSDN also an
3985 * OpenPrinter should be performed on every remote printer.
3987 * If level is set to 4 (officially WinNT only):
3988 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3989 * Fast: Only the registry is queried to retrieve printer names,
3990 * no connection to the driver is made.
3991 * Returns an array of PRINTER_INFO_4 data structures in the
3992 * lpbPrinters buffer.
3994 * If level is set to 5 (officially WinNT4/Win9x only):
3995 * Fast: Only the registry is queried to retrieve printer names,
3996 * no connection to the driver is made.
3997 * Returns an array of PRINTER_INFO_5 data structures in the
3998 * lpbPrinters buffer.
4000 * If level set to 3 or 6+:
4001 * returns zero (failure!)
4003 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4007 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4008 * - Only levels 2, 4 and 5 are implemented at the moment.
4009 * - 16-bit printer drivers are not enumerated.
4010 * - Returned amount of bytes used/needed does not match the real Windoze
4011 * implementation (as in this implementation, all strings are part
4012 * of the buffer, whereas Win32 keeps them somewhere else)
4013 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4016 * - In a regular Wine installation, no registry settings for printers
4017 * exist, which makes this function return an empty list.
4019 BOOL WINAPI EnumPrintersW(
4020 DWORD dwType, /* [in] Types of print objects to enumerate */
4021 LPWSTR lpszName, /* [in] name of objects to enumerate */
4022 DWORD dwLevel, /* [in] type of printer info structure */
4023 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4024 DWORD cbBuf, /* [in] max size of buffer in bytes */
4025 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4026 LPDWORD lpdwReturned /* [out] number of entries returned */
4029 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4030 lpdwNeeded, lpdwReturned, TRUE);
4033 /******************************************************************
4034 * EnumPrintersA [WINSPOOL.@]
4037 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4038 DWORD dwLevel, LPBYTE lpbPrinters,
4039 DWORD cbBuf, LPDWORD lpdwNeeded,
4040 LPDWORD lpdwReturned)
4042 BOOL ret, unicode = FALSE;
4043 UNICODE_STRING lpszNameW;
4046 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4047 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4048 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4049 lpdwNeeded, lpdwReturned, unicode);
4050 RtlFreeUnicodeString(&lpszNameW);
4054 /*****************************************************************************
4055 * WINSPOOL_GetDriverInfoFromReg [internal]
4057 * Enters the information from the registry into the DRIVER_INFO struct
4060 * zero if the printer driver does not exist in the registry
4061 * (only if Level > 1) otherwise nonzero
4063 static BOOL WINSPOOL_GetDriverInfoFromReg(
4066 LPCWSTR pEnvironment,
4068 LPBYTE ptr, /* DRIVER_INFO */
4069 LPBYTE pDriverStrings, /* strings buffer */
4070 DWORD cbBuf, /* size of string buffer */
4071 LPDWORD pcbNeeded, /* space needed for str. */
4072 BOOL unicode) /* type of strings */
4076 LPBYTE strPtr = pDriverStrings;
4078 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4079 debugstr_w(DriverName), debugstr_w(pEnvironment),
4080 Level, ptr, pDriverStrings, cbBuf, unicode);
4083 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4084 if (*pcbNeeded <= cbBuf)
4085 strcpyW((LPWSTR)strPtr, DriverName);
4087 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4089 if(*pcbNeeded <= cbBuf)
4090 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4091 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4095 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4099 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4100 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4103 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4104 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
4105 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4110 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4113 pEnvironment = DefaultEnvironmentW;
4115 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4117 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4120 if(*pcbNeeded <= cbBuf) {
4122 strcpyW((LPWSTR)strPtr, pEnvironment);
4124 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4125 (LPSTR)strPtr, size, NULL, NULL);
4127 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4128 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4131 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4134 if(*pcbNeeded <= cbBuf)
4135 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4138 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4139 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4142 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4145 if(*pcbNeeded <= cbBuf)
4146 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4149 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4150 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4153 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4154 0, &size, unicode)) {
4156 if(*pcbNeeded <= cbBuf)
4157 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4158 size, &tmp, unicode);
4160 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4161 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4165 RegCloseKey(hkeyDriver);
4166 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4170 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4173 if(*pcbNeeded <= cbBuf)
4174 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4175 size, &tmp, unicode);
4177 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4178 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4181 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4184 if(*pcbNeeded <= cbBuf)
4185 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4186 size, &tmp, unicode);
4188 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4189 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4192 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4195 if(*pcbNeeded <= cbBuf)
4196 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4197 size, &tmp, unicode);
4199 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4200 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4203 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4206 if(*pcbNeeded <= cbBuf)
4207 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4208 size, &tmp, unicode);
4210 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4211 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4214 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4215 RegCloseKey(hkeyDriver);
4219 /*****************************************************************************
4220 * WINSPOOL_GetPrinterDriver
4222 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
4223 DWORD Level, LPBYTE pDriverInfo,
4224 DWORD cbBuf, LPDWORD pcbNeeded,
4228 WCHAR DriverName[100];
4229 DWORD ret, type, size, needed = 0;
4231 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4233 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4234 Level,pDriverInfo,cbBuf, pcbNeeded);
4236 ZeroMemory(pDriverInfo, cbBuf);
4238 if (!(name = get_opened_printer_name(hPrinter))) {
4239 SetLastError(ERROR_INVALID_HANDLE);
4242 if(Level < 1 || Level > 6) {
4243 SetLastError(ERROR_INVALID_LEVEL);
4246 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4248 ERR("Can't create Printers key\n");
4251 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4253 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4254 RegCloseKey(hkeyPrinters);
4255 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4258 size = sizeof(DriverName);
4260 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4261 (LPBYTE)DriverName, &size);
4262 RegCloseKey(hkeyPrinter);
4263 RegCloseKey(hkeyPrinters);
4264 if(ret != ERROR_SUCCESS) {
4265 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4269 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4271 ERR("Can't create Drivers key\n");
4277 size = sizeof(DRIVER_INFO_1W);
4280 size = sizeof(DRIVER_INFO_2W);
4283 size = sizeof(DRIVER_INFO_3W);
4286 size = sizeof(DRIVER_INFO_4W);
4289 size = sizeof(DRIVER_INFO_5W);
4292 size = sizeof(DRIVER_INFO_6W);
4295 ERR("Invalid level\n");
4300 ptr = pDriverInfo + size;
4302 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4303 pEnvironment, Level, pDriverInfo,
4304 (cbBuf < size) ? NULL : ptr,
4305 (cbBuf < size) ? 0 : cbBuf - size,
4306 &needed, unicode)) {
4307 RegCloseKey(hkeyDrivers);
4311 RegCloseKey(hkeyDrivers);
4313 if(pcbNeeded) *pcbNeeded = size + needed;
4314 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4315 if(cbBuf >= needed) return TRUE;
4316 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4320 /*****************************************************************************
4321 * GetPrinterDriverA [WINSPOOL.@]
4323 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4324 DWORD Level, LPBYTE pDriverInfo,
4325 DWORD cbBuf, LPDWORD pcbNeeded)
4328 UNICODE_STRING pEnvW;
4331 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4332 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4333 cbBuf, pcbNeeded, FALSE);
4334 RtlFreeUnicodeString(&pEnvW);
4337 /*****************************************************************************
4338 * GetPrinterDriverW [WINSPOOL.@]
4340 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4341 DWORD Level, LPBYTE pDriverInfo,
4342 DWORD cbBuf, LPDWORD pcbNeeded)
4344 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4345 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4348 /*****************************************************************************
4349 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4351 * Return the PATH for the Printer-Drivers (UNICODE)
4354 * pName [I] Servername (NT only) or NULL (local Computer)
4355 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4356 * Level [I] Structure-Level (must be 1)
4357 * pDriverDirectory [O] PTR to Buffer that receives the Result
4358 * cbBuf [I] Size of Buffer at pDriverDirectory
4359 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4360 * required for pDriverDirectory
4363 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4364 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4365 * if cbBuf is too small
4367 * Native Values returned in pDriverDirectory on Success:
4368 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4369 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4370 *| win9x(Windows 4.0): "%winsysdir%"
4372 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4375 *- Only NULL or "" is supported for pName
4378 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4379 DWORD Level, LPBYTE pDriverDirectory,
4380 DWORD cbBuf, LPDWORD pcbNeeded)
4383 const printenv_t * env;
4385 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4386 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4387 if(pName != NULL && pName[0]) {
4388 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4389 SetLastError(ERROR_INVALID_PARAMETER);
4393 env = validate_envW(pEnvironment);
4394 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4397 WARN("(Level: %d) is ignored in win9x\n", Level);
4398 SetLastError(ERROR_INVALID_LEVEL);
4402 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4403 needed = GetSystemDirectoryW(NULL, 0);
4404 /* add the Size for the Subdirectories */
4405 needed += lstrlenW(spooldriversW);
4406 needed += lstrlenW(env->subdir);
4407 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4410 *pcbNeeded = needed;
4411 TRACE("required: 0x%x/%d\n", needed, needed);
4412 if(needed > cbBuf) {
4413 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4416 if(pcbNeeded == NULL) {
4417 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4418 SetLastError(RPC_X_NULL_REF_POINTER);
4421 if(pDriverDirectory == NULL) {
4422 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4423 SetLastError(ERROR_INVALID_USER_BUFFER);
4427 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4428 /* add the Subdirectories */
4429 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4430 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4431 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4436 /*****************************************************************************
4437 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4439 * Return the PATH for the Printer-Drivers (ANSI)
4441 * See GetPrinterDriverDirectoryW.
4444 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4447 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4448 DWORD Level, LPBYTE pDriverDirectory,
4449 DWORD cbBuf, LPDWORD pcbNeeded)
4451 UNICODE_STRING nameW, environmentW;
4454 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4455 WCHAR *driverDirectoryW = NULL;
4457 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4458 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4460 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4462 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4463 else nameW.Buffer = NULL;
4464 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4465 else environmentW.Buffer = NULL;
4467 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4468 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4471 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4472 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4474 *pcbNeeded = needed;
4475 ret = (needed <= cbBuf) ? TRUE : FALSE;
4477 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4479 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4481 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4482 RtlFreeUnicodeString(&environmentW);
4483 RtlFreeUnicodeString(&nameW);
4488 /*****************************************************************************
4489 * AddPrinterDriverA [WINSPOOL.@]
4491 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4494 HKEY hkeyDrivers, hkeyName;
4495 static CHAR empty[] = "",
4498 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4500 if(level != 2 && level != 3) {
4501 SetLastError(ERROR_INVALID_LEVEL);
4504 if ((pName) && (pName[0])) {
4505 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4506 SetLastError(ERROR_INVALID_PARAMETER);
4510 WARN("pDriverInfo == NULL\n");
4511 SetLastError(ERROR_INVALID_PARAMETER);
4516 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4518 memset(&di3, 0, sizeof(di3));
4519 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4522 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4524 SetLastError(ERROR_INVALID_PARAMETER);
4528 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4529 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4530 if(!di3.pHelpFile) di3.pHelpFile = empty;
4531 if(!di3.pMonitorName) di3.pMonitorName = empty;
4533 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4536 ERR("Can't create Drivers key\n");
4540 if(level == 2) { /* apparently can't overwrite with level2 */
4541 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4542 RegCloseKey(hkeyName);
4543 RegCloseKey(hkeyDrivers);
4544 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4545 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4549 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4550 RegCloseKey(hkeyDrivers);
4551 ERR("Can't create Name key\n");
4554 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4555 lstrlenA(di3.pConfigFile) + 1);
4556 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4557 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4558 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4560 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4561 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4562 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4563 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4564 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4565 RegCloseKey(hkeyName);
4566 RegCloseKey(hkeyDrivers);
4571 /*****************************************************************************
4572 * AddPrinterDriverW [WINSPOOL.@]
4574 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4577 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4582 /*****************************************************************************
4583 * AddPrintProcessorA [WINSPOOL.@]
4585 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4586 LPSTR pPrintProcessorName)
4588 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4589 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4593 /*****************************************************************************
4594 * AddPrintProcessorW [WINSPOOL.@]
4596 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4597 LPWSTR pPrintProcessorName)
4599 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4600 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4604 /*****************************************************************************
4605 * AddPrintProvidorA [WINSPOOL.@]
4607 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4609 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4613 /*****************************************************************************
4614 * AddPrintProvidorW [WINSPOOL.@]
4616 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4618 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4622 /*****************************************************************************
4623 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4625 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4626 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4628 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4629 pDevModeOutput, pDevModeInput);
4633 /*****************************************************************************
4634 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4636 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4637 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4639 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4640 pDevModeOutput, pDevModeInput);
4644 /*****************************************************************************
4645 * PrinterProperties [WINSPOOL.@]
4647 * Displays a dialog to set the properties of the printer.
4650 * nonzero on success or zero on failure
4653 * implemented as stub only
4655 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4656 HANDLE hPrinter /* [in] handle to printer object */
4658 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4659 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4663 /*****************************************************************************
4664 * EnumJobsA [WINSPOOL.@]
4667 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4668 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4671 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4672 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4674 if(pcbNeeded) *pcbNeeded = 0;
4675 if(pcReturned) *pcReturned = 0;
4680 /*****************************************************************************
4681 * EnumJobsW [WINSPOOL.@]
4684 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4685 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4688 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4689 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4691 if(pcbNeeded) *pcbNeeded = 0;
4692 if(pcReturned) *pcReturned = 0;
4696 /*****************************************************************************
4697 * WINSPOOL_EnumPrinterDrivers [internal]
4699 * Delivers information about all printer drivers installed on the
4700 * localhost or a given server
4703 * nonzero on success or zero on failure. If the buffer for the returned
4704 * information is too small the function will return an error
4707 * - only implemented for localhost, foreign hosts will return an error
4709 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4710 DWORD Level, LPBYTE pDriverInfo,
4711 DWORD cbBuf, LPDWORD pcbNeeded,
4712 LPDWORD pcReturned, BOOL unicode)
4715 DWORD i, needed, number = 0, size = 0;
4716 WCHAR DriverNameW[255];
4719 TRACE("%s,%s,%d,%p,%d,%d\n",
4720 debugstr_w(pName), debugstr_w(pEnvironment),
4721 Level, pDriverInfo, cbBuf, unicode);
4723 /* check for local drivers */
4724 if((pName) && (pName[0])) {
4725 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4726 SetLastError(ERROR_ACCESS_DENIED);
4730 /* check input parameter */
4731 if((Level < 1) || (Level > 3)) {
4732 ERR("unsupported level %d\n", Level);
4733 SetLastError(ERROR_INVALID_LEVEL);
4737 /* initialize return values */
4739 memset( pDriverInfo, 0, cbBuf);
4743 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4745 ERR("Can't open Drivers key\n");
4749 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4750 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4751 RegCloseKey(hkeyDrivers);
4752 ERR("Can't query Drivers key\n");
4755 TRACE("Found %d Drivers\n", number);
4757 /* get size of single struct
4758 * unicode and ascii structure have the same size
4762 size = sizeof(DRIVER_INFO_1A);
4765 size = sizeof(DRIVER_INFO_2A);
4768 size = sizeof(DRIVER_INFO_3A);
4772 /* calculate required buffer size */
4773 *pcbNeeded = size * number;
4775 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4777 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4778 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4780 ERR("Can't enum key number %d\n", i);
4781 RegCloseKey(hkeyDrivers);
4784 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4785 pEnvironment, Level, ptr,
4786 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4787 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4788 &needed, unicode)) {
4789 RegCloseKey(hkeyDrivers);
4792 (*pcbNeeded) += needed;
4795 RegCloseKey(hkeyDrivers);
4797 if(cbBuf < *pcbNeeded){
4798 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4802 *pcReturned = number;
4806 /*****************************************************************************
4807 * EnumPrinterDriversW [WINSPOOL.@]
4809 * see function EnumPrinterDrivers for RETURNS, BUGS
4811 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4812 LPBYTE pDriverInfo, DWORD cbBuf,
4813 LPDWORD pcbNeeded, LPDWORD pcReturned)
4815 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4816 cbBuf, pcbNeeded, pcReturned, TRUE);
4819 /*****************************************************************************
4820 * EnumPrinterDriversA [WINSPOOL.@]
4822 * see function EnumPrinterDrivers for RETURNS, BUGS
4824 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4825 LPBYTE pDriverInfo, DWORD cbBuf,
4826 LPDWORD pcbNeeded, LPDWORD pcReturned)
4828 UNICODE_STRING pNameW, pEnvironmentW;
4829 PWSTR pwstrNameW, pwstrEnvironmentW;
4831 pwstrNameW = asciitounicode(&pNameW, pName);
4832 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4834 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4835 Level, pDriverInfo, cbBuf, pcbNeeded,
4837 RtlFreeUnicodeString(&pNameW);
4838 RtlFreeUnicodeString(&pEnvironmentW);
4843 /******************************************************************************
4844 * EnumPortsA (WINSPOOL.@)
4849 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4850 LPDWORD pcbNeeded, LPDWORD pcReturned)
4853 LPBYTE bufferW = NULL;
4854 LPWSTR nameW = NULL;
4856 DWORD numentries = 0;
4859 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4860 cbBuf, pcbNeeded, pcReturned);
4862 /* convert servername to unicode */
4864 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4865 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4866 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4868 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4869 needed = cbBuf * sizeof(WCHAR);
4870 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4871 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4873 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4874 if (pcbNeeded) needed = *pcbNeeded;
4875 /* HeapReAlloc return NULL, when bufferW was NULL */
4876 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4877 HeapAlloc(GetProcessHeap(), 0, needed);
4879 /* Try again with the large Buffer */
4880 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4882 needed = pcbNeeded ? *pcbNeeded : 0;
4883 numentries = pcReturned ? *pcReturned : 0;
4886 W2k require the buffersize from EnumPortsW also for EnumPortsA.
4887 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4890 /* EnumPortsW collected all Data. Parse them to caclulate ANSI-Size */
4891 DWORD entrysize = 0;
4894 LPPORT_INFO_2W pi2w;
4895 LPPORT_INFO_2A pi2a;
4898 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
4900 /* First pass: calculate the size for all Entries */
4901 pi2w = (LPPORT_INFO_2W) bufferW;
4902 pi2a = (LPPORT_INFO_2A) pPorts;
4904 while (index < numentries) {
4906 needed += entrysize; /* PORT_INFO_?A */
4907 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
4909 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4910 NULL, 0, NULL, NULL);
4912 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4913 NULL, 0, NULL, NULL);
4914 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4915 NULL, 0, NULL, NULL);
4917 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4918 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4919 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4922 /* check for errors and quit on failure */
4923 if (cbBuf < needed) {
4924 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4928 len = entrysize * numentries; /* room for all PORT_INFO_?A */
4929 ptr = (LPSTR) &pPorts[len]; /* room for strings */
4930 cbBuf -= len ; /* free Bytes in the user-Buffer */
4931 pi2w = (LPPORT_INFO_2W) bufferW;
4932 pi2a = (LPPORT_INFO_2A) pPorts;
4934 /* Second Pass: Fill the User Buffer (if we have one) */
4935 while ((index < numentries) && pPorts) {
4937 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
4938 pi2a->pPortName = ptr;
4939 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4940 ptr, cbBuf , NULL, NULL);
4944 pi2a->pMonitorName = ptr;
4945 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4946 ptr, cbBuf, NULL, NULL);
4950 pi2a->pDescription = ptr;
4951 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4952 ptr, cbBuf, NULL, NULL);
4956 pi2a->fPortType = pi2w->fPortType;
4957 pi2a->Reserved = 0; /* documented: "must be zero" */
4960 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4961 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4962 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4967 if (pcbNeeded) *pcbNeeded = needed;
4968 if (pcReturned) *pcReturned = (res) ? numentries : 0;
4970 HeapFree(GetProcessHeap(), 0, nameW);
4971 HeapFree(GetProcessHeap(), 0, bufferW);
4973 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
4974 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
4980 /******************************************************************************
4981 * EnumPortsW (WINSPOOL.@)
4983 * Enumerate available Ports
4986 * name [I] Servername or NULL (local Computer)
4987 * level [I] Structure-Level (1 or 2)
4988 * buffer [O] PTR to Buffer that receives the Result
4989 * bufsize [I] Size of Buffer at buffer
4990 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4991 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4995 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4999 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5002 DWORD numentries = 0;
5005 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5006 cbBuf, pcbNeeded, pcReturned);
5008 if (pName && (pName[0])) {
5009 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5010 SetLastError(ERROR_ACCESS_DENIED);
5014 /* Level is not checked in win9x */
5015 if (!Level || (Level > 2)) {
5016 WARN("level (%d) is ignored in win9x\n", Level);
5017 SetLastError(ERROR_INVALID_LEVEL);
5021 SetLastError(RPC_X_NULL_REF_POINTER);
5025 EnterCriticalSection(&monitor_handles_cs);
5028 /* Scan all local Ports */
5030 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5032 /* we calculated the needed buffersize. now do the error-checks */
5033 if (cbBuf < needed) {
5034 monitor_unloadall();
5035 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5036 goto emP_cleanup_cs;
5038 else if (!pPorts || !pcReturned) {
5039 monitor_unloadall();
5040 SetLastError(RPC_X_NULL_REF_POINTER);
5041 goto emP_cleanup_cs;
5044 /* Fill the Buffer */
5045 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5047 monitor_unloadall();
5050 LeaveCriticalSection(&monitor_handles_cs);
5053 if (pcbNeeded) *pcbNeeded = needed;
5054 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5056 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5057 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5062 /******************************************************************************
5063 * GetDefaultPrinterW (WINSPOOL.@)
5066 * This function must read the value from data 'device' of key
5067 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5069 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5073 WCHAR *buffer, *ptr;
5077 SetLastError(ERROR_INVALID_PARAMETER);
5081 /* make the buffer big enough for the stuff from the profile/registry,
5082 * the content must fit into the local buffer to compute the correct
5083 * size even if the extern buffer is too small or not given.
5084 * (20 for ,driver,port) */
5086 len = max(100, (insize + 20));
5087 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5089 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5091 SetLastError (ERROR_FILE_NOT_FOUND);
5095 TRACE("%s\n", debugstr_w(buffer));
5097 if ((ptr = strchrW(buffer, ',')) == NULL)
5099 SetLastError(ERROR_INVALID_NAME);
5105 *namesize = strlenW(buffer) + 1;
5106 if(!name || (*namesize > insize))
5108 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5112 strcpyW(name, buffer);
5115 HeapFree( GetProcessHeap(), 0, buffer);
5120 /******************************************************************************
5121 * GetDefaultPrinterA (WINSPOOL.@)
5123 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5127 WCHAR *bufferW = NULL;
5131 SetLastError(ERROR_INVALID_PARAMETER);
5135 if(name && *namesize) {
5137 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5140 if(!GetDefaultPrinterW( bufferW, namesize)) {
5145 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5149 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5152 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5155 HeapFree( GetProcessHeap(), 0, bufferW);
5160 /******************************************************************************
5161 * SetDefaultPrinterW (WINSPOOL.204)
5163 * Set the Name of the Default Printer
5166 * pszPrinter [I] Name of the Printer or NULL
5173 * When the Parameter is NULL or points to an Empty String and
5174 * a Default Printer was already present, then this Function changes nothing.
5175 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5176 * the First enumerated local Printer is used.
5179 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5182 TRACE("(%s)\n", debugstr_w(pszPrinter));
5184 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5188 /******************************************************************************
5189 * SetDefaultPrinterA (WINSPOOL.202)
5191 * See SetDefaultPrinterW.
5194 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5197 TRACE("(%s)\n", debugstr_a(pszPrinter));
5199 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5204 /******************************************************************************
5205 * SetPrinterDataExA (WINSPOOL.@)
5207 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5208 LPCSTR pValueName, DWORD Type,
5209 LPBYTE pData, DWORD cbData)
5211 HKEY hkeyPrinter, hkeySubkey;
5214 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5215 debugstr_a(pValueName), Type, pData, cbData);
5217 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5221 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5223 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5224 RegCloseKey(hkeyPrinter);
5227 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5228 RegCloseKey(hkeySubkey);
5229 RegCloseKey(hkeyPrinter);
5233 /******************************************************************************
5234 * SetPrinterDataExW (WINSPOOL.@)
5236 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5237 LPCWSTR pValueName, DWORD Type,
5238 LPBYTE pData, DWORD cbData)
5240 HKEY hkeyPrinter, hkeySubkey;
5243 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5244 debugstr_w(pValueName), Type, pData, cbData);
5246 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5250 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5252 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5253 RegCloseKey(hkeyPrinter);
5256 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5257 RegCloseKey(hkeySubkey);
5258 RegCloseKey(hkeyPrinter);
5262 /******************************************************************************
5263 * SetPrinterDataA (WINSPOOL.@)
5265 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5266 LPBYTE pData, DWORD cbData)
5268 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5272 /******************************************************************************
5273 * SetPrinterDataW (WINSPOOL.@)
5275 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5276 LPBYTE pData, DWORD cbData)
5278 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5282 /******************************************************************************
5283 * GetPrinterDataExA (WINSPOOL.@)
5285 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5286 LPCSTR pValueName, LPDWORD pType,
5287 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5289 HKEY hkeyPrinter, hkeySubkey;
5292 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5293 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5296 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5300 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5302 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5303 RegCloseKey(hkeyPrinter);
5307 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5308 RegCloseKey(hkeySubkey);
5309 RegCloseKey(hkeyPrinter);
5313 /******************************************************************************
5314 * GetPrinterDataExW (WINSPOOL.@)
5316 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5317 LPCWSTR pValueName, LPDWORD pType,
5318 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5320 HKEY hkeyPrinter, hkeySubkey;
5323 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5324 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5327 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5331 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5333 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5334 RegCloseKey(hkeyPrinter);
5338 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5339 RegCloseKey(hkeySubkey);
5340 RegCloseKey(hkeyPrinter);
5344 /******************************************************************************
5345 * GetPrinterDataA (WINSPOOL.@)
5347 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5348 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5350 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5351 pData, nSize, pcbNeeded);
5354 /******************************************************************************
5355 * GetPrinterDataW (WINSPOOL.@)
5357 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5358 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5360 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5361 pData, nSize, pcbNeeded);
5364 /*******************************************************************************
5365 * EnumPrinterDataExW [WINSPOOL.@]
5367 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5368 LPBYTE pEnumValues, DWORD cbEnumValues,
5369 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5371 HKEY hkPrinter, hkSubKey;
5372 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5373 cbValueNameLen, cbMaxValueLen, cbValueLen,
5378 PPRINTER_ENUM_VALUESW ppev;
5380 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5382 if (pKeyName == NULL || *pKeyName == 0)
5383 return ERROR_INVALID_PARAMETER;
5385 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5386 if (ret != ERROR_SUCCESS)
5388 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5393 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5394 if (ret != ERROR_SUCCESS)
5396 r = RegCloseKey (hkPrinter);
5397 if (r != ERROR_SUCCESS)
5398 WARN ("RegCloseKey returned %i\n", r);
5399 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5400 debugstr_w (pKeyName), ret);
5404 ret = RegCloseKey (hkPrinter);
5405 if (ret != ERROR_SUCCESS)
5407 ERR ("RegCloseKey returned %i\n", ret);
5408 r = RegCloseKey (hkSubKey);
5409 if (r != ERROR_SUCCESS)
5410 WARN ("RegCloseKey returned %i\n", r);
5414 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5415 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5416 if (ret != ERROR_SUCCESS)
5418 r = RegCloseKey (hkSubKey);
5419 if (r != ERROR_SUCCESS)
5420 WARN ("RegCloseKey returned %i\n", r);
5421 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5425 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5426 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5428 if (cValues == 0) /* empty key */
5430 r = RegCloseKey (hkSubKey);
5431 if (r != ERROR_SUCCESS)
5432 WARN ("RegCloseKey returned %i\n", r);
5433 *pcbEnumValues = *pnEnumValues = 0;
5434 return ERROR_SUCCESS;
5437 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5439 hHeap = GetProcessHeap ();
5442 ERR ("GetProcessHeap failed\n");
5443 r = RegCloseKey (hkSubKey);
5444 if (r != ERROR_SUCCESS)
5445 WARN ("RegCloseKey returned %i\n", r);
5446 return ERROR_OUTOFMEMORY;
5449 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5450 if (lpValueName == NULL)
5452 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5453 r = RegCloseKey (hkSubKey);
5454 if (r != ERROR_SUCCESS)
5455 WARN ("RegCloseKey returned %i\n", r);
5456 return ERROR_OUTOFMEMORY;
5459 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5460 if (lpValue == NULL)
5462 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5463 if (HeapFree (hHeap, 0, lpValueName) == 0)
5464 WARN ("HeapFree failed with code %i\n", GetLastError ());
5465 r = RegCloseKey (hkSubKey);
5466 if (r != ERROR_SUCCESS)
5467 WARN ("RegCloseKey returned %i\n", r);
5468 return ERROR_OUTOFMEMORY;
5471 TRACE ("pass 1: calculating buffer required for all names and values\n");
5473 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5475 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5477 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5479 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5480 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5481 NULL, NULL, lpValue, &cbValueLen);
5482 if (ret != ERROR_SUCCESS)
5484 if (HeapFree (hHeap, 0, lpValue) == 0)
5485 WARN ("HeapFree failed with code %i\n", GetLastError ());
5486 if (HeapFree (hHeap, 0, lpValueName) == 0)
5487 WARN ("HeapFree failed with code %i\n", GetLastError ());
5488 r = RegCloseKey (hkSubKey);
5489 if (r != ERROR_SUCCESS)
5490 WARN ("RegCloseKey returned %i\n", r);
5491 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5495 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5496 debugstr_w (lpValueName), dwIndex,
5497 cbValueNameLen + 1, cbValueLen);
5499 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5500 cbBufSize += cbValueLen;
5503 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5505 *pcbEnumValues = cbBufSize;
5506 *pnEnumValues = cValues;
5508 if (cbEnumValues < cbBufSize) /* buffer too small */
5510 if (HeapFree (hHeap, 0, lpValue) == 0)
5511 WARN ("HeapFree failed with code %i\n", GetLastError ());
5512 if (HeapFree (hHeap, 0, lpValueName) == 0)
5513 WARN ("HeapFree failed with code %i\n", GetLastError ());
5514 r = RegCloseKey (hkSubKey);
5515 if (r != ERROR_SUCCESS)
5516 WARN ("RegCloseKey returned %i\n", r);
5517 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5518 return ERROR_MORE_DATA;
5521 TRACE ("pass 2: copying all names and values to buffer\n");
5523 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5524 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5526 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5528 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5529 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5530 NULL, &dwType, lpValue, &cbValueLen);
5531 if (ret != ERROR_SUCCESS)
5533 if (HeapFree (hHeap, 0, lpValue) == 0)
5534 WARN ("HeapFree failed with code %i\n", GetLastError ());
5535 if (HeapFree (hHeap, 0, lpValueName) == 0)
5536 WARN ("HeapFree failed with code %i\n", GetLastError ());
5537 r = RegCloseKey (hkSubKey);
5538 if (r != ERROR_SUCCESS)
5539 WARN ("RegCloseKey returned %i\n", r);
5540 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5544 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5545 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5546 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5547 pEnumValues += cbValueNameLen;
5549 /* return # of *bytes* (including trailing \0), not # of chars */
5550 ppev[dwIndex].cbValueName = cbValueNameLen;
5552 ppev[dwIndex].dwType = dwType;
5554 memcpy (pEnumValues, lpValue, cbValueLen);
5555 ppev[dwIndex].pData = pEnumValues;
5556 pEnumValues += cbValueLen;
5558 ppev[dwIndex].cbData = cbValueLen;
5560 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5561 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5564 if (HeapFree (hHeap, 0, lpValue) == 0)
5566 ret = GetLastError ();
5567 ERR ("HeapFree failed with code %i\n", ret);
5568 if (HeapFree (hHeap, 0, lpValueName) == 0)
5569 WARN ("HeapFree failed with code %i\n", GetLastError ());
5570 r = RegCloseKey (hkSubKey);
5571 if (r != ERROR_SUCCESS)
5572 WARN ("RegCloseKey returned %i\n", r);
5576 if (HeapFree (hHeap, 0, lpValueName) == 0)
5578 ret = GetLastError ();
5579 ERR ("HeapFree failed with code %i\n", ret);
5580 r = RegCloseKey (hkSubKey);
5581 if (r != ERROR_SUCCESS)
5582 WARN ("RegCloseKey returned %i\n", r);
5586 ret = RegCloseKey (hkSubKey);
5587 if (ret != ERROR_SUCCESS)
5589 ERR ("RegCloseKey returned %i\n", ret);
5593 return ERROR_SUCCESS;
5596 /*******************************************************************************
5597 * EnumPrinterDataExA [WINSPOOL.@]
5599 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5600 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5601 * what Windows 2000 SP1 does.
5604 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5605 LPBYTE pEnumValues, DWORD cbEnumValues,
5606 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5610 DWORD ret, dwIndex, dwBufSize;
5614 TRACE ("%p %s\n", hPrinter, pKeyName);
5616 if (pKeyName == NULL || *pKeyName == 0)
5617 return ERROR_INVALID_PARAMETER;
5619 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5622 ret = GetLastError ();
5623 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5627 hHeap = GetProcessHeap ();
5630 ERR ("GetProcessHeap failed\n");
5631 return ERROR_OUTOFMEMORY;
5634 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5635 if (pKeyNameW == NULL)
5637 ERR ("Failed to allocate %i bytes from process heap\n",
5638 (LONG)(len * sizeof (WCHAR)));
5639 return ERROR_OUTOFMEMORY;
5642 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5644 ret = GetLastError ();
5645 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5646 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5647 WARN ("HeapFree failed with code %i\n", GetLastError ());
5651 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5652 pcbEnumValues, pnEnumValues);
5653 if (ret != ERROR_SUCCESS)
5655 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5656 WARN ("HeapFree failed with code %i\n", GetLastError ());
5657 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5661 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5663 ret = GetLastError ();
5664 ERR ("HeapFree failed with code %i\n", ret);
5668 if (*pnEnumValues == 0) /* empty key */
5669 return ERROR_SUCCESS;
5672 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5674 PPRINTER_ENUM_VALUESW ppev =
5675 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5677 if (dwBufSize < ppev->cbValueName)
5678 dwBufSize = ppev->cbValueName;
5680 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5681 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5682 dwBufSize = ppev->cbData;
5685 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5687 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5688 if (pBuffer == NULL)
5690 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5691 return ERROR_OUTOFMEMORY;
5694 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5696 PPRINTER_ENUM_VALUESW ppev =
5697 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5699 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5700 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5704 ret = GetLastError ();
5705 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5706 if (HeapFree (hHeap, 0, pBuffer) == 0)
5707 WARN ("HeapFree failed with code %i\n", GetLastError ());
5711 memcpy (ppev->pValueName, pBuffer, len);
5713 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5715 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5716 ppev->dwType != REG_MULTI_SZ)
5719 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5720 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5723 ret = GetLastError ();
5724 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5725 if (HeapFree (hHeap, 0, pBuffer) == 0)
5726 WARN ("HeapFree failed with code %i\n", GetLastError ());
5730 memcpy (ppev->pData, pBuffer, len);
5732 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5733 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5736 if (HeapFree (hHeap, 0, pBuffer) == 0)
5738 ret = GetLastError ();
5739 ERR ("HeapFree failed with code %i\n", ret);
5743 return ERROR_SUCCESS;
5746 /******************************************************************************
5747 * AbortPrinter (WINSPOOL.@)
5749 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5751 FIXME("(%p), stub!\n", hPrinter);
5755 /******************************************************************************
5756 * AddPortA (WINSPOOL.@)
5761 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5763 LPWSTR nameW = NULL;
5764 LPWSTR monitorW = NULL;
5768 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5771 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5772 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5773 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5777 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5778 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5779 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5781 res = AddPortW(nameW, hWnd, monitorW);
5782 HeapFree(GetProcessHeap(), 0, nameW);
5783 HeapFree(GetProcessHeap(), 0, monitorW);
5787 /******************************************************************************
5788 * AddPortW (WINSPOOL.@)
5790 * Add a Port for a specific Monitor
5793 * pName [I] Servername or NULL (local Computer)
5794 * hWnd [I] Handle to parent Window for the Dialog-Box
5795 * pMonitorName [I] Name of the Monitor that manage the Port
5802 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5805 DWORD res = ROUTER_UNKNOWN;
5807 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5809 if (pName && pName[0]) {
5810 SetLastError(ERROR_INVALID_PARAMETER);
5814 if (!pMonitorName) {
5815 SetLastError(RPC_X_NULL_REF_POINTER);
5819 /* an empty Monitorname is Invalid */
5820 if (!pMonitorName[0]) goto cleanup;
5822 pm = monitor_load(pMonitorName, NULL);
5823 if (pm && pm->monitor) {
5824 if (pm->monitor->pfnAddPort != NULL) {
5825 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
5826 TRACE("got %d with %d\n", res, GetLastError());
5828 else if (pm->monitor->pfnXcvOpenPort != NULL)
5830 FIXME("XcvOpenPort not implemented (dwMonitorSize: %d)\n", pm->dwMonitorSize);
5832 /* invalidate cached PORT_INFO_2W */
5833 if (res == ROUTER_SUCCESS) monitor_flush(pm);
5838 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
5839 if (res == ROUTER_UNKNOWN) SetLastError(ERROR_NOT_SUPPORTED);
5840 TRACE("returning %d with %d\n", (res == ROUTER_SUCCESS), GetLastError());
5841 return (res == ROUTER_SUCCESS);
5844 /******************************************************************************
5845 * AddPortExA (WINSPOOL.@)
5850 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5852 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5853 lpBuffer, debugstr_a(lpMonitorName));
5857 /******************************************************************************
5858 * AddPortExW (WINSPOOL.@)
5860 * Add a Port for a specific Monitor, without presenting a user interface
5863 * hMonitor [I] Handle from InitializePrintMonitor2()
5864 * pName [I] Servername or NULL (local Computer)
5865 * Level [I] Structure-Level (1 or 2) for lpBuffer
5866 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5867 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5877 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5879 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5880 lpBuffer, debugstr_w(lpMonitorName));
5884 /******************************************************************************
5885 * AddPrinterConnectionA (WINSPOOL.@)
5887 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5889 FIXME("%s\n", debugstr_a(pName));
5893 /******************************************************************************
5894 * AddPrinterConnectionW (WINSPOOL.@)
5896 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5898 FIXME("%s\n", debugstr_w(pName));
5902 /******************************************************************************
5903 * AddPrinterDriverExW (WINSPOOL.@)
5905 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5906 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5908 FIXME("%s %d %p %d\n", debugstr_w(pName),
5909 Level, pDriverInfo, dwFileCopyFlags);
5910 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5914 /******************************************************************************
5915 * AddPrinterDriverExA (WINSPOOL.@)
5917 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5918 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5920 FIXME("%s %d %p %d\n", debugstr_a(pName),
5921 Level, pDriverInfo, dwFileCopyFlags);
5922 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5926 /******************************************************************************
5927 * ConfigurePortA (WINSPOOL.@)
5929 * See ConfigurePortW.
5932 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5934 LPWSTR nameW = NULL;
5935 LPWSTR portW = NULL;
5939 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5941 /* convert servername to unicode */
5943 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5944 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5945 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5948 /* convert portname to unicode */
5950 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
5951 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5952 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
5955 res = ConfigurePortW(nameW, hWnd, portW);
5956 HeapFree(GetProcessHeap(), 0, nameW);
5957 HeapFree(GetProcessHeap(), 0, portW);
5961 /******************************************************************************
5962 * ConfigurePortW (WINSPOOL.@)
5964 * Display the Configuration-Dialog for a specific Port
5967 * pName [I] Servername or NULL (local Computer)
5968 * hWnd [I] Handle to parent Window for the Dialog-Box
5969 * pPortName [I] Name of the Port, that should be configured
5976 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5979 DWORD res = ROUTER_UNKNOWN;
5981 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5983 if (pName && pName[0]) {
5984 SetLastError(ERROR_INVALID_PARAMETER);
5989 SetLastError(RPC_X_NULL_REF_POINTER);
5993 /* an empty Portname is Invalid, but can popup a Dialog */
5994 if (!pPortName[0]) goto cleanup;
5997 pm = monitor_load_by_port(pPortName);
5998 if (pm && pm->monitor) {
5999 if (pm->monitor->pfnConfigurePort != NULL) {
6000 TRACE("Using %s for %s:\n", debugstr_w(pm->name), debugstr_w(pPortName));
6001 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6002 TRACE("got %d with %d\n", res, GetLastError());
6006 FIXME("XcvOpenPort not implemented (dwMonitorSize: %d)\n", pm->dwMonitorSize);
6012 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6013 if (res == ROUTER_UNKNOWN) SetLastError(ERROR_NOT_SUPPORTED);
6014 TRACE("returning %d with %d\n", (res == ROUTER_SUCCESS), GetLastError());
6015 return (res == ROUTER_SUCCESS);
6018 /******************************************************************************
6019 * ConnectToPrinterDlg (WINSPOOL.@)
6021 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6023 FIXME("%p %x\n", hWnd, Flags);
6027 /******************************************************************************
6028 * DeletePrinterConnectionA (WINSPOOL.@)
6030 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6032 FIXME("%s\n", debugstr_a(pName));
6036 /******************************************************************************
6037 * DeletePrinterConnectionW (WINSPOOL.@)
6039 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6041 FIXME("%s\n", debugstr_w(pName));
6045 /******************************************************************************
6046 * DeletePrinterDriverExW (WINSPOOL.@)
6048 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6049 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6054 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6055 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6057 if(pName && pName[0])
6059 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6060 SetLastError(ERROR_INVALID_PARAMETER);
6066 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6067 SetLastError(ERROR_INVALID_PARAMETER);
6071 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6075 ERR("Can't open drivers key\n");
6079 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6082 RegCloseKey(hkey_drivers);
6087 /******************************************************************************
6088 * DeletePrinterDriverExA (WINSPOOL.@)
6090 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6091 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6093 UNICODE_STRING NameW, EnvW, DriverW;
6096 asciitounicode(&NameW, pName);
6097 asciitounicode(&EnvW, pEnvironment);
6098 asciitounicode(&DriverW, pDriverName);
6100 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6102 RtlFreeUnicodeString(&DriverW);
6103 RtlFreeUnicodeString(&EnvW);
6104 RtlFreeUnicodeString(&NameW);
6109 /******************************************************************************
6110 * DeletePrinterDataExW (WINSPOOL.@)
6112 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6115 FIXME("%p %s %s\n", hPrinter,
6116 debugstr_w(pKeyName), debugstr_w(pValueName));
6117 return ERROR_INVALID_PARAMETER;
6120 /******************************************************************************
6121 * DeletePrinterDataExA (WINSPOOL.@)
6123 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6126 FIXME("%p %s %s\n", hPrinter,
6127 debugstr_a(pKeyName), debugstr_a(pValueName));
6128 return ERROR_INVALID_PARAMETER;
6131 /******************************************************************************
6132 * DeletePrintProcessorA (WINSPOOL.@)
6134 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6136 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6137 debugstr_a(pPrintProcessorName));
6141 /******************************************************************************
6142 * DeletePrintProcessorW (WINSPOOL.@)
6144 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6146 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6147 debugstr_w(pPrintProcessorName));
6151 /******************************************************************************
6152 * DeletePrintProvidorA (WINSPOOL.@)
6154 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6156 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6157 debugstr_a(pPrintProviderName));
6161 /******************************************************************************
6162 * DeletePrintProvidorW (WINSPOOL.@)
6164 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6166 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6167 debugstr_w(pPrintProviderName));
6171 /******************************************************************************
6172 * EnumFormsA (WINSPOOL.@)
6174 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6175 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6177 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6178 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6182 /******************************************************************************
6183 * EnumFormsW (WINSPOOL.@)
6185 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6186 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6188 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6189 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6193 /*****************************************************************************
6194 * EnumMonitorsA [WINSPOOL.@]
6196 * See EnumMonitorsW.
6199 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6200 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6203 LPBYTE bufferW = NULL;
6204 LPWSTR nameW = NULL;
6206 DWORD numentries = 0;
6209 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6210 cbBuf, pcbNeeded, pcReturned);
6212 /* convert servername to unicode */
6214 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6215 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6216 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6218 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6219 needed = cbBuf * sizeof(WCHAR);
6220 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6221 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6223 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6224 if (pcbNeeded) needed = *pcbNeeded;
6225 /* HeapReAlloc return NULL, when bufferW was NULL */
6226 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6227 HeapAlloc(GetProcessHeap(), 0, needed);
6229 /* Try again with the large Buffer */
6230 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6232 numentries = pcReturned ? *pcReturned : 0;
6235 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6236 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6239 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
6240 DWORD entrysize = 0;
6243 LPMONITOR_INFO_2W mi2w;
6244 LPMONITOR_INFO_2A mi2a;
6246 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6247 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6249 /* First pass: calculate the size for all Entries */
6250 mi2w = (LPMONITOR_INFO_2W) bufferW;
6251 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6253 while (index < numentries) {
6255 needed += entrysize; /* MONITOR_INFO_?A */
6256 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6258 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6259 NULL, 0, NULL, NULL);
6261 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6262 NULL, 0, NULL, NULL);
6263 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6264 NULL, 0, NULL, NULL);
6266 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6267 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6268 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6271 /* check for errors and quit on failure */
6272 if (cbBuf < needed) {
6273 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6277 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6278 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6279 cbBuf -= len ; /* free Bytes in the user-Buffer */
6280 mi2w = (LPMONITOR_INFO_2W) bufferW;
6281 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6283 /* Second Pass: Fill the User Buffer (if we have one) */
6284 while ((index < numentries) && pMonitors) {
6286 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6288 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6289 ptr, cbBuf , NULL, NULL);
6293 mi2a->pEnvironment = ptr;
6294 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6295 ptr, cbBuf, NULL, NULL);
6299 mi2a->pDLLName = ptr;
6300 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6301 ptr, cbBuf, NULL, NULL);
6305 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6306 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6307 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6311 if (pcbNeeded) *pcbNeeded = needed;
6312 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6314 HeapFree(GetProcessHeap(), 0, nameW);
6315 HeapFree(GetProcessHeap(), 0, bufferW);
6317 TRACE("returning %d with %d (%d byte for %d entries)\n",
6318 (res), GetLastError(), needed, numentries);
6324 /*****************************************************************************
6325 * EnumMonitorsW [WINSPOOL.@]
6327 * Enumerate available Port-Monitors
6330 * pName [I] Servername or NULL (local Computer)
6331 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6332 * pMonitors [O] PTR to Buffer that receives the Result
6333 * cbBuf [I] Size of Buffer at pMonitors
6334 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6335 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6339 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6342 * Windows reads the Registry once and cache the Results.
6344 *| Language-Monitors are also installed in the same Registry-Location but
6345 *| they are filtered in Windows (not returned by EnumMonitors).
6346 *| We do no filtering to simplify our Code.
6349 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6350 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6353 DWORD numentries = 0;
6356 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6357 cbBuf, pcbNeeded, pcReturned);
6359 if (pName && (lstrlenW(pName))) {
6360 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6361 SetLastError(ERROR_ACCESS_DENIED);
6365 /* Level is not checked in win9x */
6366 if (!Level || (Level > 2)) {
6367 WARN("level (%d) is ignored in win9x\n", Level);
6368 SetLastError(ERROR_INVALID_LEVEL);
6372 SetLastError(RPC_X_NULL_REF_POINTER);
6376 /* Scan all Monitor-Keys */
6378 needed = get_local_monitors(Level, NULL, 0, &numentries);
6380 /* we calculated the needed buffersize. now do the error-checks */
6381 if (cbBuf < needed) {
6382 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6385 else if (!pMonitors || !pcReturned) {
6386 SetLastError(RPC_X_NULL_REF_POINTER);
6390 /* fill the Buffer with the Monitor-Keys */
6391 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6395 if (pcbNeeded) *pcbNeeded = needed;
6396 if (pcReturned) *pcReturned = numentries;
6398 TRACE("returning %d with %d (%d byte for %d entries)\n",
6399 res, GetLastError(), needed, numentries);
6404 /******************************************************************************
6405 * XcvDataW (WINSPOOL.@)
6408 * There doesn't seem to be an A version...
6410 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6411 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6412 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6414 FIXME("%p %s %p %d %p %d %p %p\n", hXcv, debugstr_w(pszDataName),
6415 pInputData, cbInputData, pOutputData,
6416 cbOutputData, pcbOutputNeeded, pdwStatus);
6420 /*****************************************************************************
6421 * EnumPrinterDataA [WINSPOOL.@]
6424 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6425 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6426 DWORD cbData, LPDWORD pcbData )
6428 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6429 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6430 return ERROR_NO_MORE_ITEMS;
6433 /*****************************************************************************
6434 * EnumPrinterDataW [WINSPOOL.@]
6437 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6438 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6439 DWORD cbData, LPDWORD pcbData )
6441 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6442 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6443 return ERROR_NO_MORE_ITEMS;
6446 /*****************************************************************************
6447 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6450 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6451 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6452 LPDWORD pcbNeeded, LPDWORD pcReturned)
6454 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6455 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6456 pcbNeeded, pcReturned);
6460 /*****************************************************************************
6461 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6464 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6465 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6466 LPDWORD pcbNeeded, LPDWORD pcReturned)
6468 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6469 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6470 pcbNeeded, pcReturned);
6474 /*****************************************************************************
6475 * EnumPrintProcessorsA [WINSPOOL.@]
6478 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6479 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6481 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6482 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6486 /*****************************************************************************
6487 * EnumPrintProcessorsW [WINSPOOL.@]
6490 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6491 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6493 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6494 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6495 cbBuf, pcbNeeded, pcbReturned);
6499 /*****************************************************************************
6500 * ExtDeviceMode [WINSPOOL.@]
6503 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6504 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6507 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6508 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6509 debugstr_a(pProfile), fMode);
6513 /*****************************************************************************
6514 * FindClosePrinterChangeNotification [WINSPOOL.@]
6517 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6519 FIXME("Stub: %p\n", hChange);
6523 /*****************************************************************************
6524 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6527 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6528 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6530 FIXME("Stub: %p %x %x %p\n",
6531 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6532 return INVALID_HANDLE_VALUE;
6535 /*****************************************************************************
6536 * FindNextPrinterChangeNotification [WINSPOOL.@]
6539 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6540 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6542 FIXME("Stub: %p %p %p %p\n",
6543 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6547 /*****************************************************************************
6548 * FreePrinterNotifyInfo [WINSPOOL.@]
6551 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6553 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6557 /*****************************************************************************
6560 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6561 * ansi depending on the unicode parameter.
6563 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6573 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6576 memcpy(ptr, str, *size);
6583 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6586 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6593 /*****************************************************************************
6596 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6597 LPDWORD pcbNeeded, BOOL unicode)
6599 DWORD size, left = cbBuf;
6600 BOOL space = (cbBuf > 0);
6607 ji1->JobId = job->job_id;
6610 string_to_buf(job->document_title, ptr, left, &size, unicode);
6611 if(space && size <= left)
6613 ji1->pDocument = (LPWSTR)ptr;
6624 /*****************************************************************************
6627 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6628 LPDWORD pcbNeeded, BOOL unicode)
6630 DWORD size, left = cbBuf;
6631 BOOL space = (cbBuf > 0);
6638 ji2->JobId = job->job_id;
6641 string_to_buf(job->document_title, ptr, left, &size, unicode);
6642 if(space && size <= left)
6644 ji2->pDocument = (LPWSTR)ptr;
6655 /*****************************************************************************
6658 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6659 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6662 DWORD needed = 0, size;
6666 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6668 EnterCriticalSection(&printer_handles_cs);
6669 job = get_job(hPrinter, JobId);
6676 size = sizeof(JOB_INFO_1W);
6681 memset(pJob, 0, size);
6685 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6690 size = sizeof(JOB_INFO_2W);
6695 memset(pJob, 0, size);
6699 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6704 size = sizeof(JOB_INFO_3);
6708 memset(pJob, 0, size);
6717 SetLastError(ERROR_INVALID_LEVEL);
6721 *pcbNeeded = needed;
6723 LeaveCriticalSection(&printer_handles_cs);
6727 /*****************************************************************************
6728 * GetJobA [WINSPOOL.@]
6731 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6732 DWORD cbBuf, LPDWORD pcbNeeded)
6734 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6737 /*****************************************************************************
6738 * GetJobW [WINSPOOL.@]
6741 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6742 DWORD cbBuf, LPDWORD pcbNeeded)
6744 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6747 /*****************************************************************************
6750 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6752 char *unixname, *queue, *cmd;
6753 char fmt[] = "lpr -P%s %s";
6756 if(!(unixname = wine_get_unix_file_name(filename)))
6759 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6760 queue = HeapAlloc(GetProcessHeap(), 0, len);
6761 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6763 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6764 sprintf(cmd, fmt, queue, unixname);
6766 TRACE("printing with: %s\n", cmd);
6769 HeapFree(GetProcessHeap(), 0, cmd);
6770 HeapFree(GetProcessHeap(), 0, queue);
6771 HeapFree(GetProcessHeap(), 0, unixname);
6775 /*****************************************************************************
6778 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6780 #if HAVE_CUPS_CUPS_H
6783 char *unixname, *queue, *doc_titleA;
6787 if(!(unixname = wine_get_unix_file_name(filename)))
6790 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6791 queue = HeapAlloc(GetProcessHeap(), 0, len);
6792 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6794 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6795 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6796 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6798 TRACE("printing via cups\n");
6799 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6800 HeapFree(GetProcessHeap(), 0, doc_titleA);
6801 HeapFree(GetProcessHeap(), 0, queue);
6802 HeapFree(GetProcessHeap(), 0, unixname);
6808 return schedule_lpr(printer_name, filename);
6812 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6819 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6823 if(HIWORD(wparam) == BN_CLICKED)
6825 if(LOWORD(wparam) == IDOK)
6828 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6831 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6832 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6834 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6836 WCHAR caption[200], message[200];
6839 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6840 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6841 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6842 if(mb_ret == IDCANCEL)
6844 HeapFree(GetProcessHeap(), 0, filename);
6848 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6849 if(hf == INVALID_HANDLE_VALUE)
6851 WCHAR caption[200], message[200];
6853 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6854 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6855 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6856 HeapFree(GetProcessHeap(), 0, filename);
6860 DeleteFileW(filename);
6861 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6863 EndDialog(hwnd, IDOK);
6866 if(LOWORD(wparam) == IDCANCEL)
6868 EndDialog(hwnd, IDCANCEL);
6877 /*****************************************************************************
6880 static BOOL get_filename(LPWSTR *filename)
6882 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6883 file_dlg_proc, (LPARAM)filename) == IDOK;
6886 /*****************************************************************************
6889 static BOOL schedule_file(LPCWSTR filename)
6891 LPWSTR output = NULL;
6893 if(get_filename(&output))
6895 TRACE("copy to %s\n", debugstr_w(output));
6896 CopyFileW(filename, output, FALSE);
6897 HeapFree(GetProcessHeap(), 0, output);
6903 /*****************************************************************************
6906 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6909 char *unixname, *cmdA;
6911 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6915 if(!(unixname = wine_get_unix_file_name(filename)))
6918 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6919 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6920 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6922 TRACE("printing with: %s\n", cmdA);
6924 if((file_fd = open(unixname, O_RDONLY)) == -1)
6929 ERR("pipe() failed!\n");
6939 /* reset signals that we previously set to SIG_IGN */
6940 signal(SIGPIPE, SIG_DFL);
6941 signal(SIGCHLD, SIG_DFL);
6947 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6948 write(fds[1], buf, no_read);
6953 if(file_fd != -1) close(file_fd);
6954 if(fds[0] != -1) close(fds[0]);
6955 if(fds[1] != -1) close(fds[1]);
6957 HeapFree(GetProcessHeap(), 0, cmdA);
6958 HeapFree(GetProcessHeap(), 0, unixname);
6965 /*****************************************************************************
6968 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6970 int in_fd, out_fd, no_read;
6973 char *unixname, *outputA;
6976 if(!(unixname = wine_get_unix_file_name(filename)))
6979 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6980 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6981 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6983 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6984 in_fd = open(unixname, O_RDONLY);
6985 if(out_fd == -1 || in_fd == -1)
6988 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6989 write(out_fd, buf, no_read);
6993 if(in_fd != -1) close(in_fd);
6994 if(out_fd != -1) close(out_fd);
6995 HeapFree(GetProcessHeap(), 0, outputA);
6996 HeapFree(GetProcessHeap(), 0, unixname);
7000 /*****************************************************************************
7001 * ScheduleJob [WINSPOOL.@]
7004 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7006 opened_printer_t *printer;
7008 struct list *cursor, *cursor2;
7010 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7011 EnterCriticalSection(&printer_handles_cs);
7012 printer = get_opened_printer(hPrinter);
7016 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7018 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7021 if(job->job_id != dwJobID) continue;
7023 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7024 if(hf != INVALID_HANDLE_VALUE)
7026 PRINTER_INFO_5W *pi5;
7030 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7031 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7033 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7034 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7035 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7036 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7037 debugstr_w(pi5->pPortName));
7041 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7042 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7044 DWORD type, count = sizeof(output);
7045 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7048 if(output[0] == '|')
7050 schedule_pipe(output + 1, job->filename);
7054 schedule_unixfile(output, job->filename);
7056 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7058 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7060 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7062 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7064 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7066 schedule_file(job->filename);
7070 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7072 HeapFree(GetProcessHeap(), 0, pi5);
7074 DeleteFileW(job->filename);
7076 list_remove(cursor);
7077 HeapFree(GetProcessHeap(), 0, job->document_title);
7078 HeapFree(GetProcessHeap(), 0, job->filename);
7079 HeapFree(GetProcessHeap(), 0, job);
7084 LeaveCriticalSection(&printer_handles_cs);
7088 /*****************************************************************************
7089 * StartDocDlgA [WINSPOOL.@]
7091 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7093 UNICODE_STRING usBuffer;
7096 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7099 docW.cbSize = sizeof(docW);
7100 if (doc->lpszDocName)
7102 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7103 if (!(docW.lpszDocName = docnameW)) return NULL;
7105 if (doc->lpszOutput)
7107 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7108 if (!(docW.lpszOutput = outputW)) return NULL;
7110 if (doc->lpszDatatype)
7112 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7113 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7115 docW.fwType = doc->fwType;
7117 retW = StartDocDlgW(hPrinter, &docW);
7121 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7122 ret = HeapAlloc(GetProcessHeap(), 0, len);
7123 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7124 HeapFree(GetProcessHeap(), 0, retW);
7127 HeapFree(GetProcessHeap(), 0, datatypeW);
7128 HeapFree(GetProcessHeap(), 0, outputW);
7129 HeapFree(GetProcessHeap(), 0, docnameW);
7134 /*****************************************************************************
7135 * StartDocDlgW [WINSPOOL.@]
7137 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7138 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7139 * port is "FILE:". Also returns the full path if passed a relative path.
7141 * The caller should free the returned string from the process heap.
7143 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7148 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7150 PRINTER_INFO_5W *pi5;
7151 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7152 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7154 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7155 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7156 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7158 HeapFree(GetProcessHeap(), 0, pi5);
7161 HeapFree(GetProcessHeap(), 0, pi5);
7164 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7167 get_filename(&name);
7170 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7172 HeapFree(GetProcessHeap(), 0, name);
7175 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7176 GetFullPathNameW(name, len, ret, NULL);
7177 HeapFree(GetProcessHeap(), 0, name);
7182 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7185 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7186 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7188 attr = GetFileAttributesW(ret);
7189 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7191 HeapFree(GetProcessHeap(), 0, ret);