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-2009 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 /* ############################### */
112 HANDLE backend_printer;
121 WCHAR *document_title;
129 LPCWSTR versionregpath;
130 LPCWSTR versionsubdir;
133 /* ############################### */
135 static struct list monitor_handles = LIST_INIT( monitor_handles );
136 static monitor_t * pm_localport;
138 static opened_printer_t **printer_handles;
139 static UINT nb_printer_handles;
140 static LONG next_job_id = 1;
142 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
143 WORD fwCapability, LPSTR lpszOutput,
145 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
146 LPSTR lpszDevice, LPSTR lpszPort,
147 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
150 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
151 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
152 'c','o','n','t','r','o','l','\\',
153 'P','r','i','n','t','\\',
154 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
155 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
157 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
158 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
159 'C','o','n','t','r','o','l','\\',
160 'P','r','i','n','t','\\',
161 'M','o','n','i','t','o','r','s','\\',0};
163 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
164 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
165 'C','o','n','t','r','o','l','\\',
166 'P','r','i','n','t','\\',
167 'P','r','i','n','t','e','r','s',0};
169 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
171 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
172 'M','i','c','r','o','s','o','f','t','\\',
173 'W','i','n','d','o','w','s',' ','N','T','\\',
174 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
175 'W','i','n','d','o','w','s',0};
177 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
178 'M','i','c','r','o','s','o','f','t','\\',
179 'W','i','n','d','o','w','s',' ','N','T','\\',
180 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
181 'D','e','v','i','c','e','s',0};
183 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
184 'M','i','c','r','o','s','o','f','t','\\',
185 'W','i','n','d','o','w','s',' ','N','T','\\',
186 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
187 'P','o','r','t','s',0};
189 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
190 'M','i','c','r','o','s','o','f','t','\\',
191 'W','i','n','d','o','w','s',' ','N','T','\\',
192 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
193 'P','r','i','n','t','e','r','P','o','r','t','s',0};
195 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
196 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
197 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
198 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
200 static const WCHAR subdir_x64W[] = {'x','6','4',0};
201 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
202 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
203 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
204 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
205 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
207 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
208 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
210 static const WCHAR backslashW[] = {'\\',0};
211 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
212 'i','o','n',' ','F','i','l','e',0};
213 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
214 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
215 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
216 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
217 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
218 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
219 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
220 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
221 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
222 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
223 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
224 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
225 static const WCHAR NameW[] = {'N','a','m','e',0};
226 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
227 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
228 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
229 static const WCHAR PortW[] = {'P','o','r','t',0};
230 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
231 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
232 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
233 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
234 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
235 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
236 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
237 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
238 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
239 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
240 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
241 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
242 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
243 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
244 static const WCHAR emptyStringW[] = {0};
246 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
248 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
249 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
250 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
252 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
253 'D','o','c','u','m','e','n','t',0};
255 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
256 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
257 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
258 0, sizeof(DRIVER_INFO_8W)};
261 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
262 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
263 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
264 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
265 sizeof(PRINTER_INFO_9W)};
267 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
268 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
269 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
271 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
273 /******************************************************************
274 * validate the user-supplied printing-environment [internal]
277 * env [I] PTR to Environment-String or NULL
281 * Success: PTR to printenv_t
284 * An empty string is handled the same way as NULL.
285 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
289 static const printenv_t * validate_envW(LPCWSTR env)
291 const printenv_t *result = NULL;
294 TRACE("testing %s\n", debugstr_w(env));
297 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
299 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
301 result = all_printenv[i];
306 if (result == NULL) {
307 FIXME("unsupported Environment: %s\n", debugstr_w(env));
308 SetLastError(ERROR_INVALID_ENVIRONMENT);
310 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
314 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
316 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
322 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
323 if passed a NULL string. This returns NULLs to the result.
325 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
329 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
330 return usBufferPtr->Buffer;
332 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
336 static LPWSTR strdupW(LPCWSTR p)
342 len = (strlenW(p) + 1) * sizeof(WCHAR);
343 ret = HeapAlloc(GetProcessHeap(), 0, len);
348 static LPSTR strdupWtoA( LPCWSTR str )
353 if (!str) return NULL;
354 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
355 ret = HeapAlloc( GetProcessHeap(), 0, len );
356 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
360 /******************************************************************
361 * Return the number of bytes for an multi_sz string.
362 * The result includes all \0s
363 * (specifically the extra \0, that is needed as multi_sz terminator).
366 static int multi_sz_lenW(const WCHAR *str)
368 const WCHAR *ptr = str;
372 ptr += lstrlenW(ptr) + 1;
375 return (ptr - str + 1) * sizeof(WCHAR);
378 /* ################################ */
380 static int multi_sz_lenA(const char *str)
382 const char *ptr = str;
386 ptr += lstrlenA(ptr) + 1;
389 return ptr - str + 1;
393 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
396 /* If forcing, or no profile string entry for device yet, set the entry
398 * The always change entry if not WINEPS yet is discussable.
401 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
403 !strstr(qbuf,"WINEPS.DRV")
405 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
408 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
409 WriteProfileStringA("windows","device",buf);
410 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
411 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
414 HeapFree(GetProcessHeap(),0,buf);
418 static BOOL add_printer_driver(const char *name)
422 static char driver_9x[] = "wineps16.drv",
423 driver_nt[] = "wineps.drv",
424 env_9x[] = "Windows 4.0",
425 env_nt[] = "Windows NT x86",
426 data_file[] = "generic.ppd",
427 default_data_type[] = "RAW";
429 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
431 di3a.pName = (char *)name;
432 di3a.pEnvironment = env_nt;
433 di3a.pDriverPath = driver_nt;
434 di3a.pDataFile = data_file;
435 di3a.pConfigFile = driver_nt;
436 di3a.pDefaultDataType = default_data_type;
438 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
439 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
442 di3a.pEnvironment = env_9x;
443 di3a.pDriverPath = driver_9x;
444 di3a.pConfigFile = driver_9x;
445 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
446 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
451 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
452 debugstr_a(di3a.pEnvironment), GetLastError());
456 #ifdef SONAME_LIBCUPS
457 static typeof(cupsFreeDests) *pcupsFreeDests;
458 static typeof(cupsGetDests) *pcupsGetDests;
459 static typeof(cupsGetPPD) *pcupsGetPPD;
460 static typeof(cupsPrintFile) *pcupsPrintFile;
461 static void *cupshandle;
463 static BOOL CUPS_LoadPrinters(void)
466 BOOL hadprinter = FALSE, haddefault = FALSE;
468 PRINTER_INFO_2A pinfo2a;
470 HKEY hkeyPrinter, hkeyPrinters, hkey;
473 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
475 TRACE("%s\n", loaderror);
478 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
481 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
482 if (!p##x) return FALSE;
484 DYNCUPS(cupsFreeDests);
486 DYNCUPS(cupsGetDests);
487 DYNCUPS(cupsPrintFile);
490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
492 ERR("Can't create Printers key\n");
496 nrofdests = pcupsGetDests(&dests);
497 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
498 for (i=0;i<nrofdests;i++) {
499 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
500 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
501 sprintf(port,"LPR:%s", dests[i].name);
502 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
503 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
504 sprintf(devline, "WINEPS.DRV,%s", port);
505 WriteProfileStringA("devices", dests[i].name, devline);
506 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
507 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
511 lstrcatA(devline, ",15,45");
512 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
513 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
514 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
518 HeapFree(GetProcessHeap(), 0, devline);
520 TRACE("Printer %d: %s\n", i, dests[i].name);
521 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
522 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
524 TRACE("Printer already exists\n");
525 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
526 RegCloseKey(hkeyPrinter);
528 static CHAR data_type[] = "RAW",
529 print_proc[] = "WinPrint",
530 comment[] = "WINEPS Printer using CUPS",
531 location[] = "<physical location of printer>",
532 params[] = "<parameters?>",
533 share_name[] = "<share name?>",
534 sep_file[] = "<sep file?>";
536 add_printer_driver(dests[i].name);
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = dests[i].name;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = dests[i].name;
543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = location;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
555 HeapFree(GetProcessHeap(),0,port);
558 if (dests[i].is_default) {
559 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
563 if (hadprinter & !haddefault)
564 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
565 pcupsFreeDests(nrofdests, dests);
566 RegCloseKey(hkeyPrinters);
572 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
573 PRINTER_INFO_2A pinfo2a;
574 char *e,*s,*name,*prettyname,*devname;
575 BOOL ret = FALSE, set_default = FALSE;
576 char *port = NULL, *devline,*env_default;
577 HKEY hkeyPrinter, hkeyPrinters, hkey;
579 while (isspace(*pent)) pent++;
580 s = strchr(pent,':');
582 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
590 TRACE("name=%s entry=%s\n",name, pent);
592 if(ispunct(*name)) { /* a tc entry, not a real printer */
593 TRACE("skipping tc entry\n");
597 if(strstr(pent,":server")) { /* server only version so skip */
598 TRACE("skipping server entry\n");
602 /* Determine whether this is a postscript printer. */
605 env_default = getenv("PRINTER");
607 /* Get longest name, usually the one at the right for later display. */
608 while((s=strchr(prettyname,'|'))) {
611 while(isspace(*--e)) *e = '\0';
612 TRACE("\t%s\n", debugstr_a(prettyname));
613 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
614 for(prettyname = s+1; isspace(*prettyname); prettyname++)
617 e = prettyname + strlen(prettyname);
618 while(isspace(*--e)) *e = '\0';
619 TRACE("\t%s\n", debugstr_a(prettyname));
620 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
622 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
623 * if it is too long, we use it as comment below. */
624 devname = prettyname;
625 if (strlen(devname)>=CCHDEVICENAME-1)
627 if (strlen(devname)>=CCHDEVICENAME-1) {
632 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
633 sprintf(port,"LPR:%s",name);
635 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
636 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
637 sprintf(devline, "WINEPS.DRV,%s", port);
638 WriteProfileStringA("devices", devname, devline);
639 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
640 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
644 lstrcatA(devline, ",15,45");
645 WriteProfileStringA("PrinterPorts", devname, devline);
646 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
647 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
651 HeapFree(GetProcessHeap(),0,devline);
653 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
655 ERR("Can't create Printers key\n");
659 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
660 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
662 TRACE("Printer already exists\n");
663 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
664 RegCloseKey(hkeyPrinter);
666 static CHAR data_type[] = "RAW",
667 print_proc[] = "WinPrint",
668 comment[] = "WINEPS Printer using LPR",
669 params[] = "<parameters?>",
670 share_name[] = "<share name?>",
671 sep_file[] = "<sep file?>";
673 add_printer_driver(devname);
675 memset(&pinfo2a,0,sizeof(pinfo2a));
676 pinfo2a.pPrinterName = devname;
677 pinfo2a.pDatatype = data_type;
678 pinfo2a.pPrintProcessor = print_proc;
679 pinfo2a.pDriverName = devname;
680 pinfo2a.pComment = comment;
681 pinfo2a.pLocation = prettyname;
682 pinfo2a.pPortName = port;
683 pinfo2a.pParameters = params;
684 pinfo2a.pShareName = share_name;
685 pinfo2a.pSepFile = sep_file;
687 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
688 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
689 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
692 RegCloseKey(hkeyPrinters);
694 if (isfirst || set_default)
695 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
698 HeapFree(GetProcessHeap(), 0, port);
699 HeapFree(GetProcessHeap(), 0, name);
704 PRINTCAP_LoadPrinters(void) {
705 BOOL hadprinter = FALSE;
709 BOOL had_bash = FALSE;
711 f = fopen("/etc/printcap","r");
715 while(fgets(buf,sizeof(buf),f)) {
718 end=strchr(buf,'\n');
722 while(isspace(*start)) start++;
723 if(*start == '#' || *start == '\0')
726 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
727 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
728 HeapFree(GetProcessHeap(),0,pent);
732 if (end && *--end == '\\') {
739 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
742 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
748 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
749 HeapFree(GetProcessHeap(),0,pent);
755 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
758 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
759 (lstrlenW(value) + 1) * sizeof(WCHAR));
761 return ERROR_FILE_NOT_FOUND;
764 /******************************************************************
765 * monitor_unload [internal]
767 * release a printmonitor and unload it from memory, when needed
770 static void monitor_unload(monitor_t * pm)
772 if (pm == NULL) return;
773 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
775 EnterCriticalSection(&monitor_handles_cs);
777 if (pm->refcount) pm->refcount--;
779 if (pm->refcount == 0) {
780 list_remove(&pm->entry);
781 FreeLibrary(pm->hdll);
782 HeapFree(GetProcessHeap(), 0, pm->name);
783 HeapFree(GetProcessHeap(), 0, pm->dllname);
784 HeapFree(GetProcessHeap(), 0, pm);
786 LeaveCriticalSection(&monitor_handles_cs);
789 /******************************************************************
790 * monitor_load [internal]
792 * load a printmonitor, get the dllname from the registry, when needed
793 * initialize the monitor and dump found function-pointers
795 * On failure, SetLastError() is called and NULL is returned
798 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
800 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
801 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
802 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
803 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
804 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
806 monitor_t * pm = NULL;
808 LPWSTR regroot = NULL;
809 LPWSTR driver = dllname;
811 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
812 /* Is the Monitor already loaded? */
813 EnterCriticalSection(&monitor_handles_cs);
816 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
818 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
826 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
827 if (pm == NULL) goto cleanup;
828 list_add_tail(&monitor_handles, &pm->entry);
832 if (pm->name == NULL) {
833 /* Load the monitor */
834 LPMONITOREX pmonitorEx;
838 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
839 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
843 lstrcpyW(regroot, MonitorsW);
844 lstrcatW(regroot, name);
845 /* Get the Driver from the Registry */
846 if (driver == NULL) {
849 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
850 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
851 &namesize) == ERROR_SUCCESS) {
852 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
853 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
860 pm->name = strdupW(name);
861 pm->dllname = strdupW(driver);
863 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
865 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
870 pm->hdll = LoadLibraryW(driver);
871 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
873 if (pm->hdll == NULL) {
875 SetLastError(ERROR_MOD_NOT_FOUND);
880 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
881 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
882 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
883 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
884 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
887 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
888 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
889 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
890 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
891 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
893 if (pInitializePrintMonitorUI != NULL) {
894 pm->monitorUI = pInitializePrintMonitorUI();
895 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
897 TRACE( "0x%08x: dwMonitorSize (%d)\n",
898 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
903 if (pInitializePrintMonitor && regroot) {
904 pmonitorEx = pInitializePrintMonitor(regroot);
905 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
906 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
909 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
910 pm->monitor = &(pmonitorEx->Monitor);
915 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
919 if (!pm->monitor && regroot) {
920 if (pInitializePrintMonitor2 != NULL) {
921 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
923 if (pInitializeMonitorEx != NULL) {
924 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
926 if (pInitializeMonitor != NULL) {
927 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
930 if (!pm->monitor && !pm->monitorUI) {
932 SetLastError(ERROR_PROC_NOT_FOUND);
937 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
941 LeaveCriticalSection(&monitor_handles_cs);
942 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
943 HeapFree(GetProcessHeap(), 0, regroot);
944 TRACE("=> %p\n", pm);
948 /******************************************************************
949 * monitor_loadui [internal]
951 * load the userinterface-dll for a given portmonitor
953 * On failure, NULL is returned
956 static monitor_t * monitor_loadui(monitor_t * pm)
958 monitor_t * pui = NULL;
959 LPWSTR buffer[MAX_PATH];
964 if (pm == NULL) return NULL;
965 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
967 /* Try the Portmonitor first; works for many monitors */
969 EnterCriticalSection(&monitor_handles_cs);
971 LeaveCriticalSection(&monitor_handles_cs);
975 /* query the userinterface-dllname from the Portmonitor */
976 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
977 /* building (",XcvMonitor %s",pm->name) not needed yet */
978 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
979 TRACE("got %u with %p\n", res, hXcv);
981 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
982 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
983 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
984 pm->monitor->pfnXcvClosePort(hXcv);
991 /******************************************************************
992 * monitor_load_by_port [internal]
994 * load a printmonitor for a given port
996 * On failure, NULL is returned
999 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1004 monitor_t * pm = NULL;
1005 DWORD registered = 0;
1009 TRACE("(%s)\n", debugstr_w(portname));
1011 /* Try the Local Monitor first */
1012 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1013 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1014 /* found the portname */
1016 return monitor_load(LocalPortW, NULL);
1021 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1022 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1023 if (buffer == NULL) return NULL;
1025 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1026 EnterCriticalSection(&monitor_handles_cs);
1027 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1029 while ((pm == NULL) && (id < registered)) {
1031 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1032 TRACE("testing %s\n", debugstr_w(buffer));
1033 len = lstrlenW(buffer);
1034 lstrcatW(buffer, bs_Ports_bsW);
1035 lstrcatW(buffer, portname);
1036 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1038 buffer[len] = '\0'; /* use only the Monitor-Name */
1039 pm = monitor_load(buffer, NULL);
1043 LeaveCriticalSection(&monitor_handles_cs);
1046 HeapFree(GetProcessHeap(), 0, buffer);
1050 /******************************************************************
1051 * get_servername_from_name (internal)
1053 * for an external server, a copy of the serverpart from the full name is returned
1056 static LPWSTR get_servername_from_name(LPCWSTR name)
1060 WCHAR buffer[MAX_PATH];
1063 if (name == NULL) return NULL;
1064 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1066 server = strdupW(&name[2]); /* skip over both backslash */
1067 if (server == NULL) return NULL;
1069 /* strip '\' and the printername */
1070 ptr = strchrW(server, '\\');
1071 if (ptr) ptr[0] = '\0';
1073 TRACE("found %s\n", debugstr_w(server));
1075 len = sizeof(buffer)/sizeof(buffer[0]);
1076 if (GetComputerNameW(buffer, &len)) {
1077 if (lstrcmpW(buffer, server) == 0) {
1078 /* The requested Servername is our computername */
1079 HeapFree(GetProcessHeap(), 0, server);
1086 /******************************************************************
1087 * get_basename_from_name (internal)
1089 * skip over the serverpart from the full name
1092 static LPCWSTR get_basename_from_name(LPCWSTR name)
1094 if (name == NULL) return NULL;
1095 if ((name[0] == '\\') && (name[1] == '\\')) {
1096 /* skip over the servername and search for the following '\' */
1097 name = strchrW(&name[2], '\\');
1098 if ((name) && (name[1])) {
1099 /* found a separator ('\') followed by a name:
1100 skip over the separator and return the rest */
1105 /* no basename present (we found only a servername) */
1112 /******************************************************************
1113 * get_opened_printer_entry
1114 * Get the first place empty in the opened printer table
1117 * - pDefault is ignored
1119 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1121 UINT_PTR handle = nb_printer_handles, i;
1122 jobqueue_t *queue = NULL;
1123 opened_printer_t *printer = NULL;
1125 LPCWSTR printername;
1127 if ((backend == NULL) && !load_backend()) return NULL;
1129 servername = get_servername_from_name(name);
1131 FIXME("server %s not supported\n", debugstr_w(servername));
1132 HeapFree(GetProcessHeap(), 0, servername);
1133 SetLastError(ERROR_INVALID_PRINTER_NAME);
1137 printername = get_basename_from_name(name);
1138 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1140 /* an empty printername is invalid */
1141 if (printername && (!printername[0])) {
1142 SetLastError(ERROR_INVALID_PARAMETER);
1146 EnterCriticalSection(&printer_handles_cs);
1148 for (i = 0; i < nb_printer_handles; i++)
1150 if (!printer_handles[i])
1152 if(handle == nb_printer_handles)
1157 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1158 queue = printer_handles[i]->queue;
1162 if (handle >= nb_printer_handles)
1164 opened_printer_t **new_array;
1165 if (printer_handles)
1166 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1167 (nb_printer_handles + 16) * sizeof(*new_array) );
1169 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1170 (nb_printer_handles + 16) * sizeof(*new_array) );
1177 printer_handles = new_array;
1178 nb_printer_handles += 16;
1181 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1187 /* get a printer handle from the backend */
1188 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1193 /* clone the base name. This is NULL for the printserver */
1194 printer->printername = strdupW(printername);
1196 /* clone the full name */
1197 printer->name = strdupW(name);
1198 if (name && (!printer->name)) {
1204 printer->queue = queue;
1207 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1208 if (!printer->queue) {
1212 list_init(&printer->queue->jobs);
1213 printer->queue->ref = 0;
1215 InterlockedIncrement(&printer->queue->ref);
1217 printer_handles[handle] = printer;
1220 LeaveCriticalSection(&printer_handles_cs);
1221 if (!handle && printer) {
1222 /* Something failed: Free all resources */
1223 HeapFree(GetProcessHeap(), 0, printer->printername);
1224 HeapFree(GetProcessHeap(), 0, printer->name);
1225 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1226 HeapFree(GetProcessHeap(), 0, printer);
1229 return (HANDLE)handle;
1232 /******************************************************************
1233 * get_opened_printer
1234 * Get the pointer to the opened printer referred by the handle
1236 static opened_printer_t *get_opened_printer(HANDLE hprn)
1238 UINT_PTR idx = (UINT_PTR)hprn;
1239 opened_printer_t *ret = NULL;
1241 EnterCriticalSection(&printer_handles_cs);
1243 if ((idx > 0) && (idx <= nb_printer_handles)) {
1244 ret = printer_handles[idx - 1];
1246 LeaveCriticalSection(&printer_handles_cs);
1250 /******************************************************************
1251 * get_opened_printer_name
1252 * Get the pointer to the opened printer name referred by the handle
1254 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1256 opened_printer_t *printer = get_opened_printer(hprn);
1257 if(!printer) return NULL;
1258 return printer->name;
1261 /******************************************************************
1262 * WINSPOOL_GetOpenedPrinterRegKey
1265 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1267 LPCWSTR name = get_opened_printer_name(hPrinter);
1271 if(!name) return ERROR_INVALID_HANDLE;
1273 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1277 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1279 ERR("Can't find opened printer %s in registry\n",
1281 RegCloseKey(hkeyPrinters);
1282 return ERROR_INVALID_PRINTER_NAME; /* ? */
1284 RegCloseKey(hkeyPrinters);
1285 return ERROR_SUCCESS;
1288 void WINSPOOL_LoadSystemPrinters(void)
1290 HKEY hkey, hkeyPrinters;
1292 DWORD needed, num, i;
1293 WCHAR PrinterName[256];
1296 /* This ensures that all printer entries have a valid Name value. If causes
1297 problems later if they don't. If one is found to be missed we create one
1298 and set it equal to the name of the key */
1299 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1300 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1301 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1302 for(i = 0; i < num; i++) {
1303 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1304 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1305 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1306 set_reg_szW(hkey, NameW, PrinterName);
1313 RegCloseKey(hkeyPrinters);
1316 /* We want to avoid calling AddPrinter on printers as much as
1317 possible, because on cups printers this will (eventually) lead
1318 to a call to cupsGetPPD which takes forever, even with non-cups
1319 printers AddPrinter takes a while. So we'll tag all printers that
1320 were automatically added last time around, if they still exist
1321 we'll leave them be otherwise we'll delete them. */
1322 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1324 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1325 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1326 for(i = 0; i < num; i++) {
1327 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1328 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1329 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1331 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1339 HeapFree(GetProcessHeap(), 0, pi);
1343 #ifdef SONAME_LIBCUPS
1344 done = CUPS_LoadPrinters();
1347 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1348 PRINTCAP_LoadPrinters();
1350 /* Now enumerate the list again and delete any printers that are still tagged */
1351 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1353 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1354 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1355 for(i = 0; i < num; i++) {
1356 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1357 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1358 BOOL delete_driver = FALSE;
1359 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1360 DWORD dw, type, size = sizeof(dw);
1361 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1362 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1363 DeletePrinter(hprn);
1364 delete_driver = TRUE;
1370 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1375 HeapFree(GetProcessHeap(), 0, pi);
1382 /******************************************************************
1385 * Get the pointer to the specified job.
1386 * Should hold the printer_handles_cs before calling.
1388 static job_t *get_job(HANDLE hprn, DWORD JobId)
1390 opened_printer_t *printer = get_opened_printer(hprn);
1393 if(!printer) return NULL;
1394 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1396 if(job->job_id == JobId)
1402 /***********************************************************
1405 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1408 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1411 Formname = (dmA->dmSize > off_formname);
1412 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1413 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1414 dmW->dmDeviceName, CCHDEVICENAME);
1416 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1417 dmA->dmSize - CCHDEVICENAME);
1419 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1420 off_formname - CCHDEVICENAME);
1421 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1422 dmW->dmFormName, CCHFORMNAME);
1423 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1424 (off_formname + CCHFORMNAME));
1427 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1428 dmA->dmDriverExtra);
1432 /***********************************************************
1434 * Creates an ansi copy of supplied devmode
1436 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1441 if (!dmW) return NULL;
1442 size = dmW->dmSize - CCHDEVICENAME -
1443 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1445 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1446 if (!dmA) return NULL;
1448 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1449 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1451 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1452 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1453 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1457 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1458 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1459 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1460 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1462 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1466 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1470 /******************************************************************
1471 * convert_printerinfo_W_to_A [internal]
1474 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1475 DWORD level, DWORD outlen, DWORD numentries)
1481 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1483 len = pi_sizeof[level] * numentries;
1484 ptr = (LPSTR) out + len;
1487 /* copy the numbers of all PRINTER_INFO_* first */
1488 memcpy(out, pPrintersW, len);
1490 while (id < numentries) {
1494 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1495 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1497 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1498 if (piW->pDescription) {
1499 piA->pDescription = ptr;
1500 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1501 ptr, outlen, NULL, NULL);
1507 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1508 ptr, outlen, NULL, NULL);
1512 if (piW->pComment) {
1513 piA->pComment = ptr;
1514 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1515 ptr, outlen, NULL, NULL);
1524 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1525 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1528 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1529 if (piW->pServerName) {
1530 piA->pServerName = ptr;
1531 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1532 ptr, outlen, NULL, NULL);
1536 if (piW->pPrinterName) {
1537 piA->pPrinterName = ptr;
1538 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1539 ptr, outlen, NULL, NULL);
1543 if (piW->pShareName) {
1544 piA->pShareName = ptr;
1545 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1546 ptr, outlen, NULL, NULL);
1550 if (piW->pPortName) {
1551 piA->pPortName = ptr;
1552 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1553 ptr, outlen, NULL, NULL);
1557 if (piW->pDriverName) {
1558 piA->pDriverName = ptr;
1559 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1560 ptr, outlen, NULL, NULL);
1564 if (piW->pComment) {
1565 piA->pComment = ptr;
1566 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1567 ptr, outlen, NULL, NULL);
1571 if (piW->pLocation) {
1572 piA->pLocation = ptr;
1573 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1574 ptr, outlen, NULL, NULL);
1579 dmA = DEVMODEdupWtoA(piW->pDevMode);
1581 /* align DEVMODEA to a DWORD boundary */
1582 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1586 piA->pDevMode = (LPDEVMODEA) ptr;
1587 len = dmA->dmSize + dmA->dmDriverExtra;
1588 memcpy(ptr, dmA, len);
1589 HeapFree(GetProcessHeap(), 0, dmA);
1595 if (piW->pSepFile) {
1596 piA->pSepFile = ptr;
1597 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1598 ptr, outlen, NULL, NULL);
1602 if (piW->pPrintProcessor) {
1603 piA->pPrintProcessor = ptr;
1604 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1605 ptr, outlen, NULL, NULL);
1609 if (piW->pDatatype) {
1610 piA->pDatatype = ptr;
1611 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1612 ptr, outlen, NULL, NULL);
1616 if (piW->pParameters) {
1617 piA->pParameters = ptr;
1618 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1619 ptr, outlen, NULL, NULL);
1623 if (piW->pSecurityDescriptor) {
1624 piA->pSecurityDescriptor = NULL;
1625 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1632 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1633 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1635 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1637 if (piW->pPrinterName) {
1638 piA->pPrinterName = ptr;
1639 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1640 ptr, outlen, NULL, NULL);
1644 if (piW->pServerName) {
1645 piA->pServerName = ptr;
1646 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1647 ptr, outlen, NULL, NULL);
1656 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1657 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1659 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1661 if (piW->pPrinterName) {
1662 piA->pPrinterName = ptr;
1663 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1664 ptr, outlen, NULL, NULL);
1668 if (piW->pPortName) {
1669 piA->pPortName = ptr;
1670 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1671 ptr, outlen, NULL, NULL);
1679 FIXME("for level %u\n", level);
1681 pPrintersW += pi_sizeof[level];
1682 out += pi_sizeof[level];
1687 /***********************************************************
1688 * PRINTER_INFO_2AtoW
1689 * Creates a unicode copy of PRINTER_INFO_2A on heap
1691 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1693 LPPRINTER_INFO_2W piW;
1694 UNICODE_STRING usBuffer;
1696 if(!piA) return NULL;
1697 piW = HeapAlloc(heap, 0, sizeof(*piW));
1698 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1700 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1701 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1702 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1703 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1704 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1705 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1706 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1707 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1708 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1709 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1710 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1711 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1715 /***********************************************************
1716 * FREE_PRINTER_INFO_2W
1717 * Free PRINTER_INFO_2W and all strings
1719 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1723 HeapFree(heap,0,piW->pServerName);
1724 HeapFree(heap,0,piW->pPrinterName);
1725 HeapFree(heap,0,piW->pShareName);
1726 HeapFree(heap,0,piW->pPortName);
1727 HeapFree(heap,0,piW->pDriverName);
1728 HeapFree(heap,0,piW->pComment);
1729 HeapFree(heap,0,piW->pLocation);
1730 HeapFree(heap,0,piW->pDevMode);
1731 HeapFree(heap,0,piW->pSepFile);
1732 HeapFree(heap,0,piW->pPrintProcessor);
1733 HeapFree(heap,0,piW->pDatatype);
1734 HeapFree(heap,0,piW->pParameters);
1735 HeapFree(heap,0,piW);
1739 /******************************************************************
1740 * DeviceCapabilities [WINSPOOL.@]
1741 * DeviceCapabilitiesA [WINSPOOL.@]
1744 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1745 LPSTR pOutput, LPDEVMODEA lpdm)
1749 if (!GDI_CallDeviceCapabilities16)
1751 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1753 if (!GDI_CallDeviceCapabilities16) return -1;
1755 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1757 /* If DC_PAPERSIZE map POINT16s to POINTs */
1758 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1759 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1760 POINT *pt = (POINT *)pOutput;
1762 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1763 for(i = 0; i < ret; i++, pt++)
1768 HeapFree( GetProcessHeap(), 0, tmp );
1774 /*****************************************************************************
1775 * DeviceCapabilitiesW [WINSPOOL.@]
1777 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1780 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1781 WORD fwCapability, LPWSTR pOutput,
1782 const DEVMODEW *pDevMode)
1784 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1785 LPSTR pDeviceA = strdupWtoA(pDevice);
1786 LPSTR pPortA = strdupWtoA(pPort);
1789 if(pOutput && (fwCapability == DC_BINNAMES ||
1790 fwCapability == DC_FILEDEPENDENCIES ||
1791 fwCapability == DC_PAPERNAMES)) {
1792 /* These need A -> W translation */
1795 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1799 switch(fwCapability) {
1804 case DC_FILEDEPENDENCIES:
1808 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1809 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1811 for(i = 0; i < ret; i++)
1812 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1813 pOutput + (i * size), size);
1814 HeapFree(GetProcessHeap(), 0, pOutputA);
1816 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1817 (LPSTR)pOutput, dmA);
1819 HeapFree(GetProcessHeap(),0,pPortA);
1820 HeapFree(GetProcessHeap(),0,pDeviceA);
1821 HeapFree(GetProcessHeap(),0,dmA);
1825 /******************************************************************
1826 * DocumentPropertiesA [WINSPOOL.@]
1828 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1830 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1831 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1832 LPDEVMODEA pDevModeInput,DWORD fMode )
1834 LPSTR lpName = pDeviceName;
1835 static CHAR port[] = "LPT1:";
1838 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1839 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1843 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1845 ERR("no name from hPrinter?\n");
1846 SetLastError(ERROR_INVALID_HANDLE);
1849 lpName = strdupWtoA(lpNameW);
1852 if (!GDI_CallExtDeviceMode16)
1854 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1856 if (!GDI_CallExtDeviceMode16) {
1857 ERR("No CallExtDeviceMode16?\n");
1861 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1862 pDevModeInput, NULL, fMode);
1865 HeapFree(GetProcessHeap(),0,lpName);
1870 /*****************************************************************************
1871 * DocumentPropertiesW (WINSPOOL.@)
1873 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1875 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1877 LPDEVMODEW pDevModeOutput,
1878 LPDEVMODEW pDevModeInput, DWORD fMode)
1881 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1882 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1883 LPDEVMODEA pDevModeOutputA = NULL;
1886 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1887 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1889 if(pDevModeOutput) {
1890 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1891 if(ret < 0) return ret;
1892 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1894 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1895 pDevModeInputA, fMode);
1896 if(pDevModeOutput) {
1897 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1898 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1900 if(fMode == 0 && ret > 0)
1901 ret += (CCHDEVICENAME + CCHFORMNAME);
1902 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1903 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1907 /******************************************************************
1908 * OpenPrinterA [WINSPOOL.@]
1913 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1914 LPPRINTER_DEFAULTSA pDefault)
1916 UNICODE_STRING lpPrinterNameW;
1917 UNICODE_STRING usBuffer;
1918 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1919 PWSTR pwstrPrinterNameW;
1922 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1925 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1926 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1927 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1928 pDefaultW = &DefaultW;
1930 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1932 RtlFreeUnicodeString(&usBuffer);
1933 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1935 RtlFreeUnicodeString(&lpPrinterNameW);
1939 /******************************************************************
1940 * OpenPrinterW [WINSPOOL.@]
1942 * Open a Printer / Printserver or a Printer-Object
1945 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1946 * phPrinter [O] The resulting Handle is stored here
1947 * pDefault [I] PTR to Default Printer Settings or NULL
1954 * lpPrinterName is one of:
1955 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1956 *| Printer: "PrinterName"
1957 *| Printer-Object: "PrinterName,Job xxx"
1958 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1959 *| XcvPort: "Servername,XcvPort PortName"
1962 *| Printer-Object not supported
1963 *| pDefaults is ignored
1966 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1969 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1971 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1972 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1976 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1977 SetLastError(ERROR_INVALID_PARAMETER);
1981 /* Get the unique handle of the printer or Printserver */
1982 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1983 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1984 return (*phPrinter != 0);
1987 /******************************************************************
1988 * AddMonitorA [WINSPOOL.@]
1993 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1995 LPWSTR nameW = NULL;
1998 LPMONITOR_INFO_2A mi2a;
1999 MONITOR_INFO_2W mi2w;
2001 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2002 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2003 debugstr_a(mi2a ? mi2a->pName : NULL),
2004 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2005 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2008 SetLastError(ERROR_INVALID_LEVEL);
2012 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2018 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2019 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2020 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2023 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2025 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2026 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2027 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2029 if (mi2a->pEnvironment) {
2030 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2031 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2032 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2034 if (mi2a->pDLLName) {
2035 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2036 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2037 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2040 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2042 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2043 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2044 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2046 HeapFree(GetProcessHeap(), 0, nameW);
2050 /******************************************************************************
2051 * AddMonitorW [WINSPOOL.@]
2053 * Install a Printmonitor
2056 * pName [I] Servername or NULL (local Computer)
2057 * Level [I] Structure-Level (Must be 2)
2058 * pMonitors [I] PTR to MONITOR_INFO_2
2065 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2068 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2070 LPMONITOR_INFO_2W mi2w;
2072 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2073 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2074 debugstr_w(mi2w ? mi2w->pName : NULL),
2075 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2076 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2078 if ((backend == NULL) && !load_backend()) return FALSE;
2081 SetLastError(ERROR_INVALID_LEVEL);
2085 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2090 return backend->fpAddMonitor(pName, Level, pMonitors);
2093 /******************************************************************
2094 * DeletePrinterDriverA [WINSPOOL.@]
2097 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2099 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2102 /******************************************************************
2103 * DeletePrinterDriverW [WINSPOOL.@]
2106 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2108 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2111 /******************************************************************
2112 * DeleteMonitorA [WINSPOOL.@]
2114 * See DeleteMonitorW.
2117 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2119 LPWSTR nameW = NULL;
2120 LPWSTR EnvironmentW = NULL;
2121 LPWSTR MonitorNameW = NULL;
2126 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2127 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2128 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2132 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2133 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2134 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2137 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2138 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2139 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2142 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2144 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2145 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2146 HeapFree(GetProcessHeap(), 0, nameW);
2150 /******************************************************************
2151 * DeleteMonitorW [WINSPOOL.@]
2153 * Delete a specific Printmonitor from a Printing-Environment
2156 * pName [I] Servername or NULL (local Computer)
2157 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2158 * pMonitorName [I] Name of the Monitor, that should be deleted
2165 * pEnvironment is ignored in Windows for the local Computer.
2168 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2171 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2172 debugstr_w(pMonitorName));
2174 if ((backend == NULL) && !load_backend()) return FALSE;
2176 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2180 /******************************************************************
2181 * DeletePortA [WINSPOOL.@]
2186 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2188 LPWSTR nameW = NULL;
2189 LPWSTR portW = NULL;
2193 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2195 /* convert servername to unicode */
2197 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2198 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2199 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2202 /* convert portname to unicode */
2204 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2205 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2209 res = DeletePortW(nameW, hWnd, portW);
2210 HeapFree(GetProcessHeap(), 0, nameW);
2211 HeapFree(GetProcessHeap(), 0, portW);
2215 /******************************************************************
2216 * DeletePortW [WINSPOOL.@]
2218 * Delete a specific Port
2221 * pName [I] Servername or NULL (local Computer)
2222 * hWnd [I] Handle to parent Window for the Dialog-Box
2223 * pPortName [I] Name of the Port, that should be deleted
2230 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2236 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2238 if (pName && pName[0]) {
2239 SetLastError(ERROR_INVALID_PARAMETER);
2244 SetLastError(RPC_X_NULL_REF_POINTER);
2248 /* an empty Portname is Invalid */
2249 if (!pPortName[0]) {
2250 SetLastError(ERROR_NOT_SUPPORTED);
2254 pm = monitor_load_by_port(pPortName);
2255 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2256 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2257 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2258 TRACE("got %d with %u\n", res, GetLastError());
2262 pui = monitor_loadui(pm);
2263 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2264 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2265 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2266 TRACE("got %d with %u\n", res, GetLastError());
2270 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2271 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2273 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2274 SetLastError(ERROR_NOT_SUPPORTED);
2277 monitor_unload(pui);
2281 TRACE("returning %d with %u\n", res, GetLastError());
2285 /******************************************************************************
2286 * SetPrinterW [WINSPOOL.@]
2288 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2290 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2291 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2295 /******************************************************************************
2296 * WritePrinter [WINSPOOL.@]
2298 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2300 opened_printer_t *printer;
2303 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2305 EnterCriticalSection(&printer_handles_cs);
2306 printer = get_opened_printer(hPrinter);
2309 SetLastError(ERROR_INVALID_HANDLE);
2315 SetLastError(ERROR_SPL_NO_STARTDOC);
2319 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2321 LeaveCriticalSection(&printer_handles_cs);
2325 /*****************************************************************************
2326 * AddFormA [WINSPOOL.@]
2328 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2330 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2334 /*****************************************************************************
2335 * AddFormW [WINSPOOL.@]
2337 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2339 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2343 /*****************************************************************************
2344 * AddJobA [WINSPOOL.@]
2346 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2349 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2353 SetLastError(ERROR_INVALID_LEVEL);
2357 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2360 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2361 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2362 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2363 if(*pcbNeeded > cbBuf) {
2364 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2367 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2368 addjobA->JobId = addjobW->JobId;
2369 addjobA->Path = (char *)(addjobA + 1);
2370 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2376 /*****************************************************************************
2377 * AddJobW [WINSPOOL.@]
2379 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2381 opened_printer_t *printer;
2384 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2385 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2386 WCHAR path[MAX_PATH], filename[MAX_PATH];
2388 ADDJOB_INFO_1W *addjob;
2390 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2392 EnterCriticalSection(&printer_handles_cs);
2394 printer = get_opened_printer(hPrinter);
2397 SetLastError(ERROR_INVALID_HANDLE);
2402 SetLastError(ERROR_INVALID_LEVEL);
2406 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2410 job->job_id = InterlockedIncrement(&next_job_id);
2412 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2413 if(path[len - 1] != '\\')
2415 memcpy(path + len, spool_path, sizeof(spool_path));
2416 sprintfW(filename, fmtW, path, job->job_id);
2418 len = strlenW(filename);
2419 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2420 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2421 job->document_title = strdupW(default_doc_title);
2422 list_add_tail(&printer->queue->jobs, &job->entry);
2424 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2425 if(*pcbNeeded <= cbBuf) {
2426 addjob = (ADDJOB_INFO_1W*)pData;
2427 addjob->JobId = job->job_id;
2428 addjob->Path = (WCHAR *)(addjob + 1);
2429 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2432 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2435 LeaveCriticalSection(&printer_handles_cs);
2439 /*****************************************************************************
2440 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2442 * Return the PATH for the Print-Processors
2444 * See GetPrintProcessorDirectoryW.
2448 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2449 DWORD level, LPBYTE Info,
2450 DWORD cbBuf, LPDWORD pcbNeeded)
2452 LPWSTR serverW = NULL;
2457 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2458 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2462 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2463 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2464 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2468 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2469 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2470 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2473 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2474 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2476 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2479 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2480 cbBuf, NULL, NULL) > 0;
2483 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2484 HeapFree(GetProcessHeap(), 0, envW);
2485 HeapFree(GetProcessHeap(), 0, serverW);
2489 /*****************************************************************************
2490 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2492 * Return the PATH for the Print-Processors
2495 * server [I] Servername (NT only) or NULL (local Computer)
2496 * env [I] Printing-Environment (see below) or NULL (Default)
2497 * level [I] Structure-Level (must be 1)
2498 * Info [O] PTR to Buffer that receives the Result
2499 * cbBuf [I] Size of Buffer at "Info"
2500 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2501 * required for the Buffer at "Info"
2504 * Success: TRUE and in pcbNeeded the Bytes used in Info
2505 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2506 * if cbBuf is too small
2508 * Native Values returned in Info on Success:
2509 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2510 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2511 *| win9x(Windows 4.0): "%winsysdir%"
2513 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2516 * Only NULL or "" is supported for server
2519 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2520 DWORD level, LPBYTE Info,
2521 DWORD cbBuf, LPDWORD pcbNeeded)
2524 const printenv_t * env_t;
2526 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2527 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2529 if(server != NULL && server[0]) {
2530 FIXME("server not supported: %s\n", debugstr_w(server));
2531 SetLastError(ERROR_INVALID_PARAMETER);
2535 env_t = validate_envW(env);
2536 if(!env_t) return FALSE; /* environment invalid or unsupported */
2539 WARN("(Level: %d) is ignored in win9x\n", level);
2540 SetLastError(ERROR_INVALID_LEVEL);
2544 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2545 needed = GetSystemDirectoryW(NULL, 0);
2546 /* add the Size for the Subdirectories */
2547 needed += lstrlenW(spoolprtprocsW);
2548 needed += lstrlenW(env_t->subdir);
2549 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2551 if(pcbNeeded) *pcbNeeded = needed;
2552 TRACE ("required: 0x%x/%d\n", needed, needed);
2553 if (needed > cbBuf) {
2554 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2557 if(pcbNeeded == NULL) {
2558 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2559 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2560 SetLastError(RPC_X_NULL_REF_POINTER);
2564 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2565 SetLastError(RPC_X_NULL_REF_POINTER);
2569 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2570 /* add the Subdirectories */
2571 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2572 lstrcatW((LPWSTR) Info, env_t->subdir);
2573 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2577 /*****************************************************************************
2578 * WINSPOOL_OpenDriverReg [internal]
2580 * opens the registry for the printer drivers depending on the given input
2581 * variable pEnvironment
2584 * the opened hkey on success
2587 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2591 const printenv_t * env;
2594 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2596 if (!pEnvironment || unicode) {
2597 /* pEnvironment was NULL or a Unicode-String: use it direct */
2598 env = validate_envW(pEnvironment);
2602 /* pEnvironment was an ANSI-String: convert to unicode first */
2604 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2605 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2606 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2607 env = validate_envW(buffer);
2608 HeapFree(GetProcessHeap(), 0, buffer);
2610 if (!env) return NULL;
2612 buffer = HeapAlloc( GetProcessHeap(), 0,
2613 (strlenW(DriversW) + strlenW(env->envname) +
2614 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2616 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2617 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2618 HeapFree(GetProcessHeap(), 0, buffer);
2623 /*****************************************************************************
2624 * AddPrinterW [WINSPOOL.@]
2626 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2628 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2632 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2634 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2635 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2636 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2637 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2638 statusW[] = {'S','t','a','t','u','s',0},
2639 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2641 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2644 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2645 SetLastError(ERROR_INVALID_PARAMETER);
2649 ERR("Level = %d, unsupported!\n", Level);
2650 SetLastError(ERROR_INVALID_LEVEL);
2654 SetLastError(ERROR_INVALID_PARAMETER);
2657 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2659 ERR("Can't create Printers key\n");
2662 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2663 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2664 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2665 RegCloseKey(hkeyPrinter);
2666 RegCloseKey(hkeyPrinters);
2669 RegCloseKey(hkeyPrinter);
2671 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2673 ERR("Can't create Drivers key\n");
2674 RegCloseKey(hkeyPrinters);
2677 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2679 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2680 RegCloseKey(hkeyPrinters);
2681 RegCloseKey(hkeyDrivers);
2682 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2685 RegCloseKey(hkeyDriver);
2686 RegCloseKey(hkeyDrivers);
2688 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2689 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2690 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2691 RegCloseKey(hkeyPrinters);
2695 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2697 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2698 SetLastError(ERROR_INVALID_PRINTER_NAME);
2699 RegCloseKey(hkeyPrinters);
2702 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2703 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2704 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2706 /* See if we can load the driver. We may need the devmode structure anyway
2709 * Note that DocumentPropertiesW will briefly try to open the printer we
2710 * just create to find a DEVMODEA struct (it will use the WINEPS default
2711 * one in case it is not there, so we are ok).
2713 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2716 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2717 size = sizeof(DEVMODEW);
2723 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2725 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2727 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2728 HeapFree(GetProcessHeap(),0,dmW);
2733 /* set devmode to printer name */
2734 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2738 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2739 and we support these drivers. NT writes DEVMODEW so somehow
2740 we'll need to distinguish between these when we support NT
2744 dmA = DEVMODEdupWtoA(dmW);
2745 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2746 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2747 HeapFree(GetProcessHeap(), 0, dmA);
2749 HeapFree(GetProcessHeap(), 0, dmW);
2751 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2752 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2753 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2754 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2756 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2757 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2758 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2759 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2760 (LPBYTE)&pi->Priority, sizeof(DWORD));
2761 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2762 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2763 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2764 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2765 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2766 (LPBYTE)&pi->Status, sizeof(DWORD));
2767 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2768 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2770 RegCloseKey(hkeyPrinter);
2771 RegCloseKey(hkeyPrinters);
2772 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2773 ERR("OpenPrinter failing\n");
2779 /*****************************************************************************
2780 * AddPrinterA [WINSPOOL.@]
2782 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2784 UNICODE_STRING pNameW;
2786 PRINTER_INFO_2W *piW;
2787 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2790 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2792 ERR("Level = %d, unsupported!\n", Level);
2793 SetLastError(ERROR_INVALID_LEVEL);
2796 pwstrNameW = asciitounicode(&pNameW,pName);
2797 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2799 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2801 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2802 RtlFreeUnicodeString(&pNameW);
2807 /*****************************************************************************
2808 * ClosePrinter [WINSPOOL.@]
2810 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2812 UINT_PTR i = (UINT_PTR)hPrinter;
2813 opened_printer_t *printer = NULL;
2816 TRACE("(%p)\n", hPrinter);
2818 EnterCriticalSection(&printer_handles_cs);
2820 if ((i > 0) && (i <= nb_printer_handles))
2821 printer = printer_handles[i - 1];
2826 struct list *cursor, *cursor2;
2828 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2830 if (printer->backend_printer) {
2831 backend->fpClosePrinter(printer->backend_printer);
2835 EndDocPrinter(hPrinter);
2837 if(InterlockedDecrement(&printer->queue->ref) == 0)
2839 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2841 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2842 ScheduleJob(hPrinter, job->job_id);
2844 HeapFree(GetProcessHeap(), 0, printer->queue);
2847 HeapFree(GetProcessHeap(), 0, printer->printername);
2848 HeapFree(GetProcessHeap(), 0, printer->name);
2849 HeapFree(GetProcessHeap(), 0, printer);
2850 printer_handles[i - 1] = NULL;
2853 LeaveCriticalSection(&printer_handles_cs);
2857 /*****************************************************************************
2858 * DeleteFormA [WINSPOOL.@]
2860 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2862 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2866 /*****************************************************************************
2867 * DeleteFormW [WINSPOOL.@]
2869 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2871 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2875 /*****************************************************************************
2876 * DeletePrinter [WINSPOOL.@]
2878 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2880 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2881 HKEY hkeyPrinters, hkey;
2884 SetLastError(ERROR_INVALID_HANDLE);
2887 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2888 RegDeleteTreeW(hkeyPrinters, lpNameW);
2889 RegCloseKey(hkeyPrinters);
2891 WriteProfileStringW(devicesW, lpNameW, NULL);
2892 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2894 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2895 RegDeleteValueW(hkey, lpNameW);
2899 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2900 RegDeleteValueW(hkey, lpNameW);
2906 /*****************************************************************************
2907 * SetPrinterA [WINSPOOL.@]
2909 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2912 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2916 /*****************************************************************************
2917 * SetJobA [WINSPOOL.@]
2919 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2920 LPBYTE pJob, DWORD Command)
2924 UNICODE_STRING usBuffer;
2926 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2928 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2929 are all ignored by SetJob, so we don't bother copying them */
2937 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2938 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2940 JobW = (LPBYTE)info1W;
2941 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2942 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2943 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2944 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2945 info1W->Status = info1A->Status;
2946 info1W->Priority = info1A->Priority;
2947 info1W->Position = info1A->Position;
2948 info1W->PagesPrinted = info1A->PagesPrinted;
2953 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2954 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2956 JobW = (LPBYTE)info2W;
2957 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2958 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2959 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2960 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2961 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2962 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2963 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2964 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2965 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2966 info2W->Status = info2A->Status;
2967 info2W->Priority = info2A->Priority;
2968 info2W->Position = info2A->Position;
2969 info2W->StartTime = info2A->StartTime;
2970 info2W->UntilTime = info2A->UntilTime;
2971 info2W->PagesPrinted = info2A->PagesPrinted;
2975 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2976 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2979 SetLastError(ERROR_INVALID_LEVEL);
2983 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2989 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2990 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2991 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2992 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2993 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2998 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2999 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3000 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3001 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3002 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3003 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3004 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3005 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3006 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3010 HeapFree(GetProcessHeap(), 0, JobW);
3015 /*****************************************************************************
3016 * SetJobW [WINSPOOL.@]
3018 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3019 LPBYTE pJob, DWORD Command)
3024 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3025 FIXME("Ignoring everything other than document title\n");
3027 EnterCriticalSection(&printer_handles_cs);
3028 job = get_job(hPrinter, JobId);
3038 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3039 HeapFree(GetProcessHeap(), 0, job->document_title);
3040 job->document_title = strdupW(info1->pDocument);
3045 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3046 HeapFree(GetProcessHeap(), 0, job->document_title);
3047 job->document_title = strdupW(info2->pDocument);
3053 SetLastError(ERROR_INVALID_LEVEL);
3058 LeaveCriticalSection(&printer_handles_cs);
3062 /*****************************************************************************
3063 * EndDocPrinter [WINSPOOL.@]
3065 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3067 opened_printer_t *printer;
3069 TRACE("(%p)\n", hPrinter);
3071 EnterCriticalSection(&printer_handles_cs);
3073 printer = get_opened_printer(hPrinter);
3076 SetLastError(ERROR_INVALID_HANDLE);
3082 SetLastError(ERROR_SPL_NO_STARTDOC);
3086 CloseHandle(printer->doc->hf);
3087 ScheduleJob(hPrinter, printer->doc->job_id);
3088 HeapFree(GetProcessHeap(), 0, printer->doc);
3089 printer->doc = NULL;
3092 LeaveCriticalSection(&printer_handles_cs);
3096 /*****************************************************************************
3097 * EndPagePrinter [WINSPOOL.@]
3099 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3101 FIXME("(%p): stub\n", hPrinter);
3105 /*****************************************************************************
3106 * StartDocPrinterA [WINSPOOL.@]
3108 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3110 UNICODE_STRING usBuffer;
3112 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3115 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3116 or one (DOC_INFO_3) extra DWORDs */
3120 doc2W.JobId = doc2->JobId;
3123 doc2W.dwMode = doc2->dwMode;
3126 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3127 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3128 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3132 SetLastError(ERROR_INVALID_LEVEL);
3136 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3138 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3139 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3140 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3145 /*****************************************************************************
3146 * StartDocPrinterW [WINSPOOL.@]
3148 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3150 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3151 opened_printer_t *printer;
3152 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3153 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3154 JOB_INFO_1W job_info;
3155 DWORD needed, ret = 0;
3159 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3160 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3161 debugstr_w(doc->pDatatype));
3163 if(Level < 1 || Level > 3)
3165 SetLastError(ERROR_INVALID_LEVEL);
3169 EnterCriticalSection(&printer_handles_cs);
3170 printer = get_opened_printer(hPrinter);
3173 SetLastError(ERROR_INVALID_HANDLE);
3179 SetLastError(ERROR_INVALID_PRINTER_STATE);
3183 /* Even if we're printing to a file we still add a print job, we'll
3184 just ignore the spool file name */
3186 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3188 ERR("AddJob failed gle %u\n", GetLastError());
3192 if(doc->pOutputFile)
3193 filename = doc->pOutputFile;
3195 filename = addjob->Path;
3197 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3198 if(hf == INVALID_HANDLE_VALUE)
3201 memset(&job_info, 0, sizeof(job_info));
3202 job_info.pDocument = doc->pDocName;
3203 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3205 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3206 printer->doc->hf = hf;
3207 ret = printer->doc->job_id = addjob->JobId;
3209 LeaveCriticalSection(&printer_handles_cs);
3214 /*****************************************************************************
3215 * StartPagePrinter [WINSPOOL.@]
3217 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3219 FIXME("(%p): stub\n", hPrinter);
3223 /*****************************************************************************
3224 * GetFormA [WINSPOOL.@]
3226 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3227 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3229 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3230 Level,pForm,cbBuf,pcbNeeded);
3234 /*****************************************************************************
3235 * GetFormW [WINSPOOL.@]
3237 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3238 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3240 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3241 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3245 /*****************************************************************************
3246 * SetFormA [WINSPOOL.@]
3248 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3251 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3255 /*****************************************************************************
3256 * SetFormW [WINSPOOL.@]
3258 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3261 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3265 /*****************************************************************************
3266 * ReadPrinter [WINSPOOL.@]
3268 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3269 LPDWORD pNoBytesRead)
3271 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3275 /*****************************************************************************
3276 * ResetPrinterA [WINSPOOL.@]
3278 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3280 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3284 /*****************************************************************************
3285 * ResetPrinterW [WINSPOOL.@]
3287 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3289 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3293 /*****************************************************************************
3294 * WINSPOOL_GetDWORDFromReg
3296 * Return DWORD associated with ValueName from hkey.
3298 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3300 DWORD sz = sizeof(DWORD), type, value = 0;
3303 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3305 if(ret != ERROR_SUCCESS) {
3306 WARN("Got ret = %d on name %s\n", ret, ValueName);
3309 if(type != REG_DWORD) {
3310 ERR("Got type %d\n", type);
3317 /*****************************************************************************
3318 * get_filename_from_reg [internal]
3320 * Get ValueName from hkey storing result in out
3321 * when the Value in the registry has only a filename, use driverdir as prefix
3322 * outlen is space left in out
3323 * String is stored either as unicode or ascii
3327 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3328 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3330 WCHAR filename[MAX_PATH];
3334 LPWSTR buffer = filename;
3338 size = sizeof(filename);
3340 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3341 if (ret == ERROR_MORE_DATA) {
3342 TRACE("need dynamic buffer: %u\n", size);
3343 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3345 /* No Memory is bad */
3349 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3352 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3353 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3359 /* do we have a full path ? */
3360 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3361 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3364 /* we must build the full Path */
3366 if ((out) && (outlen > dirlen)) {
3368 lstrcpyW((LPWSTR)out, driverdir);
3372 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3381 /* write the filename */
3383 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3384 if ((out) && (outlen >= size)) {
3385 lstrcpyW((LPWSTR)out, ptr);
3394 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3395 if ((out) && (outlen >= size)) {
3396 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3404 ptr += lstrlenW(ptr)+1;
3405 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3408 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3410 /* write the multisz-termination */
3411 if (type == REG_MULTI_SZ) {
3412 size = (unicode) ? sizeof(WCHAR) : 1;
3415 if (out && (outlen >= size)) {
3416 memset (out, 0, size);
3422 /*****************************************************************************
3423 * WINSPOOL_GetStringFromReg
3425 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3426 * String is stored either as unicode or ascii.
3427 * Bit of a hack here to get the ValueName if we want ascii.
3429 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3430 DWORD buflen, DWORD *needed,
3433 DWORD sz = buflen, type;
3437 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3439 LPSTR ValueNameA = strdupWtoA(ValueName);
3440 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3441 HeapFree(GetProcessHeap(),0,ValueNameA);
3443 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3444 WARN("Got ret = %d\n", ret);
3448 /* add space for terminating '\0' */
3449 sz += unicode ? sizeof(WCHAR) : 1;
3453 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3458 /*****************************************************************************
3459 * WINSPOOL_GetDefaultDevMode
3461 * Get a default DevMode values for wineps.
3465 static void WINSPOOL_GetDefaultDevMode(
3467 DWORD buflen, DWORD *needed,
3471 static const char szwps[] = "wineps.drv";
3473 /* fill default DEVMODE - should be read from ppd... */
3474 ZeroMemory( &dm, sizeof(dm) );
3475 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3476 dm.dmSpecVersion = DM_SPECVERSION;
3477 dm.dmDriverVersion = 1;
3478 dm.dmSize = sizeof(DEVMODEA);
3479 dm.dmDriverExtra = 0;
3481 DM_ORIENTATION | DM_PAPERSIZE |
3482 DM_PAPERLENGTH | DM_PAPERWIDTH |
3485 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3486 DM_YRESOLUTION | DM_TTOPTION;
3488 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3489 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3490 dm.u1.s1.dmPaperLength = 2970;
3491 dm.u1.s1.dmPaperWidth = 2100;
3493 dm.u1.s1.dmScale = 100;
3494 dm.u1.s1.dmCopies = 1;
3495 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3496 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3499 dm.dmYResolution = 300; /* 300dpi */
3500 dm.dmTTOption = DMTT_BITMAP;
3503 /* dm.dmLogPixels */
3504 /* dm.dmBitsPerPel */
3505 /* dm.dmPelsWidth */
3506 /* dm.dmPelsHeight */
3507 /* dm.u2.dmDisplayFlags */
3508 /* dm.dmDisplayFrequency */
3509 /* dm.dmICMMethod */
3510 /* dm.dmICMIntent */
3511 /* dm.dmMediaType */
3512 /* dm.dmDitherType */
3513 /* dm.dmReserved1 */
3514 /* dm.dmReserved2 */
3515 /* dm.dmPanningWidth */
3516 /* dm.dmPanningHeight */
3519 if(buflen >= sizeof(DEVMODEW)) {
3520 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3521 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3522 HeapFree(GetProcessHeap(),0,pdmW);
3524 *needed = sizeof(DEVMODEW);
3528 if(buflen >= sizeof(DEVMODEA)) {
3529 memcpy(ptr, &dm, sizeof(DEVMODEA));
3531 *needed = sizeof(DEVMODEA);
3535 /*****************************************************************************
3536 * WINSPOOL_GetDevModeFromReg
3538 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3539 * DevMode is stored either as unicode or ascii.
3541 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3543 DWORD buflen, DWORD *needed,
3546 DWORD sz = buflen, type;
3549 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3550 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3551 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3552 if (sz < sizeof(DEVMODEA))
3554 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3557 /* ensures that dmSize is not erratically bogus if registry is invalid */
3558 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3559 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3561 sz += (CCHDEVICENAME + CCHFORMNAME);
3563 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3564 memcpy(ptr, dmW, sz);
3565 HeapFree(GetProcessHeap(),0,dmW);
3572 /*********************************************************************
3573 * WINSPOOL_GetPrinter_1
3575 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3576 * The strings are either stored as unicode or ascii.
3578 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3579 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3582 DWORD size, left = cbBuf;
3583 BOOL space = (cbBuf > 0);
3588 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3590 if(space && size <= left) {
3591 pi1->pName = (LPWSTR)ptr;
3599 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3600 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3602 if(space && size <= left) {
3603 pi1->pDescription = (LPWSTR)ptr;
3611 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3613 if(space && size <= left) {
3614 pi1->pComment = (LPWSTR)ptr;
3622 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3624 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3625 memset(pi1, 0, sizeof(*pi1));
3629 /*********************************************************************
3630 * WINSPOOL_GetPrinter_2
3632 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3633 * The strings are either stored as unicode or ascii.
3635 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3636 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3639 DWORD size, left = cbBuf;
3640 BOOL space = (cbBuf > 0);
3645 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3647 if(space && size <= left) {
3648 pi2->pPrinterName = (LPWSTR)ptr;
3655 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3657 if(space && size <= left) {
3658 pi2->pShareName = (LPWSTR)ptr;
3665 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3667 if(space && size <= left) {
3668 pi2->pPortName = (LPWSTR)ptr;
3675 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3677 if(space && size <= left) {
3678 pi2->pDriverName = (LPWSTR)ptr;
3685 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3687 if(space && size <= left) {
3688 pi2->pComment = (LPWSTR)ptr;
3695 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3697 if(space && size <= left) {
3698 pi2->pLocation = (LPWSTR)ptr;
3705 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3707 if(space && size <= left) {
3708 pi2->pDevMode = (LPDEVMODEW)ptr;
3717 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3718 if(space && size <= left) {
3719 pi2->pDevMode = (LPDEVMODEW)ptr;
3726 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3728 if(space && size <= left) {
3729 pi2->pSepFile = (LPWSTR)ptr;
3736 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3738 if(space && size <= left) {
3739 pi2->pPrintProcessor = (LPWSTR)ptr;
3746 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3748 if(space && size <= left) {
3749 pi2->pDatatype = (LPWSTR)ptr;
3756 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3758 if(space && size <= left) {
3759 pi2->pParameters = (LPWSTR)ptr;
3767 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3768 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3769 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3770 "Default Priority");
3771 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3772 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3775 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3776 memset(pi2, 0, sizeof(*pi2));
3781 /*********************************************************************
3782 * WINSPOOL_GetPrinter_4
3784 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3786 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3787 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3790 DWORD size, left = cbBuf;
3791 BOOL space = (cbBuf > 0);
3796 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3798 if(space && size <= left) {
3799 pi4->pPrinterName = (LPWSTR)ptr;
3807 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3810 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3811 memset(pi4, 0, sizeof(*pi4));
3816 /*********************************************************************
3817 * WINSPOOL_GetPrinter_5
3819 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3821 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3822 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3825 DWORD size, left = cbBuf;
3826 BOOL space = (cbBuf > 0);
3831 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3833 if(space && size <= left) {
3834 pi5->pPrinterName = (LPWSTR)ptr;
3841 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3843 if(space && size <= left) {
3844 pi5->pPortName = (LPWSTR)ptr;
3852 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3853 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3855 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3859 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3860 memset(pi5, 0, sizeof(*pi5));
3865 /*********************************************************************
3866 * WINSPOOL_GetPrinter_7
3868 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3870 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3871 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3873 DWORD size, left = cbBuf;
3874 BOOL space = (cbBuf > 0);
3879 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3881 if (space && size <= left) {
3882 pi7->pszObjectGUID = (LPWSTR)ptr;
3890 /* We do not have a Directory Service */
3891 pi7->dwAction = DSPRINT_UNPUBLISH;
3894 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3895 memset(pi7, 0, sizeof(*pi7));
3900 /*********************************************************************
3901 * WINSPOOL_GetPrinter_9
3903 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3904 * The strings are either stored as unicode or ascii.
3906 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3907 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3910 BOOL space = (cbBuf > 0);
3914 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3915 if(space && size <= cbBuf) {
3916 pi9->pDevMode = (LPDEVMODEW)buf;
3923 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3924 if(space && size <= cbBuf) {
3925 pi9->pDevMode = (LPDEVMODEW)buf;
3931 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3932 memset(pi9, 0, sizeof(*pi9));
3937 /*****************************************************************************
3938 * WINSPOOL_GetPrinter
3940 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3941 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3942 * just a collection of pointers to strings.
3944 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3945 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3948 DWORD size, needed = 0;
3950 HKEY hkeyPrinter, hkeyPrinters;
3953 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3955 if (!(name = get_opened_printer_name(hPrinter))) {
3956 SetLastError(ERROR_INVALID_HANDLE);
3960 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3962 ERR("Can't create Printers key\n");
3965 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3967 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3968 RegCloseKey(hkeyPrinters);
3969 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3976 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3978 size = sizeof(PRINTER_INFO_2W);
3980 ptr = pPrinter + size;
3982 memset(pPrinter, 0, size);
3987 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3995 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3997 size = sizeof(PRINTER_INFO_4W);
3999 ptr = pPrinter + size;
4001 memset(pPrinter, 0, size);
4006 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4015 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4017 size = sizeof(PRINTER_INFO_5W);
4019 ptr = pPrinter + size;
4021 memset(pPrinter, 0, size);
4027 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4036 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4038 size = sizeof(PRINTER_INFO_6);
4039 if (size <= cbBuf) {
4040 /* FIXME: We do not update the status yet */
4041 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4053 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4055 size = sizeof(PRINTER_INFO_7W);
4056 if (size <= cbBuf) {
4057 ptr = pPrinter + size;
4059 memset(pPrinter, 0, size);
4065 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4073 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4075 size = sizeof(PRINTER_INFO_9W);
4077 ptr = pPrinter + size;
4079 memset(pPrinter, 0, size);
4085 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4092 FIXME("Unimplemented level %d\n", Level);
4093 SetLastError(ERROR_INVALID_LEVEL);
4094 RegCloseKey(hkeyPrinters);
4095 RegCloseKey(hkeyPrinter);
4099 RegCloseKey(hkeyPrinter);
4100 RegCloseKey(hkeyPrinters);
4102 TRACE("returning %d needed = %d\n", ret, needed);
4103 if(pcbNeeded) *pcbNeeded = needed;
4105 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4109 /*****************************************************************************
4110 * GetPrinterW [WINSPOOL.@]
4112 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4113 DWORD cbBuf, LPDWORD pcbNeeded)
4115 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4119 /*****************************************************************************
4120 * GetPrinterA [WINSPOOL.@]
4122 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4123 DWORD cbBuf, LPDWORD pcbNeeded)
4125 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4129 /*****************************************************************************
4130 * WINSPOOL_EnumPrinters
4132 * Implementation of EnumPrintersA|W
4134 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4135 DWORD dwLevel, LPBYTE lpbPrinters,
4136 DWORD cbBuf, LPDWORD lpdwNeeded,
4137 LPDWORD lpdwReturned, BOOL unicode)
4140 HKEY hkeyPrinters, hkeyPrinter;
4141 WCHAR PrinterName[255];
4142 DWORD needed = 0, number = 0;
4143 DWORD used, i, left;
4147 memset(lpbPrinters, 0, cbBuf);
4153 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4154 if(dwType == PRINTER_ENUM_DEFAULT)
4157 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4158 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4159 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4161 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4169 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4170 FIXME("dwType = %08x\n", dwType);
4171 SetLastError(ERROR_INVALID_FLAGS);
4175 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4177 ERR("Can't create Printers key\n");
4181 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4182 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4183 RegCloseKey(hkeyPrinters);
4184 ERR("Can't query Printers key\n");
4187 TRACE("Found %d printers\n", number);
4191 used = number * sizeof(PRINTER_INFO_1W);
4194 used = number * sizeof(PRINTER_INFO_2W);
4197 used = number * sizeof(PRINTER_INFO_4W);
4200 used = number * sizeof(PRINTER_INFO_5W);
4204 SetLastError(ERROR_INVALID_LEVEL);
4205 RegCloseKey(hkeyPrinters);
4208 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4210 for(i = 0; i < number; i++) {
4211 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4213 ERR("Can't enum key number %d\n", i);
4214 RegCloseKey(hkeyPrinters);
4217 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4218 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4220 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4221 RegCloseKey(hkeyPrinters);
4226 buf = lpbPrinters + used;
4227 left = cbBuf - used;
4235 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4236 left, &needed, unicode);
4238 if(pi) pi += sizeof(PRINTER_INFO_1W);
4241 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4242 left, &needed, unicode);
4244 if(pi) pi += sizeof(PRINTER_INFO_2W);
4247 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4248 left, &needed, unicode);
4250 if(pi) pi += sizeof(PRINTER_INFO_4W);
4253 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4254 left, &needed, unicode);
4256 if(pi) pi += sizeof(PRINTER_INFO_5W);
4259 ERR("Shouldn't be here!\n");
4260 RegCloseKey(hkeyPrinter);
4261 RegCloseKey(hkeyPrinters);
4264 RegCloseKey(hkeyPrinter);
4266 RegCloseKey(hkeyPrinters);
4273 memset(lpbPrinters, 0, cbBuf);
4274 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4278 *lpdwReturned = number;
4279 SetLastError(ERROR_SUCCESS);
4284 /******************************************************************
4285 * EnumPrintersW [WINSPOOL.@]
4287 * Enumerates the available printers, print servers and print
4288 * providers, depending on the specified flags, name and level.
4292 * If level is set to 1:
4293 * Returns an array of PRINTER_INFO_1 data structures in the
4294 * lpbPrinters buffer.
4296 * If level is set to 2:
4297 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4298 * Returns an array of PRINTER_INFO_2 data structures in the
4299 * lpbPrinters buffer. Note that according to MSDN also an
4300 * OpenPrinter should be performed on every remote printer.
4302 * If level is set to 4 (officially WinNT only):
4303 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4304 * Fast: Only the registry is queried to retrieve printer names,
4305 * no connection to the driver is made.
4306 * Returns an array of PRINTER_INFO_4 data structures in the
4307 * lpbPrinters buffer.
4309 * If level is set to 5 (officially WinNT4/Win9x only):
4310 * Fast: Only the registry is queried to retrieve printer names,
4311 * no connection to the driver is made.
4312 * Returns an array of PRINTER_INFO_5 data structures in the
4313 * lpbPrinters buffer.
4315 * If level set to 3 or 6+:
4316 * returns zero (failure!)
4318 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4322 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4323 * - Only levels 2, 4 and 5 are implemented at the moment.
4324 * - 16-bit printer drivers are not enumerated.
4325 * - Returned amount of bytes used/needed does not match the real Windoze
4326 * implementation (as in this implementation, all strings are part
4327 * of the buffer, whereas Win32 keeps them somewhere else)
4328 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4331 * - In a regular Wine installation, no registry settings for printers
4332 * exist, which makes this function return an empty list.
4334 BOOL WINAPI EnumPrintersW(
4335 DWORD dwType, /* [in] Types of print objects to enumerate */
4336 LPWSTR lpszName, /* [in] name of objects to enumerate */
4337 DWORD dwLevel, /* [in] type of printer info structure */
4338 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4339 DWORD cbBuf, /* [in] max size of buffer in bytes */
4340 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4341 LPDWORD lpdwReturned /* [out] number of entries returned */
4344 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4345 lpdwNeeded, lpdwReturned, TRUE);
4348 /******************************************************************
4349 * EnumPrintersA [WINSPOOL.@]
4354 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4355 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4358 UNICODE_STRING pNameU;
4362 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4363 pPrinters, cbBuf, pcbNeeded, pcReturned);
4365 pNameW = asciitounicode(&pNameU, pName);
4367 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4368 MS Office need this */
4369 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4371 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4373 RtlFreeUnicodeString(&pNameU);
4375 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4377 HeapFree(GetProcessHeap(), 0, pPrintersW);
4381 /*****************************************************************************
4382 * WINSPOOL_GetDriverInfoFromReg [internal]
4384 * Enters the information from the registry into the DRIVER_INFO struct
4387 * zero if the printer driver does not exist in the registry
4388 * (only if Level > 1) otherwise nonzero
4390 static BOOL WINSPOOL_GetDriverInfoFromReg(
4393 const printenv_t * env,
4395 LPBYTE ptr, /* DRIVER_INFO */
4396 LPBYTE pDriverStrings, /* strings buffer */
4397 DWORD cbBuf, /* size of string buffer */
4398 LPDWORD pcbNeeded, /* space needed for str. */
4399 BOOL unicode) /* type of strings */
4403 WCHAR driverdir[MAX_PATH];
4405 LPBYTE strPtr = pDriverStrings;
4406 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4408 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4409 debugstr_w(DriverName), env,
4410 Level, di, pDriverStrings, cbBuf, unicode);
4412 if (di) ZeroMemory(di, di_sizeof[Level]);
4415 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4416 if (*pcbNeeded <= cbBuf)
4417 strcpyW((LPWSTR)strPtr, DriverName);
4421 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4422 if (*pcbNeeded <= cbBuf)
4423 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4426 /* pName for level 1 has a different offset! */
4428 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4432 /* .cVersion and .pName for level > 1 */
4434 di->cVersion = env->driverversion;
4435 di->pName = (LPWSTR) strPtr;
4436 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4439 /* Reserve Space for the largest subdir and a Backslash*/
4440 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4441 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4442 /* Should never Fail */
4445 lstrcatW(driverdir, env->versionsubdir);
4446 lstrcatW(driverdir, backslashW);
4448 /* dirlen must not include the terminating zero */
4449 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4450 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4452 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4453 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4454 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4460 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4462 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4465 if (*pcbNeeded <= cbBuf) {
4467 lstrcpyW((LPWSTR)strPtr, env->envname);
4471 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4473 if (di) di->pEnvironment = (LPWSTR)strPtr;
4474 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4477 /* .pDriverPath is the Graphics rendering engine.
4478 The full Path is required to avoid a crash in some apps */
4479 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4481 if (*pcbNeeded <= cbBuf)
4482 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4484 if (di) di->pDriverPath = (LPWSTR)strPtr;
4485 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4488 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4489 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4491 if (*pcbNeeded <= cbBuf)
4492 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4494 if (di) di->pDataFile = (LPWSTR)strPtr;
4495 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4498 /* .pConfigFile is the Driver user Interface */
4499 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4501 if (*pcbNeeded <= cbBuf)
4502 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4504 if (di) di->pConfigFile = (LPWSTR)strPtr;
4505 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4509 RegCloseKey(hkeyDriver);
4510 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4515 RegCloseKey(hkeyDriver);
4516 FIXME("level 5: incomplete\n");
4521 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4523 if (*pcbNeeded <= cbBuf)
4524 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4526 if (di) di->pHelpFile = (LPWSTR)strPtr;
4527 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4530 /* .pDependentFiles */
4531 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4533 if (*pcbNeeded <= cbBuf)
4534 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4536 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4537 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4539 else if (GetVersion() & 0x80000000) {
4540 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4541 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4543 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4545 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4546 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4549 /* .pMonitorName is the optional Language Monitor */
4550 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4552 if (*pcbNeeded <= cbBuf)
4553 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4555 if (di) di->pMonitorName = (LPWSTR)strPtr;
4556 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4559 /* .pDefaultDataType */
4560 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4562 if(*pcbNeeded <= cbBuf)
4563 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4565 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4566 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4570 RegCloseKey(hkeyDriver);
4571 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4575 /* .pszzPreviousNames */
4576 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4578 if(*pcbNeeded <= cbBuf)
4579 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4581 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4582 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4586 RegCloseKey(hkeyDriver);
4587 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4591 /* support is missing, but not important enough for a FIXME */
4592 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4595 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4597 if(*pcbNeeded <= cbBuf)
4598 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4600 if (di) di->pszMfgName = (LPWSTR)strPtr;
4601 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4605 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4607 if(*pcbNeeded <= cbBuf)
4608 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4610 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4611 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4614 /* .pszHardwareID */
4615 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4617 if(*pcbNeeded <= cbBuf)
4618 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4620 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4621 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4625 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4627 if(*pcbNeeded <= cbBuf)
4628 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4630 if (di) di->pszProvider = (LPWSTR)strPtr;
4631 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4635 RegCloseKey(hkeyDriver);
4639 /* support is missing, but not important enough for a FIXME */
4640 TRACE("level 8: incomplete\n");
4642 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4643 RegCloseKey(hkeyDriver);
4647 /*****************************************************************************
4648 * WINSPOOL_GetPrinterDriver
4650 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4651 DWORD Level, LPBYTE pDriverInfo,
4652 DWORD cbBuf, LPDWORD pcbNeeded,
4656 WCHAR DriverName[100];
4657 DWORD ret, type, size, needed = 0;
4659 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4660 const printenv_t * env;
4662 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4663 Level,pDriverInfo,cbBuf, pcbNeeded);
4666 if (!(name = get_opened_printer_name(hPrinter))) {
4667 SetLastError(ERROR_INVALID_HANDLE);
4671 if (Level < 1 || Level == 7 || Level > 8) {
4672 SetLastError(ERROR_INVALID_LEVEL);
4676 env = validate_envW(pEnvironment);
4677 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4679 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4681 ERR("Can't create Printers key\n");
4684 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4686 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4687 RegCloseKey(hkeyPrinters);
4688 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4691 size = sizeof(DriverName);
4693 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4694 (LPBYTE)DriverName, &size);
4695 RegCloseKey(hkeyPrinter);
4696 RegCloseKey(hkeyPrinters);
4697 if(ret != ERROR_SUCCESS) {
4698 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4702 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4704 ERR("Can't create Drivers key\n");
4708 size = di_sizeof[Level];
4709 if ((size <= cbBuf) && pDriverInfo)
4710 ptr = pDriverInfo + size;
4712 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4713 env, Level, pDriverInfo, ptr,
4714 (cbBuf < size) ? 0 : cbBuf - size,
4715 &needed, unicode)) {
4716 RegCloseKey(hkeyDrivers);
4720 RegCloseKey(hkeyDrivers);
4722 if(pcbNeeded) *pcbNeeded = size + needed;
4723 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4724 if(cbBuf >= needed) return TRUE;
4725 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4729 /*****************************************************************************
4730 * GetPrinterDriverA [WINSPOOL.@]
4732 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4733 DWORD Level, LPBYTE pDriverInfo,
4734 DWORD cbBuf, LPDWORD pcbNeeded)
4737 UNICODE_STRING pEnvW;
4740 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4741 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4742 cbBuf, pcbNeeded, FALSE);
4743 RtlFreeUnicodeString(&pEnvW);
4746 /*****************************************************************************
4747 * GetPrinterDriverW [WINSPOOL.@]
4749 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4750 DWORD Level, LPBYTE pDriverInfo,
4751 DWORD cbBuf, LPDWORD pcbNeeded)
4753 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4754 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4757 /*****************************************************************************
4758 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4760 * Return the PATH for the Printer-Drivers (UNICODE)
4763 * pName [I] Servername (NT only) or NULL (local Computer)
4764 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4765 * Level [I] Structure-Level (must be 1)
4766 * pDriverDirectory [O] PTR to Buffer that receives the Result
4767 * cbBuf [I] Size of Buffer at pDriverDirectory
4768 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4769 * required for pDriverDirectory
4772 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4773 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4774 * if cbBuf is too small
4776 * Native Values returned in pDriverDirectory on Success:
4777 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4778 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4779 *| win9x(Windows 4.0): "%winsysdir%"
4781 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4784 *- Only NULL or "" is supported for pName
4787 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4788 DWORD Level, LPBYTE pDriverDirectory,
4789 DWORD cbBuf, LPDWORD pcbNeeded)
4791 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4792 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4794 if ((backend == NULL) && !load_backend()) return FALSE;
4797 /* (Level != 1) is ignored in win9x */
4798 SetLastError(ERROR_INVALID_LEVEL);
4801 if (pcbNeeded == NULL) {
4802 /* (pcbNeeded == NULL) is ignored in win9x */
4803 SetLastError(RPC_X_NULL_REF_POINTER);
4807 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4808 pDriverDirectory, cbBuf, pcbNeeded);
4813 /*****************************************************************************
4814 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4816 * Return the PATH for the Printer-Drivers (ANSI)
4818 * See GetPrinterDriverDirectoryW.
4821 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4824 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4825 DWORD Level, LPBYTE pDriverDirectory,
4826 DWORD cbBuf, LPDWORD pcbNeeded)
4828 UNICODE_STRING nameW, environmentW;
4831 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4832 WCHAR *driverDirectoryW = NULL;
4834 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4835 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4837 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4839 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4840 else nameW.Buffer = NULL;
4841 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4842 else environmentW.Buffer = NULL;
4844 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4845 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4848 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4849 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4851 *pcbNeeded = needed;
4852 ret = (needed <= cbBuf) ? TRUE : FALSE;
4854 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4856 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4858 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4859 RtlFreeUnicodeString(&environmentW);
4860 RtlFreeUnicodeString(&nameW);
4865 /*****************************************************************************
4866 * AddPrinterDriverA [WINSPOOL.@]
4868 * See AddPrinterDriverW.
4871 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4873 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4874 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4877 /******************************************************************************
4878 * AddPrinterDriverW (WINSPOOL.@)
4880 * Install a Printer Driver
4883 * pName [I] Servername or NULL (local Computer)
4884 * level [I] Level for the supplied DRIVER_INFO_*W struct
4885 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4892 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4894 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4895 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4898 /*****************************************************************************
4899 * AddPrintProcessorA [WINSPOOL.@]
4901 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4902 LPSTR pPrintProcessorName)
4904 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4905 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4909 /*****************************************************************************
4910 * AddPrintProcessorW [WINSPOOL.@]
4912 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4913 LPWSTR pPrintProcessorName)
4915 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4916 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4920 /*****************************************************************************
4921 * AddPrintProvidorA [WINSPOOL.@]
4923 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4925 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4929 /*****************************************************************************
4930 * AddPrintProvidorW [WINSPOOL.@]
4932 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4934 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4938 /*****************************************************************************
4939 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4941 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4942 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4944 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4945 pDevModeOutput, pDevModeInput);
4949 /*****************************************************************************
4950 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4952 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4953 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4955 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4956 pDevModeOutput, pDevModeInput);
4960 /*****************************************************************************
4961 * PrinterProperties [WINSPOOL.@]
4963 * Displays a dialog to set the properties of the printer.
4966 * nonzero on success or zero on failure
4969 * implemented as stub only
4971 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4972 HANDLE hPrinter /* [in] handle to printer object */
4974 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4975 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4979 /*****************************************************************************
4980 * EnumJobsA [WINSPOOL.@]
4983 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4984 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4987 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4988 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4990 if(pcbNeeded) *pcbNeeded = 0;
4991 if(pcReturned) *pcReturned = 0;
4996 /*****************************************************************************
4997 * EnumJobsW [WINSPOOL.@]
5000 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5001 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5004 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5005 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5007 if(pcbNeeded) *pcbNeeded = 0;
5008 if(pcReturned) *pcReturned = 0;
5012 /*****************************************************************************
5013 * WINSPOOL_EnumPrinterDrivers [internal]
5015 * Delivers information about all printer drivers installed on the
5016 * localhost or a given server
5019 * nonzero on success or zero on failure. If the buffer for the returned
5020 * information is too small the function will return an error
5023 * - only implemented for localhost, foreign hosts will return an error
5025 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5026 DWORD Level, LPBYTE pDriverInfo,
5027 DWORD cbBuf, LPDWORD pcbNeeded,
5028 LPDWORD pcReturned, BOOL unicode)
5031 DWORD i, needed, number = 0, size = 0;
5032 WCHAR DriverNameW[255];
5034 const printenv_t * env;
5036 TRACE("%s,%s,%d,%p,%d,%d\n",
5037 debugstr_w(pName), debugstr_w(pEnvironment),
5038 Level, pDriverInfo, cbBuf, unicode);
5040 /* check for local drivers */
5041 if((pName) && (pName[0])) {
5042 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5043 SetLastError(ERROR_ACCESS_DENIED);
5047 env = validate_envW(pEnvironment);
5048 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5050 /* check input parameter */
5051 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5052 SetLastError(ERROR_INVALID_LEVEL);
5056 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5057 SetLastError(RPC_X_NULL_REF_POINTER);
5061 /* initialize return values */
5063 memset( pDriverInfo, 0, cbBuf);
5067 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5069 ERR("Can't open Drivers key\n");
5073 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5074 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5075 RegCloseKey(hkeyDrivers);
5076 ERR("Can't query Drivers key\n");
5079 TRACE("Found %d Drivers\n", number);
5081 /* get size of single struct
5082 * unicode and ascii structure have the same size
5084 size = di_sizeof[Level];
5086 /* calculate required buffer size */
5087 *pcbNeeded = size * number;
5089 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5091 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5092 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5094 ERR("Can't enum key number %d\n", i);
5095 RegCloseKey(hkeyDrivers);
5098 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5100 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5101 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5102 &needed, unicode)) {
5103 RegCloseKey(hkeyDrivers);
5106 *pcbNeeded += needed;
5109 RegCloseKey(hkeyDrivers);
5111 if(cbBuf < *pcbNeeded){
5112 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5116 *pcReturned = number;
5120 /*****************************************************************************
5121 * EnumPrinterDriversW [WINSPOOL.@]
5123 * see function EnumPrinterDrivers for RETURNS, BUGS
5125 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5126 LPBYTE pDriverInfo, DWORD cbBuf,
5127 LPDWORD pcbNeeded, LPDWORD pcReturned)
5129 static const WCHAR allW[] = {'a','l','l',0};
5131 if (pEnvironment && !strcmpW(pEnvironment, allW))
5134 DWORD i, needed, returned, bufsize = cbBuf;
5136 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5138 needed = returned = 0;
5139 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5140 pDriverInfo, bufsize, &needed, &returned, TRUE);
5141 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5145 if (pDriverInfo) pDriverInfo += needed;
5146 if (pcReturned) *pcReturned += returned;
5148 if (pcbNeeded) *pcbNeeded += needed;
5152 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5153 cbBuf, pcbNeeded, pcReturned, TRUE);
5156 /*****************************************************************************
5157 * EnumPrinterDriversA [WINSPOOL.@]
5159 * see function EnumPrinterDrivers for RETURNS, BUGS
5161 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5162 LPBYTE pDriverInfo, DWORD cbBuf,
5163 LPDWORD pcbNeeded, LPDWORD pcReturned)
5166 UNICODE_STRING pNameW, pEnvironmentW;
5167 PWSTR pwstrNameW, pwstrEnvironmentW;
5169 pwstrNameW = asciitounicode(&pNameW, pName);
5170 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5172 if (pEnvironment && !strcmp(pEnvironment, "all"))
5174 DWORD i, needed, returned, bufsize = cbBuf;
5176 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5178 needed = returned = 0;
5179 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
5180 pDriverInfo, bufsize, &needed, &returned, FALSE);
5181 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
5185 if (pDriverInfo) pDriverInfo += needed;
5186 if (pcReturned) *pcReturned += returned;
5188 if (pcbNeeded) *pcbNeeded += needed;
5191 else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5192 Level, pDriverInfo, cbBuf, pcbNeeded,
5194 RtlFreeUnicodeString(&pNameW);
5195 RtlFreeUnicodeString(&pEnvironmentW);
5200 /******************************************************************************
5201 * EnumPortsA (WINSPOOL.@)
5206 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5207 LPDWORD pcbNeeded, LPDWORD pcReturned)
5210 LPBYTE bufferW = NULL;
5211 LPWSTR nameW = NULL;
5213 DWORD numentries = 0;
5216 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5217 cbBuf, pcbNeeded, pcReturned);
5219 /* convert servername to unicode */
5221 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5222 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5223 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5225 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5226 needed = cbBuf * sizeof(WCHAR);
5227 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5228 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5230 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5231 if (pcbNeeded) needed = *pcbNeeded;
5232 /* HeapReAlloc return NULL, when bufferW was NULL */
5233 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5234 HeapAlloc(GetProcessHeap(), 0, needed);
5236 /* Try again with the large Buffer */
5237 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5239 needed = pcbNeeded ? *pcbNeeded : 0;
5240 numentries = pcReturned ? *pcReturned : 0;
5243 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5244 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5247 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5248 DWORD entrysize = 0;
5251 LPPORT_INFO_2W pi2w;
5252 LPPORT_INFO_2A pi2a;
5255 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5257 /* First pass: calculate the size for all Entries */
5258 pi2w = (LPPORT_INFO_2W) bufferW;
5259 pi2a = (LPPORT_INFO_2A) pPorts;
5261 while (index < numentries) {
5263 needed += entrysize; /* PORT_INFO_?A */
5264 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5266 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5267 NULL, 0, NULL, NULL);
5269 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5270 NULL, 0, NULL, NULL);
5271 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5272 NULL, 0, NULL, NULL);
5274 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5275 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5276 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5279 /* check for errors and quit on failure */
5280 if (cbBuf < needed) {
5281 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5285 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5286 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5287 cbBuf -= len ; /* free Bytes in the user-Buffer */
5288 pi2w = (LPPORT_INFO_2W) bufferW;
5289 pi2a = (LPPORT_INFO_2A) pPorts;
5291 /* Second Pass: Fill the User Buffer (if we have one) */
5292 while ((index < numentries) && pPorts) {
5294 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5295 pi2a->pPortName = ptr;
5296 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5297 ptr, cbBuf , NULL, NULL);
5301 pi2a->pMonitorName = ptr;
5302 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5303 ptr, cbBuf, NULL, NULL);
5307 pi2a->pDescription = ptr;
5308 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5309 ptr, cbBuf, NULL, NULL);
5313 pi2a->fPortType = pi2w->fPortType;
5314 pi2a->Reserved = 0; /* documented: "must be zero" */
5317 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5318 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5319 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5324 if (pcbNeeded) *pcbNeeded = needed;
5325 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5327 HeapFree(GetProcessHeap(), 0, nameW);
5328 HeapFree(GetProcessHeap(), 0, bufferW);
5330 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5331 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5337 /******************************************************************************
5338 * EnumPortsW (WINSPOOL.@)
5340 * Enumerate available Ports
5343 * pName [I] Servername or NULL (local Computer)
5344 * Level [I] Structure-Level (1 or 2)
5345 * pPorts [O] PTR to Buffer that receives the Result
5346 * cbBuf [I] Size of Buffer at pPorts
5347 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5348 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5352 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5355 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5358 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5359 cbBuf, pcbNeeded, pcReturned);
5361 if ((backend == NULL) && !load_backend()) return FALSE;
5363 /* Level is not checked in win9x */
5364 if (!Level || (Level > 2)) {
5365 WARN("level (%d) is ignored in win9x\n", Level);
5366 SetLastError(ERROR_INVALID_LEVEL);
5369 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5370 SetLastError(RPC_X_NULL_REF_POINTER);
5374 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5377 /******************************************************************************
5378 * GetDefaultPrinterW (WINSPOOL.@)
5381 * This function must read the value from data 'device' of key
5382 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5384 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5388 WCHAR *buffer, *ptr;
5392 SetLastError(ERROR_INVALID_PARAMETER);
5396 /* make the buffer big enough for the stuff from the profile/registry,
5397 * the content must fit into the local buffer to compute the correct
5398 * size even if the extern buffer is too small or not given.
5399 * (20 for ,driver,port) */
5401 len = max(100, (insize + 20));
5402 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5404 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5406 SetLastError (ERROR_FILE_NOT_FOUND);
5410 TRACE("%s\n", debugstr_w(buffer));
5412 if ((ptr = strchrW(buffer, ',')) == NULL)
5414 SetLastError(ERROR_INVALID_NAME);
5420 *namesize = strlenW(buffer) + 1;
5421 if(!name || (*namesize > insize))
5423 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5427 strcpyW(name, buffer);
5430 HeapFree( GetProcessHeap(), 0, buffer);
5435 /******************************************************************************
5436 * GetDefaultPrinterA (WINSPOOL.@)
5438 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5442 WCHAR *bufferW = NULL;
5446 SetLastError(ERROR_INVALID_PARAMETER);
5450 if(name && *namesize) {
5452 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5455 if(!GetDefaultPrinterW( bufferW, namesize)) {
5460 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5464 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5467 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5470 HeapFree( GetProcessHeap(), 0, bufferW);
5475 /******************************************************************************
5476 * SetDefaultPrinterW (WINSPOOL.204)
5478 * Set the Name of the Default Printer
5481 * pszPrinter [I] Name of the Printer or NULL
5488 * When the Parameter is NULL or points to an Empty String and
5489 * a Default Printer was already present, then this Function changes nothing.
5490 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5491 * the First enumerated local Printer is used.
5494 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5497 TRACE("(%s)\n", debugstr_w(pszPrinter));
5499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5503 /******************************************************************************
5504 * SetDefaultPrinterA (WINSPOOL.202)
5506 * See SetDefaultPrinterW.
5509 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5512 TRACE("(%s)\n", debugstr_a(pszPrinter));
5514 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5519 /******************************************************************************
5520 * SetPrinterDataExA (WINSPOOL.@)
5522 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5523 LPCSTR pValueName, DWORD Type,
5524 LPBYTE pData, DWORD cbData)
5526 HKEY hkeyPrinter, hkeySubkey;
5529 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5530 debugstr_a(pValueName), Type, pData, cbData);
5532 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5536 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5538 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5539 RegCloseKey(hkeyPrinter);
5542 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5543 RegCloseKey(hkeySubkey);
5544 RegCloseKey(hkeyPrinter);
5548 /******************************************************************************
5549 * SetPrinterDataExW (WINSPOOL.@)
5551 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5552 LPCWSTR pValueName, DWORD Type,
5553 LPBYTE pData, DWORD cbData)
5555 HKEY hkeyPrinter, hkeySubkey;
5558 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5559 debugstr_w(pValueName), Type, pData, cbData);
5561 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5565 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5567 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5568 RegCloseKey(hkeyPrinter);
5571 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5572 RegCloseKey(hkeySubkey);
5573 RegCloseKey(hkeyPrinter);
5577 /******************************************************************************
5578 * SetPrinterDataA (WINSPOOL.@)
5580 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5581 LPBYTE pData, DWORD cbData)
5583 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5587 /******************************************************************************
5588 * SetPrinterDataW (WINSPOOL.@)
5590 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5591 LPBYTE pData, DWORD cbData)
5593 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5597 /******************************************************************************
5598 * GetPrinterDataExA (WINSPOOL.@)
5600 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5601 LPCSTR pValueName, LPDWORD pType,
5602 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5604 HKEY hkeyPrinter, hkeySubkey;
5607 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5608 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5611 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5615 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5617 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5618 RegCloseKey(hkeyPrinter);
5622 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5623 RegCloseKey(hkeySubkey);
5624 RegCloseKey(hkeyPrinter);
5628 /******************************************************************************
5629 * GetPrinterDataExW (WINSPOOL.@)
5631 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5632 LPCWSTR pValueName, LPDWORD pType,
5633 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5635 HKEY hkeyPrinter, hkeySubkey;
5638 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5639 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5642 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5646 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5648 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5649 RegCloseKey(hkeyPrinter);
5653 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5654 RegCloseKey(hkeySubkey);
5655 RegCloseKey(hkeyPrinter);
5659 /******************************************************************************
5660 * GetPrinterDataA (WINSPOOL.@)
5662 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5663 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5665 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5666 pData, nSize, pcbNeeded);
5669 /******************************************************************************
5670 * GetPrinterDataW (WINSPOOL.@)
5672 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5673 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5675 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5676 pData, nSize, pcbNeeded);
5679 /*******************************************************************************
5680 * EnumPrinterDataExW [WINSPOOL.@]
5682 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5683 LPBYTE pEnumValues, DWORD cbEnumValues,
5684 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5686 HKEY hkPrinter, hkSubKey;
5687 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5688 cbValueNameLen, cbMaxValueLen, cbValueLen,
5693 PPRINTER_ENUM_VALUESW ppev;
5695 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5697 if (pKeyName == NULL || *pKeyName == 0)
5698 return ERROR_INVALID_PARAMETER;
5700 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5701 if (ret != ERROR_SUCCESS)
5703 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5708 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5709 if (ret != ERROR_SUCCESS)
5711 r = RegCloseKey (hkPrinter);
5712 if (r != ERROR_SUCCESS)
5713 WARN ("RegCloseKey returned %i\n", r);
5714 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5715 debugstr_w (pKeyName), ret);
5719 ret = RegCloseKey (hkPrinter);
5720 if (ret != ERROR_SUCCESS)
5722 ERR ("RegCloseKey returned %i\n", ret);
5723 r = RegCloseKey (hkSubKey);
5724 if (r != ERROR_SUCCESS)
5725 WARN ("RegCloseKey returned %i\n", r);
5729 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5730 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5731 if (ret != ERROR_SUCCESS)
5733 r = RegCloseKey (hkSubKey);
5734 if (r != ERROR_SUCCESS)
5735 WARN ("RegCloseKey returned %i\n", r);
5736 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5740 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5741 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5743 if (cValues == 0) /* empty key */
5745 r = RegCloseKey (hkSubKey);
5746 if (r != ERROR_SUCCESS)
5747 WARN ("RegCloseKey returned %i\n", r);
5748 *pcbEnumValues = *pnEnumValues = 0;
5749 return ERROR_SUCCESS;
5752 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5754 hHeap = GetProcessHeap ();
5757 ERR ("GetProcessHeap failed\n");
5758 r = RegCloseKey (hkSubKey);
5759 if (r != ERROR_SUCCESS)
5760 WARN ("RegCloseKey returned %i\n", r);
5761 return ERROR_OUTOFMEMORY;
5764 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5765 if (lpValueName == NULL)
5767 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5768 r = RegCloseKey (hkSubKey);
5769 if (r != ERROR_SUCCESS)
5770 WARN ("RegCloseKey returned %i\n", r);
5771 return ERROR_OUTOFMEMORY;
5774 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5775 if (lpValue == NULL)
5777 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5778 if (HeapFree (hHeap, 0, lpValueName) == 0)
5779 WARN ("HeapFree failed with code %i\n", GetLastError ());
5780 r = RegCloseKey (hkSubKey);
5781 if (r != ERROR_SUCCESS)
5782 WARN ("RegCloseKey returned %i\n", r);
5783 return ERROR_OUTOFMEMORY;
5786 TRACE ("pass 1: calculating buffer required for all names and values\n");
5788 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5790 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5792 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5794 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5795 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5796 NULL, NULL, lpValue, &cbValueLen);
5797 if (ret != ERROR_SUCCESS)
5799 if (HeapFree (hHeap, 0, lpValue) == 0)
5800 WARN ("HeapFree failed with code %i\n", GetLastError ());
5801 if (HeapFree (hHeap, 0, lpValueName) == 0)
5802 WARN ("HeapFree failed with code %i\n", GetLastError ());
5803 r = RegCloseKey (hkSubKey);
5804 if (r != ERROR_SUCCESS)
5805 WARN ("RegCloseKey returned %i\n", r);
5806 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5810 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5811 debugstr_w (lpValueName), dwIndex,
5812 cbValueNameLen + 1, cbValueLen);
5814 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5815 cbBufSize += cbValueLen;
5818 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5820 *pcbEnumValues = cbBufSize;
5821 *pnEnumValues = cValues;
5823 if (cbEnumValues < cbBufSize) /* buffer too small */
5825 if (HeapFree (hHeap, 0, lpValue) == 0)
5826 WARN ("HeapFree failed with code %i\n", GetLastError ());
5827 if (HeapFree (hHeap, 0, lpValueName) == 0)
5828 WARN ("HeapFree failed with code %i\n", GetLastError ());
5829 r = RegCloseKey (hkSubKey);
5830 if (r != ERROR_SUCCESS)
5831 WARN ("RegCloseKey returned %i\n", r);
5832 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5833 return ERROR_MORE_DATA;
5836 TRACE ("pass 2: copying all names and values to buffer\n");
5838 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5839 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5841 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5843 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5844 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5845 NULL, &dwType, lpValue, &cbValueLen);
5846 if (ret != ERROR_SUCCESS)
5848 if (HeapFree (hHeap, 0, lpValue) == 0)
5849 WARN ("HeapFree failed with code %i\n", GetLastError ());
5850 if (HeapFree (hHeap, 0, lpValueName) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5852 r = RegCloseKey (hkSubKey);
5853 if (r != ERROR_SUCCESS)
5854 WARN ("RegCloseKey returned %i\n", r);
5855 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5859 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5860 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5861 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5862 pEnumValues += cbValueNameLen;
5864 /* return # of *bytes* (including trailing \0), not # of chars */
5865 ppev[dwIndex].cbValueName = cbValueNameLen;
5867 ppev[dwIndex].dwType = dwType;
5869 memcpy (pEnumValues, lpValue, cbValueLen);
5870 ppev[dwIndex].pData = pEnumValues;
5871 pEnumValues += cbValueLen;
5873 ppev[dwIndex].cbData = cbValueLen;
5875 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5876 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5879 if (HeapFree (hHeap, 0, lpValue) == 0)
5881 ret = GetLastError ();
5882 ERR ("HeapFree failed with code %i\n", ret);
5883 if (HeapFree (hHeap, 0, lpValueName) == 0)
5884 WARN ("HeapFree failed with code %i\n", GetLastError ());
5885 r = RegCloseKey (hkSubKey);
5886 if (r != ERROR_SUCCESS)
5887 WARN ("RegCloseKey returned %i\n", r);
5891 if (HeapFree (hHeap, 0, lpValueName) == 0)
5893 ret = GetLastError ();
5894 ERR ("HeapFree failed with code %i\n", ret);
5895 r = RegCloseKey (hkSubKey);
5896 if (r != ERROR_SUCCESS)
5897 WARN ("RegCloseKey returned %i\n", r);
5901 ret = RegCloseKey (hkSubKey);
5902 if (ret != ERROR_SUCCESS)
5904 ERR ("RegCloseKey returned %i\n", ret);
5908 return ERROR_SUCCESS;
5911 /*******************************************************************************
5912 * EnumPrinterDataExA [WINSPOOL.@]
5914 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5915 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5916 * what Windows 2000 SP1 does.
5919 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5920 LPBYTE pEnumValues, DWORD cbEnumValues,
5921 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5925 DWORD ret, dwIndex, dwBufSize;
5929 TRACE ("%p %s\n", hPrinter, pKeyName);
5931 if (pKeyName == NULL || *pKeyName == 0)
5932 return ERROR_INVALID_PARAMETER;
5934 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5937 ret = GetLastError ();
5938 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5942 hHeap = GetProcessHeap ();
5945 ERR ("GetProcessHeap failed\n");
5946 return ERROR_OUTOFMEMORY;
5949 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5950 if (pKeyNameW == NULL)
5952 ERR ("Failed to allocate %i bytes from process heap\n",
5953 (LONG)(len * sizeof (WCHAR)));
5954 return ERROR_OUTOFMEMORY;
5957 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5959 ret = GetLastError ();
5960 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5961 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5962 WARN ("HeapFree failed with code %i\n", GetLastError ());
5966 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5967 pcbEnumValues, pnEnumValues);
5968 if (ret != ERROR_SUCCESS)
5970 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5971 WARN ("HeapFree failed with code %i\n", GetLastError ());
5972 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5976 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5978 ret = GetLastError ();
5979 ERR ("HeapFree failed with code %i\n", ret);
5983 if (*pnEnumValues == 0) /* empty key */
5984 return ERROR_SUCCESS;
5987 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5989 PPRINTER_ENUM_VALUESW ppev =
5990 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5992 if (dwBufSize < ppev->cbValueName)
5993 dwBufSize = ppev->cbValueName;
5995 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5996 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5997 dwBufSize = ppev->cbData;
6000 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6002 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6003 if (pBuffer == NULL)
6005 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6006 return ERROR_OUTOFMEMORY;
6009 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6011 PPRINTER_ENUM_VALUESW ppev =
6012 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6014 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6015 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6019 ret = GetLastError ();
6020 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6021 if (HeapFree (hHeap, 0, pBuffer) == 0)
6022 WARN ("HeapFree failed with code %i\n", GetLastError ());
6026 memcpy (ppev->pValueName, pBuffer, len);
6028 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6030 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6031 ppev->dwType != REG_MULTI_SZ)
6034 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6035 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6038 ret = GetLastError ();
6039 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6040 if (HeapFree (hHeap, 0, pBuffer) == 0)
6041 WARN ("HeapFree failed with code %i\n", GetLastError ());
6045 memcpy (ppev->pData, pBuffer, len);
6047 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6048 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6051 if (HeapFree (hHeap, 0, pBuffer) == 0)
6053 ret = GetLastError ();
6054 ERR ("HeapFree failed with code %i\n", ret);
6058 return ERROR_SUCCESS;
6061 /******************************************************************************
6062 * AbortPrinter (WINSPOOL.@)
6064 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6066 FIXME("(%p), stub!\n", hPrinter);
6070 /******************************************************************************
6071 * AddPortA (WINSPOOL.@)
6076 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6078 LPWSTR nameW = NULL;
6079 LPWSTR monitorW = NULL;
6083 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6086 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6087 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6088 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6092 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6093 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6094 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6096 res = AddPortW(nameW, hWnd, monitorW);
6097 HeapFree(GetProcessHeap(), 0, nameW);
6098 HeapFree(GetProcessHeap(), 0, monitorW);
6102 /******************************************************************************
6103 * AddPortW (WINSPOOL.@)
6105 * Add a Port for a specific Monitor
6108 * pName [I] Servername or NULL (local Computer)
6109 * hWnd [I] Handle to parent Window for the Dialog-Box
6110 * pMonitorName [I] Name of the Monitor that manage the Port
6117 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6123 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6125 if (pName && pName[0]) {
6126 SetLastError(ERROR_INVALID_PARAMETER);
6130 if (!pMonitorName) {
6131 SetLastError(RPC_X_NULL_REF_POINTER);
6135 /* an empty Monitorname is Invalid */
6136 if (!pMonitorName[0]) {
6137 SetLastError(ERROR_NOT_SUPPORTED);
6141 pm = monitor_load(pMonitorName, NULL);
6142 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6143 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6144 TRACE("got %d with %u\n", res, GetLastError());
6149 pui = monitor_loadui(pm);
6150 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6151 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6152 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6153 TRACE("got %d with %u\n", res, GetLastError());
6158 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6159 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6161 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6162 SetLastError(ERROR_NOT_SUPPORTED);
6165 monitor_unload(pui);
6168 TRACE("returning %d with %u\n", res, GetLastError());
6172 /******************************************************************************
6173 * AddPortExA (WINSPOOL.@)
6178 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6181 PORT_INFO_2A * pi2A;
6182 LPWSTR nameW = NULL;
6183 LPWSTR monitorW = NULL;
6187 pi2A = (PORT_INFO_2A *) pBuffer;
6189 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6190 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6192 if ((level < 1) || (level > 2)) {
6193 SetLastError(ERROR_INVALID_LEVEL);
6198 SetLastError(ERROR_INVALID_PARAMETER);
6203 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6204 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6205 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6209 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6210 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6211 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6214 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6216 if (pi2A->pPortName) {
6217 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6218 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6219 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6223 if (pi2A->pMonitorName) {
6224 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6225 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6226 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6229 if (pi2A->pDescription) {
6230 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6231 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6232 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6234 pi2W.fPortType = pi2A->fPortType;
6235 pi2W.Reserved = pi2A->Reserved;
6238 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6240 HeapFree(GetProcessHeap(), 0, nameW);
6241 HeapFree(GetProcessHeap(), 0, monitorW);
6242 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6243 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6244 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6249 /******************************************************************************
6250 * AddPortExW (WINSPOOL.@)
6252 * Add a Port for a specific Monitor, without presenting a user interface
6255 * pName [I] Servername or NULL (local Computer)
6256 * level [I] Structure-Level (1 or 2) for pBuffer
6257 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6258 * pMonitorName [I] Name of the Monitor that manage the Port
6265 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6271 pi2 = (PORT_INFO_2W *) pBuffer;
6273 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6274 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6275 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6276 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6279 if ((level < 1) || (level > 2)) {
6280 SetLastError(ERROR_INVALID_LEVEL);
6284 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6285 SetLastError(ERROR_INVALID_PARAMETER);
6289 /* load the Monitor */
6290 pm = monitor_load(pMonitorName, NULL);
6292 SetLastError(ERROR_INVALID_PARAMETER);
6296 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6297 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6298 TRACE("got %u with %u\n", res, GetLastError());
6302 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6308 /******************************************************************************
6309 * AddPrinterConnectionA (WINSPOOL.@)
6311 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6313 FIXME("%s\n", debugstr_a(pName));
6317 /******************************************************************************
6318 * AddPrinterConnectionW (WINSPOOL.@)
6320 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6322 FIXME("%s\n", debugstr_w(pName));
6326 /******************************************************************************
6327 * AddPrinterDriverExW (WINSPOOL.@)
6329 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6332 * pName [I] Servername or NULL (local Computer)
6333 * level [I] Level for the supplied DRIVER_INFO_*W struct
6334 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6335 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6342 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6344 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6346 if ((backend == NULL) && !load_backend()) return FALSE;
6348 if (level < 2 || level == 5 || level == 7 || level > 8) {
6349 SetLastError(ERROR_INVALID_LEVEL);
6354 SetLastError(ERROR_INVALID_PARAMETER);
6358 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6361 /******************************************************************************
6362 * AddPrinterDriverExA (WINSPOOL.@)
6364 * See AddPrinterDriverExW.
6367 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6369 DRIVER_INFO_8A *diA;
6371 LPWSTR nameW = NULL;
6376 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6378 diA = (DRIVER_INFO_8A *) pDriverInfo;
6379 ZeroMemory(&diW, sizeof(diW));
6381 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6382 SetLastError(ERROR_INVALID_LEVEL);
6387 SetLastError(ERROR_INVALID_PARAMETER);
6391 /* convert servername to unicode */
6393 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6394 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6395 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6399 diW.cVersion = diA->cVersion;
6402 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6403 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6404 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6407 if (diA->pEnvironment) {
6408 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6409 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6410 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6413 if (diA->pDriverPath) {
6414 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6415 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6416 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6419 if (diA->pDataFile) {
6420 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6421 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6422 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6425 if (diA->pConfigFile) {
6426 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6427 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6428 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6431 if ((Level > 2) && diA->pDependentFiles) {
6432 lenA = multi_sz_lenA(diA->pDependentFiles);
6433 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6434 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6435 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6438 if ((Level > 2) && diA->pMonitorName) {
6439 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6440 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6441 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6444 if ((Level > 3) && diA->pDefaultDataType) {
6445 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6446 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6447 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6450 if ((Level > 3) && diA->pszzPreviousNames) {
6451 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6452 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6453 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6454 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6457 if ((Level > 5) && diA->pszMfgName) {
6458 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6459 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6460 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6463 if ((Level > 5) && diA->pszOEMUrl) {
6464 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6465 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6466 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6469 if ((Level > 5) && diA->pszHardwareID) {
6470 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6471 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6472 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6475 if ((Level > 5) && diA->pszProvider) {
6476 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6477 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6478 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6482 FIXME("level %u is incomplete\n", Level);
6485 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6486 TRACE("got %u with %u\n", res, GetLastError());
6487 HeapFree(GetProcessHeap(), 0, nameW);
6488 HeapFree(GetProcessHeap(), 0, diW.pName);
6489 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6490 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6491 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6492 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6493 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6494 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6495 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6496 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6497 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6498 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6499 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6500 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6502 TRACE("=> %u with %u\n", res, GetLastError());
6506 /******************************************************************************
6507 * ConfigurePortA (WINSPOOL.@)
6509 * See ConfigurePortW.
6512 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6514 LPWSTR nameW = NULL;
6515 LPWSTR portW = NULL;
6519 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6521 /* convert servername to unicode */
6523 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6524 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6525 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6528 /* convert portname to unicode */
6530 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6531 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6532 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6535 res = ConfigurePortW(nameW, hWnd, portW);
6536 HeapFree(GetProcessHeap(), 0, nameW);
6537 HeapFree(GetProcessHeap(), 0, portW);
6541 /******************************************************************************
6542 * ConfigurePortW (WINSPOOL.@)
6544 * Display the Configuration-Dialog for a specific Port
6547 * pName [I] Servername or NULL (local Computer)
6548 * hWnd [I] Handle to parent Window for the Dialog-Box
6549 * pPortName [I] Name of the Port, that should be configured
6556 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6562 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6564 if (pName && pName[0]) {
6565 SetLastError(ERROR_INVALID_PARAMETER);
6570 SetLastError(RPC_X_NULL_REF_POINTER);
6574 /* an empty Portname is Invalid, but can popup a Dialog */
6575 if (!pPortName[0]) {
6576 SetLastError(ERROR_NOT_SUPPORTED);
6580 pm = monitor_load_by_port(pPortName);
6581 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6582 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6583 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6584 TRACE("got %d with %u\n", res, GetLastError());
6588 pui = monitor_loadui(pm);
6589 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6590 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6591 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6592 TRACE("got %d with %u\n", res, GetLastError());
6596 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6597 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6599 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6600 SetLastError(ERROR_NOT_SUPPORTED);
6603 monitor_unload(pui);
6607 TRACE("returning %d with %u\n", res, GetLastError());
6611 /******************************************************************************
6612 * ConnectToPrinterDlg (WINSPOOL.@)
6614 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6616 FIXME("%p %x\n", hWnd, Flags);
6620 /******************************************************************************
6621 * DeletePrinterConnectionA (WINSPOOL.@)
6623 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6625 FIXME("%s\n", debugstr_a(pName));
6629 /******************************************************************************
6630 * DeletePrinterConnectionW (WINSPOOL.@)
6632 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6634 FIXME("%s\n", debugstr_w(pName));
6638 /******************************************************************************
6639 * DeletePrinterDriverExW (WINSPOOL.@)
6641 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6642 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6647 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6648 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6650 if(pName && pName[0])
6652 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6653 SetLastError(ERROR_INVALID_PARAMETER);
6659 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6660 SetLastError(ERROR_INVALID_PARAMETER);
6664 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6668 ERR("Can't open drivers key\n");
6672 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6675 RegCloseKey(hkey_drivers);
6680 /******************************************************************************
6681 * DeletePrinterDriverExA (WINSPOOL.@)
6683 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6684 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6686 UNICODE_STRING NameW, EnvW, DriverW;
6689 asciitounicode(&NameW, pName);
6690 asciitounicode(&EnvW, pEnvironment);
6691 asciitounicode(&DriverW, pDriverName);
6693 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6695 RtlFreeUnicodeString(&DriverW);
6696 RtlFreeUnicodeString(&EnvW);
6697 RtlFreeUnicodeString(&NameW);
6702 /******************************************************************************
6703 * DeletePrinterDataExW (WINSPOOL.@)
6705 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6708 FIXME("%p %s %s\n", hPrinter,
6709 debugstr_w(pKeyName), debugstr_w(pValueName));
6710 return ERROR_INVALID_PARAMETER;
6713 /******************************************************************************
6714 * DeletePrinterDataExA (WINSPOOL.@)
6716 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6719 FIXME("%p %s %s\n", hPrinter,
6720 debugstr_a(pKeyName), debugstr_a(pValueName));
6721 return ERROR_INVALID_PARAMETER;
6724 /******************************************************************************
6725 * DeletePrintProcessorA (WINSPOOL.@)
6727 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6729 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6730 debugstr_a(pPrintProcessorName));
6734 /******************************************************************************
6735 * DeletePrintProcessorW (WINSPOOL.@)
6737 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6739 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6740 debugstr_w(pPrintProcessorName));
6744 /******************************************************************************
6745 * DeletePrintProvidorA (WINSPOOL.@)
6747 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6749 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6750 debugstr_a(pPrintProviderName));
6754 /******************************************************************************
6755 * DeletePrintProvidorW (WINSPOOL.@)
6757 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6759 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6760 debugstr_w(pPrintProviderName));
6764 /******************************************************************************
6765 * EnumFormsA (WINSPOOL.@)
6767 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6768 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6770 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6771 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6775 /******************************************************************************
6776 * EnumFormsW (WINSPOOL.@)
6778 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6779 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6781 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6782 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6786 /*****************************************************************************
6787 * EnumMonitorsA [WINSPOOL.@]
6789 * See EnumMonitorsW.
6792 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6793 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6796 LPBYTE bufferW = NULL;
6797 LPWSTR nameW = NULL;
6799 DWORD numentries = 0;
6802 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6803 cbBuf, pcbNeeded, pcReturned);
6805 /* convert servername to unicode */
6807 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6808 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6809 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6811 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6812 needed = cbBuf * sizeof(WCHAR);
6813 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6814 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6816 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6817 if (pcbNeeded) needed = *pcbNeeded;
6818 /* HeapReAlloc return NULL, when bufferW was NULL */
6819 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6820 HeapAlloc(GetProcessHeap(), 0, needed);
6822 /* Try again with the large Buffer */
6823 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6825 numentries = pcReturned ? *pcReturned : 0;
6828 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6829 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6832 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6833 DWORD entrysize = 0;
6836 LPMONITOR_INFO_2W mi2w;
6837 LPMONITOR_INFO_2A mi2a;
6839 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6840 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6842 /* First pass: calculate the size for all Entries */
6843 mi2w = (LPMONITOR_INFO_2W) bufferW;
6844 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6846 while (index < numentries) {
6848 needed += entrysize; /* MONITOR_INFO_?A */
6849 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6851 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6852 NULL, 0, NULL, NULL);
6854 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6855 NULL, 0, NULL, NULL);
6856 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6857 NULL, 0, NULL, NULL);
6859 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6860 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6861 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6864 /* check for errors and quit on failure */
6865 if (cbBuf < needed) {
6866 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6870 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6871 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6872 cbBuf -= len ; /* free Bytes in the user-Buffer */
6873 mi2w = (LPMONITOR_INFO_2W) bufferW;
6874 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6876 /* Second Pass: Fill the User Buffer (if we have one) */
6877 while ((index < numentries) && pMonitors) {
6879 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6881 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6882 ptr, cbBuf , NULL, NULL);
6886 mi2a->pEnvironment = ptr;
6887 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6888 ptr, cbBuf, NULL, NULL);
6892 mi2a->pDLLName = ptr;
6893 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6894 ptr, cbBuf, NULL, NULL);
6898 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6899 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6900 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6904 if (pcbNeeded) *pcbNeeded = needed;
6905 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6907 HeapFree(GetProcessHeap(), 0, nameW);
6908 HeapFree(GetProcessHeap(), 0, bufferW);
6910 TRACE("returning %d with %d (%d byte for %d entries)\n",
6911 (res), GetLastError(), needed, numentries);
6917 /*****************************************************************************
6918 * EnumMonitorsW [WINSPOOL.@]
6920 * Enumerate available Port-Monitors
6923 * pName [I] Servername or NULL (local Computer)
6924 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6925 * pMonitors [O] PTR to Buffer that receives the Result
6926 * cbBuf [I] Size of Buffer at pMonitors
6927 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6928 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6932 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6935 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6936 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6939 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6940 cbBuf, pcbNeeded, pcReturned);
6942 if ((backend == NULL) && !load_backend()) return FALSE;
6944 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6945 SetLastError(RPC_X_NULL_REF_POINTER);
6949 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6952 /******************************************************************************
6953 * SpoolerInit (WINSPOOL.@)
6955 * Initialize the Spooler
6962 * The function fails on windows, when the spooler service is not running
6965 BOOL WINAPI SpoolerInit(void)
6968 if ((backend == NULL) && !load_backend()) return FALSE;
6972 /******************************************************************************
6973 * XcvDataW (WINSPOOL.@)
6975 * Execute commands in the Printmonitor DLL
6978 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6979 * pszDataName [i] Name of the command to execute
6980 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6981 * cbInputData [i] Size in Bytes of Buffer at pInputData
6982 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6983 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6984 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6985 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6992 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6993 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6995 * Minimal List of commands, that a Printmonitor DLL should support:
6997 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6998 *| "AddPort" : Add a Port
6999 *| "DeletePort": Delete a Port
7001 * Many Printmonitors support additional commands. Examples for localspl.dll:
7002 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7003 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7006 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7007 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7008 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7010 opened_printer_t *printer;
7012 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7013 pInputData, cbInputData, pOutputData,
7014 cbOutputData, pcbOutputNeeded, pdwStatus);
7016 if ((backend == NULL) && !load_backend()) return FALSE;
7018 printer = get_opened_printer(hXcv);
7019 if (!printer || (!printer->backend_printer)) {
7020 SetLastError(ERROR_INVALID_HANDLE);
7024 if (!pcbOutputNeeded) {
7025 SetLastError(ERROR_INVALID_PARAMETER);
7029 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7030 SetLastError(RPC_X_NULL_REF_POINTER);
7034 *pcbOutputNeeded = 0;
7036 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7037 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7041 /*****************************************************************************
7042 * EnumPrinterDataA [WINSPOOL.@]
7045 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7046 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7047 DWORD cbData, LPDWORD pcbData )
7049 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7050 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7051 return ERROR_NO_MORE_ITEMS;
7054 /*****************************************************************************
7055 * EnumPrinterDataW [WINSPOOL.@]
7058 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7059 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7060 DWORD cbData, LPDWORD pcbData )
7062 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7063 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7064 return ERROR_NO_MORE_ITEMS;
7067 /*****************************************************************************
7068 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7071 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7072 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7073 LPDWORD pcbNeeded, LPDWORD pcReturned)
7075 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7076 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7077 pcbNeeded, pcReturned);
7081 /*****************************************************************************
7082 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7085 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7086 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7087 LPDWORD pcbNeeded, LPDWORD pcReturned)
7089 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7090 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7091 pcbNeeded, pcReturned);
7095 /*****************************************************************************
7096 * EnumPrintProcessorsA [WINSPOOL.@]
7099 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7100 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7102 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7103 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7107 /*****************************************************************************
7108 * EnumPrintProcessorsW [WINSPOOL.@]
7111 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7112 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7114 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7115 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7116 cbBuf, pcbNeeded, pcbReturned);
7120 /*****************************************************************************
7121 * ExtDeviceMode [WINSPOOL.@]
7124 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7125 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7128 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7129 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7130 debugstr_a(pProfile), fMode);
7134 /*****************************************************************************
7135 * FindClosePrinterChangeNotification [WINSPOOL.@]
7138 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7140 FIXME("Stub: %p\n", hChange);
7144 /*****************************************************************************
7145 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7148 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7149 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7151 FIXME("Stub: %p %x %x %p\n",
7152 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7153 return INVALID_HANDLE_VALUE;
7156 /*****************************************************************************
7157 * FindNextPrinterChangeNotification [WINSPOOL.@]
7160 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7161 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7163 FIXME("Stub: %p %p %p %p\n",
7164 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7168 /*****************************************************************************
7169 * FreePrinterNotifyInfo [WINSPOOL.@]
7172 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7174 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7178 /*****************************************************************************
7181 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7182 * ansi depending on the unicode parameter.
7184 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7194 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7197 memcpy(ptr, str, *size);
7204 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7207 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7214 /*****************************************************************************
7217 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7218 LPDWORD pcbNeeded, BOOL unicode)
7220 DWORD size, left = cbBuf;
7221 BOOL space = (cbBuf > 0);
7228 ji1->JobId = job->job_id;
7231 string_to_buf(job->document_title, ptr, left, &size, unicode);
7232 if(space && size <= left)
7234 ji1->pDocument = (LPWSTR)ptr;
7245 /*****************************************************************************
7248 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7249 LPDWORD pcbNeeded, BOOL unicode)
7251 DWORD size, left = cbBuf;
7252 BOOL space = (cbBuf > 0);
7259 ji2->JobId = job->job_id;
7262 string_to_buf(job->document_title, ptr, left, &size, unicode);
7263 if(space && size <= left)
7265 ji2->pDocument = (LPWSTR)ptr;
7276 /*****************************************************************************
7279 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7280 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7283 DWORD needed = 0, size;
7287 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7289 EnterCriticalSection(&printer_handles_cs);
7290 job = get_job(hPrinter, JobId);
7297 size = sizeof(JOB_INFO_1W);
7302 memset(pJob, 0, size);
7306 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7311 size = sizeof(JOB_INFO_2W);
7316 memset(pJob, 0, size);
7320 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7325 size = sizeof(JOB_INFO_3);
7329 memset(pJob, 0, size);
7338 SetLastError(ERROR_INVALID_LEVEL);
7342 *pcbNeeded = needed;
7344 LeaveCriticalSection(&printer_handles_cs);
7348 /*****************************************************************************
7349 * GetJobA [WINSPOOL.@]
7352 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7353 DWORD cbBuf, LPDWORD pcbNeeded)
7355 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7358 /*****************************************************************************
7359 * GetJobW [WINSPOOL.@]
7362 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7363 DWORD cbBuf, LPDWORD pcbNeeded)
7365 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7368 /*****************************************************************************
7371 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7373 char *unixname, *queue, *cmd;
7374 char fmt[] = "lpr -P%s %s";
7378 if(!(unixname = wine_get_unix_file_name(filename)))
7381 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7382 queue = HeapAlloc(GetProcessHeap(), 0, len);
7383 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7385 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7386 sprintf(cmd, fmt, queue, unixname);
7388 TRACE("printing with: %s\n", cmd);
7391 HeapFree(GetProcessHeap(), 0, cmd);
7392 HeapFree(GetProcessHeap(), 0, queue);
7393 HeapFree(GetProcessHeap(), 0, unixname);
7397 /*****************************************************************************
7400 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7402 #ifdef SONAME_LIBCUPS
7405 char *unixname, *queue, *unix_doc_title;
7409 if(!(unixname = wine_get_unix_file_name(filename)))
7412 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7413 queue = HeapAlloc(GetProcessHeap(), 0, len);
7414 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7416 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7417 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7418 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7420 TRACE("printing via cups\n");
7421 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7422 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7423 HeapFree(GetProcessHeap(), 0, queue);
7424 HeapFree(GetProcessHeap(), 0, unixname);
7430 return schedule_lpr(printer_name, filename);
7434 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7441 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7445 if(HIWORD(wparam) == BN_CLICKED)
7447 if(LOWORD(wparam) == IDOK)
7450 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7453 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7454 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7456 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7458 WCHAR caption[200], message[200];
7461 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7462 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7463 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7464 if(mb_ret == IDCANCEL)
7466 HeapFree(GetProcessHeap(), 0, filename);
7470 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7471 if(hf == INVALID_HANDLE_VALUE)
7473 WCHAR caption[200], message[200];
7475 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7476 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7477 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7478 HeapFree(GetProcessHeap(), 0, filename);
7482 DeleteFileW(filename);
7483 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7485 EndDialog(hwnd, IDOK);
7488 if(LOWORD(wparam) == IDCANCEL)
7490 EndDialog(hwnd, IDCANCEL);
7499 /*****************************************************************************
7502 static BOOL get_filename(LPWSTR *filename)
7504 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7505 file_dlg_proc, (LPARAM)filename) == IDOK;
7508 /*****************************************************************************
7511 static BOOL schedule_file(LPCWSTR filename)
7513 LPWSTR output = NULL;
7515 if(get_filename(&output))
7518 TRACE("copy to %s\n", debugstr_w(output));
7519 r = CopyFileW(filename, output, FALSE);
7520 HeapFree(GetProcessHeap(), 0, output);
7526 /*****************************************************************************
7529 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7532 char *unixname, *cmdA;
7534 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7538 if(!(unixname = wine_get_unix_file_name(filename)))
7541 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7542 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7543 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7545 TRACE("printing with: %s\n", cmdA);
7547 if((file_fd = open(unixname, O_RDONLY)) == -1)
7552 ERR("pipe() failed!\n");
7562 /* reset signals that we previously set to SIG_IGN */
7563 signal(SIGPIPE, SIG_DFL);
7564 signal(SIGCHLD, SIG_DFL);
7566 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7570 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7571 write(fds[1], buf, no_read);
7576 if(file_fd != -1) close(file_fd);
7577 if(fds[0] != -1) close(fds[0]);
7578 if(fds[1] != -1) close(fds[1]);
7580 HeapFree(GetProcessHeap(), 0, cmdA);
7581 HeapFree(GetProcessHeap(), 0, unixname);
7588 /*****************************************************************************
7591 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7593 int in_fd, out_fd, no_read;
7596 char *unixname, *outputA;
7599 if(!(unixname = wine_get_unix_file_name(filename)))
7602 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7603 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7604 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7606 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7607 in_fd = open(unixname, O_RDONLY);
7608 if(out_fd == -1 || in_fd == -1)
7611 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7612 write(out_fd, buf, no_read);
7616 if(in_fd != -1) close(in_fd);
7617 if(out_fd != -1) close(out_fd);
7618 HeapFree(GetProcessHeap(), 0, outputA);
7619 HeapFree(GetProcessHeap(), 0, unixname);
7623 /*****************************************************************************
7624 * ScheduleJob [WINSPOOL.@]
7627 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7629 opened_printer_t *printer;
7631 struct list *cursor, *cursor2;
7633 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7634 EnterCriticalSection(&printer_handles_cs);
7635 printer = get_opened_printer(hPrinter);
7639 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7641 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7644 if(job->job_id != dwJobID) continue;
7646 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7647 if(hf != INVALID_HANDLE_VALUE)
7649 PRINTER_INFO_5W *pi5;
7653 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7654 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7656 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7657 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7658 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7659 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7660 debugstr_w(pi5->pPortName));
7664 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7665 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7667 DWORD type, count = sizeof(output);
7668 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7671 if(output[0] == '|')
7673 ret = schedule_pipe(output + 1, job->filename);
7677 ret = schedule_unixfile(output, job->filename);
7679 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7681 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7683 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7685 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7687 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7689 ret = schedule_file(job->filename);
7693 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7695 HeapFree(GetProcessHeap(), 0, pi5);
7697 DeleteFileW(job->filename);
7699 list_remove(cursor);
7700 HeapFree(GetProcessHeap(), 0, job->document_title);
7701 HeapFree(GetProcessHeap(), 0, job->filename);
7702 HeapFree(GetProcessHeap(), 0, job);
7706 LeaveCriticalSection(&printer_handles_cs);
7710 /*****************************************************************************
7711 * StartDocDlgA [WINSPOOL.@]
7713 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7715 UNICODE_STRING usBuffer;
7718 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7721 docW.cbSize = sizeof(docW);
7722 if (doc->lpszDocName)
7724 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7725 if (!(docW.lpszDocName = docnameW)) return NULL;
7727 if (doc->lpszOutput)
7729 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7730 if (!(docW.lpszOutput = outputW)) return NULL;
7732 if (doc->lpszDatatype)
7734 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7735 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7737 docW.fwType = doc->fwType;
7739 retW = StartDocDlgW(hPrinter, &docW);
7743 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7744 ret = HeapAlloc(GetProcessHeap(), 0, len);
7745 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7746 HeapFree(GetProcessHeap(), 0, retW);
7749 HeapFree(GetProcessHeap(), 0, datatypeW);
7750 HeapFree(GetProcessHeap(), 0, outputW);
7751 HeapFree(GetProcessHeap(), 0, docnameW);
7756 /*****************************************************************************
7757 * StartDocDlgW [WINSPOOL.@]
7759 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7760 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7761 * port is "FILE:". Also returns the full path if passed a relative path.
7763 * The caller should free the returned string from the process heap.
7765 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7770 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7772 PRINTER_INFO_5W *pi5;
7773 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7774 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7776 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7777 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7778 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7780 HeapFree(GetProcessHeap(), 0, pi5);
7783 HeapFree(GetProcessHeap(), 0, pi5);
7786 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7790 if (get_filename(&name))
7792 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7794 HeapFree(GetProcessHeap(), 0, name);
7797 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7798 GetFullPathNameW(name, len, ret, NULL);
7799 HeapFree(GetProcessHeap(), 0, name);
7804 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7807 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7808 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7810 attr = GetFileAttributesW(ret);
7811 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7813 HeapFree(GetProcessHeap(), 0, ret);