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-2008 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>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
122 WCHAR *document_title;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
191 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
192 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
193 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
194 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
195 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
196 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
197 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
198 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
200 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
201 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
203 static const WCHAR backslashW[] = {'\\',0};
204 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
205 'i','o','n',' ','F','i','l','e',0};
206 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
207 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
208 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
209 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
210 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
211 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
212 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
213 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
214 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
215 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
216 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
217 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
218 static const WCHAR NameW[] = {'N','a','m','e',0};
219 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
220 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
221 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
222 static const WCHAR PortW[] = {'P','o','r','t',0};
223 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
224 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
225 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
226 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
227 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
228 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
229 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
230 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
232 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
233 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
234 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
235 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
236 static const WCHAR emptyStringW[] = {0};
237 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
238 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
240 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
242 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
243 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
244 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
246 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
247 'D','o','c','u','m','e','n','t',0};
249 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
250 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
251 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
252 0, sizeof(DRIVER_INFO_8W)};
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, Version0_RegPathW, Version0_SubdirW};
277 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
279 const printenv_t *result = NULL;
282 TRACE("testing %s\n", debugstr_w(env));
285 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
287 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
289 result = all_printenv[i];
294 if (result == NULL) {
295 FIXME("unsupported Environment: %s\n", debugstr_w(env));
296 SetLastError(ERROR_INVALID_ENVIRONMENT);
298 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
302 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
304 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
310 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
311 if passed a NULL string. This returns NULLs to the result.
313 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
317 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
318 return usBufferPtr->Buffer;
320 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
324 static LPWSTR strdupW(LPCWSTR p)
330 len = (strlenW(p) + 1) * sizeof(WCHAR);
331 ret = HeapAlloc(GetProcessHeap(), 0, len);
336 static LPSTR strdupWtoA( LPCWSTR str )
341 if (!str) return NULL;
342 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
343 ret = HeapAlloc( GetProcessHeap(), 0, len );
344 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
348 /******************************************************************
349 * Return the number of bytes for an multi_sz string.
350 * The result includes all \0s
351 * (specifically the extra \0, that is needed as multi_sz terminator).
354 static int multi_sz_lenW(const WCHAR *str)
356 const WCHAR *ptr = str;
360 ptr += lstrlenW(ptr) + 1;
363 return (ptr - str + 1) * sizeof(WCHAR);
366 /* ################################ */
368 static int multi_sz_lenA(const char *str)
370 const char *ptr = str;
374 ptr += lstrlenA(ptr) + 1;
377 return ptr - str + 1;
381 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
384 /* If forcing, or no profile string entry for device yet, set the entry
386 * The always change entry if not WINEPS yet is discussable.
389 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
391 !strstr(qbuf,"WINEPS.DRV")
393 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
396 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
397 WriteProfileStringA("windows","device",buf);
398 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
399 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
402 HeapFree(GetProcessHeap(),0,buf);
406 static BOOL add_printer_driver(const char *name)
410 static char driver_9x[] = "wineps16.drv",
411 driver_nt[] = "wineps.drv",
412 env_9x[] = "Windows 4.0",
413 env_nt[] = "Windows NT x86",
414 data_file[] = "generic.ppd",
415 default_data_type[] = "RAW";
417 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
419 di3a.pName = (char *)name;
420 di3a.pEnvironment = env_nt;
421 di3a.pDriverPath = driver_nt;
422 di3a.pDataFile = data_file;
423 di3a.pConfigFile = driver_nt;
424 di3a.pDefaultDataType = default_data_type;
426 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
427 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
430 di3a.pEnvironment = env_9x;
431 di3a.pDriverPath = driver_9x;
432 di3a.pConfigFile = driver_9x;
433 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
434 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
439 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
440 debugstr_a(di3a.pEnvironment), GetLastError());
444 #ifdef SONAME_LIBCUPS
445 static typeof(cupsGetDests) *pcupsGetDests;
446 static typeof(cupsGetPPD) *pcupsGetPPD;
447 static typeof(cupsPrintFile) *pcupsPrintFile;
448 static void *cupshandle;
450 static BOOL CUPS_LoadPrinters(void)
453 BOOL hadprinter = FALSE, haddefault = FALSE;
455 PRINTER_INFO_2A pinfo2a;
457 HKEY hkeyPrinter, hkeyPrinters, hkey;
460 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
462 TRACE("%s\n", loaderror);
465 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
468 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
469 if (!p##x) return FALSE;
472 DYNCUPS(cupsGetDests);
473 DYNCUPS(cupsPrintFile);
476 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
478 ERR("Can't create Printers key\n");
482 nrofdests = pcupsGetDests(&dests);
483 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
484 for (i=0;i<nrofdests;i++) {
485 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
486 sprintf(port,"LPR:%s",dests[i].name);
487 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
488 sprintf(devline,"WINEPS.DRV,%s",port);
489 WriteProfileStringA("devices",dests[i].name,devline);
490 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
491 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
494 HeapFree(GetProcessHeap(),0,devline);
496 TRACE("Printer %d: %s\n", i, dests[i].name);
497 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
498 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
500 TRACE("Printer already exists\n");
501 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
502 RegCloseKey(hkeyPrinter);
504 static CHAR data_type[] = "RAW",
505 print_proc[] = "WinPrint",
506 comment[] = "WINEPS Printer using CUPS",
507 location[] = "<physical location of printer>",
508 params[] = "<parameters?>",
509 share_name[] = "<share name?>",
510 sep_file[] = "<sep file?>";
512 add_printer_driver(dests[i].name);
514 memset(&pinfo2a,0,sizeof(pinfo2a));
515 pinfo2a.pPrinterName = dests[i].name;
516 pinfo2a.pDatatype = data_type;
517 pinfo2a.pPrintProcessor = print_proc;
518 pinfo2a.pDriverName = dests[i].name;
519 pinfo2a.pComment = comment;
520 pinfo2a.pLocation = location;
521 pinfo2a.pPortName = port;
522 pinfo2a.pParameters = params;
523 pinfo2a.pShareName = share_name;
524 pinfo2a.pSepFile = sep_file;
526 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
527 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
528 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
531 HeapFree(GetProcessHeap(),0,port);
534 if (dests[i].is_default) {
535 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
539 if (hadprinter & !haddefault)
540 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
541 RegCloseKey(hkeyPrinters);
547 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
548 PRINTER_INFO_2A pinfo2a;
549 char *e,*s,*name,*prettyname,*devname;
550 BOOL ret = FALSE, set_default = FALSE;
551 char *port = NULL, *devline,*env_default;
552 HKEY hkeyPrinter, hkeyPrinters, hkey;
554 while (isspace(*pent)) pent++;
555 s = strchr(pent,':');
557 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
565 TRACE("name=%s entry=%s\n",name, pent);
567 if(ispunct(*name)) { /* a tc entry, not a real printer */
568 TRACE("skipping tc entry\n");
572 if(strstr(pent,":server")) { /* server only version so skip */
573 TRACE("skipping server entry\n");
577 /* Determine whether this is a postscript printer. */
580 env_default = getenv("PRINTER");
582 /* Get longest name, usually the one at the right for later display. */
583 while((s=strchr(prettyname,'|'))) {
586 while(isspace(*--e)) *e = '\0';
587 TRACE("\t%s\n", debugstr_a(prettyname));
588 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
589 for(prettyname = s+1; isspace(*prettyname); prettyname++)
592 e = prettyname + strlen(prettyname);
593 while(isspace(*--e)) *e = '\0';
594 TRACE("\t%s\n", debugstr_a(prettyname));
595 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
597 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
598 * if it is too long, we use it as comment below. */
599 devname = prettyname;
600 if (strlen(devname)>=CCHDEVICENAME-1)
602 if (strlen(devname)>=CCHDEVICENAME-1) {
607 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
608 sprintf(port,"LPR:%s",name);
610 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
611 sprintf(devline,"WINEPS.DRV,%s",port);
612 WriteProfileStringA("devices",devname,devline);
613 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
614 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
617 HeapFree(GetProcessHeap(),0,devline);
619 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
621 ERR("Can't create Printers key\n");
625 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
626 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
628 TRACE("Printer already exists\n");
629 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
630 RegCloseKey(hkeyPrinter);
632 static CHAR data_type[] = "RAW",
633 print_proc[] = "WinPrint",
634 comment[] = "WINEPS Printer using LPR",
635 params[] = "<parameters?>",
636 share_name[] = "<share name?>",
637 sep_file[] = "<sep file?>";
639 add_printer_driver(devname);
641 memset(&pinfo2a,0,sizeof(pinfo2a));
642 pinfo2a.pPrinterName = devname;
643 pinfo2a.pDatatype = data_type;
644 pinfo2a.pPrintProcessor = print_proc;
645 pinfo2a.pDriverName = devname;
646 pinfo2a.pComment = comment;
647 pinfo2a.pLocation = prettyname;
648 pinfo2a.pPortName = port;
649 pinfo2a.pParameters = params;
650 pinfo2a.pShareName = share_name;
651 pinfo2a.pSepFile = sep_file;
653 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
654 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
655 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
658 RegCloseKey(hkeyPrinters);
660 if (isfirst || set_default)
661 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
664 HeapFree(GetProcessHeap(), 0, port);
665 HeapFree(GetProcessHeap(), 0, name);
670 PRINTCAP_LoadPrinters(void) {
671 BOOL hadprinter = FALSE;
675 BOOL had_bash = FALSE;
677 f = fopen("/etc/printcap","r");
681 while(fgets(buf,sizeof(buf),f)) {
684 end=strchr(buf,'\n');
688 while(isspace(*start)) start++;
689 if(*start == '#' || *start == '\0')
692 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
693 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
694 HeapFree(GetProcessHeap(),0,pent);
698 if (end && *--end == '\\') {
705 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
708 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
714 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
715 HeapFree(GetProcessHeap(),0,pent);
721 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
724 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
725 (lstrlenW(value) + 1) * sizeof(WCHAR));
727 return ERROR_FILE_NOT_FOUND;
730 /*****************************************************************************
731 * enumerate the local monitors (INTERNAL)
733 * returns the needed size (in bytes) for pMonitors
734 * and *lpreturned is set to number of entries returned in pMonitors
737 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
742 LPMONITOR_INFO_2W mi;
743 WCHAR buffer[MAX_PATH];
744 WCHAR dllname[MAX_PATH];
752 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
754 numentries = *lpreturned; /* this is 0, when we scan the registry */
755 len = entrysize * numentries;
756 ptr = (LPWSTR) &pMonitors[len];
759 len = sizeof(buffer)/sizeof(buffer[0]);
762 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
763 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
764 /* Scan all Monitor-Registry-Keys */
765 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
766 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
767 dllsize = sizeof(dllname);
770 /* The Monitor must have a Driver-DLL */
771 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
772 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
773 /* We found a valid DLL for this Monitor. */
774 TRACE("using Driver: %s\n", debugstr_w(dllname));
779 /* Windows returns only Port-Monitors here, but to simplify our code,
780 we do no filtering for Language-Monitors */
784 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
786 /* we install and return only monitors for "Windows NT x86" */
787 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
791 /* required size is calculated. Now fill the user-buffer */
792 if (pMonitors && (cbBuf >= needed)){
793 mi = (LPMONITOR_INFO_2W) pMonitors;
794 pMonitors += entrysize;
796 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
798 lstrcpyW(ptr, buffer); /* Name of the Monitor */
799 ptr += (len+1); /* len is lstrlenW(monitorname) */
801 mi->pEnvironment = ptr;
802 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
803 ptr += (lstrlenW(envname_x86W)+1);
806 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
807 ptr += (dllsize / sizeof(WCHAR));
812 len = sizeof(buffer)/sizeof(buffer[0]);
817 *lpreturned = numentries;
818 TRACE("need %d byte for %d entries\n", needed, numentries);
822 /******************************************************************
823 * monitor_unload [internal]
825 * release a printmonitor and unload it from memory, when needed
828 static void monitor_unload(monitor_t * pm)
830 if (pm == NULL) return;
831 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
833 EnterCriticalSection(&monitor_handles_cs);
835 if (pm->refcount) pm->refcount--;
837 if (pm->refcount == 0) {
838 list_remove(&pm->entry);
839 FreeLibrary(pm->hdll);
840 HeapFree(GetProcessHeap(), 0, pm->name);
841 HeapFree(GetProcessHeap(), 0, pm->dllname);
842 HeapFree(GetProcessHeap(), 0, pm);
844 LeaveCriticalSection(&monitor_handles_cs);
847 /******************************************************************
848 * monitor_unloadall [internal]
850 * release all printmonitors and unload them from memory, when needed
853 static void monitor_unloadall(void)
858 EnterCriticalSection(&monitor_handles_cs);
859 /* iterate through the list, with safety against removal */
860 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
864 LeaveCriticalSection(&monitor_handles_cs);
867 /******************************************************************
868 * monitor_load [internal]
870 * load a printmonitor, get the dllname from the registry, when needed
871 * initialize the monitor and dump found function-pointers
873 * On failure, SetLastError() is called and NULL is returned
876 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
878 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
879 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
880 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
881 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
882 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
884 monitor_t * pm = NULL;
886 LPWSTR regroot = NULL;
887 LPWSTR driver = dllname;
889 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
890 /* Is the Monitor already loaded? */
891 EnterCriticalSection(&monitor_handles_cs);
894 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
896 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
904 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
905 if (pm == NULL) goto cleanup;
906 list_add_tail(&monitor_handles, &pm->entry);
910 if (pm->name == NULL) {
911 /* Load the monitor */
912 LPMONITOREX pmonitorEx;
916 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
917 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
921 lstrcpyW(regroot, MonitorsW);
922 lstrcatW(regroot, name);
923 /* Get the Driver from the Registry */
924 if (driver == NULL) {
927 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
928 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
929 &namesize) == ERROR_SUCCESS) {
930 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
931 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
938 pm->name = strdupW(name);
939 pm->dllname = strdupW(driver);
941 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
943 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
948 pm->hdll = LoadLibraryW(driver);
949 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
951 if (pm->hdll == NULL) {
953 SetLastError(ERROR_MOD_NOT_FOUND);
958 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
959 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
960 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
961 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
962 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
965 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
966 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
967 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
968 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
969 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
971 if (pInitializePrintMonitorUI != NULL) {
972 pm->monitorUI = pInitializePrintMonitorUI();
973 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
975 TRACE( "0x%08x: dwMonitorSize (%d)\n",
976 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
981 if (pInitializePrintMonitor && regroot) {
982 pmonitorEx = pInitializePrintMonitor(regroot);
983 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
984 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
987 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
988 pm->monitor = &(pmonitorEx->Monitor);
993 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
997 if (!pm->monitor && regroot) {
998 if (pInitializePrintMonitor2 != NULL) {
999 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1001 if (pInitializeMonitorEx != NULL) {
1002 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1004 if (pInitializeMonitor != NULL) {
1005 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1008 if (!pm->monitor && !pm->monitorUI) {
1010 SetLastError(ERROR_PROC_NOT_FOUND);
1015 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1019 LeaveCriticalSection(&monitor_handles_cs);
1020 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1021 HeapFree(GetProcessHeap(), 0, regroot);
1022 TRACE("=> %p\n", pm);
1026 /******************************************************************
1027 * monitor_loadall [internal]
1029 * Load all registered monitors
1032 static DWORD monitor_loadall(void)
1035 DWORD registered = 0;
1038 WCHAR buffer[MAX_PATH];
1041 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1042 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1043 NULL, NULL, NULL, NULL, NULL);
1045 TRACE("%d monitors registered\n", registered);
1047 EnterCriticalSection(&monitor_handles_cs);
1048 while (id < registered) {
1050 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1051 pm = monitor_load(buffer, NULL);
1055 LeaveCriticalSection(&monitor_handles_cs);
1056 RegCloseKey(hmonitors);
1058 TRACE("%d monitors loaded\n", loaded);
1062 /******************************************************************
1063 * monitor_loadui [internal]
1065 * load the userinterface-dll for a given portmonitor
1067 * On failure, NULL is returned
1070 static monitor_t * monitor_loadui(monitor_t * pm)
1072 monitor_t * pui = NULL;
1073 LPWSTR buffer[MAX_PATH];
1078 if (pm == NULL) return NULL;
1079 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1081 /* Try the Portmonitor first; works for many monitors */
1082 if (pm->monitorUI) {
1083 EnterCriticalSection(&monitor_handles_cs);
1085 LeaveCriticalSection(&monitor_handles_cs);
1089 /* query the userinterface-dllname from the Portmonitor */
1090 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1091 /* building (",XcvMonitor %s",pm->name) not needed yet */
1092 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1093 TRACE("got %u with %p\n", res, hXcv);
1095 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1096 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1097 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1098 pm->monitor->pfnXcvClosePort(hXcv);
1105 /******************************************************************
1106 * monitor_load_by_port [internal]
1108 * load a printmonitor for a given port
1110 * On failure, NULL is returned
1113 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1118 monitor_t * pm = NULL;
1119 DWORD registered = 0;
1123 TRACE("(%s)\n", debugstr_w(portname));
1125 /* Try the Local Monitor first */
1126 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1127 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1128 /* found the portname */
1130 return monitor_load(LocalPortW, NULL);
1135 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1136 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1137 if (buffer == NULL) return NULL;
1139 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1140 EnterCriticalSection(&monitor_handles_cs);
1141 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1143 while ((pm == NULL) && (id < registered)) {
1145 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1146 TRACE("testing %s\n", debugstr_w(buffer));
1147 len = lstrlenW(buffer);
1148 lstrcatW(buffer, bs_Ports_bsW);
1149 lstrcatW(buffer, portname);
1150 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1152 buffer[len] = '\0'; /* use only the Monitor-Name */
1153 pm = monitor_load(buffer, NULL);
1157 LeaveCriticalSection(&monitor_handles_cs);
1160 HeapFree(GetProcessHeap(), 0, buffer);
1164 /******************************************************************
1165 * enumerate the local Ports from all loaded monitors (internal)
1167 * returns the needed size (in bytes) for pPorts
1168 * and *lpreturned is set to number of entries returned in pPorts
1171 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1175 LPPORT_INFO_2W cache;
1177 LPBYTE pi_buffer = NULL;
1178 DWORD pi_allocated = 0;
1189 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1190 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1192 numentries = *lpreturned; /* this is 0, when we scan the registry */
1193 needed = entrysize * numentries;
1194 ptr = (LPWSTR) &pPorts[needed];
1199 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1201 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1204 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1205 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1206 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1207 HeapFree(GetProcessHeap(), 0, pi_buffer);
1208 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1209 pi_allocated = (pi_buffer) ? pi_needed : 0;
1210 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1212 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1213 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1215 numentries += pi_returned;
1216 needed += pi_needed;
1218 /* fill the output-buffer (pPorts), if we have one */
1219 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1221 while (pi_returned > pi_index) {
1222 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1223 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1224 out->pPortName = ptr;
1225 lstrcpyW(ptr, cache->pPortName);
1226 ptr += (lstrlenW(ptr)+1);
1228 out->pMonitorName = ptr;
1229 lstrcpyW(ptr, cache->pMonitorName);
1230 ptr += (lstrlenW(ptr)+1);
1232 out->pDescription = ptr;
1233 lstrcpyW(ptr, cache->pDescription);
1234 ptr += (lstrlenW(ptr)+1);
1235 out->fPortType = cache->fPortType;
1236 out->Reserved = cache->Reserved;
1244 /* the temporary portinfo-buffer is no longer needed */
1245 HeapFree(GetProcessHeap(), 0, pi_buffer);
1247 *lpreturned = numentries;
1248 TRACE("need %d byte for %d entries\n", needed, numentries);
1252 /******************************************************************
1253 * get_servername_from_name (internal)
1255 * for an external server, a copy of the serverpart from the full name is returned
1258 static LPWSTR get_servername_from_name(LPCWSTR name)
1262 WCHAR buffer[MAX_PATH];
1265 if (name == NULL) return NULL;
1266 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1268 server = strdupW(&name[2]); /* skip over both backslash */
1269 if (server == NULL) return NULL;
1271 /* strip '\' and the printername */
1272 ptr = strchrW(server, '\\');
1273 if (ptr) ptr[0] = '\0';
1275 TRACE("found %s\n", debugstr_w(server));
1277 len = sizeof(buffer)/sizeof(buffer[0]);
1278 if (GetComputerNameW(buffer, &len)) {
1279 if (lstrcmpW(buffer, server) == 0) {
1280 /* The requested Servername is our computername */
1281 HeapFree(GetProcessHeap(), 0, server);
1288 /******************************************************************
1289 * get_basename_from_name (internal)
1291 * skip over the serverpart from the full name
1294 static LPCWSTR get_basename_from_name(LPCWSTR name)
1296 if (name == NULL) return NULL;
1297 if ((name[0] == '\\') && (name[1] == '\\')) {
1298 /* skip over the servername and search for the following '\' */
1299 name = strchrW(&name[2], '\\');
1300 if ((name) && (name[1])) {
1301 /* found a separator ('\') followed by a name:
1302 skip over the separator and return the rest */
1307 /* no basename present (we found only a servername) */
1314 /******************************************************************
1315 * get_opened_printer_entry
1316 * Get the first place empty in the opened printer table
1319 * - pDefault is ignored
1321 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1323 UINT_PTR handle = nb_printer_handles, i;
1324 jobqueue_t *queue = NULL;
1325 opened_printer_t *printer = NULL;
1327 LPCWSTR printername;
1332 servername = get_servername_from_name(name);
1334 FIXME("server %s not supported\n", debugstr_w(servername));
1335 HeapFree(GetProcessHeap(), 0, servername);
1336 SetLastError(ERROR_INVALID_PRINTER_NAME);
1340 printername = get_basename_from_name(name);
1341 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1343 /* an empty printername is invalid */
1344 if (printername && (!printername[0])) {
1345 SetLastError(ERROR_INVALID_PARAMETER);
1349 EnterCriticalSection(&printer_handles_cs);
1351 for (i = 0; i < nb_printer_handles; i++)
1353 if (!printer_handles[i])
1355 if(handle == nb_printer_handles)
1360 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1361 queue = printer_handles[i]->queue;
1365 if (handle >= nb_printer_handles)
1367 opened_printer_t **new_array;
1368 if (printer_handles)
1369 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1370 (nb_printer_handles + 16) * sizeof(*new_array) );
1372 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1373 (nb_printer_handles + 16) * sizeof(*new_array) );
1380 printer_handles = new_array;
1381 nb_printer_handles += 16;
1384 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1391 /* clone the base name. This is NULL for the printserver */
1392 printer->printername = strdupW(printername);
1394 /* clone the full name */
1395 printer->name = strdupW(name);
1396 if (name && (!printer->name)) {
1402 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1403 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1404 /* OpenPrinter(",XcvMonitor " detected */
1405 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1406 printer->pm = monitor_load(&printername[len], NULL);
1407 if (printer->pm == NULL) {
1408 SetLastError(ERROR_UNKNOWN_PORT);
1415 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1416 if (strncmpW( printername, XcvPortW, len) == 0) {
1417 /* OpenPrinter(",XcvPort " detected */
1418 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1419 printer->pm = monitor_load_by_port(&printername[len]);
1420 if (printer->pm == NULL) {
1421 SetLastError(ERROR_UNKNOWN_PORT);
1429 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1430 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1431 pDefault ? pDefault->DesiredAccess : 0,
1434 if (printer->hXcv == NULL) {
1435 SetLastError(ERROR_INVALID_PARAMETER);
1442 /* Does the Printer exist? */
1443 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1444 ERR("Can't create Printers key\n");
1448 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1449 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1450 RegCloseKey(hkeyPrinters);
1451 SetLastError(ERROR_INVALID_PRINTER_NAME);
1455 RegCloseKey(hkeyPrinter);
1456 RegCloseKey(hkeyPrinters);
1461 TRACE("using the local printserver\n");
1465 printer->queue = queue;
1468 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1469 if (!printer->queue) {
1473 list_init(&printer->queue->jobs);
1474 printer->queue->ref = 0;
1476 InterlockedIncrement(&printer->queue->ref);
1478 printer_handles[handle] = printer;
1481 LeaveCriticalSection(&printer_handles_cs);
1482 if (!handle && printer) {
1483 /* Something failed: Free all resources */
1484 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1485 monitor_unload(printer->pm);
1486 HeapFree(GetProcessHeap(), 0, printer->printername);
1487 HeapFree(GetProcessHeap(), 0, printer->name);
1488 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1489 HeapFree(GetProcessHeap(), 0, printer);
1492 return (HANDLE)handle;
1495 /******************************************************************
1496 * get_opened_printer
1497 * Get the pointer to the opened printer referred by the handle
1499 static opened_printer_t *get_opened_printer(HANDLE hprn)
1501 UINT_PTR idx = (UINT_PTR)hprn;
1502 opened_printer_t *ret = NULL;
1504 EnterCriticalSection(&printer_handles_cs);
1506 if ((idx > 0) && (idx <= nb_printer_handles)) {
1507 ret = printer_handles[idx - 1];
1509 LeaveCriticalSection(&printer_handles_cs);
1513 /******************************************************************
1514 * get_opened_printer_name
1515 * Get the pointer to the opened printer name referred by the handle
1517 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1519 opened_printer_t *printer = get_opened_printer(hprn);
1520 if(!printer) return NULL;
1521 return printer->name;
1524 /******************************************************************
1525 * WINSPOOL_GetOpenedPrinterRegKey
1528 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1530 LPCWSTR name = get_opened_printer_name(hPrinter);
1534 if(!name) return ERROR_INVALID_HANDLE;
1536 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1540 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1542 ERR("Can't find opened printer %s in registry\n",
1544 RegCloseKey(hkeyPrinters);
1545 return ERROR_INVALID_PRINTER_NAME; /* ? */
1547 RegCloseKey(hkeyPrinters);
1548 return ERROR_SUCCESS;
1551 void WINSPOOL_LoadSystemPrinters(void)
1553 HKEY hkey, hkeyPrinters;
1555 DWORD needed, num, i;
1556 WCHAR PrinterName[256];
1559 /* This ensures that all printer entries have a valid Name value. If causes
1560 problems later if they don't. If one is found to be missed we create one
1561 and set it equal to the name of the key */
1562 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1563 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1564 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1565 for(i = 0; i < num; i++) {
1566 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1567 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1568 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1569 set_reg_szW(hkey, NameW, PrinterName);
1576 RegCloseKey(hkeyPrinters);
1579 /* We want to avoid calling AddPrinter on printers as much as
1580 possible, because on cups printers this will (eventually) lead
1581 to a call to cupsGetPPD which takes forever, even with non-cups
1582 printers AddPrinter takes a while. So we'll tag all printers that
1583 were automatically added last time around, if they still exist
1584 we'll leave them be otherwise we'll delete them. */
1585 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1587 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1588 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1589 for(i = 0; i < num; i++) {
1590 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1591 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1592 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1594 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1602 HeapFree(GetProcessHeap(), 0, pi);
1606 #ifdef SONAME_LIBCUPS
1607 done = CUPS_LoadPrinters();
1610 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1611 PRINTCAP_LoadPrinters();
1613 /* Now enumerate the list again and delete any printers that are still tagged */
1614 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1616 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1617 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1618 for(i = 0; i < num; i++) {
1619 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1620 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1621 BOOL delete_driver = FALSE;
1622 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1623 DWORD dw, type, size = sizeof(dw);
1624 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1625 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1626 DeletePrinter(hprn);
1627 delete_driver = TRUE;
1633 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1638 HeapFree(GetProcessHeap(), 0, pi);
1645 /******************************************************************
1648 * Get the pointer to the specified job.
1649 * Should hold the printer_handles_cs before calling.
1651 static job_t *get_job(HANDLE hprn, DWORD JobId)
1653 opened_printer_t *printer = get_opened_printer(hprn);
1656 if(!printer) return NULL;
1657 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1659 if(job->job_id == JobId)
1665 /***********************************************************
1668 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1671 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1674 Formname = (dmA->dmSize > off_formname);
1675 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1676 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1677 dmW->dmDeviceName, CCHDEVICENAME);
1679 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1680 dmA->dmSize - CCHDEVICENAME);
1682 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1683 off_formname - CCHDEVICENAME);
1684 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1685 dmW->dmFormName, CCHFORMNAME);
1686 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1687 (off_formname + CCHFORMNAME));
1690 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1691 dmA->dmDriverExtra);
1695 /***********************************************************
1697 * Creates an ansi copy of supplied devmode
1699 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1704 if (!dmW) return NULL;
1705 size = dmW->dmSize - CCHDEVICENAME -
1706 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1708 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1709 if (!dmA) return NULL;
1711 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1712 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1714 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1715 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1716 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1720 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1721 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1722 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1723 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1725 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1729 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1733 /***********************************************************
1734 * PRINTER_INFO_2AtoW
1735 * Creates a unicode copy of PRINTER_INFO_2A on heap
1737 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1739 LPPRINTER_INFO_2W piW;
1740 UNICODE_STRING usBuffer;
1742 if(!piA) return NULL;
1743 piW = HeapAlloc(heap, 0, sizeof(*piW));
1744 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1746 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1747 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1748 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1749 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1750 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1751 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1752 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1753 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1754 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1755 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1756 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1757 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1761 /***********************************************************
1762 * FREE_PRINTER_INFO_2W
1763 * Free PRINTER_INFO_2W and all strings
1765 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1769 HeapFree(heap,0,piW->pServerName);
1770 HeapFree(heap,0,piW->pPrinterName);
1771 HeapFree(heap,0,piW->pShareName);
1772 HeapFree(heap,0,piW->pPortName);
1773 HeapFree(heap,0,piW->pDriverName);
1774 HeapFree(heap,0,piW->pComment);
1775 HeapFree(heap,0,piW->pLocation);
1776 HeapFree(heap,0,piW->pDevMode);
1777 HeapFree(heap,0,piW->pSepFile);
1778 HeapFree(heap,0,piW->pPrintProcessor);
1779 HeapFree(heap,0,piW->pDatatype);
1780 HeapFree(heap,0,piW->pParameters);
1781 HeapFree(heap,0,piW);
1785 /******************************************************************
1786 * DeviceCapabilities [WINSPOOL.@]
1787 * DeviceCapabilitiesA [WINSPOOL.@]
1790 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1791 LPSTR pOutput, LPDEVMODEA lpdm)
1795 if (!GDI_CallDeviceCapabilities16)
1797 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1799 if (!GDI_CallDeviceCapabilities16) return -1;
1801 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1803 /* If DC_PAPERSIZE map POINT16s to POINTs */
1804 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1805 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1806 POINT *pt = (POINT *)pOutput;
1808 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1809 for(i = 0; i < ret; i++, pt++)
1814 HeapFree( GetProcessHeap(), 0, tmp );
1820 /*****************************************************************************
1821 * DeviceCapabilitiesW [WINSPOOL.@]
1823 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1826 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1827 WORD fwCapability, LPWSTR pOutput,
1828 const DEVMODEW *pDevMode)
1830 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1831 LPSTR pDeviceA = strdupWtoA(pDevice);
1832 LPSTR pPortA = strdupWtoA(pPort);
1835 if(pOutput && (fwCapability == DC_BINNAMES ||
1836 fwCapability == DC_FILEDEPENDENCIES ||
1837 fwCapability == DC_PAPERNAMES)) {
1838 /* These need A -> W translation */
1841 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1845 switch(fwCapability) {
1850 case DC_FILEDEPENDENCIES:
1854 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1855 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1857 for(i = 0; i < ret; i++)
1858 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1859 pOutput + (i * size), size);
1860 HeapFree(GetProcessHeap(), 0, pOutputA);
1862 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1863 (LPSTR)pOutput, dmA);
1865 HeapFree(GetProcessHeap(),0,pPortA);
1866 HeapFree(GetProcessHeap(),0,pDeviceA);
1867 HeapFree(GetProcessHeap(),0,dmA);
1871 /******************************************************************
1872 * DocumentPropertiesA [WINSPOOL.@]
1874 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1876 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1877 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1878 LPDEVMODEA pDevModeInput,DWORD fMode )
1880 LPSTR lpName = pDeviceName;
1881 static CHAR port[] = "LPT1:";
1884 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1885 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1889 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1891 ERR("no name from hPrinter?\n");
1892 SetLastError(ERROR_INVALID_HANDLE);
1895 lpName = strdupWtoA(lpNameW);
1898 if (!GDI_CallExtDeviceMode16)
1900 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1902 if (!GDI_CallExtDeviceMode16) {
1903 ERR("No CallExtDeviceMode16?\n");
1907 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1908 pDevModeInput, NULL, fMode);
1911 HeapFree(GetProcessHeap(),0,lpName);
1916 /*****************************************************************************
1917 * DocumentPropertiesW (WINSPOOL.@)
1919 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1921 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1923 LPDEVMODEW pDevModeOutput,
1924 LPDEVMODEW pDevModeInput, DWORD fMode)
1927 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1928 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1929 LPDEVMODEA pDevModeOutputA = NULL;
1932 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1933 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1935 if(pDevModeOutput) {
1936 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1937 if(ret < 0) return ret;
1938 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1940 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1941 pDevModeInputA, fMode);
1942 if(pDevModeOutput) {
1943 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1944 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1946 if(fMode == 0 && ret > 0)
1947 ret += (CCHDEVICENAME + CCHFORMNAME);
1948 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1949 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1953 /******************************************************************
1954 * OpenPrinterA [WINSPOOL.@]
1959 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1960 LPPRINTER_DEFAULTSA pDefault)
1962 UNICODE_STRING lpPrinterNameW;
1963 UNICODE_STRING usBuffer;
1964 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1965 PWSTR pwstrPrinterNameW;
1968 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1971 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1972 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1973 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1974 pDefaultW = &DefaultW;
1976 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1978 RtlFreeUnicodeString(&usBuffer);
1979 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1981 RtlFreeUnicodeString(&lpPrinterNameW);
1985 /******************************************************************
1986 * OpenPrinterW [WINSPOOL.@]
1988 * Open a Printer / Printserver or a Printer-Object
1991 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1992 * phPrinter [O] The resulting Handle is stored here
1993 * pDefault [I] PTR to Default Printer Settings or NULL
2000 * lpPrinterName is one of:
2001 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2002 *| Printer: "PrinterName"
2003 *| Printer-Object: "PrinterName,Job xxx"
2004 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2005 *| XcvPort: "Servername,XcvPort PortName"
2008 *| Printer-Object not supported
2009 *| pDefaults is ignored
2012 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2015 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2017 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2018 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2022 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2023 SetLastError(ERROR_INVALID_PARAMETER);
2027 /* Get the unique handle of the printer or Printserver */
2028 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2029 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2030 return (*phPrinter != 0);
2033 /******************************************************************
2034 * AddMonitorA [WINSPOOL.@]
2039 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2041 LPWSTR nameW = NULL;
2044 LPMONITOR_INFO_2A mi2a;
2045 MONITOR_INFO_2W mi2w;
2047 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2048 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2049 mi2a ? debugstr_a(mi2a->pName) : NULL,
2050 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2051 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2054 SetLastError(ERROR_INVALID_LEVEL);
2058 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2064 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2065 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2066 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2069 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2071 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2072 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2073 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2075 if (mi2a->pEnvironment) {
2076 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2077 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2078 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2080 if (mi2a->pDLLName) {
2081 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2082 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2083 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2086 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2088 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2089 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2090 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2092 HeapFree(GetProcessHeap(), 0, nameW);
2096 /******************************************************************************
2097 * AddMonitorW [WINSPOOL.@]
2099 * Install a Printmonitor
2102 * pName [I] Servername or NULL (local Computer)
2103 * Level [I] Structure-Level (Must be 2)
2104 * pMonitors [I] PTR to MONITOR_INFO_2
2111 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2114 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2116 monitor_t * pm = NULL;
2117 LPMONITOR_INFO_2W mi2w;
2123 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2124 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2125 mi2w ? debugstr_w(mi2w->pName) : NULL,
2126 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2127 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2130 SetLastError(ERROR_INVALID_LEVEL);
2134 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2139 if (pName && (pName[0])) {
2140 FIXME("for server %s not implemented\n", debugstr_w(pName));
2141 SetLastError(ERROR_ACCESS_DENIED);
2146 if (!mi2w->pName || (! mi2w->pName[0])) {
2147 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2148 SetLastError(ERROR_INVALID_PARAMETER);
2151 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2152 WARN("Environment %s requested (we support only %s)\n",
2153 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2154 SetLastError(ERROR_INVALID_ENVIRONMENT);
2158 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2159 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2160 SetLastError(ERROR_INVALID_PARAMETER);
2164 /* Load and initialize the monitor. SetLastError() is called on failure */
2165 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2170 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2171 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2175 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2176 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2177 &disposition) == ERROR_SUCCESS) {
2179 /* Some installers set options for the port before calling AddMonitor.
2180 We query the "Driver" entry to verify that the monitor is installed,
2181 before we return an error.
2182 When a user installs two print monitors at the same time with the
2183 same name but with a different driver DLL and a task switch comes
2184 between RegQueryValueExW and RegSetValueExW, a race condition
2185 is possible but silently ignored. */
2189 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2190 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2191 &namesize) == ERROR_SUCCESS)) {
2192 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2193 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2194 9x: ERROR_ALREADY_EXISTS (183) */
2195 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2200 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2201 res = (RegSetValueExW(hentry, DriverW, 0,
2202 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2204 RegCloseKey(hentry);
2211 /******************************************************************
2212 * DeletePrinterDriverA [WINSPOOL.@]
2215 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2217 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2220 /******************************************************************
2221 * DeletePrinterDriverW [WINSPOOL.@]
2224 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2226 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2229 /******************************************************************
2230 * DeleteMonitorA [WINSPOOL.@]
2232 * See DeleteMonitorW.
2235 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2237 LPWSTR nameW = NULL;
2238 LPWSTR EnvironmentW = NULL;
2239 LPWSTR MonitorNameW = NULL;
2244 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2245 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2246 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2250 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2251 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2252 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2255 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2256 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2257 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2260 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2262 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2263 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2264 HeapFree(GetProcessHeap(), 0, nameW);
2268 /******************************************************************
2269 * DeleteMonitorW [WINSPOOL.@]
2271 * Delete a specific Printmonitor from a Printing-Environment
2274 * pName [I] Servername or NULL (local Computer)
2275 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2276 * pMonitorName [I] Name of the Monitor, that should be deleted
2283 * pEnvironment is ignored in Windows for the local Computer.
2287 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2291 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2292 debugstr_w(pMonitorName));
2294 if (pName && (pName[0])) {
2295 FIXME("for server %s not implemented\n", debugstr_w(pName));
2296 SetLastError(ERROR_ACCESS_DENIED);
2300 /* pEnvironment is ignored in Windows for the local Computer */
2302 if (!pMonitorName || !pMonitorName[0]) {
2303 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2304 SetLastError(ERROR_INVALID_PARAMETER);
2308 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2309 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2313 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2314 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2319 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2322 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2323 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2327 /******************************************************************
2328 * DeletePortA [WINSPOOL.@]
2333 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2335 LPWSTR nameW = NULL;
2336 LPWSTR portW = NULL;
2340 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2342 /* convert servername to unicode */
2344 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2345 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2346 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2349 /* convert portname to unicode */
2351 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2352 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2353 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2356 res = DeletePortW(nameW, hWnd, portW);
2357 HeapFree(GetProcessHeap(), 0, nameW);
2358 HeapFree(GetProcessHeap(), 0, portW);
2362 /******************************************************************
2363 * DeletePortW [WINSPOOL.@]
2365 * Delete a specific Port
2368 * pName [I] Servername or NULL (local Computer)
2369 * hWnd [I] Handle to parent Window for the Dialog-Box
2370 * pPortName [I] Name of the Port, that should be deleted
2377 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2383 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2385 if (pName && pName[0]) {
2386 SetLastError(ERROR_INVALID_PARAMETER);
2391 SetLastError(RPC_X_NULL_REF_POINTER);
2395 /* an empty Portname is Invalid */
2396 if (!pPortName[0]) {
2397 SetLastError(ERROR_NOT_SUPPORTED);
2401 pm = monitor_load_by_port(pPortName);
2402 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2403 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2404 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2405 TRACE("got %d with %u\n", res, GetLastError());
2409 pui = monitor_loadui(pm);
2410 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2411 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2412 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2413 TRACE("got %d with %u\n", res, GetLastError());
2417 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2418 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2420 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2421 SetLastError(ERROR_NOT_SUPPORTED);
2424 monitor_unload(pui);
2428 TRACE("returning %d with %u\n", res, GetLastError());
2432 /******************************************************************************
2433 * SetPrinterW [WINSPOOL.@]
2435 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2437 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2438 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2442 /******************************************************************************
2443 * WritePrinter [WINSPOOL.@]
2445 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2447 opened_printer_t *printer;
2450 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2452 EnterCriticalSection(&printer_handles_cs);
2453 printer = get_opened_printer(hPrinter);
2456 SetLastError(ERROR_INVALID_HANDLE);
2462 SetLastError(ERROR_SPL_NO_STARTDOC);
2466 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2468 LeaveCriticalSection(&printer_handles_cs);
2472 /*****************************************************************************
2473 * AddFormA [WINSPOOL.@]
2475 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2477 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2481 /*****************************************************************************
2482 * AddFormW [WINSPOOL.@]
2484 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2486 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2490 /*****************************************************************************
2491 * AddJobA [WINSPOOL.@]
2493 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2496 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2500 SetLastError(ERROR_INVALID_LEVEL);
2504 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2507 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2508 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2509 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2510 if(*pcbNeeded > cbBuf) {
2511 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2514 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2515 addjobA->JobId = addjobW->JobId;
2516 addjobA->Path = (char *)(addjobA + 1);
2517 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2523 /*****************************************************************************
2524 * AddJobW [WINSPOOL.@]
2526 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2528 opened_printer_t *printer;
2531 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2532 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2533 WCHAR path[MAX_PATH], filename[MAX_PATH];
2535 ADDJOB_INFO_1W *addjob;
2537 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2539 EnterCriticalSection(&printer_handles_cs);
2541 printer = get_opened_printer(hPrinter);
2544 SetLastError(ERROR_INVALID_HANDLE);
2549 SetLastError(ERROR_INVALID_LEVEL);
2553 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2557 job->job_id = InterlockedIncrement(&next_job_id);
2559 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2560 if(path[len - 1] != '\\')
2562 memcpy(path + len, spool_path, sizeof(spool_path));
2563 sprintfW(filename, fmtW, path, job->job_id);
2565 len = strlenW(filename);
2566 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2567 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2568 job->document_title = strdupW(default_doc_title);
2569 list_add_tail(&printer->queue->jobs, &job->entry);
2571 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2572 if(*pcbNeeded <= cbBuf) {
2573 addjob = (ADDJOB_INFO_1W*)pData;
2574 addjob->JobId = job->job_id;
2575 addjob->Path = (WCHAR *)(addjob + 1);
2576 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2579 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2582 LeaveCriticalSection(&printer_handles_cs);
2586 /*****************************************************************************
2587 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2589 * Return the PATH for the Print-Processors
2591 * See GetPrintProcessorDirectoryW.
2595 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2596 DWORD level, LPBYTE Info,
2597 DWORD cbBuf, LPDWORD pcbNeeded)
2599 LPWSTR serverW = NULL;
2604 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2605 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2609 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2610 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2611 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2615 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2616 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2617 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2620 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2621 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2623 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2626 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2627 cbBuf, NULL, NULL) > 0;
2630 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2631 HeapFree(GetProcessHeap(), 0, envW);
2632 HeapFree(GetProcessHeap(), 0, serverW);
2636 /*****************************************************************************
2637 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2639 * Return the PATH for the Print-Processors
2642 * server [I] Servername (NT only) or NULL (local Computer)
2643 * env [I] Printing-Environment (see below) or NULL (Default)
2644 * level [I] Structure-Level (must be 1)
2645 * Info [O] PTR to Buffer that receives the Result
2646 * cbBuf [I] Size of Buffer at "Info"
2647 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2648 * required for the Buffer at "Info"
2651 * Success: TRUE and in pcbNeeded the Bytes used in Info
2652 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2653 * if cbBuf is too small
2655 * Native Values returned in Info on Success:
2656 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2657 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2658 *| win9x(Windows 4.0): "%winsysdir%"
2660 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2663 * Only NULL or "" is supported for server
2666 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2667 DWORD level, LPBYTE Info,
2668 DWORD cbBuf, LPDWORD pcbNeeded)
2671 const printenv_t * env_t;
2673 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2674 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2676 if(server != NULL && server[0]) {
2677 FIXME("server not supported: %s\n", debugstr_w(server));
2678 SetLastError(ERROR_INVALID_PARAMETER);
2682 env_t = validate_envW(env);
2683 if(!env_t) return FALSE; /* environment invalid or unsupported */
2686 WARN("(Level: %d) is ignored in win9x\n", level);
2687 SetLastError(ERROR_INVALID_LEVEL);
2691 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2692 needed = GetSystemDirectoryW(NULL, 0);
2693 /* add the Size for the Subdirectories */
2694 needed += lstrlenW(spoolprtprocsW);
2695 needed += lstrlenW(env_t->subdir);
2696 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2698 if(pcbNeeded) *pcbNeeded = needed;
2699 TRACE ("required: 0x%x/%d\n", needed, needed);
2700 if (needed > cbBuf) {
2701 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2704 if(pcbNeeded == NULL) {
2705 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2706 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2707 SetLastError(RPC_X_NULL_REF_POINTER);
2711 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2712 SetLastError(RPC_X_NULL_REF_POINTER);
2716 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2717 /* add the Subdirectories */
2718 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2719 lstrcatW((LPWSTR) Info, env_t->subdir);
2720 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2724 /*****************************************************************************
2725 * WINSPOOL_OpenDriverReg [internal]
2727 * opens the registry for the printer drivers depending on the given input
2728 * variable pEnvironment
2731 * the opened hkey on success
2734 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2738 const printenv_t * env;
2741 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2743 if (!pEnvironment || unicode) {
2744 /* pEnvironment was NULL or an Unicode-String: use it direct */
2745 env = validate_envW(pEnvironment);
2749 /* pEnvironment was an ANSI-String: convert to unicode first */
2751 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2752 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2753 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2754 env = validate_envW(buffer);
2755 HeapFree(GetProcessHeap(), 0, buffer);
2757 if (!env) return NULL;
2759 buffer = HeapAlloc( GetProcessHeap(), 0,
2760 (strlenW(DriversW) + strlenW(env->envname) +
2761 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2763 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2764 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2765 HeapFree(GetProcessHeap(), 0, buffer);
2770 /*****************************************************************************
2771 * AddPrinterW [WINSPOOL.@]
2773 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2775 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2779 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2781 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2782 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2783 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2784 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2785 statusW[] = {'S','t','a','t','u','s',0},
2786 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2788 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2791 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2792 SetLastError(ERROR_INVALID_PARAMETER);
2796 ERR("Level = %d, unsupported!\n", Level);
2797 SetLastError(ERROR_INVALID_LEVEL);
2801 SetLastError(ERROR_INVALID_PARAMETER);
2804 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2806 ERR("Can't create Printers key\n");
2809 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2810 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2811 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2812 RegCloseKey(hkeyPrinter);
2813 RegCloseKey(hkeyPrinters);
2816 RegCloseKey(hkeyPrinter);
2818 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2820 ERR("Can't create Drivers key\n");
2821 RegCloseKey(hkeyPrinters);
2824 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2826 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2827 RegCloseKey(hkeyPrinters);
2828 RegCloseKey(hkeyDrivers);
2829 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2832 RegCloseKey(hkeyDriver);
2833 RegCloseKey(hkeyDrivers);
2835 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2836 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2837 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2838 RegCloseKey(hkeyPrinters);
2842 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2844 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2845 SetLastError(ERROR_INVALID_PRINTER_NAME);
2846 RegCloseKey(hkeyPrinters);
2849 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2850 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2851 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2853 /* See if we can load the driver. We may need the devmode structure anyway
2856 * Note that DocumentPropertiesW will briefly try to open the printer we
2857 * just create to find a DEVMODEA struct (it will use the WINEPS default
2858 * one in case it is not there, so we are ok).
2860 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2863 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2864 size = sizeof(DEVMODEW);
2870 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2872 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2874 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2875 HeapFree(GetProcessHeap(),0,dmW);
2880 /* set devmode to printer name */
2881 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2885 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2886 and we support these drivers. NT writes DEVMODEW so somehow
2887 we'll need to distinguish between these when we support NT
2891 dmA = DEVMODEdupWtoA(dmW);
2892 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2893 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2894 HeapFree(GetProcessHeap(), 0, dmA);
2896 HeapFree(GetProcessHeap(), 0, dmW);
2898 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2899 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2900 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2901 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2903 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2904 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2905 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2906 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2907 (LPBYTE)&pi->Priority, sizeof(DWORD));
2908 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2909 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2910 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2911 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2912 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2913 (LPBYTE)&pi->Status, sizeof(DWORD));
2914 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2915 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2917 RegCloseKey(hkeyPrinter);
2918 RegCloseKey(hkeyPrinters);
2919 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2920 ERR("OpenPrinter failing\n");
2926 /*****************************************************************************
2927 * AddPrinterA [WINSPOOL.@]
2929 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2931 UNICODE_STRING pNameW;
2933 PRINTER_INFO_2W *piW;
2934 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2937 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2939 ERR("Level = %d, unsupported!\n", Level);
2940 SetLastError(ERROR_INVALID_LEVEL);
2943 pwstrNameW = asciitounicode(&pNameW,pName);
2944 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2946 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2948 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2949 RtlFreeUnicodeString(&pNameW);
2954 /*****************************************************************************
2955 * ClosePrinter [WINSPOOL.@]
2957 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2959 UINT_PTR i = (UINT_PTR)hPrinter;
2960 opened_printer_t *printer = NULL;
2963 TRACE("(%p)\n", hPrinter);
2965 EnterCriticalSection(&printer_handles_cs);
2967 if ((i > 0) && (i <= nb_printer_handles))
2968 printer = printer_handles[i - 1];
2973 struct list *cursor, *cursor2;
2975 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2976 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2977 printer->hXcv, debugstr_w(printer->name), printer->doc );
2980 EndDocPrinter(hPrinter);
2982 if(InterlockedDecrement(&printer->queue->ref) == 0)
2984 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2986 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2987 ScheduleJob(hPrinter, job->job_id);
2989 HeapFree(GetProcessHeap(), 0, printer->queue);
2991 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2992 monitor_unload(printer->pm);
2993 HeapFree(GetProcessHeap(), 0, printer->printername);
2994 HeapFree(GetProcessHeap(), 0, printer->name);
2995 HeapFree(GetProcessHeap(), 0, printer);
2996 printer_handles[i - 1] = NULL;
2999 LeaveCriticalSection(&printer_handles_cs);
3003 /*****************************************************************************
3004 * DeleteFormA [WINSPOOL.@]
3006 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3008 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3012 /*****************************************************************************
3013 * DeleteFormW [WINSPOOL.@]
3015 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3017 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3021 /*****************************************************************************
3022 * DeletePrinter [WINSPOOL.@]
3024 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3026 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3027 HKEY hkeyPrinters, hkey;
3030 SetLastError(ERROR_INVALID_HANDLE);
3033 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3034 RegDeleteTreeW(hkeyPrinters, lpNameW);
3035 RegCloseKey(hkeyPrinters);
3037 WriteProfileStringW(devicesW, lpNameW, NULL);
3038 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3039 RegDeleteValueW(hkey, lpNameW);
3045 /*****************************************************************************
3046 * SetPrinterA [WINSPOOL.@]
3048 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3051 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3055 /*****************************************************************************
3056 * SetJobA [WINSPOOL.@]
3058 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3059 LPBYTE pJob, DWORD Command)
3063 UNICODE_STRING usBuffer;
3065 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3067 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3068 are all ignored by SetJob, so we don't bother copying them */
3076 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3077 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3079 JobW = (LPBYTE)info1W;
3080 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3081 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3082 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3083 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3084 info1W->Status = info1A->Status;
3085 info1W->Priority = info1A->Priority;
3086 info1W->Position = info1A->Position;
3087 info1W->PagesPrinted = info1A->PagesPrinted;
3092 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3093 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3095 JobW = (LPBYTE)info2W;
3096 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3097 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3098 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3099 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3100 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3101 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3102 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3103 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3104 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3105 info2W->Status = info2A->Status;
3106 info2W->Priority = info2A->Priority;
3107 info2W->Position = info2A->Position;
3108 info2W->StartTime = info2A->StartTime;
3109 info2W->UntilTime = info2A->UntilTime;
3110 info2W->PagesPrinted = info2A->PagesPrinted;
3114 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3115 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3118 SetLastError(ERROR_INVALID_LEVEL);
3122 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3128 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3129 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3130 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3131 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3132 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3137 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3138 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3139 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3140 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3141 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3142 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3143 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3144 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3145 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3149 HeapFree(GetProcessHeap(), 0, JobW);
3154 /*****************************************************************************
3155 * SetJobW [WINSPOOL.@]
3157 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3158 LPBYTE pJob, DWORD Command)
3163 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3164 FIXME("Ignoring everything other than document title\n");
3166 EnterCriticalSection(&printer_handles_cs);
3167 job = get_job(hPrinter, JobId);
3177 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3178 HeapFree(GetProcessHeap(), 0, job->document_title);
3179 job->document_title = strdupW(info1->pDocument);
3184 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3185 HeapFree(GetProcessHeap(), 0, job->document_title);
3186 job->document_title = strdupW(info2->pDocument);
3192 SetLastError(ERROR_INVALID_LEVEL);
3197 LeaveCriticalSection(&printer_handles_cs);
3201 /*****************************************************************************
3202 * EndDocPrinter [WINSPOOL.@]
3204 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3206 opened_printer_t *printer;
3208 TRACE("(%p)\n", hPrinter);
3210 EnterCriticalSection(&printer_handles_cs);
3212 printer = get_opened_printer(hPrinter);
3215 SetLastError(ERROR_INVALID_HANDLE);
3221 SetLastError(ERROR_SPL_NO_STARTDOC);
3225 CloseHandle(printer->doc->hf);
3226 ScheduleJob(hPrinter, printer->doc->job_id);
3227 HeapFree(GetProcessHeap(), 0, printer->doc);
3228 printer->doc = NULL;
3231 LeaveCriticalSection(&printer_handles_cs);
3235 /*****************************************************************************
3236 * EndPagePrinter [WINSPOOL.@]
3238 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3240 FIXME("(%p): stub\n", hPrinter);
3244 /*****************************************************************************
3245 * StartDocPrinterA [WINSPOOL.@]
3247 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3249 UNICODE_STRING usBuffer;
3251 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3254 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3255 or one (DOC_INFO_3) extra DWORDs */
3259 doc2W.JobId = doc2->JobId;
3262 doc2W.dwMode = doc2->dwMode;
3265 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3266 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3267 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3271 SetLastError(ERROR_INVALID_LEVEL);
3275 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3277 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3278 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3279 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3284 /*****************************************************************************
3285 * StartDocPrinterW [WINSPOOL.@]
3287 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3289 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3290 opened_printer_t *printer;
3291 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3292 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3293 JOB_INFO_1W job_info;
3294 DWORD needed, ret = 0;
3298 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3299 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3300 debugstr_w(doc->pDatatype));
3302 if(Level < 1 || Level > 3)
3304 SetLastError(ERROR_INVALID_LEVEL);
3308 EnterCriticalSection(&printer_handles_cs);
3309 printer = get_opened_printer(hPrinter);
3312 SetLastError(ERROR_INVALID_HANDLE);
3318 SetLastError(ERROR_INVALID_PRINTER_STATE);
3322 /* Even if we're printing to a file we still add a print job, we'll
3323 just ignore the spool file name */
3325 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3327 ERR("AddJob failed gle %u\n", GetLastError());
3331 if(doc->pOutputFile)
3332 filename = doc->pOutputFile;
3334 filename = addjob->Path;
3336 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3337 if(hf == INVALID_HANDLE_VALUE)
3340 memset(&job_info, 0, sizeof(job_info));
3341 job_info.pDocument = doc->pDocName;
3342 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3344 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3345 printer->doc->hf = hf;
3346 ret = printer->doc->job_id = addjob->JobId;
3348 LeaveCriticalSection(&printer_handles_cs);
3353 /*****************************************************************************
3354 * StartPagePrinter [WINSPOOL.@]
3356 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3358 FIXME("(%p): stub\n", hPrinter);
3362 /*****************************************************************************
3363 * GetFormA [WINSPOOL.@]
3365 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3366 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3368 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3369 Level,pForm,cbBuf,pcbNeeded);
3373 /*****************************************************************************
3374 * GetFormW [WINSPOOL.@]
3376 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3377 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3379 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3380 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3384 /*****************************************************************************
3385 * SetFormA [WINSPOOL.@]
3387 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3390 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3394 /*****************************************************************************
3395 * SetFormW [WINSPOOL.@]
3397 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3400 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3404 /*****************************************************************************
3405 * ReadPrinter [WINSPOOL.@]
3407 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3408 LPDWORD pNoBytesRead)
3410 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3414 /*****************************************************************************
3415 * ResetPrinterA [WINSPOOL.@]
3417 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3419 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3423 /*****************************************************************************
3424 * ResetPrinterW [WINSPOOL.@]
3426 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3428 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3432 /*****************************************************************************
3433 * WINSPOOL_GetDWORDFromReg
3435 * Return DWORD associated with ValueName from hkey.
3437 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3439 DWORD sz = sizeof(DWORD), type, value = 0;
3442 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3444 if(ret != ERROR_SUCCESS) {
3445 WARN("Got ret = %d on name %s\n", ret, ValueName);
3448 if(type != REG_DWORD) {
3449 ERR("Got type %d\n", type);
3456 /*****************************************************************************
3457 * get_filename_from_reg [internal]
3459 * Get ValueName from hkey storing result in out
3460 * when the Value in the registry has only a filename, use driverdir as prefix
3461 * outlen is space left in out
3462 * String is stored either as unicode or ascii
3466 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3467 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3469 WCHAR filename[MAX_PATH];
3473 LPWSTR buffer = filename;
3477 size = sizeof(filename);
3479 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3480 if (ret == ERROR_MORE_DATA) {
3481 TRACE("need dynamic buffer: %u\n", size);
3482 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3484 /* No Memory is bad */
3488 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3491 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3492 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3498 /* do we have a full path ? */
3499 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3500 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3503 /* we must build the full Path */
3505 if ((out) && (outlen > dirlen)) {
3507 lstrcpyW((LPWSTR)out, driverdir);
3511 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3520 /* write the filename */
3522 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3523 if ((out) && (outlen >= size)) {
3524 lstrcpyW((LPWSTR)out, ptr);
3533 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3534 if ((out) && (outlen >= size)) {
3535 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3543 ptr += lstrlenW(ptr)+1;
3544 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3547 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3549 /* write the multisz-termination */
3550 if (type == REG_MULTI_SZ) {
3551 size = (unicode) ? sizeof(WCHAR) : 1;
3554 if (out && (outlen >= size)) {
3555 memset (out, 0, size);
3561 /*****************************************************************************
3562 * WINSPOOL_GetStringFromReg
3564 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3565 * String is stored either as unicode or ascii.
3566 * Bit of a hack here to get the ValueName if we want ascii.
3568 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3569 DWORD buflen, DWORD *needed,
3572 DWORD sz = buflen, type;
3576 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3578 LPSTR ValueNameA = strdupWtoA(ValueName);
3579 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3580 HeapFree(GetProcessHeap(),0,ValueNameA);
3582 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3583 WARN("Got ret = %d\n", ret);
3587 /* add space for terminating '\0' */
3588 sz += unicode ? sizeof(WCHAR) : 1;
3592 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3597 /*****************************************************************************
3598 * WINSPOOL_GetDefaultDevMode
3600 * Get a default DevMode values for wineps.
3604 static void WINSPOOL_GetDefaultDevMode(
3606 DWORD buflen, DWORD *needed,
3610 static const char szwps[] = "wineps.drv";
3612 /* fill default DEVMODE - should be read from ppd... */
3613 ZeroMemory( &dm, sizeof(dm) );
3614 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3615 dm.dmSpecVersion = DM_SPECVERSION;
3616 dm.dmDriverVersion = 1;
3617 dm.dmSize = sizeof(DEVMODEA);
3618 dm.dmDriverExtra = 0;
3620 DM_ORIENTATION | DM_PAPERSIZE |
3621 DM_PAPERLENGTH | DM_PAPERWIDTH |
3624 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3625 DM_YRESOLUTION | DM_TTOPTION;
3627 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3628 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3629 dm.u1.s1.dmPaperLength = 2970;
3630 dm.u1.s1.dmPaperWidth = 2100;
3632 dm.u1.s1.dmScale = 100;
3633 dm.u1.s1.dmCopies = 1;
3634 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3635 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3638 dm.dmYResolution = 300; /* 300dpi */
3639 dm.dmTTOption = DMTT_BITMAP;
3642 /* dm.dmLogPixels */
3643 /* dm.dmBitsPerPel */
3644 /* dm.dmPelsWidth */
3645 /* dm.dmPelsHeight */
3646 /* dm.u2.dmDisplayFlags */
3647 /* dm.dmDisplayFrequency */
3648 /* dm.dmICMMethod */
3649 /* dm.dmICMIntent */
3650 /* dm.dmMediaType */
3651 /* dm.dmDitherType */
3652 /* dm.dmReserved1 */
3653 /* dm.dmReserved2 */
3654 /* dm.dmPanningWidth */
3655 /* dm.dmPanningHeight */
3658 if(buflen >= sizeof(DEVMODEW)) {
3659 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3660 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3661 HeapFree(GetProcessHeap(),0,pdmW);
3663 *needed = sizeof(DEVMODEW);
3667 if(buflen >= sizeof(DEVMODEA)) {
3668 memcpy(ptr, &dm, sizeof(DEVMODEA));
3670 *needed = sizeof(DEVMODEA);
3674 /*****************************************************************************
3675 * WINSPOOL_GetDevModeFromReg
3677 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3678 * DevMode is stored either as unicode or ascii.
3680 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3682 DWORD buflen, DWORD *needed,
3685 DWORD sz = buflen, type;
3688 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3689 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3690 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3691 if (sz < sizeof(DEVMODEA))
3693 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3696 /* ensures that dmSize is not erratically bogus if registry is invalid */
3697 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3698 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3700 sz += (CCHDEVICENAME + CCHFORMNAME);
3702 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3703 memcpy(ptr, dmW, sz);
3704 HeapFree(GetProcessHeap(),0,dmW);
3711 /*********************************************************************
3712 * WINSPOOL_GetPrinter_1
3714 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3715 * The strings are either stored as unicode or ascii.
3717 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3718 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3721 DWORD size, left = cbBuf;
3722 BOOL space = (cbBuf > 0);
3727 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3729 if(space && size <= left) {
3730 pi1->pName = (LPWSTR)ptr;
3738 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3739 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3741 if(space && size <= left) {
3742 pi1->pDescription = (LPWSTR)ptr;
3750 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3752 if(space && size <= left) {
3753 pi1->pComment = (LPWSTR)ptr;
3761 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3763 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3764 memset(pi1, 0, sizeof(*pi1));
3768 /*********************************************************************
3769 * WINSPOOL_GetPrinter_2
3771 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3772 * The strings are either stored as unicode or ascii.
3774 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3775 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3778 DWORD size, left = cbBuf;
3779 BOOL space = (cbBuf > 0);
3784 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3786 if(space && size <= left) {
3787 pi2->pPrinterName = (LPWSTR)ptr;
3794 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3796 if(space && size <= left) {
3797 pi2->pShareName = (LPWSTR)ptr;
3804 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3806 if(space && size <= left) {
3807 pi2->pPortName = (LPWSTR)ptr;
3814 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3816 if(space && size <= left) {
3817 pi2->pDriverName = (LPWSTR)ptr;
3824 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3826 if(space && size <= left) {
3827 pi2->pComment = (LPWSTR)ptr;
3834 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3836 if(space && size <= left) {
3837 pi2->pLocation = (LPWSTR)ptr;
3844 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3846 if(space && size <= left) {
3847 pi2->pDevMode = (LPDEVMODEW)ptr;
3856 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3857 if(space && size <= left) {
3858 pi2->pDevMode = (LPDEVMODEW)ptr;
3865 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3867 if(space && size <= left) {
3868 pi2->pSepFile = (LPWSTR)ptr;
3875 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3877 if(space && size <= left) {
3878 pi2->pPrintProcessor = (LPWSTR)ptr;
3885 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3887 if(space && size <= left) {
3888 pi2->pDatatype = (LPWSTR)ptr;
3895 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3897 if(space && size <= left) {
3898 pi2->pParameters = (LPWSTR)ptr;
3906 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3907 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3908 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3909 "Default Priority");
3910 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3911 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3914 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3915 memset(pi2, 0, sizeof(*pi2));
3920 /*********************************************************************
3921 * WINSPOOL_GetPrinter_4
3923 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3925 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3926 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3929 DWORD size, left = cbBuf;
3930 BOOL space = (cbBuf > 0);
3935 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3937 if(space && size <= left) {
3938 pi4->pPrinterName = (LPWSTR)ptr;
3946 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3949 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3950 memset(pi4, 0, sizeof(*pi4));
3955 /*********************************************************************
3956 * WINSPOOL_GetPrinter_5
3958 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3960 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3961 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3964 DWORD size, left = cbBuf;
3965 BOOL space = (cbBuf > 0);
3970 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3972 if(space && size <= left) {
3973 pi5->pPrinterName = (LPWSTR)ptr;
3980 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3982 if(space && size <= left) {
3983 pi5->pPortName = (LPWSTR)ptr;
3991 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3992 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3994 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3998 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3999 memset(pi5, 0, sizeof(*pi5));
4004 /*********************************************************************
4005 * WINSPOOL_GetPrinter_7
4007 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4009 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4010 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4012 DWORD size, left = cbBuf;
4013 BOOL space = (cbBuf > 0);
4018 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4020 if (space && size <= left) {
4021 pi7->pszObjectGUID = (LPWSTR)ptr;
4029 /* We do not have a Directory Service */
4030 pi7->dwAction = DSPRINT_UNPUBLISH;
4033 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4034 memset(pi7, 0, sizeof(*pi7));
4039 /*********************************************************************
4040 * WINSPOOL_GetPrinter_9
4042 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4043 * The strings are either stored as unicode or ascii.
4045 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4046 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4049 BOOL space = (cbBuf > 0);
4053 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4054 if(space && size <= cbBuf) {
4055 pi9->pDevMode = (LPDEVMODEW)buf;
4062 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4063 if(space && size <= cbBuf) {
4064 pi9->pDevMode = (LPDEVMODEW)buf;
4070 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4071 memset(pi9, 0, sizeof(*pi9));
4076 /*****************************************************************************
4077 * WINSPOOL_GetPrinter
4079 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4080 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4081 * just a collection of pointers to strings.
4083 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4084 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4087 DWORD size, needed = 0;
4089 HKEY hkeyPrinter, hkeyPrinters;
4092 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4094 if (!(name = get_opened_printer_name(hPrinter))) {
4095 SetLastError(ERROR_INVALID_HANDLE);
4099 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4101 ERR("Can't create Printers key\n");
4104 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4106 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4107 RegCloseKey(hkeyPrinters);
4108 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4115 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4117 size = sizeof(PRINTER_INFO_2W);
4119 ptr = pPrinter + size;
4121 memset(pPrinter, 0, size);
4126 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4134 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4136 size = sizeof(PRINTER_INFO_4W);
4138 ptr = pPrinter + size;
4140 memset(pPrinter, 0, size);
4145 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4154 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4156 size = sizeof(PRINTER_INFO_5W);
4158 ptr = pPrinter + size;
4160 memset(pPrinter, 0, size);
4166 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4175 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4177 size = sizeof(PRINTER_INFO_6);
4178 if (size <= cbBuf) {
4179 /* FIXME: We do not update the status yet */
4180 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4192 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4194 size = sizeof(PRINTER_INFO_7W);
4195 if (size <= cbBuf) {
4196 ptr = pPrinter + size;
4198 memset(pPrinter, 0, size);
4204 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4212 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4214 size = sizeof(PRINTER_INFO_9W);
4216 ptr = pPrinter + size;
4218 memset(pPrinter, 0, size);
4224 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4231 FIXME("Unimplemented level %d\n", Level);
4232 SetLastError(ERROR_INVALID_LEVEL);
4233 RegCloseKey(hkeyPrinters);
4234 RegCloseKey(hkeyPrinter);
4238 RegCloseKey(hkeyPrinter);
4239 RegCloseKey(hkeyPrinters);
4241 TRACE("returning %d needed = %d\n", ret, needed);
4242 if(pcbNeeded) *pcbNeeded = needed;
4244 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4248 /*****************************************************************************
4249 * GetPrinterW [WINSPOOL.@]
4251 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4252 DWORD cbBuf, LPDWORD pcbNeeded)
4254 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4258 /*****************************************************************************
4259 * GetPrinterA [WINSPOOL.@]
4261 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4262 DWORD cbBuf, LPDWORD pcbNeeded)
4264 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4268 /*****************************************************************************
4269 * WINSPOOL_EnumPrinters
4271 * Implementation of EnumPrintersA|W
4273 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4274 DWORD dwLevel, LPBYTE lpbPrinters,
4275 DWORD cbBuf, LPDWORD lpdwNeeded,
4276 LPDWORD lpdwReturned, BOOL unicode)
4279 HKEY hkeyPrinters, hkeyPrinter;
4280 WCHAR PrinterName[255];
4281 DWORD needed = 0, number = 0;
4282 DWORD used, i, left;
4286 memset(lpbPrinters, 0, cbBuf);
4292 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4293 if(dwType == PRINTER_ENUM_DEFAULT)
4296 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4297 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4298 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4300 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4308 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4309 FIXME("dwType = %08x\n", dwType);
4310 SetLastError(ERROR_INVALID_FLAGS);
4314 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4316 ERR("Can't create Printers key\n");
4320 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4321 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4322 RegCloseKey(hkeyPrinters);
4323 ERR("Can't query Printers key\n");
4326 TRACE("Found %d printers\n", number);
4330 used = number * sizeof(PRINTER_INFO_1W);
4333 used = number * sizeof(PRINTER_INFO_2W);
4336 used = number * sizeof(PRINTER_INFO_4W);
4339 used = number * sizeof(PRINTER_INFO_5W);
4343 SetLastError(ERROR_INVALID_LEVEL);
4344 RegCloseKey(hkeyPrinters);
4347 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4349 for(i = 0; i < number; i++) {
4350 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4352 ERR("Can't enum key number %d\n", i);
4353 RegCloseKey(hkeyPrinters);
4356 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4357 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4359 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4360 RegCloseKey(hkeyPrinters);
4365 buf = lpbPrinters + used;
4366 left = cbBuf - used;
4374 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4375 left, &needed, unicode);
4377 if(pi) pi += sizeof(PRINTER_INFO_1W);
4380 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4381 left, &needed, unicode);
4383 if(pi) pi += sizeof(PRINTER_INFO_2W);
4386 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4387 left, &needed, unicode);
4389 if(pi) pi += sizeof(PRINTER_INFO_4W);
4392 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4393 left, &needed, unicode);
4395 if(pi) pi += sizeof(PRINTER_INFO_5W);
4398 ERR("Shouldn't be here!\n");
4399 RegCloseKey(hkeyPrinter);
4400 RegCloseKey(hkeyPrinters);
4403 RegCloseKey(hkeyPrinter);
4405 RegCloseKey(hkeyPrinters);
4412 memset(lpbPrinters, 0, cbBuf);
4413 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4417 *lpdwReturned = number;
4418 SetLastError(ERROR_SUCCESS);
4423 /******************************************************************
4424 * EnumPrintersW [WINSPOOL.@]
4426 * Enumerates the available printers, print servers and print
4427 * providers, depending on the specified flags, name and level.
4431 * If level is set to 1:
4432 * Returns an array of PRINTER_INFO_1 data structures in the
4433 * lpbPrinters buffer.
4435 * If level is set to 2:
4436 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4437 * Returns an array of PRINTER_INFO_2 data structures in the
4438 * lpbPrinters buffer. Note that according to MSDN also an
4439 * OpenPrinter should be performed on every remote printer.
4441 * If level is set to 4 (officially WinNT only):
4442 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4443 * Fast: Only the registry is queried to retrieve printer names,
4444 * no connection to the driver is made.
4445 * Returns an array of PRINTER_INFO_4 data structures in the
4446 * lpbPrinters buffer.
4448 * If level is set to 5 (officially WinNT4/Win9x only):
4449 * Fast: Only the registry is queried to retrieve printer names,
4450 * no connection to the driver is made.
4451 * Returns an array of PRINTER_INFO_5 data structures in the
4452 * lpbPrinters buffer.
4454 * If level set to 3 or 6+:
4455 * returns zero (failure!)
4457 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4461 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4462 * - Only levels 2, 4 and 5 are implemented at the moment.
4463 * - 16-bit printer drivers are not enumerated.
4464 * - Returned amount of bytes used/needed does not match the real Windoze
4465 * implementation (as in this implementation, all strings are part
4466 * of the buffer, whereas Win32 keeps them somewhere else)
4467 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4470 * - In a regular Wine installation, no registry settings for printers
4471 * exist, which makes this function return an empty list.
4473 BOOL WINAPI EnumPrintersW(
4474 DWORD dwType, /* [in] Types of print objects to enumerate */
4475 LPWSTR lpszName, /* [in] name of objects to enumerate */
4476 DWORD dwLevel, /* [in] type of printer info structure */
4477 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4478 DWORD cbBuf, /* [in] max size of buffer in bytes */
4479 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4480 LPDWORD lpdwReturned /* [out] number of entries returned */
4483 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4484 lpdwNeeded, lpdwReturned, TRUE);
4487 /******************************************************************
4488 * EnumPrintersA [WINSPOOL.@]
4491 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4492 DWORD dwLevel, LPBYTE lpbPrinters,
4493 DWORD cbBuf, LPDWORD lpdwNeeded,
4494 LPDWORD lpdwReturned)
4496 BOOL ret, unicode = FALSE;
4497 UNICODE_STRING lpszNameW;
4500 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4501 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4502 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4503 lpdwNeeded, lpdwReturned, unicode);
4504 RtlFreeUnicodeString(&lpszNameW);
4508 /*****************************************************************************
4509 * WINSPOOL_GetDriverInfoFromReg [internal]
4511 * Enters the information from the registry into the DRIVER_INFO struct
4514 * zero if the printer driver does not exist in the registry
4515 * (only if Level > 1) otherwise nonzero
4517 static BOOL WINSPOOL_GetDriverInfoFromReg(
4520 const printenv_t * env,
4522 LPBYTE ptr, /* DRIVER_INFO */
4523 LPBYTE pDriverStrings, /* strings buffer */
4524 DWORD cbBuf, /* size of string buffer */
4525 LPDWORD pcbNeeded, /* space needed for str. */
4526 BOOL unicode) /* type of strings */
4530 WCHAR driverdir[MAX_PATH];
4532 LPBYTE strPtr = pDriverStrings;
4533 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4535 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4536 debugstr_w(DriverName), env,
4537 Level, di, pDriverStrings, cbBuf, unicode);
4539 if (di) ZeroMemory(di, di_sizeof[Level]);
4542 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4543 if (*pcbNeeded <= cbBuf)
4544 strcpyW((LPWSTR)strPtr, DriverName);
4548 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4549 if (*pcbNeeded <= cbBuf)
4550 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4553 /* pName for level 1 has a different offset! */
4555 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4559 /* .cVersion and .pName for level > 1 */
4561 di->cVersion = env->driverversion;
4562 di->pName = (LPWSTR) strPtr;
4563 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4566 /* Reserve Space for the largest subdir and a Backslash*/
4567 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4568 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4569 /* Should never Fail */
4572 lstrcatW(driverdir, env->versionsubdir);
4573 lstrcatW(driverdir, backslashW);
4575 /* dirlen must not include the terminating zero */
4576 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4577 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4579 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4580 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4581 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4587 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4589 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4592 if (*pcbNeeded <= cbBuf) {
4594 lstrcpyW((LPWSTR)strPtr, env->envname);
4598 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4600 if (di) di->pEnvironment = (LPWSTR)strPtr;
4601 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4604 /* .pDriverPath is the Graphics rendering engine.
4605 The full Path is required to avoid a crash in some apps */
4606 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4608 if (*pcbNeeded <= cbBuf)
4609 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4611 if (di) di->pDriverPath = (LPWSTR)strPtr;
4612 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4615 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4616 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4618 if (*pcbNeeded <= cbBuf)
4619 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4621 if (di) di->pDataFile = (LPWSTR)strPtr;
4622 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4625 /* .pConfigFile is the Driver user Interface */
4626 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4628 if (*pcbNeeded <= cbBuf)
4629 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4631 if (di) di->pConfigFile = (LPWSTR)strPtr;
4632 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4636 RegCloseKey(hkeyDriver);
4637 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4642 RegCloseKey(hkeyDriver);
4643 FIXME("level 5: incomplete\n");
4648 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4650 if (*pcbNeeded <= cbBuf)
4651 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4653 if (di) di->pHelpFile = (LPWSTR)strPtr;
4654 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4657 /* .pDependentFiles */
4658 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4660 if (*pcbNeeded <= cbBuf)
4661 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4663 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4664 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4666 else if (GetVersion() & 0x80000000) {
4667 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4668 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4670 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4672 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4673 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4676 /* .pMonitorName is the optional Language Monitor */
4677 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4679 if (*pcbNeeded <= cbBuf)
4680 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4682 if (di) di->pMonitorName = (LPWSTR)strPtr;
4683 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4686 /* .pDefaultDataType */
4687 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4689 if(*pcbNeeded <= cbBuf)
4690 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4692 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4693 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4697 RegCloseKey(hkeyDriver);
4698 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4702 /* .pszzPreviousNames */
4703 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4705 if(*pcbNeeded <= cbBuf)
4706 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4708 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4709 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4713 RegCloseKey(hkeyDriver);
4714 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4718 /* support is missing, but not important enough for a FIXME */
4719 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4722 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4724 if(*pcbNeeded <= cbBuf)
4725 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4727 if (di) di->pszMfgName = (LPWSTR)strPtr;
4728 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4732 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4734 if(*pcbNeeded <= cbBuf)
4735 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4737 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4738 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4741 /* .pszHardwareID */
4742 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4744 if(*pcbNeeded <= cbBuf)
4745 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4747 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4748 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4752 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4754 if(*pcbNeeded <= cbBuf)
4755 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4757 if (di) di->pszProvider = (LPWSTR)strPtr;
4758 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4762 RegCloseKey(hkeyDriver);
4766 /* support is missing, but not important enough for a FIXME */
4767 TRACE("level 8: incomplete\n");
4769 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4770 RegCloseKey(hkeyDriver);
4774 /*****************************************************************************
4775 * WINSPOOL_GetPrinterDriver
4777 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4778 DWORD Level, LPBYTE pDriverInfo,
4779 DWORD cbBuf, LPDWORD pcbNeeded,
4783 WCHAR DriverName[100];
4784 DWORD ret, type, size, needed = 0;
4786 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4787 const printenv_t * env;
4789 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4790 Level,pDriverInfo,cbBuf, pcbNeeded);
4793 if (!(name = get_opened_printer_name(hPrinter))) {
4794 SetLastError(ERROR_INVALID_HANDLE);
4798 if (Level < 1 || Level == 7 || Level > 8) {
4799 SetLastError(ERROR_INVALID_LEVEL);
4803 env = validate_envW(pEnvironment);
4804 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4806 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4808 ERR("Can't create Printers key\n");
4811 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4813 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4814 RegCloseKey(hkeyPrinters);
4815 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4818 size = sizeof(DriverName);
4820 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4821 (LPBYTE)DriverName, &size);
4822 RegCloseKey(hkeyPrinter);
4823 RegCloseKey(hkeyPrinters);
4824 if(ret != ERROR_SUCCESS) {
4825 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4829 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4831 ERR("Can't create Drivers key\n");
4835 size = di_sizeof[Level];
4836 if ((size <= cbBuf) && pDriverInfo)
4837 ptr = pDriverInfo + size;
4839 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4840 env, Level, pDriverInfo, ptr,
4841 (cbBuf < size) ? 0 : cbBuf - size,
4842 &needed, unicode)) {
4843 RegCloseKey(hkeyDrivers);
4847 RegCloseKey(hkeyDrivers);
4849 if(pcbNeeded) *pcbNeeded = size + needed;
4850 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4851 if(cbBuf >= needed) return TRUE;
4852 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4856 /*****************************************************************************
4857 * GetPrinterDriverA [WINSPOOL.@]
4859 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4860 DWORD Level, LPBYTE pDriverInfo,
4861 DWORD cbBuf, LPDWORD pcbNeeded)
4864 UNICODE_STRING pEnvW;
4867 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4868 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4869 cbBuf, pcbNeeded, FALSE);
4870 RtlFreeUnicodeString(&pEnvW);
4873 /*****************************************************************************
4874 * GetPrinterDriverW [WINSPOOL.@]
4876 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4877 DWORD Level, LPBYTE pDriverInfo,
4878 DWORD cbBuf, LPDWORD pcbNeeded)
4880 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4881 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4884 /*****************************************************************************
4885 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4887 * Return the PATH for the Printer-Drivers (UNICODE)
4890 * pName [I] Servername (NT only) or NULL (local Computer)
4891 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4892 * Level [I] Structure-Level (must be 1)
4893 * pDriverDirectory [O] PTR to Buffer that receives the Result
4894 * cbBuf [I] Size of Buffer at pDriverDirectory
4895 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4896 * required for pDriverDirectory
4899 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4900 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4901 * if cbBuf is too small
4903 * Native Values returned in pDriverDirectory on Success:
4904 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4905 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4906 *| win9x(Windows 4.0): "%winsysdir%"
4908 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4911 *- Only NULL or "" is supported for pName
4914 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4915 DWORD Level, LPBYTE pDriverDirectory,
4916 DWORD cbBuf, LPDWORD pcbNeeded)
4918 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4919 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4921 if ((backend == NULL) && !load_backend()) return FALSE;
4924 /* (Level != 1) is ignored in win9x */
4925 SetLastError(ERROR_INVALID_LEVEL);
4928 if (pcbNeeded == NULL) {
4929 /* (pcbNeeded == NULL) is ignored in win9x */
4930 SetLastError(RPC_X_NULL_REF_POINTER);
4934 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4935 pDriverDirectory, cbBuf, pcbNeeded);
4940 /*****************************************************************************
4941 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4943 * Return the PATH for the Printer-Drivers (ANSI)
4945 * See GetPrinterDriverDirectoryW.
4948 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4951 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4952 DWORD Level, LPBYTE pDriverDirectory,
4953 DWORD cbBuf, LPDWORD pcbNeeded)
4955 UNICODE_STRING nameW, environmentW;
4958 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4959 WCHAR *driverDirectoryW = NULL;
4961 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4962 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4964 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4966 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4967 else nameW.Buffer = NULL;
4968 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4969 else environmentW.Buffer = NULL;
4971 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4972 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4975 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4976 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4978 *pcbNeeded = needed;
4979 ret = (needed <= cbBuf) ? TRUE : FALSE;
4981 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4983 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4985 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4986 RtlFreeUnicodeString(&environmentW);
4987 RtlFreeUnicodeString(&nameW);
4992 /*****************************************************************************
4993 * AddPrinterDriverA [WINSPOOL.@]
4995 * See AddPrinterDriverW.
4998 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5000 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5001 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5004 /******************************************************************************
5005 * AddPrinterDriverW (WINSPOOL.@)
5007 * Install a Printer Driver
5010 * pName [I] Servername or NULL (local Computer)
5011 * level [I] Level for the supplied DRIVER_INFO_*W struct
5012 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5019 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5021 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5022 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5025 /*****************************************************************************
5026 * AddPrintProcessorA [WINSPOOL.@]
5028 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5029 LPSTR pPrintProcessorName)
5031 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5032 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5036 /*****************************************************************************
5037 * AddPrintProcessorW [WINSPOOL.@]
5039 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5040 LPWSTR pPrintProcessorName)
5042 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5043 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5047 /*****************************************************************************
5048 * AddPrintProvidorA [WINSPOOL.@]
5050 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5052 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5056 /*****************************************************************************
5057 * AddPrintProvidorW [WINSPOOL.@]
5059 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5061 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5065 /*****************************************************************************
5066 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5068 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5069 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5071 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5072 pDevModeOutput, pDevModeInput);
5076 /*****************************************************************************
5077 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5079 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5080 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5082 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5083 pDevModeOutput, pDevModeInput);
5087 /*****************************************************************************
5088 * PrinterProperties [WINSPOOL.@]
5090 * Displays a dialog to set the properties of the printer.
5093 * nonzero on success or zero on failure
5096 * implemented as stub only
5098 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5099 HANDLE hPrinter /* [in] handle to printer object */
5101 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5102 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5106 /*****************************************************************************
5107 * EnumJobsA [WINSPOOL.@]
5110 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5111 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5114 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5115 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5117 if(pcbNeeded) *pcbNeeded = 0;
5118 if(pcReturned) *pcReturned = 0;
5123 /*****************************************************************************
5124 * EnumJobsW [WINSPOOL.@]
5127 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5128 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5131 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5132 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5134 if(pcbNeeded) *pcbNeeded = 0;
5135 if(pcReturned) *pcReturned = 0;
5139 /*****************************************************************************
5140 * WINSPOOL_EnumPrinterDrivers [internal]
5142 * Delivers information about all printer drivers installed on the
5143 * localhost or a given server
5146 * nonzero on success or zero on failure. If the buffer for the returned
5147 * information is too small the function will return an error
5150 * - only implemented for localhost, foreign hosts will return an error
5152 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5153 DWORD Level, LPBYTE pDriverInfo,
5154 DWORD cbBuf, LPDWORD pcbNeeded,
5155 LPDWORD pcReturned, BOOL unicode)
5158 DWORD i, needed, number = 0, size = 0;
5159 WCHAR DriverNameW[255];
5161 const printenv_t * env;
5163 TRACE("%s,%s,%d,%p,%d,%d\n",
5164 debugstr_w(pName), debugstr_w(pEnvironment),
5165 Level, pDriverInfo, cbBuf, unicode);
5167 /* check for local drivers */
5168 if((pName) && (pName[0])) {
5169 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5170 SetLastError(ERROR_ACCESS_DENIED);
5174 env = validate_envW(pEnvironment);
5175 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5177 /* check input parameter */
5178 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5179 SetLastError(ERROR_INVALID_LEVEL);
5183 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5184 SetLastError(RPC_X_NULL_REF_POINTER);
5188 /* initialize return values */
5190 memset( pDriverInfo, 0, cbBuf);
5194 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5196 ERR("Can't open Drivers key\n");
5200 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5201 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5202 RegCloseKey(hkeyDrivers);
5203 ERR("Can't query Drivers key\n");
5206 TRACE("Found %d Drivers\n", number);
5208 /* get size of single struct
5209 * unicode and ascii structure have the same size
5211 size = di_sizeof[Level];
5213 /* calculate required buffer size */
5214 *pcbNeeded = size * number;
5216 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5218 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5219 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5221 ERR("Can't enum key number %d\n", i);
5222 RegCloseKey(hkeyDrivers);
5225 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5227 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5228 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5229 &needed, unicode)) {
5230 RegCloseKey(hkeyDrivers);
5233 (*pcbNeeded) += needed;
5236 RegCloseKey(hkeyDrivers);
5238 if(cbBuf < *pcbNeeded){
5239 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5243 *pcReturned = number;
5247 /*****************************************************************************
5248 * EnumPrinterDriversW [WINSPOOL.@]
5250 * see function EnumPrinterDrivers for RETURNS, BUGS
5252 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5253 LPBYTE pDriverInfo, DWORD cbBuf,
5254 LPDWORD pcbNeeded, LPDWORD pcReturned)
5256 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5257 cbBuf, pcbNeeded, pcReturned, TRUE);
5260 /*****************************************************************************
5261 * EnumPrinterDriversA [WINSPOOL.@]
5263 * see function EnumPrinterDrivers for RETURNS, BUGS
5265 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5266 LPBYTE pDriverInfo, DWORD cbBuf,
5267 LPDWORD pcbNeeded, LPDWORD pcReturned)
5269 UNICODE_STRING pNameW, pEnvironmentW;
5270 PWSTR pwstrNameW, pwstrEnvironmentW;
5272 pwstrNameW = asciitounicode(&pNameW, pName);
5273 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5275 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5276 Level, pDriverInfo, cbBuf, pcbNeeded,
5278 RtlFreeUnicodeString(&pNameW);
5279 RtlFreeUnicodeString(&pEnvironmentW);
5284 /******************************************************************************
5285 * EnumPortsA (WINSPOOL.@)
5290 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5291 LPDWORD pcbNeeded, LPDWORD pcReturned)
5294 LPBYTE bufferW = NULL;
5295 LPWSTR nameW = NULL;
5297 DWORD numentries = 0;
5300 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5301 cbBuf, pcbNeeded, pcReturned);
5303 /* convert servername to unicode */
5305 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5306 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5307 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5309 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5310 needed = cbBuf * sizeof(WCHAR);
5311 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5312 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5314 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5315 if (pcbNeeded) needed = *pcbNeeded;
5316 /* HeapReAlloc return NULL, when bufferW was NULL */
5317 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5318 HeapAlloc(GetProcessHeap(), 0, needed);
5320 /* Try again with the large Buffer */
5321 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5323 needed = pcbNeeded ? *pcbNeeded : 0;
5324 numentries = pcReturned ? *pcReturned : 0;
5327 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5328 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5331 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5332 DWORD entrysize = 0;
5335 LPPORT_INFO_2W pi2w;
5336 LPPORT_INFO_2A pi2a;
5339 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5341 /* First pass: calculate the size for all Entries */
5342 pi2w = (LPPORT_INFO_2W) bufferW;
5343 pi2a = (LPPORT_INFO_2A) pPorts;
5345 while (index < numentries) {
5347 needed += entrysize; /* PORT_INFO_?A */
5348 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5350 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5351 NULL, 0, NULL, NULL);
5353 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5354 NULL, 0, NULL, NULL);
5355 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5356 NULL, 0, NULL, NULL);
5358 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5359 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5360 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5363 /* check for errors and quit on failure */
5364 if (cbBuf < needed) {
5365 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5369 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5370 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5371 cbBuf -= len ; /* free Bytes in the user-Buffer */
5372 pi2w = (LPPORT_INFO_2W) bufferW;
5373 pi2a = (LPPORT_INFO_2A) pPorts;
5375 /* Second Pass: Fill the User Buffer (if we have one) */
5376 while ((index < numentries) && pPorts) {
5378 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5379 pi2a->pPortName = ptr;
5380 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5381 ptr, cbBuf , NULL, NULL);
5385 pi2a->pMonitorName = ptr;
5386 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5387 ptr, cbBuf, NULL, NULL);
5391 pi2a->pDescription = ptr;
5392 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5393 ptr, cbBuf, NULL, NULL);
5397 pi2a->fPortType = pi2w->fPortType;
5398 pi2a->Reserved = 0; /* documented: "must be zero" */
5401 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5402 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5403 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5408 if (pcbNeeded) *pcbNeeded = needed;
5409 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5411 HeapFree(GetProcessHeap(), 0, nameW);
5412 HeapFree(GetProcessHeap(), 0, bufferW);
5414 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5415 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5421 /******************************************************************************
5422 * EnumPortsW (WINSPOOL.@)
5424 * Enumerate available Ports
5427 * name [I] Servername or NULL (local Computer)
5428 * level [I] Structure-Level (1 or 2)
5429 * buffer [O] PTR to Buffer that receives the Result
5430 * bufsize [I] Size of Buffer at buffer
5431 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5432 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5436 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5440 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5443 DWORD numentries = 0;
5446 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5447 cbBuf, pcbNeeded, pcReturned);
5449 if (pName && (pName[0])) {
5450 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5451 SetLastError(ERROR_ACCESS_DENIED);
5455 /* Level is not checked in win9x */
5456 if (!Level || (Level > 2)) {
5457 WARN("level (%d) is ignored in win9x\n", Level);
5458 SetLastError(ERROR_INVALID_LEVEL);
5462 SetLastError(RPC_X_NULL_REF_POINTER);
5466 EnterCriticalSection(&monitor_handles_cs);
5469 /* Scan all local Ports */
5471 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5473 /* we calculated the needed buffersize. now do the error-checks */
5474 if (cbBuf < needed) {
5475 monitor_unloadall();
5476 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5477 goto emP_cleanup_cs;
5479 else if (!pPorts || !pcReturned) {
5480 monitor_unloadall();
5481 SetLastError(RPC_X_NULL_REF_POINTER);
5482 goto emP_cleanup_cs;
5485 /* Fill the Buffer */
5486 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5488 monitor_unloadall();
5491 LeaveCriticalSection(&monitor_handles_cs);
5494 if (pcbNeeded) *pcbNeeded = needed;
5495 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5497 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5498 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5503 /******************************************************************************
5504 * GetDefaultPrinterW (WINSPOOL.@)
5507 * This function must read the value from data 'device' of key
5508 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5510 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5514 WCHAR *buffer, *ptr;
5518 SetLastError(ERROR_INVALID_PARAMETER);
5522 /* make the buffer big enough for the stuff from the profile/registry,
5523 * the content must fit into the local buffer to compute the correct
5524 * size even if the extern buffer is too small or not given.
5525 * (20 for ,driver,port) */
5527 len = max(100, (insize + 20));
5528 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5530 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5532 SetLastError (ERROR_FILE_NOT_FOUND);
5536 TRACE("%s\n", debugstr_w(buffer));
5538 if ((ptr = strchrW(buffer, ',')) == NULL)
5540 SetLastError(ERROR_INVALID_NAME);
5546 *namesize = strlenW(buffer) + 1;
5547 if(!name || (*namesize > insize))
5549 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5553 strcpyW(name, buffer);
5556 HeapFree( GetProcessHeap(), 0, buffer);
5561 /******************************************************************************
5562 * GetDefaultPrinterA (WINSPOOL.@)
5564 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5568 WCHAR *bufferW = NULL;
5572 SetLastError(ERROR_INVALID_PARAMETER);
5576 if(name && *namesize) {
5578 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5581 if(!GetDefaultPrinterW( bufferW, namesize)) {
5586 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5590 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5593 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5596 HeapFree( GetProcessHeap(), 0, bufferW);
5601 /******************************************************************************
5602 * SetDefaultPrinterW (WINSPOOL.204)
5604 * Set the Name of the Default Printer
5607 * pszPrinter [I] Name of the Printer or NULL
5614 * When the Parameter is NULL or points to an Empty String and
5615 * a Default Printer was already present, then this Function changes nothing.
5616 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5617 * the First enumerated local Printer is used.
5620 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5623 TRACE("(%s)\n", debugstr_w(pszPrinter));
5625 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5629 /******************************************************************************
5630 * SetDefaultPrinterA (WINSPOOL.202)
5632 * See SetDefaultPrinterW.
5635 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5638 TRACE("(%s)\n", debugstr_a(pszPrinter));
5640 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5645 /******************************************************************************
5646 * SetPrinterDataExA (WINSPOOL.@)
5648 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5649 LPCSTR pValueName, DWORD Type,
5650 LPBYTE pData, DWORD cbData)
5652 HKEY hkeyPrinter, hkeySubkey;
5655 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5656 debugstr_a(pValueName), Type, pData, cbData);
5658 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5662 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5664 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5665 RegCloseKey(hkeyPrinter);
5668 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5669 RegCloseKey(hkeySubkey);
5670 RegCloseKey(hkeyPrinter);
5674 /******************************************************************************
5675 * SetPrinterDataExW (WINSPOOL.@)
5677 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5678 LPCWSTR pValueName, DWORD Type,
5679 LPBYTE pData, DWORD cbData)
5681 HKEY hkeyPrinter, hkeySubkey;
5684 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5685 debugstr_w(pValueName), Type, pData, cbData);
5687 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5691 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5693 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5694 RegCloseKey(hkeyPrinter);
5697 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5698 RegCloseKey(hkeySubkey);
5699 RegCloseKey(hkeyPrinter);
5703 /******************************************************************************
5704 * SetPrinterDataA (WINSPOOL.@)
5706 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5707 LPBYTE pData, DWORD cbData)
5709 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5713 /******************************************************************************
5714 * SetPrinterDataW (WINSPOOL.@)
5716 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5717 LPBYTE pData, DWORD cbData)
5719 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5723 /******************************************************************************
5724 * GetPrinterDataExA (WINSPOOL.@)
5726 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5727 LPCSTR pValueName, LPDWORD pType,
5728 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5730 HKEY hkeyPrinter, hkeySubkey;
5733 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5734 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5737 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5741 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5743 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5744 RegCloseKey(hkeyPrinter);
5748 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5749 RegCloseKey(hkeySubkey);
5750 RegCloseKey(hkeyPrinter);
5754 /******************************************************************************
5755 * GetPrinterDataExW (WINSPOOL.@)
5757 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5758 LPCWSTR pValueName, LPDWORD pType,
5759 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5761 HKEY hkeyPrinter, hkeySubkey;
5764 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5765 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5768 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5772 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5774 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5775 RegCloseKey(hkeyPrinter);
5779 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5780 RegCloseKey(hkeySubkey);
5781 RegCloseKey(hkeyPrinter);
5785 /******************************************************************************
5786 * GetPrinterDataA (WINSPOOL.@)
5788 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5789 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5791 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5792 pData, nSize, pcbNeeded);
5795 /******************************************************************************
5796 * GetPrinterDataW (WINSPOOL.@)
5798 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5799 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5801 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5802 pData, nSize, pcbNeeded);
5805 /*******************************************************************************
5806 * EnumPrinterDataExW [WINSPOOL.@]
5808 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5809 LPBYTE pEnumValues, DWORD cbEnumValues,
5810 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5812 HKEY hkPrinter, hkSubKey;
5813 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5814 cbValueNameLen, cbMaxValueLen, cbValueLen,
5819 PPRINTER_ENUM_VALUESW ppev;
5821 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5823 if (pKeyName == NULL || *pKeyName == 0)
5824 return ERROR_INVALID_PARAMETER;
5826 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5827 if (ret != ERROR_SUCCESS)
5829 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5834 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5835 if (ret != ERROR_SUCCESS)
5837 r = RegCloseKey (hkPrinter);
5838 if (r != ERROR_SUCCESS)
5839 WARN ("RegCloseKey returned %i\n", r);
5840 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5841 debugstr_w (pKeyName), ret);
5845 ret = RegCloseKey (hkPrinter);
5846 if (ret != ERROR_SUCCESS)
5848 ERR ("RegCloseKey returned %i\n", ret);
5849 r = RegCloseKey (hkSubKey);
5850 if (r != ERROR_SUCCESS)
5851 WARN ("RegCloseKey returned %i\n", r);
5855 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5856 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5857 if (ret != ERROR_SUCCESS)
5859 r = RegCloseKey (hkSubKey);
5860 if (r != ERROR_SUCCESS)
5861 WARN ("RegCloseKey returned %i\n", r);
5862 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5866 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5867 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5869 if (cValues == 0) /* empty key */
5871 r = RegCloseKey (hkSubKey);
5872 if (r != ERROR_SUCCESS)
5873 WARN ("RegCloseKey returned %i\n", r);
5874 *pcbEnumValues = *pnEnumValues = 0;
5875 return ERROR_SUCCESS;
5878 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5880 hHeap = GetProcessHeap ();
5883 ERR ("GetProcessHeap failed\n");
5884 r = RegCloseKey (hkSubKey);
5885 if (r != ERROR_SUCCESS)
5886 WARN ("RegCloseKey returned %i\n", r);
5887 return ERROR_OUTOFMEMORY;
5890 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5891 if (lpValueName == NULL)
5893 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5894 r = RegCloseKey (hkSubKey);
5895 if (r != ERROR_SUCCESS)
5896 WARN ("RegCloseKey returned %i\n", r);
5897 return ERROR_OUTOFMEMORY;
5900 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5901 if (lpValue == NULL)
5903 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5904 if (HeapFree (hHeap, 0, lpValueName) == 0)
5905 WARN ("HeapFree failed with code %i\n", GetLastError ());
5906 r = RegCloseKey (hkSubKey);
5907 if (r != ERROR_SUCCESS)
5908 WARN ("RegCloseKey returned %i\n", r);
5909 return ERROR_OUTOFMEMORY;
5912 TRACE ("pass 1: calculating buffer required for all names and values\n");
5914 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5916 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5918 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5920 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5921 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5922 NULL, NULL, lpValue, &cbValueLen);
5923 if (ret != ERROR_SUCCESS)
5925 if (HeapFree (hHeap, 0, lpValue) == 0)
5926 WARN ("HeapFree failed with code %i\n", GetLastError ());
5927 if (HeapFree (hHeap, 0, lpValueName) == 0)
5928 WARN ("HeapFree failed with code %i\n", GetLastError ());
5929 r = RegCloseKey (hkSubKey);
5930 if (r != ERROR_SUCCESS)
5931 WARN ("RegCloseKey returned %i\n", r);
5932 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5936 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5937 debugstr_w (lpValueName), dwIndex,
5938 cbValueNameLen + 1, cbValueLen);
5940 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5941 cbBufSize += cbValueLen;
5944 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5946 *pcbEnumValues = cbBufSize;
5947 *pnEnumValues = cValues;
5949 if (cbEnumValues < cbBufSize) /* buffer too small */
5951 if (HeapFree (hHeap, 0, lpValue) == 0)
5952 WARN ("HeapFree failed with code %i\n", GetLastError ());
5953 if (HeapFree (hHeap, 0, lpValueName) == 0)
5954 WARN ("HeapFree failed with code %i\n", GetLastError ());
5955 r = RegCloseKey (hkSubKey);
5956 if (r != ERROR_SUCCESS)
5957 WARN ("RegCloseKey returned %i\n", r);
5958 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5959 return ERROR_MORE_DATA;
5962 TRACE ("pass 2: copying all names and values to buffer\n");
5964 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5965 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5967 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5969 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5970 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5971 NULL, &dwType, lpValue, &cbValueLen);
5972 if (ret != ERROR_SUCCESS)
5974 if (HeapFree (hHeap, 0, lpValue) == 0)
5975 WARN ("HeapFree failed with code %i\n", GetLastError ());
5976 if (HeapFree (hHeap, 0, lpValueName) == 0)
5977 WARN ("HeapFree failed with code %i\n", GetLastError ());
5978 r = RegCloseKey (hkSubKey);
5979 if (r != ERROR_SUCCESS)
5980 WARN ("RegCloseKey returned %i\n", r);
5981 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5985 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5986 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5987 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5988 pEnumValues += cbValueNameLen;
5990 /* return # of *bytes* (including trailing \0), not # of chars */
5991 ppev[dwIndex].cbValueName = cbValueNameLen;
5993 ppev[dwIndex].dwType = dwType;
5995 memcpy (pEnumValues, lpValue, cbValueLen);
5996 ppev[dwIndex].pData = pEnumValues;
5997 pEnumValues += cbValueLen;
5999 ppev[dwIndex].cbData = cbValueLen;
6001 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6002 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6005 if (HeapFree (hHeap, 0, lpValue) == 0)
6007 ret = GetLastError ();
6008 ERR ("HeapFree failed with code %i\n", ret);
6009 if (HeapFree (hHeap, 0, lpValueName) == 0)
6010 WARN ("HeapFree failed with code %i\n", GetLastError ());
6011 r = RegCloseKey (hkSubKey);
6012 if (r != ERROR_SUCCESS)
6013 WARN ("RegCloseKey returned %i\n", r);
6017 if (HeapFree (hHeap, 0, lpValueName) == 0)
6019 ret = GetLastError ();
6020 ERR ("HeapFree failed with code %i\n", ret);
6021 r = RegCloseKey (hkSubKey);
6022 if (r != ERROR_SUCCESS)
6023 WARN ("RegCloseKey returned %i\n", r);
6027 ret = RegCloseKey (hkSubKey);
6028 if (ret != ERROR_SUCCESS)
6030 ERR ("RegCloseKey returned %i\n", ret);
6034 return ERROR_SUCCESS;
6037 /*******************************************************************************
6038 * EnumPrinterDataExA [WINSPOOL.@]
6040 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6041 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6042 * what Windows 2000 SP1 does.
6045 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6046 LPBYTE pEnumValues, DWORD cbEnumValues,
6047 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6051 DWORD ret, dwIndex, dwBufSize;
6055 TRACE ("%p %s\n", hPrinter, pKeyName);
6057 if (pKeyName == NULL || *pKeyName == 0)
6058 return ERROR_INVALID_PARAMETER;
6060 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6063 ret = GetLastError ();
6064 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6068 hHeap = GetProcessHeap ();
6071 ERR ("GetProcessHeap failed\n");
6072 return ERROR_OUTOFMEMORY;
6075 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6076 if (pKeyNameW == NULL)
6078 ERR ("Failed to allocate %i bytes from process heap\n",
6079 (LONG)(len * sizeof (WCHAR)));
6080 return ERROR_OUTOFMEMORY;
6083 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6085 ret = GetLastError ();
6086 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6087 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6088 WARN ("HeapFree failed with code %i\n", GetLastError ());
6092 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6093 pcbEnumValues, pnEnumValues);
6094 if (ret != ERROR_SUCCESS)
6096 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6097 WARN ("HeapFree failed with code %i\n", GetLastError ());
6098 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6102 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6104 ret = GetLastError ();
6105 ERR ("HeapFree failed with code %i\n", ret);
6109 if (*pnEnumValues == 0) /* empty key */
6110 return ERROR_SUCCESS;
6113 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6115 PPRINTER_ENUM_VALUESW ppev =
6116 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6118 if (dwBufSize < ppev->cbValueName)
6119 dwBufSize = ppev->cbValueName;
6121 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6122 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6123 dwBufSize = ppev->cbData;
6126 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6128 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6129 if (pBuffer == NULL)
6131 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6132 return ERROR_OUTOFMEMORY;
6135 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6137 PPRINTER_ENUM_VALUESW ppev =
6138 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6140 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6141 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6145 ret = GetLastError ();
6146 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6147 if (HeapFree (hHeap, 0, pBuffer) == 0)
6148 WARN ("HeapFree failed with code %i\n", GetLastError ());
6152 memcpy (ppev->pValueName, pBuffer, len);
6154 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6156 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6157 ppev->dwType != REG_MULTI_SZ)
6160 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6161 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6164 ret = GetLastError ();
6165 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6166 if (HeapFree (hHeap, 0, pBuffer) == 0)
6167 WARN ("HeapFree failed with code %i\n", GetLastError ());
6171 memcpy (ppev->pData, pBuffer, len);
6173 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6174 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6177 if (HeapFree (hHeap, 0, pBuffer) == 0)
6179 ret = GetLastError ();
6180 ERR ("HeapFree failed with code %i\n", ret);
6184 return ERROR_SUCCESS;
6187 /******************************************************************************
6188 * AbortPrinter (WINSPOOL.@)
6190 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6192 FIXME("(%p), stub!\n", hPrinter);
6196 /******************************************************************************
6197 * AddPortA (WINSPOOL.@)
6202 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6204 LPWSTR nameW = NULL;
6205 LPWSTR monitorW = NULL;
6209 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6212 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6213 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6214 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6218 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6219 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6220 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6222 res = AddPortW(nameW, hWnd, monitorW);
6223 HeapFree(GetProcessHeap(), 0, nameW);
6224 HeapFree(GetProcessHeap(), 0, monitorW);
6228 /******************************************************************************
6229 * AddPortW (WINSPOOL.@)
6231 * Add a Port for a specific Monitor
6234 * pName [I] Servername or NULL (local Computer)
6235 * hWnd [I] Handle to parent Window for the Dialog-Box
6236 * pMonitorName [I] Name of the Monitor that manage the Port
6243 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6249 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6251 if (pName && pName[0]) {
6252 SetLastError(ERROR_INVALID_PARAMETER);
6256 if (!pMonitorName) {
6257 SetLastError(RPC_X_NULL_REF_POINTER);
6261 /* an empty Monitorname is Invalid */
6262 if (!pMonitorName[0]) {
6263 SetLastError(ERROR_NOT_SUPPORTED);
6267 pm = monitor_load(pMonitorName, NULL);
6268 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6269 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6270 TRACE("got %d with %u\n", res, GetLastError());
6275 pui = monitor_loadui(pm);
6276 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6277 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6278 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6279 TRACE("got %d with %u\n", res, GetLastError());
6284 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6285 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6287 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6288 SetLastError(ERROR_NOT_SUPPORTED);
6291 monitor_unload(pui);
6294 TRACE("returning %d with %u\n", res, GetLastError());
6298 /******************************************************************************
6299 * AddPortExA (WINSPOOL.@)
6304 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6307 PORT_INFO_2A * pi2A;
6308 LPWSTR nameW = NULL;
6309 LPWSTR monitorW = NULL;
6313 pi2A = (PORT_INFO_2A *) pBuffer;
6315 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6316 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6318 if ((level < 1) || (level > 2)) {
6319 SetLastError(ERROR_INVALID_LEVEL);
6324 SetLastError(ERROR_INVALID_PARAMETER);
6329 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6330 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6331 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6335 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6336 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6337 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6340 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6342 if (pi2A->pPortName) {
6343 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6344 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6345 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6349 if (pi2A->pMonitorName) {
6350 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6351 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6352 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6355 if (pi2A->pDescription) {
6356 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6357 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6358 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6360 pi2W.fPortType = pi2A->fPortType;
6361 pi2W.Reserved = pi2A->Reserved;
6364 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6366 HeapFree(GetProcessHeap(), 0, nameW);
6367 HeapFree(GetProcessHeap(), 0, monitorW);
6368 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6369 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6370 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6375 /******************************************************************************
6376 * AddPortExW (WINSPOOL.@)
6378 * Add a Port for a specific Monitor, without presenting a user interface
6381 * pName [I] Servername or NULL (local Computer)
6382 * level [I] Structure-Level (1 or 2) for pBuffer
6383 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6384 * pMonitorName [I] Name of the Monitor that manage the Port
6391 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6397 pi2 = (PORT_INFO_2W *) pBuffer;
6399 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6400 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6401 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6402 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6405 if ((level < 1) || (level > 2)) {
6406 SetLastError(ERROR_INVALID_LEVEL);
6410 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6411 SetLastError(ERROR_INVALID_PARAMETER);
6415 /* load the Monitor */
6416 pm = monitor_load(pMonitorName, NULL);
6418 SetLastError(ERROR_INVALID_PARAMETER);
6422 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6423 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6424 TRACE("got %u with %u\n", res, GetLastError());
6428 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6434 /******************************************************************************
6435 * AddPrinterConnectionA (WINSPOOL.@)
6437 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6439 FIXME("%s\n", debugstr_a(pName));
6443 /******************************************************************************
6444 * AddPrinterConnectionW (WINSPOOL.@)
6446 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6448 FIXME("%s\n", debugstr_w(pName));
6452 /******************************************************************************
6453 * AddPrinterDriverExW (WINSPOOL.@)
6455 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6458 * pName [I] Servername or NULL (local Computer)
6459 * level [I] Level for the supplied DRIVER_INFO_*W struct
6460 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6461 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6468 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6470 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6472 if ((backend == NULL) && !load_backend()) return FALSE;
6474 if (level < 2 || level == 5 || level == 7 || level > 8) {
6475 SetLastError(ERROR_INVALID_LEVEL);
6480 SetLastError(ERROR_INVALID_PARAMETER);
6484 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6487 /******************************************************************************
6488 * AddPrinterDriverExA (WINSPOOL.@)
6490 * See AddPrinterDriverExW.
6493 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6495 DRIVER_INFO_8A *diA;
6497 LPWSTR nameW = NULL;
6502 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6504 diA = (DRIVER_INFO_8A *) pDriverInfo;
6505 ZeroMemory(&diW, sizeof(diW));
6507 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6508 SetLastError(ERROR_INVALID_LEVEL);
6513 SetLastError(ERROR_INVALID_PARAMETER);
6517 /* convert servername to unicode */
6519 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6520 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6521 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6525 diW.cVersion = diA->cVersion;
6528 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6529 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6530 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6533 if (diA->pEnvironment) {
6534 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6535 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6536 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6539 if (diA->pDriverPath) {
6540 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6541 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6542 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6545 if (diA->pDataFile) {
6546 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6547 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6548 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6551 if (diA->pConfigFile) {
6552 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6553 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6554 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6557 if ((Level > 2) && diA->pDependentFiles) {
6558 lenA = multi_sz_lenA(diA->pDependentFiles);
6559 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6560 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6561 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6564 if ((Level > 2) && diA->pMonitorName) {
6565 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6566 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6567 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6570 if ((Level > 3) && diA->pDefaultDataType) {
6571 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6572 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6573 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6576 if ((Level > 3) && diA->pszzPreviousNames) {
6577 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6578 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6579 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6580 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6583 if ((Level > 5) && diA->pszMfgName) {
6584 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6585 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6586 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6589 if ((Level > 5) && diA->pszOEMUrl) {
6590 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6591 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6592 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6595 if ((Level > 5) && diA->pszHardwareID) {
6596 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6597 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6598 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6601 if ((Level > 5) && diA->pszProvider) {
6602 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6603 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6604 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6608 FIXME("level %u is incomplete\n", Level);
6611 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6612 TRACE("got %u with %u\n", res, GetLastError());
6613 HeapFree(GetProcessHeap(), 0, nameW);
6614 HeapFree(GetProcessHeap(), 0, diW.pName);
6615 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6616 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6617 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6618 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6619 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6620 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6621 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6622 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6623 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6624 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6625 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6626 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6628 TRACE("=> %u with %u\n", res, GetLastError());
6632 /******************************************************************************
6633 * ConfigurePortA (WINSPOOL.@)
6635 * See ConfigurePortW.
6638 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6640 LPWSTR nameW = NULL;
6641 LPWSTR portW = NULL;
6645 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6647 /* convert servername to unicode */
6649 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6650 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6651 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6654 /* convert portname to unicode */
6656 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6657 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6658 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6661 res = ConfigurePortW(nameW, hWnd, portW);
6662 HeapFree(GetProcessHeap(), 0, nameW);
6663 HeapFree(GetProcessHeap(), 0, portW);
6667 /******************************************************************************
6668 * ConfigurePortW (WINSPOOL.@)
6670 * Display the Configuration-Dialog for a specific Port
6673 * pName [I] Servername or NULL (local Computer)
6674 * hWnd [I] Handle to parent Window for the Dialog-Box
6675 * pPortName [I] Name of the Port, that should be configured
6682 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6688 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6690 if (pName && pName[0]) {
6691 SetLastError(ERROR_INVALID_PARAMETER);
6696 SetLastError(RPC_X_NULL_REF_POINTER);
6700 /* an empty Portname is Invalid, but can popup a Dialog */
6701 if (!pPortName[0]) {
6702 SetLastError(ERROR_NOT_SUPPORTED);
6706 pm = monitor_load_by_port(pPortName);
6707 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6708 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6709 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6710 TRACE("got %d with %u\n", res, GetLastError());
6714 pui = monitor_loadui(pm);
6715 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6716 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6717 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6718 TRACE("got %d with %u\n", res, GetLastError());
6722 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6723 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6725 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6726 SetLastError(ERROR_NOT_SUPPORTED);
6729 monitor_unload(pui);
6733 TRACE("returning %d with %u\n", res, GetLastError());
6737 /******************************************************************************
6738 * ConnectToPrinterDlg (WINSPOOL.@)
6740 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6742 FIXME("%p %x\n", hWnd, Flags);
6746 /******************************************************************************
6747 * DeletePrinterConnectionA (WINSPOOL.@)
6749 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6751 FIXME("%s\n", debugstr_a(pName));
6755 /******************************************************************************
6756 * DeletePrinterConnectionW (WINSPOOL.@)
6758 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6760 FIXME("%s\n", debugstr_w(pName));
6764 /******************************************************************************
6765 * DeletePrinterDriverExW (WINSPOOL.@)
6767 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6768 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6773 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6774 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6776 if(pName && pName[0])
6778 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6779 SetLastError(ERROR_INVALID_PARAMETER);
6785 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6786 SetLastError(ERROR_INVALID_PARAMETER);
6790 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6794 ERR("Can't open drivers key\n");
6798 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6801 RegCloseKey(hkey_drivers);
6806 /******************************************************************************
6807 * DeletePrinterDriverExA (WINSPOOL.@)
6809 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6810 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6812 UNICODE_STRING NameW, EnvW, DriverW;
6815 asciitounicode(&NameW, pName);
6816 asciitounicode(&EnvW, pEnvironment);
6817 asciitounicode(&DriverW, pDriverName);
6819 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6821 RtlFreeUnicodeString(&DriverW);
6822 RtlFreeUnicodeString(&EnvW);
6823 RtlFreeUnicodeString(&NameW);
6828 /******************************************************************************
6829 * DeletePrinterDataExW (WINSPOOL.@)
6831 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6834 FIXME("%p %s %s\n", hPrinter,
6835 debugstr_w(pKeyName), debugstr_w(pValueName));
6836 return ERROR_INVALID_PARAMETER;
6839 /******************************************************************************
6840 * DeletePrinterDataExA (WINSPOOL.@)
6842 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6845 FIXME("%p %s %s\n", hPrinter,
6846 debugstr_a(pKeyName), debugstr_a(pValueName));
6847 return ERROR_INVALID_PARAMETER;
6850 /******************************************************************************
6851 * DeletePrintProcessorA (WINSPOOL.@)
6853 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6855 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6856 debugstr_a(pPrintProcessorName));
6860 /******************************************************************************
6861 * DeletePrintProcessorW (WINSPOOL.@)
6863 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6865 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6866 debugstr_w(pPrintProcessorName));
6870 /******************************************************************************
6871 * DeletePrintProvidorA (WINSPOOL.@)
6873 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6875 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6876 debugstr_a(pPrintProviderName));
6880 /******************************************************************************
6881 * DeletePrintProvidorW (WINSPOOL.@)
6883 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6885 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6886 debugstr_w(pPrintProviderName));
6890 /******************************************************************************
6891 * EnumFormsA (WINSPOOL.@)
6893 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6894 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6896 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6897 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6901 /******************************************************************************
6902 * EnumFormsW (WINSPOOL.@)
6904 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6905 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6907 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6908 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6912 /*****************************************************************************
6913 * EnumMonitorsA [WINSPOOL.@]
6915 * See EnumMonitorsW.
6918 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6919 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6922 LPBYTE bufferW = NULL;
6923 LPWSTR nameW = NULL;
6925 DWORD numentries = 0;
6928 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6929 cbBuf, pcbNeeded, pcReturned);
6931 /* convert servername to unicode */
6933 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6934 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6935 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6937 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6938 needed = cbBuf * sizeof(WCHAR);
6939 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6940 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6942 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6943 if (pcbNeeded) needed = *pcbNeeded;
6944 /* HeapReAlloc return NULL, when bufferW was NULL */
6945 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6946 HeapAlloc(GetProcessHeap(), 0, needed);
6948 /* Try again with the large Buffer */
6949 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6951 numentries = pcReturned ? *pcReturned : 0;
6954 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6955 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6958 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6959 DWORD entrysize = 0;
6962 LPMONITOR_INFO_2W mi2w;
6963 LPMONITOR_INFO_2A mi2a;
6965 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6966 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6968 /* First pass: calculate the size for all Entries */
6969 mi2w = (LPMONITOR_INFO_2W) bufferW;
6970 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6972 while (index < numentries) {
6974 needed += entrysize; /* MONITOR_INFO_?A */
6975 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6977 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6978 NULL, 0, NULL, NULL);
6980 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6981 NULL, 0, NULL, NULL);
6982 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6983 NULL, 0, NULL, NULL);
6985 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6986 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6987 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6990 /* check for errors and quit on failure */
6991 if (cbBuf < needed) {
6992 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6996 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6997 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6998 cbBuf -= len ; /* free Bytes in the user-Buffer */
6999 mi2w = (LPMONITOR_INFO_2W) bufferW;
7000 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7002 /* Second Pass: Fill the User Buffer (if we have one) */
7003 while ((index < numentries) && pMonitors) {
7005 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7007 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7008 ptr, cbBuf , NULL, NULL);
7012 mi2a->pEnvironment = ptr;
7013 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7014 ptr, cbBuf, NULL, NULL);
7018 mi2a->pDLLName = ptr;
7019 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7020 ptr, cbBuf, NULL, NULL);
7024 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7025 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7026 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7030 if (pcbNeeded) *pcbNeeded = needed;
7031 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7033 HeapFree(GetProcessHeap(), 0, nameW);
7034 HeapFree(GetProcessHeap(), 0, bufferW);
7036 TRACE("returning %d with %d (%d byte for %d entries)\n",
7037 (res), GetLastError(), needed, numentries);
7043 /*****************************************************************************
7044 * EnumMonitorsW [WINSPOOL.@]
7046 * Enumerate available Port-Monitors
7049 * pName [I] Servername or NULL (local Computer)
7050 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7051 * pMonitors [O] PTR to Buffer that receives the Result
7052 * cbBuf [I] Size of Buffer at pMonitors
7053 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7054 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7058 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7061 * Windows reads the Registry once and cache the Results.
7063 *| Language-Monitors are also installed in the same Registry-Location but
7064 *| they are filtered in Windows (not returned by EnumMonitors).
7065 *| We do no filtering to simplify our Code.
7068 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7069 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7072 DWORD numentries = 0;
7075 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7076 cbBuf, pcbNeeded, pcReturned);
7078 if (pName && (lstrlenW(pName))) {
7079 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7080 SetLastError(ERROR_ACCESS_DENIED);
7084 /* Level is not checked in win9x */
7085 if (!Level || (Level > 2)) {
7086 WARN("level (%d) is ignored in win9x\n", Level);
7087 SetLastError(ERROR_INVALID_LEVEL);
7091 SetLastError(RPC_X_NULL_REF_POINTER);
7095 /* Scan all Monitor-Keys */
7097 needed = get_local_monitors(Level, NULL, 0, &numentries);
7099 /* we calculated the needed buffersize. now do the error-checks */
7100 if (cbBuf < needed) {
7101 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7104 else if (!pMonitors || !pcReturned) {
7105 SetLastError(RPC_X_NULL_REF_POINTER);
7109 /* fill the Buffer with the Monitor-Keys */
7110 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7114 if (pcbNeeded) *pcbNeeded = needed;
7115 if (pcReturned) *pcReturned = numentries;
7117 TRACE("returning %d with %d (%d byte for %d entries)\n",
7118 res, GetLastError(), needed, numentries);
7123 /******************************************************************************
7124 * SpoolerInit (WINSPOOL.@)
7126 * Initialize the Spooler
7133 * The function fails on windows, when the spooler service is not running
7136 BOOL WINAPI SpoolerInit(void)
7139 if ((backend == NULL) && !load_backend()) return FALSE;
7143 /******************************************************************************
7144 * XcvDataW (WINSPOOL.@)
7146 * Execute commands in the Printmonitor DLL
7149 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7150 * pszDataName [i] Name of the command to execute
7151 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7152 * cbInputData [i] Size in Bytes of Buffer at pInputData
7153 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7154 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7155 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7156 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7163 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7164 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7166 * Minimal List of commands, that a Printmonitor DLL should support:
7168 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7169 *| "AddPort" : Add a Port
7170 *| "DeletePort": Delete a Port
7172 * Many Printmonitors support additional commands. Examples for localspl.dll:
7173 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7174 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7177 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7178 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7179 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7181 opened_printer_t *printer;
7183 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7184 pInputData, cbInputData, pOutputData,
7185 cbOutputData, pcbOutputNeeded, pdwStatus);
7187 printer = get_opened_printer(hXcv);
7188 if (!printer || (!printer->hXcv)) {
7189 SetLastError(ERROR_INVALID_HANDLE);
7193 if (!pcbOutputNeeded) {
7194 SetLastError(ERROR_INVALID_PARAMETER);
7198 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7199 SetLastError(RPC_X_NULL_REF_POINTER);
7203 *pcbOutputNeeded = 0;
7205 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7206 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7211 /*****************************************************************************
7212 * EnumPrinterDataA [WINSPOOL.@]
7215 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7216 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7217 DWORD cbData, LPDWORD pcbData )
7219 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7220 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7221 return ERROR_NO_MORE_ITEMS;
7224 /*****************************************************************************
7225 * EnumPrinterDataW [WINSPOOL.@]
7228 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7229 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7230 DWORD cbData, LPDWORD pcbData )
7232 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7233 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7234 return ERROR_NO_MORE_ITEMS;
7237 /*****************************************************************************
7238 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7241 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7242 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7243 LPDWORD pcbNeeded, LPDWORD pcReturned)
7245 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7246 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7247 pcbNeeded, pcReturned);
7251 /*****************************************************************************
7252 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7255 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7256 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7257 LPDWORD pcbNeeded, LPDWORD pcReturned)
7259 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7260 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7261 pcbNeeded, pcReturned);
7265 /*****************************************************************************
7266 * EnumPrintProcessorsA [WINSPOOL.@]
7269 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7270 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7272 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7273 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7277 /*****************************************************************************
7278 * EnumPrintProcessorsW [WINSPOOL.@]
7281 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7282 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7284 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7285 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7286 cbBuf, pcbNeeded, pcbReturned);
7290 /*****************************************************************************
7291 * ExtDeviceMode [WINSPOOL.@]
7294 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7295 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7298 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7299 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7300 debugstr_a(pProfile), fMode);
7304 /*****************************************************************************
7305 * FindClosePrinterChangeNotification [WINSPOOL.@]
7308 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7310 FIXME("Stub: %p\n", hChange);
7314 /*****************************************************************************
7315 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7318 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7319 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7321 FIXME("Stub: %p %x %x %p\n",
7322 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7323 return INVALID_HANDLE_VALUE;
7326 /*****************************************************************************
7327 * FindNextPrinterChangeNotification [WINSPOOL.@]
7330 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7331 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7333 FIXME("Stub: %p %p %p %p\n",
7334 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7338 /*****************************************************************************
7339 * FreePrinterNotifyInfo [WINSPOOL.@]
7342 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7344 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7348 /*****************************************************************************
7351 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7352 * ansi depending on the unicode parameter.
7354 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7364 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7367 memcpy(ptr, str, *size);
7374 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7377 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7384 /*****************************************************************************
7387 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7388 LPDWORD pcbNeeded, BOOL unicode)
7390 DWORD size, left = cbBuf;
7391 BOOL space = (cbBuf > 0);
7398 ji1->JobId = job->job_id;
7401 string_to_buf(job->document_title, ptr, left, &size, unicode);
7402 if(space && size <= left)
7404 ji1->pDocument = (LPWSTR)ptr;
7415 /*****************************************************************************
7418 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7419 LPDWORD pcbNeeded, BOOL unicode)
7421 DWORD size, left = cbBuf;
7422 BOOL space = (cbBuf > 0);
7429 ji2->JobId = job->job_id;
7432 string_to_buf(job->document_title, ptr, left, &size, unicode);
7433 if(space && size <= left)
7435 ji2->pDocument = (LPWSTR)ptr;
7446 /*****************************************************************************
7449 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7450 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7453 DWORD needed = 0, size;
7457 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7459 EnterCriticalSection(&printer_handles_cs);
7460 job = get_job(hPrinter, JobId);
7467 size = sizeof(JOB_INFO_1W);
7472 memset(pJob, 0, size);
7476 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7481 size = sizeof(JOB_INFO_2W);
7486 memset(pJob, 0, size);
7490 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7495 size = sizeof(JOB_INFO_3);
7499 memset(pJob, 0, size);
7508 SetLastError(ERROR_INVALID_LEVEL);
7512 *pcbNeeded = needed;
7514 LeaveCriticalSection(&printer_handles_cs);
7518 /*****************************************************************************
7519 * GetJobA [WINSPOOL.@]
7522 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7523 DWORD cbBuf, LPDWORD pcbNeeded)
7525 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7528 /*****************************************************************************
7529 * GetJobW [WINSPOOL.@]
7532 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7533 DWORD cbBuf, LPDWORD pcbNeeded)
7535 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7538 /*****************************************************************************
7541 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7543 char *unixname, *queue, *cmd;
7544 char fmt[] = "lpr -P%s %s";
7547 if(!(unixname = wine_get_unix_file_name(filename)))
7550 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7551 queue = HeapAlloc(GetProcessHeap(), 0, len);
7552 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7554 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7555 sprintf(cmd, fmt, queue, unixname);
7557 TRACE("printing with: %s\n", cmd);
7560 HeapFree(GetProcessHeap(), 0, cmd);
7561 HeapFree(GetProcessHeap(), 0, queue);
7562 HeapFree(GetProcessHeap(), 0, unixname);
7566 /*****************************************************************************
7569 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7571 #ifdef SONAME_LIBCUPS
7574 char *unixname, *queue, *doc_titleA;
7578 if(!(unixname = wine_get_unix_file_name(filename)))
7581 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7582 queue = HeapAlloc(GetProcessHeap(), 0, len);
7583 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7585 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7586 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7587 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7589 TRACE("printing via cups\n");
7590 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7591 HeapFree(GetProcessHeap(), 0, doc_titleA);
7592 HeapFree(GetProcessHeap(), 0, queue);
7593 HeapFree(GetProcessHeap(), 0, unixname);
7599 return schedule_lpr(printer_name, filename);
7603 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7610 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7614 if(HIWORD(wparam) == BN_CLICKED)
7616 if(LOWORD(wparam) == IDOK)
7619 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7622 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7623 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7625 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7627 WCHAR caption[200], message[200];
7630 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7631 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7632 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7633 if(mb_ret == IDCANCEL)
7635 HeapFree(GetProcessHeap(), 0, filename);
7639 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7640 if(hf == INVALID_HANDLE_VALUE)
7642 WCHAR caption[200], message[200];
7644 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7645 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7646 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7647 HeapFree(GetProcessHeap(), 0, filename);
7651 DeleteFileW(filename);
7652 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7654 EndDialog(hwnd, IDOK);
7657 if(LOWORD(wparam) == IDCANCEL)
7659 EndDialog(hwnd, IDCANCEL);
7668 /*****************************************************************************
7671 static BOOL get_filename(LPWSTR *filename)
7673 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7674 file_dlg_proc, (LPARAM)filename) == IDOK;
7677 /*****************************************************************************
7680 static BOOL schedule_file(LPCWSTR filename)
7682 LPWSTR output = NULL;
7684 if(get_filename(&output))
7686 TRACE("copy to %s\n", debugstr_w(output));
7687 CopyFileW(filename, output, FALSE);
7688 HeapFree(GetProcessHeap(), 0, output);
7694 /*****************************************************************************
7697 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7700 char *unixname, *cmdA;
7702 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7706 if(!(unixname = wine_get_unix_file_name(filename)))
7709 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7710 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7711 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7713 TRACE("printing with: %s\n", cmdA);
7715 if((file_fd = open(unixname, O_RDONLY)) == -1)
7720 ERR("pipe() failed!\n");
7730 /* reset signals that we previously set to SIG_IGN */
7731 signal(SIGPIPE, SIG_DFL);
7732 signal(SIGCHLD, SIG_DFL);
7734 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7738 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7739 write(fds[1], buf, no_read);
7744 if(file_fd != -1) close(file_fd);
7745 if(fds[0] != -1) close(fds[0]);
7746 if(fds[1] != -1) close(fds[1]);
7748 HeapFree(GetProcessHeap(), 0, cmdA);
7749 HeapFree(GetProcessHeap(), 0, unixname);
7756 /*****************************************************************************
7759 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7761 int in_fd, out_fd, no_read;
7764 char *unixname, *outputA;
7767 if(!(unixname = wine_get_unix_file_name(filename)))
7770 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7771 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7772 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7774 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7775 in_fd = open(unixname, O_RDONLY);
7776 if(out_fd == -1 || in_fd == -1)
7779 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7780 write(out_fd, buf, no_read);
7784 if(in_fd != -1) close(in_fd);
7785 if(out_fd != -1) close(out_fd);
7786 HeapFree(GetProcessHeap(), 0, outputA);
7787 HeapFree(GetProcessHeap(), 0, unixname);
7791 /*****************************************************************************
7792 * ScheduleJob [WINSPOOL.@]
7795 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7797 opened_printer_t *printer;
7799 struct list *cursor, *cursor2;
7801 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7802 EnterCriticalSection(&printer_handles_cs);
7803 printer = get_opened_printer(hPrinter);
7807 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7809 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7812 if(job->job_id != dwJobID) continue;
7814 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7815 if(hf != INVALID_HANDLE_VALUE)
7817 PRINTER_INFO_5W *pi5;
7821 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7822 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7824 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7825 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7826 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7827 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7828 debugstr_w(pi5->pPortName));
7832 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7833 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7835 DWORD type, count = sizeof(output);
7836 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7839 if(output[0] == '|')
7841 schedule_pipe(output + 1, job->filename);
7845 schedule_unixfile(output, job->filename);
7847 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7849 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7851 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7853 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7855 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7857 schedule_file(job->filename);
7861 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7863 HeapFree(GetProcessHeap(), 0, pi5);
7865 DeleteFileW(job->filename);
7867 list_remove(cursor);
7868 HeapFree(GetProcessHeap(), 0, job->document_title);
7869 HeapFree(GetProcessHeap(), 0, job->filename);
7870 HeapFree(GetProcessHeap(), 0, job);
7875 LeaveCriticalSection(&printer_handles_cs);
7879 /*****************************************************************************
7880 * StartDocDlgA [WINSPOOL.@]
7882 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7884 UNICODE_STRING usBuffer;
7887 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7890 docW.cbSize = sizeof(docW);
7891 if (doc->lpszDocName)
7893 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7894 if (!(docW.lpszDocName = docnameW)) return NULL;
7896 if (doc->lpszOutput)
7898 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7899 if (!(docW.lpszOutput = outputW)) return NULL;
7901 if (doc->lpszDatatype)
7903 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7904 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7906 docW.fwType = doc->fwType;
7908 retW = StartDocDlgW(hPrinter, &docW);
7912 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7913 ret = HeapAlloc(GetProcessHeap(), 0, len);
7914 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7915 HeapFree(GetProcessHeap(), 0, retW);
7918 HeapFree(GetProcessHeap(), 0, datatypeW);
7919 HeapFree(GetProcessHeap(), 0, outputW);
7920 HeapFree(GetProcessHeap(), 0, docnameW);
7925 /*****************************************************************************
7926 * StartDocDlgW [WINSPOOL.@]
7928 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7929 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7930 * port is "FILE:". Also returns the full path if passed a relative path.
7932 * The caller should free the returned string from the process heap.
7934 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7939 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7941 PRINTER_INFO_5W *pi5;
7942 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7943 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7945 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7946 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7947 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7949 HeapFree(GetProcessHeap(), 0, pi5);
7952 HeapFree(GetProcessHeap(), 0, pi5);
7955 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7959 if (get_filename(&name))
7961 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7963 HeapFree(GetProcessHeap(), 0, name);
7966 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7967 GetFullPathNameW(name, len, ret, NULL);
7968 HeapFree(GetProcessHeap(), 0, name);
7973 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7976 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7977 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7979 attr = GetFileAttributesW(ret);
7980 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7982 HeapFree(GetProcessHeap(), 0, ret);