4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2008 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
122 WCHAR *document_title;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
191 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
192 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
193 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
194 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
195 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
196 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
197 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
198 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
200 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
201 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
203 static const WCHAR backslashW[] = {'\\',0};
204 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
205 'i','o','n',' ','F','i','l','e',0};
206 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
207 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
208 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
209 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
210 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
211 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
212 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
213 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
214 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
215 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
216 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
217 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
218 static const WCHAR NameW[] = {'N','a','m','e',0};
219 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
220 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
221 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
222 static const WCHAR PortW[] = {'P','o','r','t',0};
223 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
224 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
225 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
226 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
227 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
228 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
229 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
230 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
232 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
233 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
234 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
235 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
236 static const WCHAR emptyStringW[] = {0};
237 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
238 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
240 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
242 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
243 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
244 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
246 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
247 'D','o','c','u','m','e','n','t',0};
249 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
250 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
251 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
252 0, sizeof(DRIVER_INFO_8W)};
255 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
256 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
257 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
258 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
259 sizeof(PRINTER_INFO_9W)};
261 /******************************************************************
262 * validate the user-supplied printing-environment [internal]
265 * env [I] PTR to Environment-String or NULL
269 * Success: PTR to printenv_t
272 * An empty string is handled the same way as NULL.
273 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
277 static const printenv_t * validate_envW(LPCWSTR env)
279 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
280 3, Version3_RegPathW, Version3_SubdirW};
281 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
282 0, Version0_RegPathW, Version0_SubdirW};
284 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
286 const printenv_t *result = NULL;
289 TRACE("testing %s\n", debugstr_w(env));
292 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
294 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
296 result = all_printenv[i];
301 if (result == NULL) {
302 FIXME("unsupported Environment: %s\n", debugstr_w(env));
303 SetLastError(ERROR_INVALID_ENVIRONMENT);
305 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
309 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
311 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
317 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
318 if passed a NULL string. This returns NULLs to the result.
320 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
324 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
325 return usBufferPtr->Buffer;
327 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
331 static LPWSTR strdupW(LPCWSTR p)
337 len = (strlenW(p) + 1) * sizeof(WCHAR);
338 ret = HeapAlloc(GetProcessHeap(), 0, len);
343 static LPSTR strdupWtoA( LPCWSTR str )
348 if (!str) return NULL;
349 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
350 ret = HeapAlloc( GetProcessHeap(), 0, len );
351 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
355 /******************************************************************
356 * Return the number of bytes for an multi_sz string.
357 * The result includes all \0s
358 * (specifically the extra \0, that is needed as multi_sz terminator).
361 static int multi_sz_lenW(const WCHAR *str)
363 const WCHAR *ptr = str;
367 ptr += lstrlenW(ptr) + 1;
370 return (ptr - str + 1) * sizeof(WCHAR);
373 /* ################################ */
375 static int multi_sz_lenA(const char *str)
377 const char *ptr = str;
381 ptr += lstrlenA(ptr) + 1;
384 return ptr - str + 1;
388 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
391 /* If forcing, or no profile string entry for device yet, set the entry
393 * The always change entry if not WINEPS yet is discussable.
396 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
398 !strstr(qbuf,"WINEPS.DRV")
400 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
403 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
404 WriteProfileStringA("windows","device",buf);
405 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
406 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
409 HeapFree(GetProcessHeap(),0,buf);
413 static BOOL add_printer_driver(const char *name)
417 static char driver_9x[] = "wineps16.drv",
418 driver_nt[] = "wineps.drv",
419 env_9x[] = "Windows 4.0",
420 env_nt[] = "Windows NT x86",
421 data_file[] = "generic.ppd",
422 default_data_type[] = "RAW";
424 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
426 di3a.pName = (char *)name;
427 di3a.pEnvironment = env_nt;
428 di3a.pDriverPath = driver_nt;
429 di3a.pDataFile = data_file;
430 di3a.pConfigFile = driver_nt;
431 di3a.pDefaultDataType = default_data_type;
433 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
434 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
437 di3a.pEnvironment = env_9x;
438 di3a.pDriverPath = driver_9x;
439 di3a.pConfigFile = driver_9x;
440 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
441 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
446 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
447 debugstr_a(di3a.pEnvironment), GetLastError());
451 #ifdef SONAME_LIBCUPS
452 static typeof(cupsGetDests) *pcupsGetDests;
453 static typeof(cupsGetPPD) *pcupsGetPPD;
454 static typeof(cupsPrintFile) *pcupsPrintFile;
455 static void *cupshandle;
457 static BOOL CUPS_LoadPrinters(void)
460 BOOL hadprinter = FALSE, haddefault = FALSE;
462 PRINTER_INFO_2A pinfo2a;
464 HKEY hkeyPrinter, hkeyPrinters, hkey;
467 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
469 TRACE("%s\n", loaderror);
472 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
475 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
476 if (!p##x) return FALSE;
479 DYNCUPS(cupsGetDests);
480 DYNCUPS(cupsPrintFile);
483 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
485 ERR("Can't create Printers key\n");
489 nrofdests = pcupsGetDests(&dests);
490 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
491 for (i=0;i<nrofdests;i++) {
492 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
493 sprintf(port,"LPR:%s",dests[i].name);
494 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
495 sprintf(devline,"WINEPS.DRV,%s",port);
496 WriteProfileStringA("devices",dests[i].name,devline);
497 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
498 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
501 HeapFree(GetProcessHeap(),0,devline);
503 TRACE("Printer %d: %s\n", i, dests[i].name);
504 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
505 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
507 TRACE("Printer already exists\n");
508 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
509 RegCloseKey(hkeyPrinter);
511 static CHAR data_type[] = "RAW",
512 print_proc[] = "WinPrint",
513 comment[] = "WINEPS Printer using CUPS",
514 location[] = "<physical location of printer>",
515 params[] = "<parameters?>",
516 share_name[] = "<share name?>",
517 sep_file[] = "<sep file?>";
519 add_printer_driver(dests[i].name);
521 memset(&pinfo2a,0,sizeof(pinfo2a));
522 pinfo2a.pPrinterName = dests[i].name;
523 pinfo2a.pDatatype = data_type;
524 pinfo2a.pPrintProcessor = print_proc;
525 pinfo2a.pDriverName = dests[i].name;
526 pinfo2a.pComment = comment;
527 pinfo2a.pLocation = location;
528 pinfo2a.pPortName = port;
529 pinfo2a.pParameters = params;
530 pinfo2a.pShareName = share_name;
531 pinfo2a.pSepFile = sep_file;
533 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
534 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
535 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
538 HeapFree(GetProcessHeap(),0,port);
541 if (dests[i].is_default) {
542 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
546 if (hadprinter & !haddefault)
547 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
548 RegCloseKey(hkeyPrinters);
554 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
555 PRINTER_INFO_2A pinfo2a;
556 char *e,*s,*name,*prettyname,*devname;
557 BOOL ret = FALSE, set_default = FALSE;
558 char *port = NULL, *devline,*env_default;
559 HKEY hkeyPrinter, hkeyPrinters, hkey;
561 while (isspace(*pent)) pent++;
562 s = strchr(pent,':');
564 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
572 TRACE("name=%s entry=%s\n",name, pent);
574 if(ispunct(*name)) { /* a tc entry, not a real printer */
575 TRACE("skipping tc entry\n");
579 if(strstr(pent,":server")) { /* server only version so skip */
580 TRACE("skipping server entry\n");
584 /* Determine whether this is a postscript printer. */
587 env_default = getenv("PRINTER");
589 /* Get longest name, usually the one at the right for later display. */
590 while((s=strchr(prettyname,'|'))) {
593 while(isspace(*--e)) *e = '\0';
594 TRACE("\t%s\n", debugstr_a(prettyname));
595 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
596 for(prettyname = s+1; isspace(*prettyname); prettyname++)
599 e = prettyname + strlen(prettyname);
600 while(isspace(*--e)) *e = '\0';
601 TRACE("\t%s\n", debugstr_a(prettyname));
602 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
604 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
605 * if it is too long, we use it as comment below. */
606 devname = prettyname;
607 if (strlen(devname)>=CCHDEVICENAME-1)
609 if (strlen(devname)>=CCHDEVICENAME-1) {
614 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
615 sprintf(port,"LPR:%s",name);
617 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
618 sprintf(devline,"WINEPS.DRV,%s",port);
619 WriteProfileStringA("devices",devname,devline);
620 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
621 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
624 HeapFree(GetProcessHeap(),0,devline);
626 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
628 ERR("Can't create Printers key\n");
632 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
633 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
635 TRACE("Printer already exists\n");
636 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
637 RegCloseKey(hkeyPrinter);
639 static CHAR data_type[] = "RAW",
640 print_proc[] = "WinPrint",
641 comment[] = "WINEPS Printer using LPR",
642 params[] = "<parameters?>",
643 share_name[] = "<share name?>",
644 sep_file[] = "<sep file?>";
646 add_printer_driver(devname);
648 memset(&pinfo2a,0,sizeof(pinfo2a));
649 pinfo2a.pPrinterName = devname;
650 pinfo2a.pDatatype = data_type;
651 pinfo2a.pPrintProcessor = print_proc;
652 pinfo2a.pDriverName = devname;
653 pinfo2a.pComment = comment;
654 pinfo2a.pLocation = prettyname;
655 pinfo2a.pPortName = port;
656 pinfo2a.pParameters = params;
657 pinfo2a.pShareName = share_name;
658 pinfo2a.pSepFile = sep_file;
660 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
661 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
662 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
665 RegCloseKey(hkeyPrinters);
667 if (isfirst || set_default)
668 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
671 HeapFree(GetProcessHeap(), 0, port);
672 HeapFree(GetProcessHeap(), 0, name);
677 PRINTCAP_LoadPrinters(void) {
678 BOOL hadprinter = FALSE;
682 BOOL had_bash = FALSE;
684 f = fopen("/etc/printcap","r");
688 while(fgets(buf,sizeof(buf),f)) {
691 end=strchr(buf,'\n');
695 while(isspace(*start)) start++;
696 if(*start == '#' || *start == '\0')
699 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
700 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
701 HeapFree(GetProcessHeap(),0,pent);
705 if (end && *--end == '\\') {
712 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
715 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
721 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
722 HeapFree(GetProcessHeap(),0,pent);
728 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
731 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
732 (lstrlenW(value) + 1) * sizeof(WCHAR));
734 return ERROR_FILE_NOT_FOUND;
737 /*****************************************************************************
738 * enumerate the local monitors (INTERNAL)
740 * returns the needed size (in bytes) for pMonitors
741 * and *lpreturned is set to number of entries returned in pMonitors
744 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
749 LPMONITOR_INFO_2W mi;
750 WCHAR buffer[MAX_PATH];
751 WCHAR dllname[MAX_PATH];
759 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
761 numentries = *lpreturned; /* this is 0, when we scan the registry */
762 len = entrysize * numentries;
763 ptr = (LPWSTR) &pMonitors[len];
766 len = sizeof(buffer)/sizeof(buffer[0]);
769 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
770 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
771 /* Scan all Monitor-Registry-Keys */
772 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
773 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
774 dllsize = sizeof(dllname);
777 /* The Monitor must have a Driver-DLL */
778 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
779 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
780 /* We found a valid DLL for this Monitor. */
781 TRACE("using Driver: %s\n", debugstr_w(dllname));
786 /* Windows returns only Port-Monitors here, but to simplify our code,
787 we do no filtering for Language-Monitors */
791 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
793 /* we install and return only monitors for "Windows NT x86" */
794 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
798 /* required size is calculated. Now fill the user-buffer */
799 if (pMonitors && (cbBuf >= needed)){
800 mi = (LPMONITOR_INFO_2W) pMonitors;
801 pMonitors += entrysize;
803 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
805 lstrcpyW(ptr, buffer); /* Name of the Monitor */
806 ptr += (len+1); /* len is lstrlenW(monitorname) */
808 mi->pEnvironment = ptr;
809 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
810 ptr += (lstrlenW(envname_x86W)+1);
813 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
814 ptr += (dllsize / sizeof(WCHAR));
819 len = sizeof(buffer)/sizeof(buffer[0]);
824 *lpreturned = numentries;
825 TRACE("need %d byte for %d entries\n", needed, numentries);
829 /******************************************************************
830 * monitor_unload [internal]
832 * release a printmonitor and unload it from memory, when needed
835 static void monitor_unload(monitor_t * pm)
837 if (pm == NULL) return;
838 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
840 EnterCriticalSection(&monitor_handles_cs);
842 if (pm->refcount) pm->refcount--;
844 if (pm->refcount == 0) {
845 list_remove(&pm->entry);
846 FreeLibrary(pm->hdll);
847 HeapFree(GetProcessHeap(), 0, pm->name);
848 HeapFree(GetProcessHeap(), 0, pm->dllname);
849 HeapFree(GetProcessHeap(), 0, pm);
851 LeaveCriticalSection(&monitor_handles_cs);
854 /******************************************************************
855 * monitor_unloadall [internal]
857 * release all printmonitors and unload them from memory, when needed
860 static void monitor_unloadall(void)
865 EnterCriticalSection(&monitor_handles_cs);
866 /* iterate through the list, with safety against removal */
867 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
871 LeaveCriticalSection(&monitor_handles_cs);
874 /******************************************************************
875 * monitor_load [internal]
877 * load a printmonitor, get the dllname from the registry, when needed
878 * initialize the monitor and dump found function-pointers
880 * On failure, SetLastError() is called and NULL is returned
883 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
885 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
886 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
887 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
888 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
889 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
891 monitor_t * pm = NULL;
893 LPWSTR regroot = NULL;
894 LPWSTR driver = dllname;
896 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
897 /* Is the Monitor already loaded? */
898 EnterCriticalSection(&monitor_handles_cs);
901 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
903 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
911 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
912 if (pm == NULL) goto cleanup;
913 list_add_tail(&monitor_handles, &pm->entry);
917 if (pm->name == NULL) {
918 /* Load the monitor */
919 LPMONITOREX pmonitorEx;
923 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
924 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
928 lstrcpyW(regroot, MonitorsW);
929 lstrcatW(regroot, name);
930 /* Get the Driver from the Registry */
931 if (driver == NULL) {
934 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
935 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
936 &namesize) == ERROR_SUCCESS) {
937 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
938 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
945 pm->name = strdupW(name);
946 pm->dllname = strdupW(driver);
948 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
950 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
955 pm->hdll = LoadLibraryW(driver);
956 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
958 if (pm->hdll == NULL) {
960 SetLastError(ERROR_MOD_NOT_FOUND);
965 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
966 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
967 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
968 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
969 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
972 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
973 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
974 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
975 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
976 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
978 if (pInitializePrintMonitorUI != NULL) {
979 pm->monitorUI = pInitializePrintMonitorUI();
980 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
982 TRACE( "0x%08x: dwMonitorSize (%d)\n",
983 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
988 if (pInitializePrintMonitor && regroot) {
989 pmonitorEx = pInitializePrintMonitor(regroot);
990 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
991 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
994 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
995 pm->monitor = &(pmonitorEx->Monitor);
1000 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1004 if (!pm->monitor && regroot) {
1005 if (pInitializePrintMonitor2 != NULL) {
1006 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1008 if (pInitializeMonitorEx != NULL) {
1009 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1011 if (pInitializeMonitor != NULL) {
1012 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1015 if (!pm->monitor && !pm->monitorUI) {
1017 SetLastError(ERROR_PROC_NOT_FOUND);
1022 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1026 LeaveCriticalSection(&monitor_handles_cs);
1027 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1028 HeapFree(GetProcessHeap(), 0, regroot);
1029 TRACE("=> %p\n", pm);
1033 /******************************************************************
1034 * monitor_loadall [internal]
1036 * Load all registered monitors
1039 static DWORD monitor_loadall(void)
1042 DWORD registered = 0;
1045 WCHAR buffer[MAX_PATH];
1048 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1049 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1050 NULL, NULL, NULL, NULL, NULL);
1052 TRACE("%d monitors registered\n", registered);
1054 EnterCriticalSection(&monitor_handles_cs);
1055 while (id < registered) {
1057 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1058 pm = monitor_load(buffer, NULL);
1062 LeaveCriticalSection(&monitor_handles_cs);
1063 RegCloseKey(hmonitors);
1065 TRACE("%d monitors loaded\n", loaded);
1069 /******************************************************************
1070 * monitor_loadui [internal]
1072 * load the userinterface-dll for a given portmonitor
1074 * On failure, NULL is returned
1077 static monitor_t * monitor_loadui(monitor_t * pm)
1079 monitor_t * pui = NULL;
1080 LPWSTR buffer[MAX_PATH];
1085 if (pm == NULL) return NULL;
1086 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1088 /* Try the Portmonitor first; works for many monitors */
1089 if (pm->monitorUI) {
1090 EnterCriticalSection(&monitor_handles_cs);
1092 LeaveCriticalSection(&monitor_handles_cs);
1096 /* query the userinterface-dllname from the Portmonitor */
1097 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1098 /* building (",XcvMonitor %s",pm->name) not needed yet */
1099 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1100 TRACE("got %u with %p\n", res, hXcv);
1102 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1103 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1104 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1105 pm->monitor->pfnXcvClosePort(hXcv);
1112 /******************************************************************
1113 * monitor_load_by_port [internal]
1115 * load a printmonitor for a given port
1117 * On failure, NULL is returned
1120 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1125 monitor_t * pm = NULL;
1126 DWORD registered = 0;
1130 TRACE("(%s)\n", debugstr_w(portname));
1132 /* Try the Local Monitor first */
1133 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1134 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1135 /* found the portname */
1137 return monitor_load(LocalPortW, NULL);
1142 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1143 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1144 if (buffer == NULL) return NULL;
1146 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1147 EnterCriticalSection(&monitor_handles_cs);
1148 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1150 while ((pm == NULL) && (id < registered)) {
1152 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1153 TRACE("testing %s\n", debugstr_w(buffer));
1154 len = lstrlenW(buffer);
1155 lstrcatW(buffer, bs_Ports_bsW);
1156 lstrcatW(buffer, portname);
1157 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1159 buffer[len] = '\0'; /* use only the Monitor-Name */
1160 pm = monitor_load(buffer, NULL);
1164 LeaveCriticalSection(&monitor_handles_cs);
1167 HeapFree(GetProcessHeap(), 0, buffer);
1171 /******************************************************************
1172 * enumerate the local Ports from all loaded monitors (internal)
1174 * returns the needed size (in bytes) for pPorts
1175 * and *lpreturned is set to number of entries returned in pPorts
1178 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1182 LPPORT_INFO_2W cache;
1184 LPBYTE pi_buffer = NULL;
1185 DWORD pi_allocated = 0;
1196 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1197 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1199 numentries = *lpreturned; /* this is 0, when we scan the registry */
1200 needed = entrysize * numentries;
1201 ptr = (LPWSTR) &pPorts[needed];
1206 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1208 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1211 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1212 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1213 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1214 HeapFree(GetProcessHeap(), 0, pi_buffer);
1215 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1216 pi_allocated = (pi_buffer) ? pi_needed : 0;
1217 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1219 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1220 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1222 numentries += pi_returned;
1223 needed += pi_needed;
1225 /* fill the output-buffer (pPorts), if we have one */
1226 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1228 while (pi_returned > pi_index) {
1229 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1230 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1231 out->pPortName = ptr;
1232 lstrcpyW(ptr, cache->pPortName);
1233 ptr += (lstrlenW(ptr)+1);
1235 out->pMonitorName = ptr;
1236 lstrcpyW(ptr, cache->pMonitorName);
1237 ptr += (lstrlenW(ptr)+1);
1239 out->pDescription = ptr;
1240 lstrcpyW(ptr, cache->pDescription);
1241 ptr += (lstrlenW(ptr)+1);
1242 out->fPortType = cache->fPortType;
1243 out->Reserved = cache->Reserved;
1251 /* the temporary portinfo-buffer is no longer needed */
1252 HeapFree(GetProcessHeap(), 0, pi_buffer);
1254 *lpreturned = numentries;
1255 TRACE("need %d byte for %d entries\n", needed, numentries);
1259 /******************************************************************
1260 * get_servername_from_name (internal)
1262 * for an external server, a copy of the serverpart from the full name is returned
1265 static LPWSTR get_servername_from_name(LPCWSTR name)
1269 WCHAR buffer[MAX_PATH];
1272 if (name == NULL) return NULL;
1273 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1275 server = strdupW(&name[2]); /* skip over both backslash */
1276 if (server == NULL) return NULL;
1278 /* strip '\' and the printername */
1279 ptr = strchrW(server, '\\');
1280 if (ptr) ptr[0] = '\0';
1282 TRACE("found %s\n", debugstr_w(server));
1284 len = sizeof(buffer)/sizeof(buffer[0]);
1285 if (GetComputerNameW(buffer, &len)) {
1286 if (lstrcmpW(buffer, server) == 0) {
1287 /* The requested Servername is our computername */
1288 HeapFree(GetProcessHeap(), 0, server);
1295 /******************************************************************
1296 * get_basename_from_name (internal)
1298 * skip over the serverpart from the full name
1301 static LPCWSTR get_basename_from_name(LPCWSTR name)
1303 if (name == NULL) return NULL;
1304 if ((name[0] == '\\') && (name[1] == '\\')) {
1305 /* skip over the servername and search for the following '\' */
1306 name = strchrW(&name[2], '\\');
1307 if ((name) && (name[1])) {
1308 /* found a separator ('\') followed by a name:
1309 skip over the separator and return the rest */
1314 /* no basename present (we found only a servername) */
1321 /******************************************************************
1322 * get_opened_printer_entry
1323 * Get the first place empty in the opened printer table
1326 * - pDefault is ignored
1328 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1330 UINT_PTR handle = nb_printer_handles, i;
1331 jobqueue_t *queue = NULL;
1332 opened_printer_t *printer = NULL;
1334 LPCWSTR printername;
1339 servername = get_servername_from_name(name);
1341 FIXME("server %s not supported\n", debugstr_w(servername));
1342 HeapFree(GetProcessHeap(), 0, servername);
1343 SetLastError(ERROR_INVALID_PRINTER_NAME);
1347 printername = get_basename_from_name(name);
1348 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1350 /* an empty printername is invalid */
1351 if (printername && (!printername[0])) {
1352 SetLastError(ERROR_INVALID_PARAMETER);
1356 EnterCriticalSection(&printer_handles_cs);
1358 for (i = 0; i < nb_printer_handles; i++)
1360 if (!printer_handles[i])
1362 if(handle == nb_printer_handles)
1367 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1368 queue = printer_handles[i]->queue;
1372 if (handle >= nb_printer_handles)
1374 opened_printer_t **new_array;
1375 if (printer_handles)
1376 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1377 (nb_printer_handles + 16) * sizeof(*new_array) );
1379 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1380 (nb_printer_handles + 16) * sizeof(*new_array) );
1387 printer_handles = new_array;
1388 nb_printer_handles += 16;
1391 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1398 /* clone the base name. This is NULL for the printserver */
1399 printer->printername = strdupW(printername);
1401 /* clone the full name */
1402 printer->name = strdupW(name);
1403 if (name && (!printer->name)) {
1409 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1410 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1411 /* OpenPrinter(",XcvMonitor " detected */
1412 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1413 printer->pm = monitor_load(&printername[len], NULL);
1414 if (printer->pm == NULL) {
1415 SetLastError(ERROR_UNKNOWN_PORT);
1422 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1423 if (strncmpW( printername, XcvPortW, len) == 0) {
1424 /* OpenPrinter(",XcvPort " detected */
1425 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1426 printer->pm = monitor_load_by_port(&printername[len]);
1427 if (printer->pm == NULL) {
1428 SetLastError(ERROR_UNKNOWN_PORT);
1436 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1437 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1438 pDefault ? pDefault->DesiredAccess : 0,
1441 if (printer->hXcv == NULL) {
1442 SetLastError(ERROR_INVALID_PARAMETER);
1449 /* Does the Printer exist? */
1450 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1451 ERR("Can't create Printers key\n");
1455 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1456 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1457 RegCloseKey(hkeyPrinters);
1458 SetLastError(ERROR_INVALID_PRINTER_NAME);
1462 RegCloseKey(hkeyPrinter);
1463 RegCloseKey(hkeyPrinters);
1468 TRACE("using the local printserver\n");
1472 printer->queue = queue;
1475 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1476 if (!printer->queue) {
1480 list_init(&printer->queue->jobs);
1481 printer->queue->ref = 0;
1483 InterlockedIncrement(&printer->queue->ref);
1485 printer_handles[handle] = printer;
1488 LeaveCriticalSection(&printer_handles_cs);
1489 if (!handle && printer) {
1490 /* Something failed: Free all resources */
1491 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1492 monitor_unload(printer->pm);
1493 HeapFree(GetProcessHeap(), 0, printer->printername);
1494 HeapFree(GetProcessHeap(), 0, printer->name);
1495 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1496 HeapFree(GetProcessHeap(), 0, printer);
1499 return (HANDLE)handle;
1502 /******************************************************************
1503 * get_opened_printer
1504 * Get the pointer to the opened printer referred by the handle
1506 static opened_printer_t *get_opened_printer(HANDLE hprn)
1508 UINT_PTR idx = (UINT_PTR)hprn;
1509 opened_printer_t *ret = NULL;
1511 EnterCriticalSection(&printer_handles_cs);
1513 if ((idx > 0) && (idx <= nb_printer_handles)) {
1514 ret = printer_handles[idx - 1];
1516 LeaveCriticalSection(&printer_handles_cs);
1520 /******************************************************************
1521 * get_opened_printer_name
1522 * Get the pointer to the opened printer name referred by the handle
1524 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1526 opened_printer_t *printer = get_opened_printer(hprn);
1527 if(!printer) return NULL;
1528 return printer->name;
1531 /******************************************************************
1532 * WINSPOOL_GetOpenedPrinterRegKey
1535 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1537 LPCWSTR name = get_opened_printer_name(hPrinter);
1541 if(!name) return ERROR_INVALID_HANDLE;
1543 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1547 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1549 ERR("Can't find opened printer %s in registry\n",
1551 RegCloseKey(hkeyPrinters);
1552 return ERROR_INVALID_PRINTER_NAME; /* ? */
1554 RegCloseKey(hkeyPrinters);
1555 return ERROR_SUCCESS;
1558 void WINSPOOL_LoadSystemPrinters(void)
1560 HKEY hkey, hkeyPrinters;
1562 DWORD needed, num, i;
1563 WCHAR PrinterName[256];
1566 /* This ensures that all printer entries have a valid Name value. If causes
1567 problems later if they don't. If one is found to be missed we create one
1568 and set it equal to the name of the key */
1569 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1570 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1571 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1572 for(i = 0; i < num; i++) {
1573 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1574 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1575 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1576 set_reg_szW(hkey, NameW, PrinterName);
1583 RegCloseKey(hkeyPrinters);
1586 /* We want to avoid calling AddPrinter on printers as much as
1587 possible, because on cups printers this will (eventually) lead
1588 to a call to cupsGetPPD which takes forever, even with non-cups
1589 printers AddPrinter takes a while. So we'll tag all printers that
1590 were automatically added last time around, if they still exist
1591 we'll leave them be otherwise we'll delete them. */
1592 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1594 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1595 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1596 for(i = 0; i < num; i++) {
1597 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1598 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1599 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1601 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1609 HeapFree(GetProcessHeap(), 0, pi);
1613 #ifdef SONAME_LIBCUPS
1614 done = CUPS_LoadPrinters();
1617 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1618 PRINTCAP_LoadPrinters();
1620 /* Now enumerate the list again and delete any printers that are still tagged */
1621 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1623 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1624 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1625 for(i = 0; i < num; i++) {
1626 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1627 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1628 BOOL delete_driver = FALSE;
1629 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1630 DWORD dw, type, size = sizeof(dw);
1631 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1632 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1633 DeletePrinter(hprn);
1634 delete_driver = TRUE;
1640 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1645 HeapFree(GetProcessHeap(), 0, pi);
1652 /******************************************************************
1655 * Get the pointer to the specified job.
1656 * Should hold the printer_handles_cs before calling.
1658 static job_t *get_job(HANDLE hprn, DWORD JobId)
1660 opened_printer_t *printer = get_opened_printer(hprn);
1663 if(!printer) return NULL;
1664 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1666 if(job->job_id == JobId)
1672 /***********************************************************
1675 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1678 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1681 Formname = (dmA->dmSize > off_formname);
1682 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1683 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1684 dmW->dmDeviceName, CCHDEVICENAME);
1686 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1687 dmA->dmSize - CCHDEVICENAME);
1689 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1690 off_formname - CCHDEVICENAME);
1691 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1692 dmW->dmFormName, CCHFORMNAME);
1693 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1694 (off_formname + CCHFORMNAME));
1697 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1698 dmA->dmDriverExtra);
1702 /***********************************************************
1704 * Creates an ansi copy of supplied devmode
1706 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1711 if (!dmW) return NULL;
1712 size = dmW->dmSize - CCHDEVICENAME -
1713 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1715 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1716 if (!dmA) return NULL;
1718 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1719 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1721 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1722 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1723 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1727 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1728 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1729 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1730 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1732 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1736 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1740 /******************************************************************
1741 * convert_printerinfo_W_to_A [internal]
1744 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1745 DWORD level, DWORD outlen, DWORD numentries)
1751 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1753 len = pi_sizeof[level] * numentries;
1754 ptr = (LPSTR) out + len;
1757 /* copy the numbers of all PRINTER_INFO_* first */
1758 memcpy(out, pPrintersW, len);
1760 while (id < numentries) {
1764 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1765 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1767 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1768 if (piW->pDescription) {
1769 piA->pDescription = ptr;
1770 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1771 ptr, outlen, NULL, NULL);
1777 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1778 ptr, outlen, NULL, NULL);
1782 if (piW->pComment) {
1783 piA->pComment = ptr;
1784 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1785 ptr, outlen, NULL, NULL);
1794 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1795 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1798 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1799 if (piW->pServerName) {
1800 piA->pServerName = ptr;
1801 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1802 ptr, outlen, NULL, NULL);
1806 if (piW->pPrinterName) {
1807 piA->pPrinterName = ptr;
1808 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1809 ptr, outlen, NULL, NULL);
1813 if (piW->pShareName) {
1814 piA->pShareName = ptr;
1815 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1816 ptr, outlen, NULL, NULL);
1820 if (piW->pPortName) {
1821 piA->pPortName = ptr;
1822 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1823 ptr, outlen, NULL, NULL);
1827 if (piW->pDriverName) {
1828 piA->pDriverName = ptr;
1829 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1830 ptr, outlen, NULL, NULL);
1834 if (piW->pComment) {
1835 piA->pComment = ptr;
1836 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1837 ptr, outlen, NULL, NULL);
1841 if (piW->pLocation) {
1842 piA->pLocation = ptr;
1843 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1844 ptr, outlen, NULL, NULL);
1849 dmA = DEVMODEdupWtoA(piW->pDevMode);
1851 /* align DEVMODEA to a DWORD boundary */
1852 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1856 piA->pDevMode = (LPDEVMODEA) ptr;
1857 len = dmA->dmSize + dmA->dmDriverExtra;
1858 memcpy(ptr, dmA, len);
1859 HeapFree(GetProcessHeap(), 0, dmA);
1865 if (piW->pSepFile) {
1866 piA->pSepFile = ptr;
1867 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1868 ptr, outlen, NULL, NULL);
1872 if (piW->pPrintProcessor) {
1873 piA->pPrintProcessor = ptr;
1874 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1875 ptr, outlen, NULL, NULL);
1879 if (piW->pDatatype) {
1880 piA->pDatatype = ptr;
1881 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1882 ptr, outlen, NULL, NULL);
1886 if (piW->pParameters) {
1887 piA->pParameters = ptr;
1888 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1889 ptr, outlen, NULL, NULL);
1893 if (piW->pSecurityDescriptor) {
1894 piA->pSecurityDescriptor = NULL;
1895 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1902 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1903 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1905 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1907 if (piW->pPrinterName) {
1908 piA->pPrinterName = ptr;
1909 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1910 ptr, outlen, NULL, NULL);
1914 if (piW->pServerName) {
1915 piA->pServerName = ptr;
1916 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1917 ptr, outlen, NULL, NULL);
1926 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1927 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1929 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1931 if (piW->pPrinterName) {
1932 piA->pPrinterName = ptr;
1933 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1934 ptr, outlen, NULL, NULL);
1938 if (piW->pPortName) {
1939 piA->pPortName = ptr;
1940 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1941 ptr, outlen, NULL, NULL);
1949 FIXME("for level %u\n", level);
1951 pPrintersW += pi_sizeof[level];
1952 out += pi_sizeof[level];
1957 /***********************************************************
1958 * PRINTER_INFO_2AtoW
1959 * Creates a unicode copy of PRINTER_INFO_2A on heap
1961 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1963 LPPRINTER_INFO_2W piW;
1964 UNICODE_STRING usBuffer;
1966 if(!piA) return NULL;
1967 piW = HeapAlloc(heap, 0, sizeof(*piW));
1968 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1970 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1971 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1972 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1973 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1974 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1975 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1976 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1977 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1978 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1979 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1980 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1981 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1985 /***********************************************************
1986 * FREE_PRINTER_INFO_2W
1987 * Free PRINTER_INFO_2W and all strings
1989 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1993 HeapFree(heap,0,piW->pServerName);
1994 HeapFree(heap,0,piW->pPrinterName);
1995 HeapFree(heap,0,piW->pShareName);
1996 HeapFree(heap,0,piW->pPortName);
1997 HeapFree(heap,0,piW->pDriverName);
1998 HeapFree(heap,0,piW->pComment);
1999 HeapFree(heap,0,piW->pLocation);
2000 HeapFree(heap,0,piW->pDevMode);
2001 HeapFree(heap,0,piW->pSepFile);
2002 HeapFree(heap,0,piW->pPrintProcessor);
2003 HeapFree(heap,0,piW->pDatatype);
2004 HeapFree(heap,0,piW->pParameters);
2005 HeapFree(heap,0,piW);
2009 /******************************************************************
2010 * DeviceCapabilities [WINSPOOL.@]
2011 * DeviceCapabilitiesA [WINSPOOL.@]
2014 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2015 LPSTR pOutput, LPDEVMODEA lpdm)
2019 if (!GDI_CallDeviceCapabilities16)
2021 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2023 if (!GDI_CallDeviceCapabilities16) return -1;
2025 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2027 /* If DC_PAPERSIZE map POINT16s to POINTs */
2028 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2029 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2030 POINT *pt = (POINT *)pOutput;
2032 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2033 for(i = 0; i < ret; i++, pt++)
2038 HeapFree( GetProcessHeap(), 0, tmp );
2044 /*****************************************************************************
2045 * DeviceCapabilitiesW [WINSPOOL.@]
2047 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2050 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2051 WORD fwCapability, LPWSTR pOutput,
2052 const DEVMODEW *pDevMode)
2054 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2055 LPSTR pDeviceA = strdupWtoA(pDevice);
2056 LPSTR pPortA = strdupWtoA(pPort);
2059 if(pOutput && (fwCapability == DC_BINNAMES ||
2060 fwCapability == DC_FILEDEPENDENCIES ||
2061 fwCapability == DC_PAPERNAMES)) {
2062 /* These need A -> W translation */
2065 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2069 switch(fwCapability) {
2074 case DC_FILEDEPENDENCIES:
2078 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2079 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2081 for(i = 0; i < ret; i++)
2082 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2083 pOutput + (i * size), size);
2084 HeapFree(GetProcessHeap(), 0, pOutputA);
2086 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2087 (LPSTR)pOutput, dmA);
2089 HeapFree(GetProcessHeap(),0,pPortA);
2090 HeapFree(GetProcessHeap(),0,pDeviceA);
2091 HeapFree(GetProcessHeap(),0,dmA);
2095 /******************************************************************
2096 * DocumentPropertiesA [WINSPOOL.@]
2098 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2100 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2101 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2102 LPDEVMODEA pDevModeInput,DWORD fMode )
2104 LPSTR lpName = pDeviceName;
2105 static CHAR port[] = "LPT1:";
2108 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2109 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2113 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2115 ERR("no name from hPrinter?\n");
2116 SetLastError(ERROR_INVALID_HANDLE);
2119 lpName = strdupWtoA(lpNameW);
2122 if (!GDI_CallExtDeviceMode16)
2124 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2126 if (!GDI_CallExtDeviceMode16) {
2127 ERR("No CallExtDeviceMode16?\n");
2131 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2132 pDevModeInput, NULL, fMode);
2135 HeapFree(GetProcessHeap(),0,lpName);
2140 /*****************************************************************************
2141 * DocumentPropertiesW (WINSPOOL.@)
2143 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2145 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2147 LPDEVMODEW pDevModeOutput,
2148 LPDEVMODEW pDevModeInput, DWORD fMode)
2151 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2152 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2153 LPDEVMODEA pDevModeOutputA = NULL;
2156 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2157 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2159 if(pDevModeOutput) {
2160 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2161 if(ret < 0) return ret;
2162 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2164 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2165 pDevModeInputA, fMode);
2166 if(pDevModeOutput) {
2167 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2168 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2170 if(fMode == 0 && ret > 0)
2171 ret += (CCHDEVICENAME + CCHFORMNAME);
2172 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2173 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2177 /******************************************************************
2178 * OpenPrinterA [WINSPOOL.@]
2183 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2184 LPPRINTER_DEFAULTSA pDefault)
2186 UNICODE_STRING lpPrinterNameW;
2187 UNICODE_STRING usBuffer;
2188 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2189 PWSTR pwstrPrinterNameW;
2192 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2195 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2196 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2197 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2198 pDefaultW = &DefaultW;
2200 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2202 RtlFreeUnicodeString(&usBuffer);
2203 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2205 RtlFreeUnicodeString(&lpPrinterNameW);
2209 /******************************************************************
2210 * OpenPrinterW [WINSPOOL.@]
2212 * Open a Printer / Printserver or a Printer-Object
2215 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2216 * phPrinter [O] The resulting Handle is stored here
2217 * pDefault [I] PTR to Default Printer Settings or NULL
2224 * lpPrinterName is one of:
2225 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2226 *| Printer: "PrinterName"
2227 *| Printer-Object: "PrinterName,Job xxx"
2228 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2229 *| XcvPort: "Servername,XcvPort PortName"
2232 *| Printer-Object not supported
2233 *| pDefaults is ignored
2236 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2239 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2241 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2242 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2246 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2247 SetLastError(ERROR_INVALID_PARAMETER);
2251 /* Get the unique handle of the printer or Printserver */
2252 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2253 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2254 return (*phPrinter != 0);
2257 /******************************************************************
2258 * AddMonitorA [WINSPOOL.@]
2263 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2265 LPWSTR nameW = NULL;
2268 LPMONITOR_INFO_2A mi2a;
2269 MONITOR_INFO_2W mi2w;
2271 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2272 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2273 mi2a ? debugstr_a(mi2a->pName) : NULL,
2274 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2275 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2278 SetLastError(ERROR_INVALID_LEVEL);
2282 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2288 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2289 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2290 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2293 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2295 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2296 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2297 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2299 if (mi2a->pEnvironment) {
2300 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2301 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2302 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2304 if (mi2a->pDLLName) {
2305 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2306 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2307 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2310 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2312 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2313 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2314 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2316 HeapFree(GetProcessHeap(), 0, nameW);
2320 /******************************************************************************
2321 * AddMonitorW [WINSPOOL.@]
2323 * Install a Printmonitor
2326 * pName [I] Servername or NULL (local Computer)
2327 * Level [I] Structure-Level (Must be 2)
2328 * pMonitors [I] PTR to MONITOR_INFO_2
2335 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2338 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2340 monitor_t * pm = NULL;
2341 LPMONITOR_INFO_2W mi2w;
2347 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2348 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2349 mi2w ? debugstr_w(mi2w->pName) : NULL,
2350 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2351 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2354 SetLastError(ERROR_INVALID_LEVEL);
2358 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2363 if (pName && (pName[0])) {
2364 FIXME("for server %s not implemented\n", debugstr_w(pName));
2365 SetLastError(ERROR_ACCESS_DENIED);
2370 if (!mi2w->pName || (! mi2w->pName[0])) {
2371 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2372 SetLastError(ERROR_INVALID_PARAMETER);
2375 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2376 WARN("Environment %s requested (we support only %s)\n",
2377 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2378 SetLastError(ERROR_INVALID_ENVIRONMENT);
2382 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2383 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2384 SetLastError(ERROR_INVALID_PARAMETER);
2388 /* Load and initialize the monitor. SetLastError() is called on failure */
2389 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2394 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2395 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2399 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2400 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2401 &disposition) == ERROR_SUCCESS) {
2403 /* Some installers set options for the port before calling AddMonitor.
2404 We query the "Driver" entry to verify that the monitor is installed,
2405 before we return an error.
2406 When a user installs two print monitors at the same time with the
2407 same name but with a different driver DLL and a task switch comes
2408 between RegQueryValueExW and RegSetValueExW, a race condition
2409 is possible but silently ignored. */
2413 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2414 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2415 &namesize) == ERROR_SUCCESS)) {
2416 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2417 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2418 9x: ERROR_ALREADY_EXISTS (183) */
2419 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2424 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2425 res = (RegSetValueExW(hentry, DriverW, 0,
2426 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2428 RegCloseKey(hentry);
2435 /******************************************************************
2436 * DeletePrinterDriverA [WINSPOOL.@]
2439 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2441 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2444 /******************************************************************
2445 * DeletePrinterDriverW [WINSPOOL.@]
2448 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2450 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2453 /******************************************************************
2454 * DeleteMonitorA [WINSPOOL.@]
2456 * See DeleteMonitorW.
2459 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2461 LPWSTR nameW = NULL;
2462 LPWSTR EnvironmentW = NULL;
2463 LPWSTR MonitorNameW = NULL;
2468 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2469 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2470 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2474 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2475 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2476 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2479 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2480 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2481 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2484 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2486 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2487 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2488 HeapFree(GetProcessHeap(), 0, nameW);
2492 /******************************************************************
2493 * DeleteMonitorW [WINSPOOL.@]
2495 * Delete a specific Printmonitor from a Printing-Environment
2498 * pName [I] Servername or NULL (local Computer)
2499 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2500 * pMonitorName [I] Name of the Monitor, that should be deleted
2507 * pEnvironment is ignored in Windows for the local Computer.
2511 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2515 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2516 debugstr_w(pMonitorName));
2518 if (pName && (pName[0])) {
2519 FIXME("for server %s not implemented\n", debugstr_w(pName));
2520 SetLastError(ERROR_ACCESS_DENIED);
2524 /* pEnvironment is ignored in Windows for the local Computer */
2526 if (!pMonitorName || !pMonitorName[0]) {
2527 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2528 SetLastError(ERROR_INVALID_PARAMETER);
2532 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2533 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2537 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2538 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2543 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2546 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2547 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2551 /******************************************************************
2552 * DeletePortA [WINSPOOL.@]
2557 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2559 LPWSTR nameW = NULL;
2560 LPWSTR portW = NULL;
2564 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2566 /* convert servername to unicode */
2568 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2569 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2570 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2573 /* convert portname to unicode */
2575 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2576 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2577 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2580 res = DeletePortW(nameW, hWnd, portW);
2581 HeapFree(GetProcessHeap(), 0, nameW);
2582 HeapFree(GetProcessHeap(), 0, portW);
2586 /******************************************************************
2587 * DeletePortW [WINSPOOL.@]
2589 * Delete a specific Port
2592 * pName [I] Servername or NULL (local Computer)
2593 * hWnd [I] Handle to parent Window for the Dialog-Box
2594 * pPortName [I] Name of the Port, that should be deleted
2601 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2607 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2609 if (pName && pName[0]) {
2610 SetLastError(ERROR_INVALID_PARAMETER);
2615 SetLastError(RPC_X_NULL_REF_POINTER);
2619 /* an empty Portname is Invalid */
2620 if (!pPortName[0]) {
2621 SetLastError(ERROR_NOT_SUPPORTED);
2625 pm = monitor_load_by_port(pPortName);
2626 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2627 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2628 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2629 TRACE("got %d with %u\n", res, GetLastError());
2633 pui = monitor_loadui(pm);
2634 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2635 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2636 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2637 TRACE("got %d with %u\n", res, GetLastError());
2641 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2642 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2644 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2645 SetLastError(ERROR_NOT_SUPPORTED);
2648 monitor_unload(pui);
2652 TRACE("returning %d with %u\n", res, GetLastError());
2656 /******************************************************************************
2657 * SetPrinterW [WINSPOOL.@]
2659 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2661 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2662 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2666 /******************************************************************************
2667 * WritePrinter [WINSPOOL.@]
2669 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2671 opened_printer_t *printer;
2674 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2676 EnterCriticalSection(&printer_handles_cs);
2677 printer = get_opened_printer(hPrinter);
2680 SetLastError(ERROR_INVALID_HANDLE);
2686 SetLastError(ERROR_SPL_NO_STARTDOC);
2690 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2692 LeaveCriticalSection(&printer_handles_cs);
2696 /*****************************************************************************
2697 * AddFormA [WINSPOOL.@]
2699 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2701 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2705 /*****************************************************************************
2706 * AddFormW [WINSPOOL.@]
2708 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2710 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2714 /*****************************************************************************
2715 * AddJobA [WINSPOOL.@]
2717 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2720 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2724 SetLastError(ERROR_INVALID_LEVEL);
2728 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2731 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2732 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2733 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2734 if(*pcbNeeded > cbBuf) {
2735 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2738 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2739 addjobA->JobId = addjobW->JobId;
2740 addjobA->Path = (char *)(addjobA + 1);
2741 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2747 /*****************************************************************************
2748 * AddJobW [WINSPOOL.@]
2750 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2752 opened_printer_t *printer;
2755 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2756 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2757 WCHAR path[MAX_PATH], filename[MAX_PATH];
2759 ADDJOB_INFO_1W *addjob;
2761 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2763 EnterCriticalSection(&printer_handles_cs);
2765 printer = get_opened_printer(hPrinter);
2768 SetLastError(ERROR_INVALID_HANDLE);
2773 SetLastError(ERROR_INVALID_LEVEL);
2777 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2781 job->job_id = InterlockedIncrement(&next_job_id);
2783 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2784 if(path[len - 1] != '\\')
2786 memcpy(path + len, spool_path, sizeof(spool_path));
2787 sprintfW(filename, fmtW, path, job->job_id);
2789 len = strlenW(filename);
2790 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2791 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2792 job->document_title = strdupW(default_doc_title);
2793 list_add_tail(&printer->queue->jobs, &job->entry);
2795 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2796 if(*pcbNeeded <= cbBuf) {
2797 addjob = (ADDJOB_INFO_1W*)pData;
2798 addjob->JobId = job->job_id;
2799 addjob->Path = (WCHAR *)(addjob + 1);
2800 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2803 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2806 LeaveCriticalSection(&printer_handles_cs);
2810 /*****************************************************************************
2811 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2813 * Return the PATH for the Print-Processors
2815 * See GetPrintProcessorDirectoryW.
2819 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2820 DWORD level, LPBYTE Info,
2821 DWORD cbBuf, LPDWORD pcbNeeded)
2823 LPWSTR serverW = NULL;
2828 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2829 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2833 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2834 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2835 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2839 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2840 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2841 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2844 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2845 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2847 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2850 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2851 cbBuf, NULL, NULL) > 0;
2854 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2855 HeapFree(GetProcessHeap(), 0, envW);
2856 HeapFree(GetProcessHeap(), 0, serverW);
2860 /*****************************************************************************
2861 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2863 * Return the PATH for the Print-Processors
2866 * server [I] Servername (NT only) or NULL (local Computer)
2867 * env [I] Printing-Environment (see below) or NULL (Default)
2868 * level [I] Structure-Level (must be 1)
2869 * Info [O] PTR to Buffer that receives the Result
2870 * cbBuf [I] Size of Buffer at "Info"
2871 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2872 * required for the Buffer at "Info"
2875 * Success: TRUE and in pcbNeeded the Bytes used in Info
2876 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2877 * if cbBuf is too small
2879 * Native Values returned in Info on Success:
2880 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2881 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2882 *| win9x(Windows 4.0): "%winsysdir%"
2884 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2887 * Only NULL or "" is supported for server
2890 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2891 DWORD level, LPBYTE Info,
2892 DWORD cbBuf, LPDWORD pcbNeeded)
2895 const printenv_t * env_t;
2897 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2898 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2900 if(server != NULL && server[0]) {
2901 FIXME("server not supported: %s\n", debugstr_w(server));
2902 SetLastError(ERROR_INVALID_PARAMETER);
2906 env_t = validate_envW(env);
2907 if(!env_t) return FALSE; /* environment invalid or unsupported */
2910 WARN("(Level: %d) is ignored in win9x\n", level);
2911 SetLastError(ERROR_INVALID_LEVEL);
2915 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2916 needed = GetSystemDirectoryW(NULL, 0);
2917 /* add the Size for the Subdirectories */
2918 needed += lstrlenW(spoolprtprocsW);
2919 needed += lstrlenW(env_t->subdir);
2920 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2922 if(pcbNeeded) *pcbNeeded = needed;
2923 TRACE ("required: 0x%x/%d\n", needed, needed);
2924 if (needed > cbBuf) {
2925 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2928 if(pcbNeeded == NULL) {
2929 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2930 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2931 SetLastError(RPC_X_NULL_REF_POINTER);
2935 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2936 SetLastError(RPC_X_NULL_REF_POINTER);
2940 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2941 /* add the Subdirectories */
2942 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2943 lstrcatW((LPWSTR) Info, env_t->subdir);
2944 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2948 /*****************************************************************************
2949 * WINSPOOL_OpenDriverReg [internal]
2951 * opens the registry for the printer drivers depending on the given input
2952 * variable pEnvironment
2955 * the opened hkey on success
2958 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2962 const printenv_t * env;
2965 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2967 if (!pEnvironment || unicode) {
2968 /* pEnvironment was NULL or an Unicode-String: use it direct */
2969 env = validate_envW(pEnvironment);
2973 /* pEnvironment was an ANSI-String: convert to unicode first */
2975 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2976 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2977 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2978 env = validate_envW(buffer);
2979 HeapFree(GetProcessHeap(), 0, buffer);
2981 if (!env) return NULL;
2983 buffer = HeapAlloc( GetProcessHeap(), 0,
2984 (strlenW(DriversW) + strlenW(env->envname) +
2985 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2987 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2988 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2989 HeapFree(GetProcessHeap(), 0, buffer);
2994 /*****************************************************************************
2995 * AddPrinterW [WINSPOOL.@]
2997 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2999 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3003 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3005 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
3006 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
3007 priorityW[] = {'P','r','i','o','r','i','t','y',0},
3008 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
3009 statusW[] = {'S','t','a','t','u','s',0},
3010 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
3012 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3015 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3016 SetLastError(ERROR_INVALID_PARAMETER);
3020 ERR("Level = %d, unsupported!\n", Level);
3021 SetLastError(ERROR_INVALID_LEVEL);
3025 SetLastError(ERROR_INVALID_PARAMETER);
3028 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3030 ERR("Can't create Printers key\n");
3033 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3034 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
3035 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3036 RegCloseKey(hkeyPrinter);
3037 RegCloseKey(hkeyPrinters);
3040 RegCloseKey(hkeyPrinter);
3042 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
3044 ERR("Can't create Drivers key\n");
3045 RegCloseKey(hkeyPrinters);
3048 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3050 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3051 RegCloseKey(hkeyPrinters);
3052 RegCloseKey(hkeyDrivers);
3053 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3056 RegCloseKey(hkeyDriver);
3057 RegCloseKey(hkeyDrivers);
3059 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3060 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3061 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3062 RegCloseKey(hkeyPrinters);
3066 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3068 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3069 SetLastError(ERROR_INVALID_PRINTER_NAME);
3070 RegCloseKey(hkeyPrinters);
3073 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
3074 (LPBYTE)&pi->Attributes, sizeof(DWORD));
3075 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3077 /* See if we can load the driver. We may need the devmode structure anyway
3080 * Note that DocumentPropertiesW will briefly try to open the printer we
3081 * just create to find a DEVMODEA struct (it will use the WINEPS default
3082 * one in case it is not there, so we are ok).
3084 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3087 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3088 size = sizeof(DEVMODEW);
3094 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3096 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
3098 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3099 HeapFree(GetProcessHeap(),0,dmW);
3104 /* set devmode to printer name */
3105 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
3109 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3110 and we support these drivers. NT writes DEVMODEW so somehow
3111 we'll need to distinguish between these when we support NT
3115 dmA = DEVMODEdupWtoA(dmW);
3116 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
3117 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
3118 HeapFree(GetProcessHeap(), 0, dmA);
3120 HeapFree(GetProcessHeap(), 0, dmW);
3122 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3123 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3124 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3125 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3127 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3128 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3129 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3130 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
3131 (LPBYTE)&pi->Priority, sizeof(DWORD));
3132 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3133 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3134 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
3135 (LPBYTE)&pi->StartTime, sizeof(DWORD));
3136 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
3137 (LPBYTE)&pi->Status, sizeof(DWORD));
3138 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
3139 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
3141 RegCloseKey(hkeyPrinter);
3142 RegCloseKey(hkeyPrinters);
3143 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3144 ERR("OpenPrinter failing\n");
3150 /*****************************************************************************
3151 * AddPrinterA [WINSPOOL.@]
3153 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3155 UNICODE_STRING pNameW;
3157 PRINTER_INFO_2W *piW;
3158 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3161 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
3163 ERR("Level = %d, unsupported!\n", Level);
3164 SetLastError(ERROR_INVALID_LEVEL);
3167 pwstrNameW = asciitounicode(&pNameW,pName);
3168 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3170 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3172 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3173 RtlFreeUnicodeString(&pNameW);
3178 /*****************************************************************************
3179 * ClosePrinter [WINSPOOL.@]
3181 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3183 UINT_PTR i = (UINT_PTR)hPrinter;
3184 opened_printer_t *printer = NULL;
3187 TRACE("(%p)\n", hPrinter);
3189 EnterCriticalSection(&printer_handles_cs);
3191 if ((i > 0) && (i <= nb_printer_handles))
3192 printer = printer_handles[i - 1];
3197 struct list *cursor, *cursor2;
3199 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3200 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3201 printer->hXcv, debugstr_w(printer->name), printer->doc );
3204 EndDocPrinter(hPrinter);
3206 if(InterlockedDecrement(&printer->queue->ref) == 0)
3208 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3210 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3211 ScheduleJob(hPrinter, job->job_id);
3213 HeapFree(GetProcessHeap(), 0, printer->queue);
3215 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3216 monitor_unload(printer->pm);
3217 HeapFree(GetProcessHeap(), 0, printer->printername);
3218 HeapFree(GetProcessHeap(), 0, printer->name);
3219 HeapFree(GetProcessHeap(), 0, printer);
3220 printer_handles[i - 1] = NULL;
3223 LeaveCriticalSection(&printer_handles_cs);
3227 /*****************************************************************************
3228 * DeleteFormA [WINSPOOL.@]
3230 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3232 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3236 /*****************************************************************************
3237 * DeleteFormW [WINSPOOL.@]
3239 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3241 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3245 /*****************************************************************************
3246 * DeletePrinter [WINSPOOL.@]
3248 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3250 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3251 HKEY hkeyPrinters, hkey;
3254 SetLastError(ERROR_INVALID_HANDLE);
3257 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3258 RegDeleteTreeW(hkeyPrinters, lpNameW);
3259 RegCloseKey(hkeyPrinters);
3261 WriteProfileStringW(devicesW, lpNameW, NULL);
3262 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3263 RegDeleteValueW(hkey, lpNameW);
3269 /*****************************************************************************
3270 * SetPrinterA [WINSPOOL.@]
3272 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3275 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3279 /*****************************************************************************
3280 * SetJobA [WINSPOOL.@]
3282 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3283 LPBYTE pJob, DWORD Command)
3287 UNICODE_STRING usBuffer;
3289 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3291 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3292 are all ignored by SetJob, so we don't bother copying them */
3300 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3301 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3303 JobW = (LPBYTE)info1W;
3304 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3305 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3306 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3307 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3308 info1W->Status = info1A->Status;
3309 info1W->Priority = info1A->Priority;
3310 info1W->Position = info1A->Position;
3311 info1W->PagesPrinted = info1A->PagesPrinted;
3316 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3317 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3319 JobW = (LPBYTE)info2W;
3320 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3321 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3322 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3323 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3324 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3325 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3326 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3327 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3328 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3329 info2W->Status = info2A->Status;
3330 info2W->Priority = info2A->Priority;
3331 info2W->Position = info2A->Position;
3332 info2W->StartTime = info2A->StartTime;
3333 info2W->UntilTime = info2A->UntilTime;
3334 info2W->PagesPrinted = info2A->PagesPrinted;
3338 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3339 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3342 SetLastError(ERROR_INVALID_LEVEL);
3346 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3352 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3353 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3354 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3355 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3356 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3361 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3362 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3363 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3364 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3365 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3366 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3367 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3368 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3369 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3373 HeapFree(GetProcessHeap(), 0, JobW);
3378 /*****************************************************************************
3379 * SetJobW [WINSPOOL.@]
3381 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3382 LPBYTE pJob, DWORD Command)
3387 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3388 FIXME("Ignoring everything other than document title\n");
3390 EnterCriticalSection(&printer_handles_cs);
3391 job = get_job(hPrinter, JobId);
3401 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3402 HeapFree(GetProcessHeap(), 0, job->document_title);
3403 job->document_title = strdupW(info1->pDocument);
3408 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3409 HeapFree(GetProcessHeap(), 0, job->document_title);
3410 job->document_title = strdupW(info2->pDocument);
3416 SetLastError(ERROR_INVALID_LEVEL);
3421 LeaveCriticalSection(&printer_handles_cs);
3425 /*****************************************************************************
3426 * EndDocPrinter [WINSPOOL.@]
3428 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3430 opened_printer_t *printer;
3432 TRACE("(%p)\n", hPrinter);
3434 EnterCriticalSection(&printer_handles_cs);
3436 printer = get_opened_printer(hPrinter);
3439 SetLastError(ERROR_INVALID_HANDLE);
3445 SetLastError(ERROR_SPL_NO_STARTDOC);
3449 CloseHandle(printer->doc->hf);
3450 ScheduleJob(hPrinter, printer->doc->job_id);
3451 HeapFree(GetProcessHeap(), 0, printer->doc);
3452 printer->doc = NULL;
3455 LeaveCriticalSection(&printer_handles_cs);
3459 /*****************************************************************************
3460 * EndPagePrinter [WINSPOOL.@]
3462 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3464 FIXME("(%p): stub\n", hPrinter);
3468 /*****************************************************************************
3469 * StartDocPrinterA [WINSPOOL.@]
3471 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3473 UNICODE_STRING usBuffer;
3475 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3478 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3479 or one (DOC_INFO_3) extra DWORDs */
3483 doc2W.JobId = doc2->JobId;
3486 doc2W.dwMode = doc2->dwMode;
3489 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3490 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3491 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3495 SetLastError(ERROR_INVALID_LEVEL);
3499 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3501 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3502 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3503 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3508 /*****************************************************************************
3509 * StartDocPrinterW [WINSPOOL.@]
3511 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3513 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3514 opened_printer_t *printer;
3515 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3516 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3517 JOB_INFO_1W job_info;
3518 DWORD needed, ret = 0;
3522 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3523 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3524 debugstr_w(doc->pDatatype));
3526 if(Level < 1 || Level > 3)
3528 SetLastError(ERROR_INVALID_LEVEL);
3532 EnterCriticalSection(&printer_handles_cs);
3533 printer = get_opened_printer(hPrinter);
3536 SetLastError(ERROR_INVALID_HANDLE);
3542 SetLastError(ERROR_INVALID_PRINTER_STATE);
3546 /* Even if we're printing to a file we still add a print job, we'll
3547 just ignore the spool file name */
3549 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3551 ERR("AddJob failed gle %u\n", GetLastError());
3555 if(doc->pOutputFile)
3556 filename = doc->pOutputFile;
3558 filename = addjob->Path;
3560 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3561 if(hf == INVALID_HANDLE_VALUE)
3564 memset(&job_info, 0, sizeof(job_info));
3565 job_info.pDocument = doc->pDocName;
3566 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3568 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3569 printer->doc->hf = hf;
3570 ret = printer->doc->job_id = addjob->JobId;
3572 LeaveCriticalSection(&printer_handles_cs);
3577 /*****************************************************************************
3578 * StartPagePrinter [WINSPOOL.@]
3580 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3582 FIXME("(%p): stub\n", hPrinter);
3586 /*****************************************************************************
3587 * GetFormA [WINSPOOL.@]
3589 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3590 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3592 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3593 Level,pForm,cbBuf,pcbNeeded);
3597 /*****************************************************************************
3598 * GetFormW [WINSPOOL.@]
3600 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3601 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3603 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3604 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3608 /*****************************************************************************
3609 * SetFormA [WINSPOOL.@]
3611 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3614 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3618 /*****************************************************************************
3619 * SetFormW [WINSPOOL.@]
3621 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3624 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3628 /*****************************************************************************
3629 * ReadPrinter [WINSPOOL.@]
3631 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3632 LPDWORD pNoBytesRead)
3634 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3638 /*****************************************************************************
3639 * ResetPrinterA [WINSPOOL.@]
3641 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3643 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3647 /*****************************************************************************
3648 * ResetPrinterW [WINSPOOL.@]
3650 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3652 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3656 /*****************************************************************************
3657 * WINSPOOL_GetDWORDFromReg
3659 * Return DWORD associated with ValueName from hkey.
3661 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3663 DWORD sz = sizeof(DWORD), type, value = 0;
3666 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3668 if(ret != ERROR_SUCCESS) {
3669 WARN("Got ret = %d on name %s\n", ret, ValueName);
3672 if(type != REG_DWORD) {
3673 ERR("Got type %d\n", type);
3680 /*****************************************************************************
3681 * get_filename_from_reg [internal]
3683 * Get ValueName from hkey storing result in out
3684 * when the Value in the registry has only a filename, use driverdir as prefix
3685 * outlen is space left in out
3686 * String is stored either as unicode or ascii
3690 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3691 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3693 WCHAR filename[MAX_PATH];
3697 LPWSTR buffer = filename;
3701 size = sizeof(filename);
3703 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3704 if (ret == ERROR_MORE_DATA) {
3705 TRACE("need dynamic buffer: %u\n", size);
3706 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3708 /* No Memory is bad */
3712 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3715 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3716 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3722 /* do we have a full path ? */
3723 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3724 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3727 /* we must build the full Path */
3729 if ((out) && (outlen > dirlen)) {
3731 lstrcpyW((LPWSTR)out, driverdir);
3735 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3744 /* write the filename */
3746 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3747 if ((out) && (outlen >= size)) {
3748 lstrcpyW((LPWSTR)out, ptr);
3757 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3758 if ((out) && (outlen >= size)) {
3759 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3767 ptr += lstrlenW(ptr)+1;
3768 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3771 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3773 /* write the multisz-termination */
3774 if (type == REG_MULTI_SZ) {
3775 size = (unicode) ? sizeof(WCHAR) : 1;
3778 if (out && (outlen >= size)) {
3779 memset (out, 0, size);
3785 /*****************************************************************************
3786 * WINSPOOL_GetStringFromReg
3788 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3789 * String is stored either as unicode or ascii.
3790 * Bit of a hack here to get the ValueName if we want ascii.
3792 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3793 DWORD buflen, DWORD *needed,
3796 DWORD sz = buflen, type;
3800 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3802 LPSTR ValueNameA = strdupWtoA(ValueName);
3803 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3804 HeapFree(GetProcessHeap(),0,ValueNameA);
3806 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3807 WARN("Got ret = %d\n", ret);
3811 /* add space for terminating '\0' */
3812 sz += unicode ? sizeof(WCHAR) : 1;
3816 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3821 /*****************************************************************************
3822 * WINSPOOL_GetDefaultDevMode
3824 * Get a default DevMode values for wineps.
3828 static void WINSPOOL_GetDefaultDevMode(
3830 DWORD buflen, DWORD *needed,
3834 static const char szwps[] = "wineps.drv";
3836 /* fill default DEVMODE - should be read from ppd... */
3837 ZeroMemory( &dm, sizeof(dm) );
3838 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3839 dm.dmSpecVersion = DM_SPECVERSION;
3840 dm.dmDriverVersion = 1;
3841 dm.dmSize = sizeof(DEVMODEA);
3842 dm.dmDriverExtra = 0;
3844 DM_ORIENTATION | DM_PAPERSIZE |
3845 DM_PAPERLENGTH | DM_PAPERWIDTH |
3848 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3849 DM_YRESOLUTION | DM_TTOPTION;
3851 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3852 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3853 dm.u1.s1.dmPaperLength = 2970;
3854 dm.u1.s1.dmPaperWidth = 2100;
3856 dm.u1.s1.dmScale = 100;
3857 dm.u1.s1.dmCopies = 1;
3858 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3859 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3862 dm.dmYResolution = 300; /* 300dpi */
3863 dm.dmTTOption = DMTT_BITMAP;
3866 /* dm.dmLogPixels */
3867 /* dm.dmBitsPerPel */
3868 /* dm.dmPelsWidth */
3869 /* dm.dmPelsHeight */
3870 /* dm.u2.dmDisplayFlags */
3871 /* dm.dmDisplayFrequency */
3872 /* dm.dmICMMethod */
3873 /* dm.dmICMIntent */
3874 /* dm.dmMediaType */
3875 /* dm.dmDitherType */
3876 /* dm.dmReserved1 */
3877 /* dm.dmReserved2 */
3878 /* dm.dmPanningWidth */
3879 /* dm.dmPanningHeight */
3882 if(buflen >= sizeof(DEVMODEW)) {
3883 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3884 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3885 HeapFree(GetProcessHeap(),0,pdmW);
3887 *needed = sizeof(DEVMODEW);
3891 if(buflen >= sizeof(DEVMODEA)) {
3892 memcpy(ptr, &dm, sizeof(DEVMODEA));
3894 *needed = sizeof(DEVMODEA);
3898 /*****************************************************************************
3899 * WINSPOOL_GetDevModeFromReg
3901 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3902 * DevMode is stored either as unicode or ascii.
3904 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3906 DWORD buflen, DWORD *needed,
3909 DWORD sz = buflen, type;
3912 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3913 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3914 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3915 if (sz < sizeof(DEVMODEA))
3917 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3920 /* ensures that dmSize is not erratically bogus if registry is invalid */
3921 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3922 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3924 sz += (CCHDEVICENAME + CCHFORMNAME);
3926 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3927 memcpy(ptr, dmW, sz);
3928 HeapFree(GetProcessHeap(),0,dmW);
3935 /*********************************************************************
3936 * WINSPOOL_GetPrinter_1
3938 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3939 * The strings are either stored as unicode or ascii.
3941 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3942 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3945 DWORD size, left = cbBuf;
3946 BOOL space = (cbBuf > 0);
3951 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3953 if(space && size <= left) {
3954 pi1->pName = (LPWSTR)ptr;
3962 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3963 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3965 if(space && size <= left) {
3966 pi1->pDescription = (LPWSTR)ptr;
3974 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3976 if(space && size <= left) {
3977 pi1->pComment = (LPWSTR)ptr;
3985 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3987 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3988 memset(pi1, 0, sizeof(*pi1));
3992 /*********************************************************************
3993 * WINSPOOL_GetPrinter_2
3995 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3996 * The strings are either stored as unicode or ascii.
3998 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3999 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4002 DWORD size, left = cbBuf;
4003 BOOL space = (cbBuf > 0);
4008 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4010 if(space && size <= left) {
4011 pi2->pPrinterName = (LPWSTR)ptr;
4018 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
4020 if(space && size <= left) {
4021 pi2->pShareName = (LPWSTR)ptr;
4028 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4030 if(space && size <= left) {
4031 pi2->pPortName = (LPWSTR)ptr;
4038 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
4040 if(space && size <= left) {
4041 pi2->pDriverName = (LPWSTR)ptr;
4048 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
4050 if(space && size <= left) {
4051 pi2->pComment = (LPWSTR)ptr;
4058 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
4060 if(space && size <= left) {
4061 pi2->pLocation = (LPWSTR)ptr;
4068 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
4070 if(space && size <= left) {
4071 pi2->pDevMode = (LPDEVMODEW)ptr;
4080 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
4081 if(space && size <= left) {
4082 pi2->pDevMode = (LPDEVMODEW)ptr;
4089 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
4091 if(space && size <= left) {
4092 pi2->pSepFile = (LPWSTR)ptr;
4099 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
4101 if(space && size <= left) {
4102 pi2->pPrintProcessor = (LPWSTR)ptr;
4109 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
4111 if(space && size <= left) {
4112 pi2->pDatatype = (LPWSTR)ptr;
4119 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
4121 if(space && size <= left) {
4122 pi2->pParameters = (LPWSTR)ptr;
4130 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4131 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
4132 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4133 "Default Priority");
4134 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
4135 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
4138 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4139 memset(pi2, 0, sizeof(*pi2));
4144 /*********************************************************************
4145 * WINSPOOL_GetPrinter_4
4147 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4149 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4150 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4153 DWORD size, left = cbBuf;
4154 BOOL space = (cbBuf > 0);
4159 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4161 if(space && size <= left) {
4162 pi4->pPrinterName = (LPWSTR)ptr;
4170 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4173 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4174 memset(pi4, 0, sizeof(*pi4));
4179 /*********************************************************************
4180 * WINSPOOL_GetPrinter_5
4182 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4184 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4185 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4188 DWORD size, left = cbBuf;
4189 BOOL space = (cbBuf > 0);
4194 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4196 if(space && size <= left) {
4197 pi5->pPrinterName = (LPWSTR)ptr;
4204 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4206 if(space && size <= left) {
4207 pi5->pPortName = (LPWSTR)ptr;
4215 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4216 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4218 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4222 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4223 memset(pi5, 0, sizeof(*pi5));
4228 /*********************************************************************
4229 * WINSPOOL_GetPrinter_7
4231 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4233 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4234 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4236 DWORD size, left = cbBuf;
4237 BOOL space = (cbBuf > 0);
4242 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4244 if (space && size <= left) {
4245 pi7->pszObjectGUID = (LPWSTR)ptr;
4253 /* We do not have a Directory Service */
4254 pi7->dwAction = DSPRINT_UNPUBLISH;
4257 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4258 memset(pi7, 0, sizeof(*pi7));
4263 /*********************************************************************
4264 * WINSPOOL_GetPrinter_9
4266 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4267 * The strings are either stored as unicode or ascii.
4269 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4270 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4273 BOOL space = (cbBuf > 0);
4277 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4278 if(space && size <= cbBuf) {
4279 pi9->pDevMode = (LPDEVMODEW)buf;
4286 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4287 if(space && size <= cbBuf) {
4288 pi9->pDevMode = (LPDEVMODEW)buf;
4294 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4295 memset(pi9, 0, sizeof(*pi9));
4300 /*****************************************************************************
4301 * WINSPOOL_GetPrinter
4303 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4304 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4305 * just a collection of pointers to strings.
4307 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4308 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4311 DWORD size, needed = 0;
4313 HKEY hkeyPrinter, hkeyPrinters;
4316 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4318 if (!(name = get_opened_printer_name(hPrinter))) {
4319 SetLastError(ERROR_INVALID_HANDLE);
4323 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4325 ERR("Can't create Printers key\n");
4328 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4330 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4331 RegCloseKey(hkeyPrinters);
4332 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4339 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4341 size = sizeof(PRINTER_INFO_2W);
4343 ptr = pPrinter + size;
4345 memset(pPrinter, 0, size);
4350 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4358 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4360 size = sizeof(PRINTER_INFO_4W);
4362 ptr = pPrinter + size;
4364 memset(pPrinter, 0, size);
4369 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4378 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4380 size = sizeof(PRINTER_INFO_5W);
4382 ptr = pPrinter + size;
4384 memset(pPrinter, 0, size);
4390 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4399 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4401 size = sizeof(PRINTER_INFO_6);
4402 if (size <= cbBuf) {
4403 /* FIXME: We do not update the status yet */
4404 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4416 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4418 size = sizeof(PRINTER_INFO_7W);
4419 if (size <= cbBuf) {
4420 ptr = pPrinter + size;
4422 memset(pPrinter, 0, size);
4428 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4436 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4438 size = sizeof(PRINTER_INFO_9W);
4440 ptr = pPrinter + size;
4442 memset(pPrinter, 0, size);
4448 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4455 FIXME("Unimplemented level %d\n", Level);
4456 SetLastError(ERROR_INVALID_LEVEL);
4457 RegCloseKey(hkeyPrinters);
4458 RegCloseKey(hkeyPrinter);
4462 RegCloseKey(hkeyPrinter);
4463 RegCloseKey(hkeyPrinters);
4465 TRACE("returning %d needed = %d\n", ret, needed);
4466 if(pcbNeeded) *pcbNeeded = needed;
4468 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4472 /*****************************************************************************
4473 * GetPrinterW [WINSPOOL.@]
4475 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4476 DWORD cbBuf, LPDWORD pcbNeeded)
4478 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4482 /*****************************************************************************
4483 * GetPrinterA [WINSPOOL.@]
4485 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4486 DWORD cbBuf, LPDWORD pcbNeeded)
4488 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4492 /*****************************************************************************
4493 * WINSPOOL_EnumPrinters
4495 * Implementation of EnumPrintersA|W
4497 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4498 DWORD dwLevel, LPBYTE lpbPrinters,
4499 DWORD cbBuf, LPDWORD lpdwNeeded,
4500 LPDWORD lpdwReturned, BOOL unicode)
4503 HKEY hkeyPrinters, hkeyPrinter;
4504 WCHAR PrinterName[255];
4505 DWORD needed = 0, number = 0;
4506 DWORD used, i, left;
4510 memset(lpbPrinters, 0, cbBuf);
4516 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4517 if(dwType == PRINTER_ENUM_DEFAULT)
4520 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4521 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4522 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4524 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4532 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4533 FIXME("dwType = %08x\n", dwType);
4534 SetLastError(ERROR_INVALID_FLAGS);
4538 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4540 ERR("Can't create Printers key\n");
4544 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4545 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4546 RegCloseKey(hkeyPrinters);
4547 ERR("Can't query Printers key\n");
4550 TRACE("Found %d printers\n", number);
4554 used = number * sizeof(PRINTER_INFO_1W);
4557 used = number * sizeof(PRINTER_INFO_2W);
4560 used = number * sizeof(PRINTER_INFO_4W);
4563 used = number * sizeof(PRINTER_INFO_5W);
4567 SetLastError(ERROR_INVALID_LEVEL);
4568 RegCloseKey(hkeyPrinters);
4571 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4573 for(i = 0; i < number; i++) {
4574 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4576 ERR("Can't enum key number %d\n", i);
4577 RegCloseKey(hkeyPrinters);
4580 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4581 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4583 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4584 RegCloseKey(hkeyPrinters);
4589 buf = lpbPrinters + used;
4590 left = cbBuf - used;
4598 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4599 left, &needed, unicode);
4601 if(pi) pi += sizeof(PRINTER_INFO_1W);
4604 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4605 left, &needed, unicode);
4607 if(pi) pi += sizeof(PRINTER_INFO_2W);
4610 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4611 left, &needed, unicode);
4613 if(pi) pi += sizeof(PRINTER_INFO_4W);
4616 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4617 left, &needed, unicode);
4619 if(pi) pi += sizeof(PRINTER_INFO_5W);
4622 ERR("Shouldn't be here!\n");
4623 RegCloseKey(hkeyPrinter);
4624 RegCloseKey(hkeyPrinters);
4627 RegCloseKey(hkeyPrinter);
4629 RegCloseKey(hkeyPrinters);
4636 memset(lpbPrinters, 0, cbBuf);
4637 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4641 *lpdwReturned = number;
4642 SetLastError(ERROR_SUCCESS);
4647 /******************************************************************
4648 * EnumPrintersW [WINSPOOL.@]
4650 * Enumerates the available printers, print servers and print
4651 * providers, depending on the specified flags, name and level.
4655 * If level is set to 1:
4656 * Returns an array of PRINTER_INFO_1 data structures in the
4657 * lpbPrinters buffer.
4659 * If level is set to 2:
4660 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4661 * Returns an array of PRINTER_INFO_2 data structures in the
4662 * lpbPrinters buffer. Note that according to MSDN also an
4663 * OpenPrinter should be performed on every remote printer.
4665 * If level is set to 4 (officially WinNT only):
4666 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4667 * Fast: Only the registry is queried to retrieve printer names,
4668 * no connection to the driver is made.
4669 * Returns an array of PRINTER_INFO_4 data structures in the
4670 * lpbPrinters buffer.
4672 * If level is set to 5 (officially WinNT4/Win9x only):
4673 * Fast: Only the registry is queried to retrieve printer names,
4674 * no connection to the driver is made.
4675 * Returns an array of PRINTER_INFO_5 data structures in the
4676 * lpbPrinters buffer.
4678 * If level set to 3 or 6+:
4679 * returns zero (failure!)
4681 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4685 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4686 * - Only levels 2, 4 and 5 are implemented at the moment.
4687 * - 16-bit printer drivers are not enumerated.
4688 * - Returned amount of bytes used/needed does not match the real Windoze
4689 * implementation (as in this implementation, all strings are part
4690 * of the buffer, whereas Win32 keeps them somewhere else)
4691 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4694 * - In a regular Wine installation, no registry settings for printers
4695 * exist, which makes this function return an empty list.
4697 BOOL WINAPI EnumPrintersW(
4698 DWORD dwType, /* [in] Types of print objects to enumerate */
4699 LPWSTR lpszName, /* [in] name of objects to enumerate */
4700 DWORD dwLevel, /* [in] type of printer info structure */
4701 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4702 DWORD cbBuf, /* [in] max size of buffer in bytes */
4703 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4704 LPDWORD lpdwReturned /* [out] number of entries returned */
4707 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4708 lpdwNeeded, lpdwReturned, TRUE);
4711 /******************************************************************
4712 * EnumPrintersA [WINSPOOL.@]
4717 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4718 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4721 UNICODE_STRING pNameU;
4725 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4726 pPrinters, cbBuf, pcbNeeded, pcReturned);
4728 pNameW = asciitounicode(&pNameU, pName);
4730 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4731 MS Office need this */
4732 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4734 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4736 RtlFreeUnicodeString(&pNameU);
4738 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4740 HeapFree(GetProcessHeap(), 0, pPrintersW);
4744 /*****************************************************************************
4745 * WINSPOOL_GetDriverInfoFromReg [internal]
4747 * Enters the information from the registry into the DRIVER_INFO struct
4750 * zero if the printer driver does not exist in the registry
4751 * (only if Level > 1) otherwise nonzero
4753 static BOOL WINSPOOL_GetDriverInfoFromReg(
4756 const printenv_t * env,
4758 LPBYTE ptr, /* DRIVER_INFO */
4759 LPBYTE pDriverStrings, /* strings buffer */
4760 DWORD cbBuf, /* size of string buffer */
4761 LPDWORD pcbNeeded, /* space needed for str. */
4762 BOOL unicode) /* type of strings */
4766 WCHAR driverdir[MAX_PATH];
4768 LPBYTE strPtr = pDriverStrings;
4769 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4771 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4772 debugstr_w(DriverName), env,
4773 Level, di, pDriverStrings, cbBuf, unicode);
4775 if (di) ZeroMemory(di, di_sizeof[Level]);
4778 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4779 if (*pcbNeeded <= cbBuf)
4780 strcpyW((LPWSTR)strPtr, DriverName);
4784 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4785 if (*pcbNeeded <= cbBuf)
4786 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4789 /* pName for level 1 has a different offset! */
4791 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4795 /* .cVersion and .pName for level > 1 */
4797 di->cVersion = env->driverversion;
4798 di->pName = (LPWSTR) strPtr;
4799 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4802 /* Reserve Space for the largest subdir and a Backslash*/
4803 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4804 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4805 /* Should never Fail */
4808 lstrcatW(driverdir, env->versionsubdir);
4809 lstrcatW(driverdir, backslashW);
4811 /* dirlen must not include the terminating zero */
4812 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4813 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4815 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4816 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4817 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4823 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4825 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4828 if (*pcbNeeded <= cbBuf) {
4830 lstrcpyW((LPWSTR)strPtr, env->envname);
4834 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4836 if (di) di->pEnvironment = (LPWSTR)strPtr;
4837 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4840 /* .pDriverPath is the Graphics rendering engine.
4841 The full Path is required to avoid a crash in some apps */
4842 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4844 if (*pcbNeeded <= cbBuf)
4845 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4847 if (di) di->pDriverPath = (LPWSTR)strPtr;
4848 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4851 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4852 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4854 if (*pcbNeeded <= cbBuf)
4855 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4857 if (di) di->pDataFile = (LPWSTR)strPtr;
4858 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4861 /* .pConfigFile is the Driver user Interface */
4862 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4864 if (*pcbNeeded <= cbBuf)
4865 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4867 if (di) di->pConfigFile = (LPWSTR)strPtr;
4868 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4872 RegCloseKey(hkeyDriver);
4873 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4878 RegCloseKey(hkeyDriver);
4879 FIXME("level 5: incomplete\n");
4884 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4886 if (*pcbNeeded <= cbBuf)
4887 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4889 if (di) di->pHelpFile = (LPWSTR)strPtr;
4890 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4893 /* .pDependentFiles */
4894 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4896 if (*pcbNeeded <= cbBuf)
4897 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4899 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4900 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4902 else if (GetVersion() & 0x80000000) {
4903 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4904 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4906 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4908 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4909 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4912 /* .pMonitorName is the optional Language Monitor */
4913 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4915 if (*pcbNeeded <= cbBuf)
4916 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4918 if (di) di->pMonitorName = (LPWSTR)strPtr;
4919 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4922 /* .pDefaultDataType */
4923 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4925 if(*pcbNeeded <= cbBuf)
4926 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4928 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4929 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4933 RegCloseKey(hkeyDriver);
4934 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4938 /* .pszzPreviousNames */
4939 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4941 if(*pcbNeeded <= cbBuf)
4942 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4944 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4945 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4949 RegCloseKey(hkeyDriver);
4950 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4954 /* support is missing, but not important enough for a FIXME */
4955 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4958 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4960 if(*pcbNeeded <= cbBuf)
4961 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4963 if (di) di->pszMfgName = (LPWSTR)strPtr;
4964 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4968 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4970 if(*pcbNeeded <= cbBuf)
4971 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4973 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4974 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4977 /* .pszHardwareID */
4978 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4980 if(*pcbNeeded <= cbBuf)
4981 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4983 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4984 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4988 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4990 if(*pcbNeeded <= cbBuf)
4991 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4993 if (di) di->pszProvider = (LPWSTR)strPtr;
4994 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4998 RegCloseKey(hkeyDriver);
5002 /* support is missing, but not important enough for a FIXME */
5003 TRACE("level 8: incomplete\n");
5005 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5006 RegCloseKey(hkeyDriver);
5010 /*****************************************************************************
5011 * WINSPOOL_GetPrinterDriver
5013 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
5014 DWORD Level, LPBYTE pDriverInfo,
5015 DWORD cbBuf, LPDWORD pcbNeeded,
5019 WCHAR DriverName[100];
5020 DWORD ret, type, size, needed = 0;
5022 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
5023 const printenv_t * env;
5025 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5026 Level,pDriverInfo,cbBuf, pcbNeeded);
5029 if (!(name = get_opened_printer_name(hPrinter))) {
5030 SetLastError(ERROR_INVALID_HANDLE);
5034 if (Level < 1 || Level == 7 || Level > 8) {
5035 SetLastError(ERROR_INVALID_LEVEL);
5039 env = validate_envW(pEnvironment);
5040 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5042 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
5044 ERR("Can't create Printers key\n");
5047 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
5049 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
5050 RegCloseKey(hkeyPrinters);
5051 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
5054 size = sizeof(DriverName);
5056 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5057 (LPBYTE)DriverName, &size);
5058 RegCloseKey(hkeyPrinter);
5059 RegCloseKey(hkeyPrinters);
5060 if(ret != ERROR_SUCCESS) {
5061 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5065 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
5067 ERR("Can't create Drivers key\n");
5071 size = di_sizeof[Level];
5072 if ((size <= cbBuf) && pDriverInfo)
5073 ptr = pDriverInfo + size;
5075 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5076 env, Level, pDriverInfo, ptr,
5077 (cbBuf < size) ? 0 : cbBuf - size,
5078 &needed, unicode)) {
5079 RegCloseKey(hkeyDrivers);
5083 RegCloseKey(hkeyDrivers);
5085 if(pcbNeeded) *pcbNeeded = size + needed;
5086 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5087 if(cbBuf >= needed) return TRUE;
5088 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5092 /*****************************************************************************
5093 * GetPrinterDriverA [WINSPOOL.@]
5095 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5096 DWORD Level, LPBYTE pDriverInfo,
5097 DWORD cbBuf, LPDWORD pcbNeeded)
5100 UNICODE_STRING pEnvW;
5103 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5104 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
5105 cbBuf, pcbNeeded, FALSE);
5106 RtlFreeUnicodeString(&pEnvW);
5109 /*****************************************************************************
5110 * GetPrinterDriverW [WINSPOOL.@]
5112 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5113 DWORD Level, LPBYTE pDriverInfo,
5114 DWORD cbBuf, LPDWORD pcbNeeded)
5116 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
5117 pDriverInfo, cbBuf, pcbNeeded, TRUE);
5120 /*****************************************************************************
5121 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5123 * Return the PATH for the Printer-Drivers (UNICODE)
5126 * pName [I] Servername (NT only) or NULL (local Computer)
5127 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5128 * Level [I] Structure-Level (must be 1)
5129 * pDriverDirectory [O] PTR to Buffer that receives the Result
5130 * cbBuf [I] Size of Buffer at pDriverDirectory
5131 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5132 * required for pDriverDirectory
5135 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5136 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5137 * if cbBuf is too small
5139 * Native Values returned in pDriverDirectory on Success:
5140 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5141 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5142 *| win9x(Windows 4.0): "%winsysdir%"
5144 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5147 *- Only NULL or "" is supported for pName
5150 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5151 DWORD Level, LPBYTE pDriverDirectory,
5152 DWORD cbBuf, LPDWORD pcbNeeded)
5154 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5155 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5157 if ((backend == NULL) && !load_backend()) return FALSE;
5160 /* (Level != 1) is ignored in win9x */
5161 SetLastError(ERROR_INVALID_LEVEL);
5164 if (pcbNeeded == NULL) {
5165 /* (pcbNeeded == NULL) is ignored in win9x */
5166 SetLastError(RPC_X_NULL_REF_POINTER);
5170 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5171 pDriverDirectory, cbBuf, pcbNeeded);
5176 /*****************************************************************************
5177 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5179 * Return the PATH for the Printer-Drivers (ANSI)
5181 * See GetPrinterDriverDirectoryW.
5184 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5187 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5188 DWORD Level, LPBYTE pDriverDirectory,
5189 DWORD cbBuf, LPDWORD pcbNeeded)
5191 UNICODE_STRING nameW, environmentW;
5194 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5195 WCHAR *driverDirectoryW = NULL;
5197 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5198 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5200 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5202 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5203 else nameW.Buffer = NULL;
5204 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5205 else environmentW.Buffer = NULL;
5207 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5208 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5211 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5212 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5214 *pcbNeeded = needed;
5215 ret = (needed <= cbBuf) ? TRUE : FALSE;
5217 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5219 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5221 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5222 RtlFreeUnicodeString(&environmentW);
5223 RtlFreeUnicodeString(&nameW);
5228 /*****************************************************************************
5229 * AddPrinterDriverA [WINSPOOL.@]
5231 * See AddPrinterDriverW.
5234 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5236 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5237 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5240 /******************************************************************************
5241 * AddPrinterDriverW (WINSPOOL.@)
5243 * Install a Printer Driver
5246 * pName [I] Servername or NULL (local Computer)
5247 * level [I] Level for the supplied DRIVER_INFO_*W struct
5248 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5255 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5257 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5258 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5261 /*****************************************************************************
5262 * AddPrintProcessorA [WINSPOOL.@]
5264 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5265 LPSTR pPrintProcessorName)
5267 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5268 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5272 /*****************************************************************************
5273 * AddPrintProcessorW [WINSPOOL.@]
5275 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5276 LPWSTR pPrintProcessorName)
5278 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5279 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5283 /*****************************************************************************
5284 * AddPrintProvidorA [WINSPOOL.@]
5286 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5288 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5292 /*****************************************************************************
5293 * AddPrintProvidorW [WINSPOOL.@]
5295 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5297 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5301 /*****************************************************************************
5302 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5304 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5305 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5307 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5308 pDevModeOutput, pDevModeInput);
5312 /*****************************************************************************
5313 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5315 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5316 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5318 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5319 pDevModeOutput, pDevModeInput);
5323 /*****************************************************************************
5324 * PrinterProperties [WINSPOOL.@]
5326 * Displays a dialog to set the properties of the printer.
5329 * nonzero on success or zero on failure
5332 * implemented as stub only
5334 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5335 HANDLE hPrinter /* [in] handle to printer object */
5337 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5338 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5342 /*****************************************************************************
5343 * EnumJobsA [WINSPOOL.@]
5346 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5347 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5350 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5351 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5353 if(pcbNeeded) *pcbNeeded = 0;
5354 if(pcReturned) *pcReturned = 0;
5359 /*****************************************************************************
5360 * EnumJobsW [WINSPOOL.@]
5363 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5364 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5367 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5368 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5370 if(pcbNeeded) *pcbNeeded = 0;
5371 if(pcReturned) *pcReturned = 0;
5375 /*****************************************************************************
5376 * WINSPOOL_EnumPrinterDrivers [internal]
5378 * Delivers information about all printer drivers installed on the
5379 * localhost or a given server
5382 * nonzero on success or zero on failure. If the buffer for the returned
5383 * information is too small the function will return an error
5386 * - only implemented for localhost, foreign hosts will return an error
5388 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5389 DWORD Level, LPBYTE pDriverInfo,
5390 DWORD cbBuf, LPDWORD pcbNeeded,
5391 LPDWORD pcReturned, BOOL unicode)
5394 DWORD i, needed, number = 0, size = 0;
5395 WCHAR DriverNameW[255];
5397 const printenv_t * env;
5399 TRACE("%s,%s,%d,%p,%d,%d\n",
5400 debugstr_w(pName), debugstr_w(pEnvironment),
5401 Level, pDriverInfo, cbBuf, unicode);
5403 /* check for local drivers */
5404 if((pName) && (pName[0])) {
5405 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5406 SetLastError(ERROR_ACCESS_DENIED);
5410 env = validate_envW(pEnvironment);
5411 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5413 /* check input parameter */
5414 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5415 SetLastError(ERROR_INVALID_LEVEL);
5419 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5420 SetLastError(RPC_X_NULL_REF_POINTER);
5424 /* initialize return values */
5426 memset( pDriverInfo, 0, cbBuf);
5430 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5432 ERR("Can't open Drivers key\n");
5436 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5437 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5438 RegCloseKey(hkeyDrivers);
5439 ERR("Can't query Drivers key\n");
5442 TRACE("Found %d Drivers\n", number);
5444 /* get size of single struct
5445 * unicode and ascii structure have the same size
5447 size = di_sizeof[Level];
5449 /* calculate required buffer size */
5450 *pcbNeeded = size * number;
5452 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5454 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5455 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5457 ERR("Can't enum key number %d\n", i);
5458 RegCloseKey(hkeyDrivers);
5461 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5463 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5464 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5465 &needed, unicode)) {
5466 RegCloseKey(hkeyDrivers);
5469 (*pcbNeeded) += needed;
5472 RegCloseKey(hkeyDrivers);
5474 if(cbBuf < *pcbNeeded){
5475 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5479 *pcReturned = number;
5483 /*****************************************************************************
5484 * EnumPrinterDriversW [WINSPOOL.@]
5486 * see function EnumPrinterDrivers for RETURNS, BUGS
5488 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5489 LPBYTE pDriverInfo, DWORD cbBuf,
5490 LPDWORD pcbNeeded, LPDWORD pcReturned)
5492 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5493 cbBuf, pcbNeeded, pcReturned, TRUE);
5496 /*****************************************************************************
5497 * EnumPrinterDriversA [WINSPOOL.@]
5499 * see function EnumPrinterDrivers for RETURNS, BUGS
5501 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5502 LPBYTE pDriverInfo, DWORD cbBuf,
5503 LPDWORD pcbNeeded, LPDWORD pcReturned)
5505 UNICODE_STRING pNameW, pEnvironmentW;
5506 PWSTR pwstrNameW, pwstrEnvironmentW;
5508 pwstrNameW = asciitounicode(&pNameW, pName);
5509 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5511 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5512 Level, pDriverInfo, cbBuf, pcbNeeded,
5514 RtlFreeUnicodeString(&pNameW);
5515 RtlFreeUnicodeString(&pEnvironmentW);
5520 /******************************************************************************
5521 * EnumPortsA (WINSPOOL.@)
5526 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5527 LPDWORD pcbNeeded, LPDWORD pcReturned)
5530 LPBYTE bufferW = NULL;
5531 LPWSTR nameW = NULL;
5533 DWORD numentries = 0;
5536 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5537 cbBuf, pcbNeeded, pcReturned);
5539 /* convert servername to unicode */
5541 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5542 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5543 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5545 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5546 needed = cbBuf * sizeof(WCHAR);
5547 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5548 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5550 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5551 if (pcbNeeded) needed = *pcbNeeded;
5552 /* HeapReAlloc return NULL, when bufferW was NULL */
5553 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5554 HeapAlloc(GetProcessHeap(), 0, needed);
5556 /* Try again with the large Buffer */
5557 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5559 needed = pcbNeeded ? *pcbNeeded : 0;
5560 numentries = pcReturned ? *pcReturned : 0;
5563 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5564 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5567 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5568 DWORD entrysize = 0;
5571 LPPORT_INFO_2W pi2w;
5572 LPPORT_INFO_2A pi2a;
5575 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5577 /* First pass: calculate the size for all Entries */
5578 pi2w = (LPPORT_INFO_2W) bufferW;
5579 pi2a = (LPPORT_INFO_2A) pPorts;
5581 while (index < numentries) {
5583 needed += entrysize; /* PORT_INFO_?A */
5584 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5586 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5587 NULL, 0, NULL, NULL);
5589 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5590 NULL, 0, NULL, NULL);
5591 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5592 NULL, 0, NULL, NULL);
5594 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5595 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5596 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5599 /* check for errors and quit on failure */
5600 if (cbBuf < needed) {
5601 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5605 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5606 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5607 cbBuf -= len ; /* free Bytes in the user-Buffer */
5608 pi2w = (LPPORT_INFO_2W) bufferW;
5609 pi2a = (LPPORT_INFO_2A) pPorts;
5611 /* Second Pass: Fill the User Buffer (if we have one) */
5612 while ((index < numentries) && pPorts) {
5614 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5615 pi2a->pPortName = ptr;
5616 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5617 ptr, cbBuf , NULL, NULL);
5621 pi2a->pMonitorName = ptr;
5622 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5623 ptr, cbBuf, NULL, NULL);
5627 pi2a->pDescription = ptr;
5628 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5629 ptr, cbBuf, NULL, NULL);
5633 pi2a->fPortType = pi2w->fPortType;
5634 pi2a->Reserved = 0; /* documented: "must be zero" */
5637 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5638 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5639 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5644 if (pcbNeeded) *pcbNeeded = needed;
5645 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5647 HeapFree(GetProcessHeap(), 0, nameW);
5648 HeapFree(GetProcessHeap(), 0, bufferW);
5650 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5651 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5657 /******************************************************************************
5658 * EnumPortsW (WINSPOOL.@)
5660 * Enumerate available Ports
5663 * name [I] Servername or NULL (local Computer)
5664 * level [I] Structure-Level (1 or 2)
5665 * buffer [O] PTR to Buffer that receives the Result
5666 * bufsize [I] Size of Buffer at buffer
5667 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5668 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5672 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5676 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5679 DWORD numentries = 0;
5682 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5683 cbBuf, pcbNeeded, pcReturned);
5685 if (pName && (pName[0])) {
5686 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5687 SetLastError(ERROR_ACCESS_DENIED);
5691 /* Level is not checked in win9x */
5692 if (!Level || (Level > 2)) {
5693 WARN("level (%d) is ignored in win9x\n", Level);
5694 SetLastError(ERROR_INVALID_LEVEL);
5698 SetLastError(RPC_X_NULL_REF_POINTER);
5702 EnterCriticalSection(&monitor_handles_cs);
5705 /* Scan all local Ports */
5707 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5709 /* we calculated the needed buffersize. now do the error-checks */
5710 if (cbBuf < needed) {
5711 monitor_unloadall();
5712 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5713 goto emP_cleanup_cs;
5715 else if (!pPorts || !pcReturned) {
5716 monitor_unloadall();
5717 SetLastError(RPC_X_NULL_REF_POINTER);
5718 goto emP_cleanup_cs;
5721 /* Fill the Buffer */
5722 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5724 monitor_unloadall();
5727 LeaveCriticalSection(&monitor_handles_cs);
5730 if (pcbNeeded) *pcbNeeded = needed;
5731 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5733 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5734 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5739 /******************************************************************************
5740 * GetDefaultPrinterW (WINSPOOL.@)
5743 * This function must read the value from data 'device' of key
5744 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5746 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5750 WCHAR *buffer, *ptr;
5754 SetLastError(ERROR_INVALID_PARAMETER);
5758 /* make the buffer big enough for the stuff from the profile/registry,
5759 * the content must fit into the local buffer to compute the correct
5760 * size even if the extern buffer is too small or not given.
5761 * (20 for ,driver,port) */
5763 len = max(100, (insize + 20));
5764 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5766 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5768 SetLastError (ERROR_FILE_NOT_FOUND);
5772 TRACE("%s\n", debugstr_w(buffer));
5774 if ((ptr = strchrW(buffer, ',')) == NULL)
5776 SetLastError(ERROR_INVALID_NAME);
5782 *namesize = strlenW(buffer) + 1;
5783 if(!name || (*namesize > insize))
5785 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5789 strcpyW(name, buffer);
5792 HeapFree( GetProcessHeap(), 0, buffer);
5797 /******************************************************************************
5798 * GetDefaultPrinterA (WINSPOOL.@)
5800 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5804 WCHAR *bufferW = NULL;
5808 SetLastError(ERROR_INVALID_PARAMETER);
5812 if(name && *namesize) {
5814 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5817 if(!GetDefaultPrinterW( bufferW, namesize)) {
5822 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5826 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5829 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5832 HeapFree( GetProcessHeap(), 0, bufferW);
5837 /******************************************************************************
5838 * SetDefaultPrinterW (WINSPOOL.204)
5840 * Set the Name of the Default Printer
5843 * pszPrinter [I] Name of the Printer or NULL
5850 * When the Parameter is NULL or points to an Empty String and
5851 * a Default Printer was already present, then this Function changes nothing.
5852 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5853 * the First enumerated local Printer is used.
5856 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5859 TRACE("(%s)\n", debugstr_w(pszPrinter));
5861 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5865 /******************************************************************************
5866 * SetDefaultPrinterA (WINSPOOL.202)
5868 * See SetDefaultPrinterW.
5871 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5874 TRACE("(%s)\n", debugstr_a(pszPrinter));
5876 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5881 /******************************************************************************
5882 * SetPrinterDataExA (WINSPOOL.@)
5884 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5885 LPCSTR pValueName, DWORD Type,
5886 LPBYTE pData, DWORD cbData)
5888 HKEY hkeyPrinter, hkeySubkey;
5891 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5892 debugstr_a(pValueName), Type, pData, cbData);
5894 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5898 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5900 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5901 RegCloseKey(hkeyPrinter);
5904 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5905 RegCloseKey(hkeySubkey);
5906 RegCloseKey(hkeyPrinter);
5910 /******************************************************************************
5911 * SetPrinterDataExW (WINSPOOL.@)
5913 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5914 LPCWSTR pValueName, DWORD Type,
5915 LPBYTE pData, DWORD cbData)
5917 HKEY hkeyPrinter, hkeySubkey;
5920 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5921 debugstr_w(pValueName), Type, pData, cbData);
5923 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5927 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5929 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5930 RegCloseKey(hkeyPrinter);
5933 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5934 RegCloseKey(hkeySubkey);
5935 RegCloseKey(hkeyPrinter);
5939 /******************************************************************************
5940 * SetPrinterDataA (WINSPOOL.@)
5942 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5943 LPBYTE pData, DWORD cbData)
5945 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5949 /******************************************************************************
5950 * SetPrinterDataW (WINSPOOL.@)
5952 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5953 LPBYTE pData, DWORD cbData)
5955 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5959 /******************************************************************************
5960 * GetPrinterDataExA (WINSPOOL.@)
5962 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5963 LPCSTR pValueName, LPDWORD pType,
5964 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5966 HKEY hkeyPrinter, hkeySubkey;
5969 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5970 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5973 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5977 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5979 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5980 RegCloseKey(hkeyPrinter);
5984 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5985 RegCloseKey(hkeySubkey);
5986 RegCloseKey(hkeyPrinter);
5990 /******************************************************************************
5991 * GetPrinterDataExW (WINSPOOL.@)
5993 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5994 LPCWSTR pValueName, LPDWORD pType,
5995 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5997 HKEY hkeyPrinter, hkeySubkey;
6000 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
6001 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
6004 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6008 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6010 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
6011 RegCloseKey(hkeyPrinter);
6015 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
6016 RegCloseKey(hkeySubkey);
6017 RegCloseKey(hkeyPrinter);
6021 /******************************************************************************
6022 * GetPrinterDataA (WINSPOOL.@)
6024 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6025 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6027 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6028 pData, nSize, pcbNeeded);
6031 /******************************************************************************
6032 * GetPrinterDataW (WINSPOOL.@)
6034 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6035 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6037 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6038 pData, nSize, pcbNeeded);
6041 /*******************************************************************************
6042 * EnumPrinterDataExW [WINSPOOL.@]
6044 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6045 LPBYTE pEnumValues, DWORD cbEnumValues,
6046 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6048 HKEY hkPrinter, hkSubKey;
6049 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6050 cbValueNameLen, cbMaxValueLen, cbValueLen,
6055 PPRINTER_ENUM_VALUESW ppev;
6057 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6059 if (pKeyName == NULL || *pKeyName == 0)
6060 return ERROR_INVALID_PARAMETER;
6062 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6063 if (ret != ERROR_SUCCESS)
6065 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6070 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6071 if (ret != ERROR_SUCCESS)
6073 r = RegCloseKey (hkPrinter);
6074 if (r != ERROR_SUCCESS)
6075 WARN ("RegCloseKey returned %i\n", r);
6076 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6077 debugstr_w (pKeyName), ret);
6081 ret = RegCloseKey (hkPrinter);
6082 if (ret != ERROR_SUCCESS)
6084 ERR ("RegCloseKey returned %i\n", ret);
6085 r = RegCloseKey (hkSubKey);
6086 if (r != ERROR_SUCCESS)
6087 WARN ("RegCloseKey returned %i\n", r);
6091 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6092 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6093 if (ret != ERROR_SUCCESS)
6095 r = RegCloseKey (hkSubKey);
6096 if (r != ERROR_SUCCESS)
6097 WARN ("RegCloseKey returned %i\n", r);
6098 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6102 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6103 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6105 if (cValues == 0) /* empty key */
6107 r = RegCloseKey (hkSubKey);
6108 if (r != ERROR_SUCCESS)
6109 WARN ("RegCloseKey returned %i\n", r);
6110 *pcbEnumValues = *pnEnumValues = 0;
6111 return ERROR_SUCCESS;
6114 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6116 hHeap = GetProcessHeap ();
6119 ERR ("GetProcessHeap failed\n");
6120 r = RegCloseKey (hkSubKey);
6121 if (r != ERROR_SUCCESS)
6122 WARN ("RegCloseKey returned %i\n", r);
6123 return ERROR_OUTOFMEMORY;
6126 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6127 if (lpValueName == NULL)
6129 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6130 r = RegCloseKey (hkSubKey);
6131 if (r != ERROR_SUCCESS)
6132 WARN ("RegCloseKey returned %i\n", r);
6133 return ERROR_OUTOFMEMORY;
6136 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6137 if (lpValue == NULL)
6139 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6140 if (HeapFree (hHeap, 0, lpValueName) == 0)
6141 WARN ("HeapFree failed with code %i\n", GetLastError ());
6142 r = RegCloseKey (hkSubKey);
6143 if (r != ERROR_SUCCESS)
6144 WARN ("RegCloseKey returned %i\n", r);
6145 return ERROR_OUTOFMEMORY;
6148 TRACE ("pass 1: calculating buffer required for all names and values\n");
6150 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6152 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6154 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6156 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6157 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6158 NULL, NULL, lpValue, &cbValueLen);
6159 if (ret != ERROR_SUCCESS)
6161 if (HeapFree (hHeap, 0, lpValue) == 0)
6162 WARN ("HeapFree failed with code %i\n", GetLastError ());
6163 if (HeapFree (hHeap, 0, lpValueName) == 0)
6164 WARN ("HeapFree failed with code %i\n", GetLastError ());
6165 r = RegCloseKey (hkSubKey);
6166 if (r != ERROR_SUCCESS)
6167 WARN ("RegCloseKey returned %i\n", r);
6168 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6172 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6173 debugstr_w (lpValueName), dwIndex,
6174 cbValueNameLen + 1, cbValueLen);
6176 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6177 cbBufSize += cbValueLen;
6180 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6182 *pcbEnumValues = cbBufSize;
6183 *pnEnumValues = cValues;
6185 if (cbEnumValues < cbBufSize) /* buffer too small */
6187 if (HeapFree (hHeap, 0, lpValue) == 0)
6188 WARN ("HeapFree failed with code %i\n", GetLastError ());
6189 if (HeapFree (hHeap, 0, lpValueName) == 0)
6190 WARN ("HeapFree failed with code %i\n", GetLastError ());
6191 r = RegCloseKey (hkSubKey);
6192 if (r != ERROR_SUCCESS)
6193 WARN ("RegCloseKey returned %i\n", r);
6194 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6195 return ERROR_MORE_DATA;
6198 TRACE ("pass 2: copying all names and values to buffer\n");
6200 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6201 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6203 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6205 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6206 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6207 NULL, &dwType, lpValue, &cbValueLen);
6208 if (ret != ERROR_SUCCESS)
6210 if (HeapFree (hHeap, 0, lpValue) == 0)
6211 WARN ("HeapFree failed with code %i\n", GetLastError ());
6212 if (HeapFree (hHeap, 0, lpValueName) == 0)
6213 WARN ("HeapFree failed with code %i\n", GetLastError ());
6214 r = RegCloseKey (hkSubKey);
6215 if (r != ERROR_SUCCESS)
6216 WARN ("RegCloseKey returned %i\n", r);
6217 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6221 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6222 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6223 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6224 pEnumValues += cbValueNameLen;
6226 /* return # of *bytes* (including trailing \0), not # of chars */
6227 ppev[dwIndex].cbValueName = cbValueNameLen;
6229 ppev[dwIndex].dwType = dwType;
6231 memcpy (pEnumValues, lpValue, cbValueLen);
6232 ppev[dwIndex].pData = pEnumValues;
6233 pEnumValues += cbValueLen;
6235 ppev[dwIndex].cbData = cbValueLen;
6237 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6238 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6241 if (HeapFree (hHeap, 0, lpValue) == 0)
6243 ret = GetLastError ();
6244 ERR ("HeapFree failed with code %i\n", ret);
6245 if (HeapFree (hHeap, 0, lpValueName) == 0)
6246 WARN ("HeapFree failed with code %i\n", GetLastError ());
6247 r = RegCloseKey (hkSubKey);
6248 if (r != ERROR_SUCCESS)
6249 WARN ("RegCloseKey returned %i\n", r);
6253 if (HeapFree (hHeap, 0, lpValueName) == 0)
6255 ret = GetLastError ();
6256 ERR ("HeapFree failed with code %i\n", ret);
6257 r = RegCloseKey (hkSubKey);
6258 if (r != ERROR_SUCCESS)
6259 WARN ("RegCloseKey returned %i\n", r);
6263 ret = RegCloseKey (hkSubKey);
6264 if (ret != ERROR_SUCCESS)
6266 ERR ("RegCloseKey returned %i\n", ret);
6270 return ERROR_SUCCESS;
6273 /*******************************************************************************
6274 * EnumPrinterDataExA [WINSPOOL.@]
6276 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6277 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6278 * what Windows 2000 SP1 does.
6281 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6282 LPBYTE pEnumValues, DWORD cbEnumValues,
6283 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6287 DWORD ret, dwIndex, dwBufSize;
6291 TRACE ("%p %s\n", hPrinter, pKeyName);
6293 if (pKeyName == NULL || *pKeyName == 0)
6294 return ERROR_INVALID_PARAMETER;
6296 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6299 ret = GetLastError ();
6300 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6304 hHeap = GetProcessHeap ();
6307 ERR ("GetProcessHeap failed\n");
6308 return ERROR_OUTOFMEMORY;
6311 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6312 if (pKeyNameW == NULL)
6314 ERR ("Failed to allocate %i bytes from process heap\n",
6315 (LONG)(len * sizeof (WCHAR)));
6316 return ERROR_OUTOFMEMORY;
6319 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6321 ret = GetLastError ();
6322 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6323 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6324 WARN ("HeapFree failed with code %i\n", GetLastError ());
6328 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6329 pcbEnumValues, pnEnumValues);
6330 if (ret != ERROR_SUCCESS)
6332 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6333 WARN ("HeapFree failed with code %i\n", GetLastError ());
6334 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6338 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6340 ret = GetLastError ();
6341 ERR ("HeapFree failed with code %i\n", ret);
6345 if (*pnEnumValues == 0) /* empty key */
6346 return ERROR_SUCCESS;
6349 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6351 PPRINTER_ENUM_VALUESW ppev =
6352 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6354 if (dwBufSize < ppev->cbValueName)
6355 dwBufSize = ppev->cbValueName;
6357 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6358 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6359 dwBufSize = ppev->cbData;
6362 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6364 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6365 if (pBuffer == NULL)
6367 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6368 return ERROR_OUTOFMEMORY;
6371 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6373 PPRINTER_ENUM_VALUESW ppev =
6374 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6376 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6377 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6381 ret = GetLastError ();
6382 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6383 if (HeapFree (hHeap, 0, pBuffer) == 0)
6384 WARN ("HeapFree failed with code %i\n", GetLastError ());
6388 memcpy (ppev->pValueName, pBuffer, len);
6390 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6392 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6393 ppev->dwType != REG_MULTI_SZ)
6396 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6397 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6400 ret = GetLastError ();
6401 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6402 if (HeapFree (hHeap, 0, pBuffer) == 0)
6403 WARN ("HeapFree failed with code %i\n", GetLastError ());
6407 memcpy (ppev->pData, pBuffer, len);
6409 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6410 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6413 if (HeapFree (hHeap, 0, pBuffer) == 0)
6415 ret = GetLastError ();
6416 ERR ("HeapFree failed with code %i\n", ret);
6420 return ERROR_SUCCESS;
6423 /******************************************************************************
6424 * AbortPrinter (WINSPOOL.@)
6426 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6428 FIXME("(%p), stub!\n", hPrinter);
6432 /******************************************************************************
6433 * AddPortA (WINSPOOL.@)
6438 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6440 LPWSTR nameW = NULL;
6441 LPWSTR monitorW = NULL;
6445 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6448 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6449 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6450 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6454 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6455 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6456 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6458 res = AddPortW(nameW, hWnd, monitorW);
6459 HeapFree(GetProcessHeap(), 0, nameW);
6460 HeapFree(GetProcessHeap(), 0, monitorW);
6464 /******************************************************************************
6465 * AddPortW (WINSPOOL.@)
6467 * Add a Port for a specific Monitor
6470 * pName [I] Servername or NULL (local Computer)
6471 * hWnd [I] Handle to parent Window for the Dialog-Box
6472 * pMonitorName [I] Name of the Monitor that manage the Port
6479 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6485 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6487 if (pName && pName[0]) {
6488 SetLastError(ERROR_INVALID_PARAMETER);
6492 if (!pMonitorName) {
6493 SetLastError(RPC_X_NULL_REF_POINTER);
6497 /* an empty Monitorname is Invalid */
6498 if (!pMonitorName[0]) {
6499 SetLastError(ERROR_NOT_SUPPORTED);
6503 pm = monitor_load(pMonitorName, NULL);
6504 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6505 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6506 TRACE("got %d with %u\n", res, GetLastError());
6511 pui = monitor_loadui(pm);
6512 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6513 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6514 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6515 TRACE("got %d with %u\n", res, GetLastError());
6520 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6521 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6523 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6524 SetLastError(ERROR_NOT_SUPPORTED);
6527 monitor_unload(pui);
6530 TRACE("returning %d with %u\n", res, GetLastError());
6534 /******************************************************************************
6535 * AddPortExA (WINSPOOL.@)
6540 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6543 PORT_INFO_2A * pi2A;
6544 LPWSTR nameW = NULL;
6545 LPWSTR monitorW = NULL;
6549 pi2A = (PORT_INFO_2A *) pBuffer;
6551 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6552 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6554 if ((level < 1) || (level > 2)) {
6555 SetLastError(ERROR_INVALID_LEVEL);
6560 SetLastError(ERROR_INVALID_PARAMETER);
6565 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6566 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6567 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6571 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6572 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6573 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6576 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6578 if (pi2A->pPortName) {
6579 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6580 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6581 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6585 if (pi2A->pMonitorName) {
6586 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6587 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6588 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6591 if (pi2A->pDescription) {
6592 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6593 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6594 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6596 pi2W.fPortType = pi2A->fPortType;
6597 pi2W.Reserved = pi2A->Reserved;
6600 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6602 HeapFree(GetProcessHeap(), 0, nameW);
6603 HeapFree(GetProcessHeap(), 0, monitorW);
6604 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6605 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6606 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6611 /******************************************************************************
6612 * AddPortExW (WINSPOOL.@)
6614 * Add a Port for a specific Monitor, without presenting a user interface
6617 * pName [I] Servername or NULL (local Computer)
6618 * level [I] Structure-Level (1 or 2) for pBuffer
6619 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6620 * pMonitorName [I] Name of the Monitor that manage the Port
6627 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6633 pi2 = (PORT_INFO_2W *) pBuffer;
6635 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6636 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6637 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6638 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6641 if ((level < 1) || (level > 2)) {
6642 SetLastError(ERROR_INVALID_LEVEL);
6646 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6647 SetLastError(ERROR_INVALID_PARAMETER);
6651 /* load the Monitor */
6652 pm = monitor_load(pMonitorName, NULL);
6654 SetLastError(ERROR_INVALID_PARAMETER);
6658 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6659 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6660 TRACE("got %u with %u\n", res, GetLastError());
6664 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6670 /******************************************************************************
6671 * AddPrinterConnectionA (WINSPOOL.@)
6673 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6675 FIXME("%s\n", debugstr_a(pName));
6679 /******************************************************************************
6680 * AddPrinterConnectionW (WINSPOOL.@)
6682 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6684 FIXME("%s\n", debugstr_w(pName));
6688 /******************************************************************************
6689 * AddPrinterDriverExW (WINSPOOL.@)
6691 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6694 * pName [I] Servername or NULL (local Computer)
6695 * level [I] Level for the supplied DRIVER_INFO_*W struct
6696 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6697 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6704 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6706 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6708 if ((backend == NULL) && !load_backend()) return FALSE;
6710 if (level < 2 || level == 5 || level == 7 || level > 8) {
6711 SetLastError(ERROR_INVALID_LEVEL);
6716 SetLastError(ERROR_INVALID_PARAMETER);
6720 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6723 /******************************************************************************
6724 * AddPrinterDriverExA (WINSPOOL.@)
6726 * See AddPrinterDriverExW.
6729 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6731 DRIVER_INFO_8A *diA;
6733 LPWSTR nameW = NULL;
6738 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6740 diA = (DRIVER_INFO_8A *) pDriverInfo;
6741 ZeroMemory(&diW, sizeof(diW));
6743 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6744 SetLastError(ERROR_INVALID_LEVEL);
6749 SetLastError(ERROR_INVALID_PARAMETER);
6753 /* convert servername to unicode */
6755 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6756 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6757 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6761 diW.cVersion = diA->cVersion;
6764 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6765 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6766 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6769 if (diA->pEnvironment) {
6770 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6771 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6772 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6775 if (diA->pDriverPath) {
6776 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6777 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6778 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6781 if (diA->pDataFile) {
6782 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6783 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6784 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6787 if (diA->pConfigFile) {
6788 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6789 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6790 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6793 if ((Level > 2) && diA->pDependentFiles) {
6794 lenA = multi_sz_lenA(diA->pDependentFiles);
6795 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6796 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6797 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6800 if ((Level > 2) && diA->pMonitorName) {
6801 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6802 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6803 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6806 if ((Level > 3) && diA->pDefaultDataType) {
6807 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6808 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6809 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6812 if ((Level > 3) && diA->pszzPreviousNames) {
6813 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6814 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6815 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6816 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6819 if ((Level > 5) && diA->pszMfgName) {
6820 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6821 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6822 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6825 if ((Level > 5) && diA->pszOEMUrl) {
6826 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6827 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6828 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6831 if ((Level > 5) && diA->pszHardwareID) {
6832 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6833 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6834 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6837 if ((Level > 5) && diA->pszProvider) {
6838 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6839 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6840 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6844 FIXME("level %u is incomplete\n", Level);
6847 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6848 TRACE("got %u with %u\n", res, GetLastError());
6849 HeapFree(GetProcessHeap(), 0, nameW);
6850 HeapFree(GetProcessHeap(), 0, diW.pName);
6851 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6852 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6853 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6854 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6855 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6856 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6857 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6858 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6859 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6860 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6861 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6862 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6864 TRACE("=> %u with %u\n", res, GetLastError());
6868 /******************************************************************************
6869 * ConfigurePortA (WINSPOOL.@)
6871 * See ConfigurePortW.
6874 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6876 LPWSTR nameW = NULL;
6877 LPWSTR portW = NULL;
6881 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6883 /* convert servername to unicode */
6885 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6886 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6887 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6890 /* convert portname to unicode */
6892 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6893 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6894 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6897 res = ConfigurePortW(nameW, hWnd, portW);
6898 HeapFree(GetProcessHeap(), 0, nameW);
6899 HeapFree(GetProcessHeap(), 0, portW);
6903 /******************************************************************************
6904 * ConfigurePortW (WINSPOOL.@)
6906 * Display the Configuration-Dialog for a specific Port
6909 * pName [I] Servername or NULL (local Computer)
6910 * hWnd [I] Handle to parent Window for the Dialog-Box
6911 * pPortName [I] Name of the Port, that should be configured
6918 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6924 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6926 if (pName && pName[0]) {
6927 SetLastError(ERROR_INVALID_PARAMETER);
6932 SetLastError(RPC_X_NULL_REF_POINTER);
6936 /* an empty Portname is Invalid, but can popup a Dialog */
6937 if (!pPortName[0]) {
6938 SetLastError(ERROR_NOT_SUPPORTED);
6942 pm = monitor_load_by_port(pPortName);
6943 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6944 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6945 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6946 TRACE("got %d with %u\n", res, GetLastError());
6950 pui = monitor_loadui(pm);
6951 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6952 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6953 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6954 TRACE("got %d with %u\n", res, GetLastError());
6958 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6959 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6961 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6962 SetLastError(ERROR_NOT_SUPPORTED);
6965 monitor_unload(pui);
6969 TRACE("returning %d with %u\n", res, GetLastError());
6973 /******************************************************************************
6974 * ConnectToPrinterDlg (WINSPOOL.@)
6976 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6978 FIXME("%p %x\n", hWnd, Flags);
6982 /******************************************************************************
6983 * DeletePrinterConnectionA (WINSPOOL.@)
6985 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6987 FIXME("%s\n", debugstr_a(pName));
6991 /******************************************************************************
6992 * DeletePrinterConnectionW (WINSPOOL.@)
6994 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6996 FIXME("%s\n", debugstr_w(pName));
7000 /******************************************************************************
7001 * DeletePrinterDriverExW (WINSPOOL.@)
7003 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7004 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7009 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7010 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7012 if(pName && pName[0])
7014 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7015 SetLastError(ERROR_INVALID_PARAMETER);
7021 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7022 SetLastError(ERROR_INVALID_PARAMETER);
7026 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
7030 ERR("Can't open drivers key\n");
7034 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7037 RegCloseKey(hkey_drivers);
7042 /******************************************************************************
7043 * DeletePrinterDriverExA (WINSPOOL.@)
7045 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7046 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7048 UNICODE_STRING NameW, EnvW, DriverW;
7051 asciitounicode(&NameW, pName);
7052 asciitounicode(&EnvW, pEnvironment);
7053 asciitounicode(&DriverW, pDriverName);
7055 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7057 RtlFreeUnicodeString(&DriverW);
7058 RtlFreeUnicodeString(&EnvW);
7059 RtlFreeUnicodeString(&NameW);
7064 /******************************************************************************
7065 * DeletePrinterDataExW (WINSPOOL.@)
7067 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7070 FIXME("%p %s %s\n", hPrinter,
7071 debugstr_w(pKeyName), debugstr_w(pValueName));
7072 return ERROR_INVALID_PARAMETER;
7075 /******************************************************************************
7076 * DeletePrinterDataExA (WINSPOOL.@)
7078 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7081 FIXME("%p %s %s\n", hPrinter,
7082 debugstr_a(pKeyName), debugstr_a(pValueName));
7083 return ERROR_INVALID_PARAMETER;
7086 /******************************************************************************
7087 * DeletePrintProcessorA (WINSPOOL.@)
7089 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7091 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7092 debugstr_a(pPrintProcessorName));
7096 /******************************************************************************
7097 * DeletePrintProcessorW (WINSPOOL.@)
7099 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7101 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7102 debugstr_w(pPrintProcessorName));
7106 /******************************************************************************
7107 * DeletePrintProvidorA (WINSPOOL.@)
7109 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7111 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7112 debugstr_a(pPrintProviderName));
7116 /******************************************************************************
7117 * DeletePrintProvidorW (WINSPOOL.@)
7119 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7121 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7122 debugstr_w(pPrintProviderName));
7126 /******************************************************************************
7127 * EnumFormsA (WINSPOOL.@)
7129 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7130 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7132 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7133 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7137 /******************************************************************************
7138 * EnumFormsW (WINSPOOL.@)
7140 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7141 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7143 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7144 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7148 /*****************************************************************************
7149 * EnumMonitorsA [WINSPOOL.@]
7151 * See EnumMonitorsW.
7154 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7155 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7158 LPBYTE bufferW = NULL;
7159 LPWSTR nameW = NULL;
7161 DWORD numentries = 0;
7164 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7165 cbBuf, pcbNeeded, pcReturned);
7167 /* convert servername to unicode */
7169 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7170 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7171 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7173 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7174 needed = cbBuf * sizeof(WCHAR);
7175 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7176 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7178 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7179 if (pcbNeeded) needed = *pcbNeeded;
7180 /* HeapReAlloc return NULL, when bufferW was NULL */
7181 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7182 HeapAlloc(GetProcessHeap(), 0, needed);
7184 /* Try again with the large Buffer */
7185 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7187 numentries = pcReturned ? *pcReturned : 0;
7190 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7191 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7194 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7195 DWORD entrysize = 0;
7198 LPMONITOR_INFO_2W mi2w;
7199 LPMONITOR_INFO_2A mi2a;
7201 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7202 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7204 /* First pass: calculate the size for all Entries */
7205 mi2w = (LPMONITOR_INFO_2W) bufferW;
7206 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7208 while (index < numentries) {
7210 needed += entrysize; /* MONITOR_INFO_?A */
7211 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7213 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7214 NULL, 0, NULL, NULL);
7216 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7217 NULL, 0, NULL, NULL);
7218 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7219 NULL, 0, NULL, NULL);
7221 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7222 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7223 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7226 /* check for errors and quit on failure */
7227 if (cbBuf < needed) {
7228 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7232 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7233 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7234 cbBuf -= len ; /* free Bytes in the user-Buffer */
7235 mi2w = (LPMONITOR_INFO_2W) bufferW;
7236 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7238 /* Second Pass: Fill the User Buffer (if we have one) */
7239 while ((index < numentries) && pMonitors) {
7241 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7243 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7244 ptr, cbBuf , NULL, NULL);
7248 mi2a->pEnvironment = ptr;
7249 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7250 ptr, cbBuf, NULL, NULL);
7254 mi2a->pDLLName = ptr;
7255 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7256 ptr, cbBuf, NULL, NULL);
7260 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7261 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7262 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7266 if (pcbNeeded) *pcbNeeded = needed;
7267 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7269 HeapFree(GetProcessHeap(), 0, nameW);
7270 HeapFree(GetProcessHeap(), 0, bufferW);
7272 TRACE("returning %d with %d (%d byte for %d entries)\n",
7273 (res), GetLastError(), needed, numentries);
7279 /*****************************************************************************
7280 * EnumMonitorsW [WINSPOOL.@]
7282 * Enumerate available Port-Monitors
7285 * pName [I] Servername or NULL (local Computer)
7286 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7287 * pMonitors [O] PTR to Buffer that receives the Result
7288 * cbBuf [I] Size of Buffer at pMonitors
7289 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7290 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7294 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7297 * Windows reads the Registry once and cache the Results.
7299 *| Language-Monitors are also installed in the same Registry-Location but
7300 *| they are filtered in Windows (not returned by EnumMonitors).
7301 *| We do no filtering to simplify our Code.
7304 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7305 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7308 DWORD numentries = 0;
7311 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7312 cbBuf, pcbNeeded, pcReturned);
7314 if (pName && (lstrlenW(pName))) {
7315 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7316 SetLastError(ERROR_ACCESS_DENIED);
7320 /* Level is not checked in win9x */
7321 if (!Level || (Level > 2)) {
7322 WARN("level (%d) is ignored in win9x\n", Level);
7323 SetLastError(ERROR_INVALID_LEVEL);
7327 SetLastError(RPC_X_NULL_REF_POINTER);
7331 /* Scan all Monitor-Keys */
7333 needed = get_local_monitors(Level, NULL, 0, &numentries);
7335 /* we calculated the needed buffersize. now do the error-checks */
7336 if (cbBuf < needed) {
7337 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7340 else if (!pMonitors || !pcReturned) {
7341 SetLastError(RPC_X_NULL_REF_POINTER);
7345 /* fill the Buffer with the Monitor-Keys */
7346 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7350 if (pcbNeeded) *pcbNeeded = needed;
7351 if (pcReturned) *pcReturned = numentries;
7353 TRACE("returning %d with %d (%d byte for %d entries)\n",
7354 res, GetLastError(), needed, numentries);
7359 /******************************************************************************
7360 * SpoolerInit (WINSPOOL.@)
7362 * Initialize the Spooler
7369 * The function fails on windows, when the spooler service is not running
7372 BOOL WINAPI SpoolerInit(void)
7375 if ((backend == NULL) && !load_backend()) return FALSE;
7379 /******************************************************************************
7380 * XcvDataW (WINSPOOL.@)
7382 * Execute commands in the Printmonitor DLL
7385 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7386 * pszDataName [i] Name of the command to execute
7387 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7388 * cbInputData [i] Size in Bytes of Buffer at pInputData
7389 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7390 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7391 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7392 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7399 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7400 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7402 * Minimal List of commands, that a Printmonitor DLL should support:
7404 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7405 *| "AddPort" : Add a Port
7406 *| "DeletePort": Delete a Port
7408 * Many Printmonitors support additional commands. Examples for localspl.dll:
7409 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7410 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7413 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7414 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7415 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7417 opened_printer_t *printer;
7419 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7420 pInputData, cbInputData, pOutputData,
7421 cbOutputData, pcbOutputNeeded, pdwStatus);
7423 printer = get_opened_printer(hXcv);
7424 if (!printer || (!printer->hXcv)) {
7425 SetLastError(ERROR_INVALID_HANDLE);
7429 if (!pcbOutputNeeded) {
7430 SetLastError(ERROR_INVALID_PARAMETER);
7434 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7435 SetLastError(RPC_X_NULL_REF_POINTER);
7439 *pcbOutputNeeded = 0;
7441 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7442 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7447 /*****************************************************************************
7448 * EnumPrinterDataA [WINSPOOL.@]
7451 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7452 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7453 DWORD cbData, LPDWORD pcbData )
7455 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7456 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7457 return ERROR_NO_MORE_ITEMS;
7460 /*****************************************************************************
7461 * EnumPrinterDataW [WINSPOOL.@]
7464 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7465 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7466 DWORD cbData, LPDWORD pcbData )
7468 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7469 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7470 return ERROR_NO_MORE_ITEMS;
7473 /*****************************************************************************
7474 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7477 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7478 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7479 LPDWORD pcbNeeded, LPDWORD pcReturned)
7481 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7482 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7483 pcbNeeded, pcReturned);
7487 /*****************************************************************************
7488 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7491 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7492 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7493 LPDWORD pcbNeeded, LPDWORD pcReturned)
7495 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7496 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7497 pcbNeeded, pcReturned);
7501 /*****************************************************************************
7502 * EnumPrintProcessorsA [WINSPOOL.@]
7505 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7506 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7508 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7509 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7513 /*****************************************************************************
7514 * EnumPrintProcessorsW [WINSPOOL.@]
7517 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7518 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7520 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7521 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7522 cbBuf, pcbNeeded, pcbReturned);
7526 /*****************************************************************************
7527 * ExtDeviceMode [WINSPOOL.@]
7530 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7531 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7534 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7535 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7536 debugstr_a(pProfile), fMode);
7540 /*****************************************************************************
7541 * FindClosePrinterChangeNotification [WINSPOOL.@]
7544 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7546 FIXME("Stub: %p\n", hChange);
7550 /*****************************************************************************
7551 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7554 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7555 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7557 FIXME("Stub: %p %x %x %p\n",
7558 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7559 return INVALID_HANDLE_VALUE;
7562 /*****************************************************************************
7563 * FindNextPrinterChangeNotification [WINSPOOL.@]
7566 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7567 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7569 FIXME("Stub: %p %p %p %p\n",
7570 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7574 /*****************************************************************************
7575 * FreePrinterNotifyInfo [WINSPOOL.@]
7578 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7580 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7584 /*****************************************************************************
7587 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7588 * ansi depending on the unicode parameter.
7590 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7600 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7603 memcpy(ptr, str, *size);
7610 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7613 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7620 /*****************************************************************************
7623 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7624 LPDWORD pcbNeeded, BOOL unicode)
7626 DWORD size, left = cbBuf;
7627 BOOL space = (cbBuf > 0);
7634 ji1->JobId = job->job_id;
7637 string_to_buf(job->document_title, ptr, left, &size, unicode);
7638 if(space && size <= left)
7640 ji1->pDocument = (LPWSTR)ptr;
7651 /*****************************************************************************
7654 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7655 LPDWORD pcbNeeded, BOOL unicode)
7657 DWORD size, left = cbBuf;
7658 BOOL space = (cbBuf > 0);
7665 ji2->JobId = job->job_id;
7668 string_to_buf(job->document_title, ptr, left, &size, unicode);
7669 if(space && size <= left)
7671 ji2->pDocument = (LPWSTR)ptr;
7682 /*****************************************************************************
7685 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7686 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7689 DWORD needed = 0, size;
7693 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7695 EnterCriticalSection(&printer_handles_cs);
7696 job = get_job(hPrinter, JobId);
7703 size = sizeof(JOB_INFO_1W);
7708 memset(pJob, 0, size);
7712 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7717 size = sizeof(JOB_INFO_2W);
7722 memset(pJob, 0, size);
7726 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7731 size = sizeof(JOB_INFO_3);
7735 memset(pJob, 0, size);
7744 SetLastError(ERROR_INVALID_LEVEL);
7748 *pcbNeeded = needed;
7750 LeaveCriticalSection(&printer_handles_cs);
7754 /*****************************************************************************
7755 * GetJobA [WINSPOOL.@]
7758 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7759 DWORD cbBuf, LPDWORD pcbNeeded)
7761 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7764 /*****************************************************************************
7765 * GetJobW [WINSPOOL.@]
7768 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7769 DWORD cbBuf, LPDWORD pcbNeeded)
7771 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7774 /*****************************************************************************
7777 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7779 char *unixname, *queue, *cmd;
7780 char fmt[] = "lpr -P%s %s";
7783 if(!(unixname = wine_get_unix_file_name(filename)))
7786 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7787 queue = HeapAlloc(GetProcessHeap(), 0, len);
7788 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7790 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7791 sprintf(cmd, fmt, queue, unixname);
7793 TRACE("printing with: %s\n", cmd);
7796 HeapFree(GetProcessHeap(), 0, cmd);
7797 HeapFree(GetProcessHeap(), 0, queue);
7798 HeapFree(GetProcessHeap(), 0, unixname);
7802 /*****************************************************************************
7805 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7807 #ifdef SONAME_LIBCUPS
7810 char *unixname, *queue, *doc_titleA;
7814 if(!(unixname = wine_get_unix_file_name(filename)))
7817 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7818 queue = HeapAlloc(GetProcessHeap(), 0, len);
7819 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7821 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7822 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7823 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7825 TRACE("printing via cups\n");
7826 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7827 HeapFree(GetProcessHeap(), 0, doc_titleA);
7828 HeapFree(GetProcessHeap(), 0, queue);
7829 HeapFree(GetProcessHeap(), 0, unixname);
7835 return schedule_lpr(printer_name, filename);
7839 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7846 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7850 if(HIWORD(wparam) == BN_CLICKED)
7852 if(LOWORD(wparam) == IDOK)
7855 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7858 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7859 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7861 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7863 WCHAR caption[200], message[200];
7866 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7867 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7868 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7869 if(mb_ret == IDCANCEL)
7871 HeapFree(GetProcessHeap(), 0, filename);
7875 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7876 if(hf == INVALID_HANDLE_VALUE)
7878 WCHAR caption[200], message[200];
7880 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7881 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7882 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7883 HeapFree(GetProcessHeap(), 0, filename);
7887 DeleteFileW(filename);
7888 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7890 EndDialog(hwnd, IDOK);
7893 if(LOWORD(wparam) == IDCANCEL)
7895 EndDialog(hwnd, IDCANCEL);
7904 /*****************************************************************************
7907 static BOOL get_filename(LPWSTR *filename)
7909 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7910 file_dlg_proc, (LPARAM)filename) == IDOK;
7913 /*****************************************************************************
7916 static BOOL schedule_file(LPCWSTR filename)
7918 LPWSTR output = NULL;
7920 if(get_filename(&output))
7922 TRACE("copy to %s\n", debugstr_w(output));
7923 CopyFileW(filename, output, FALSE);
7924 HeapFree(GetProcessHeap(), 0, output);
7930 /*****************************************************************************
7933 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7936 char *unixname, *cmdA;
7938 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7942 if(!(unixname = wine_get_unix_file_name(filename)))
7945 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7946 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7947 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7949 TRACE("printing with: %s\n", cmdA);
7951 if((file_fd = open(unixname, O_RDONLY)) == -1)
7956 ERR("pipe() failed!\n");
7966 /* reset signals that we previously set to SIG_IGN */
7967 signal(SIGPIPE, SIG_DFL);
7968 signal(SIGCHLD, SIG_DFL);
7970 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7974 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7975 write(fds[1], buf, no_read);
7980 if(file_fd != -1) close(file_fd);
7981 if(fds[0] != -1) close(fds[0]);
7982 if(fds[1] != -1) close(fds[1]);
7984 HeapFree(GetProcessHeap(), 0, cmdA);
7985 HeapFree(GetProcessHeap(), 0, unixname);
7992 /*****************************************************************************
7995 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7997 int in_fd, out_fd, no_read;
8000 char *unixname, *outputA;
8003 if(!(unixname = wine_get_unix_file_name(filename)))
8006 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
8007 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8008 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
8010 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8011 in_fd = open(unixname, O_RDONLY);
8012 if(out_fd == -1 || in_fd == -1)
8015 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8016 write(out_fd, buf, no_read);
8020 if(in_fd != -1) close(in_fd);
8021 if(out_fd != -1) close(out_fd);
8022 HeapFree(GetProcessHeap(), 0, outputA);
8023 HeapFree(GetProcessHeap(), 0, unixname);
8027 /*****************************************************************************
8028 * ScheduleJob [WINSPOOL.@]
8031 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8033 opened_printer_t *printer;
8035 struct list *cursor, *cursor2;
8037 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8038 EnterCriticalSection(&printer_handles_cs);
8039 printer = get_opened_printer(hPrinter);
8043 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8045 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8048 if(job->job_id != dwJobID) continue;
8050 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8051 if(hf != INVALID_HANDLE_VALUE)
8053 PRINTER_INFO_5W *pi5;
8057 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8058 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8060 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8061 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8062 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8063 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8064 debugstr_w(pi5->pPortName));
8068 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8069 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8071 DWORD type, count = sizeof(output);
8072 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
8075 if(output[0] == '|')
8077 schedule_pipe(output + 1, job->filename);
8081 schedule_unixfile(output, job->filename);
8083 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
8085 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
8087 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
8089 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
8091 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
8093 schedule_file(job->filename);
8097 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
8099 HeapFree(GetProcessHeap(), 0, pi5);
8101 DeleteFileW(job->filename);
8103 list_remove(cursor);
8104 HeapFree(GetProcessHeap(), 0, job->document_title);
8105 HeapFree(GetProcessHeap(), 0, job->filename);
8106 HeapFree(GetProcessHeap(), 0, job);
8111 LeaveCriticalSection(&printer_handles_cs);
8115 /*****************************************************************************
8116 * StartDocDlgA [WINSPOOL.@]
8118 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8120 UNICODE_STRING usBuffer;
8123 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8126 docW.cbSize = sizeof(docW);
8127 if (doc->lpszDocName)
8129 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8130 if (!(docW.lpszDocName = docnameW)) return NULL;
8132 if (doc->lpszOutput)
8134 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8135 if (!(docW.lpszOutput = outputW)) return NULL;
8137 if (doc->lpszDatatype)
8139 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8140 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8142 docW.fwType = doc->fwType;
8144 retW = StartDocDlgW(hPrinter, &docW);
8148 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8149 ret = HeapAlloc(GetProcessHeap(), 0, len);
8150 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8151 HeapFree(GetProcessHeap(), 0, retW);
8154 HeapFree(GetProcessHeap(), 0, datatypeW);
8155 HeapFree(GetProcessHeap(), 0, outputW);
8156 HeapFree(GetProcessHeap(), 0, docnameW);
8161 /*****************************************************************************
8162 * StartDocDlgW [WINSPOOL.@]
8164 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8165 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8166 * port is "FILE:". Also returns the full path if passed a relative path.
8168 * The caller should free the returned string from the process heap.
8170 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8175 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8177 PRINTER_INFO_5W *pi5;
8178 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8179 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8181 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8182 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8183 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8185 HeapFree(GetProcessHeap(), 0, pi5);
8188 HeapFree(GetProcessHeap(), 0, pi5);
8191 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8195 if (get_filename(&name))
8197 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8199 HeapFree(GetProcessHeap(), 0, name);
8202 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8203 GetFullPathNameW(name, len, ret, NULL);
8204 HeapFree(GetProcessHeap(), 0, name);
8209 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8212 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8213 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8215 attr = GetFileAttributesW(ret);
8216 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8218 HeapFree(GetProcessHeap(), 0, ret);