4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006, 2007 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
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 /* ############################### */
89 WCHAR src[MAX_PATH+MAX_PATH];
90 WCHAR dst[MAX_PATH+MAX_PATH];
100 PMONITORUI monitorUI;
130 WCHAR *document_title;
138 LPCWSTR versionregpath;
139 LPCWSTR versionsubdir;
142 /* ############################### */
144 static struct list monitor_handles = LIST_INIT( monitor_handles );
145 static monitor_t * pm_localport;
147 static opened_printer_t **printer_handles;
148 static UINT nb_printer_handles;
149 static LONG next_job_id = 1;
151 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
152 WORD fwCapability, LPSTR lpszOutput,
154 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
155 LPSTR lpszDevice, LPSTR lpszPort,
156 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
159 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
160 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
161 'c','o','n','t','r','o','l','\\',
162 'P','r','i','n','t','\\',
163 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
164 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
166 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
167 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
168 'C','o','n','t','r','o','l','\\',
169 'P','r','i','n','t','\\',
170 'M','o','n','i','t','o','r','s','\\',0};
172 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
173 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
174 'C','o','n','t','r','o','l','\\',
175 'P','r','i','n','t','\\',
176 'P','r','i','n','t','e','r','s',0};
178 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
180 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
181 'M','i','c','r','o','s','o','f','t','\\',
182 'W','i','n','d','o','w','s',' ','N','T','\\',
183 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
184 'W','i','n','d','o','w','s',0};
186 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
187 'M','i','c','r','o','s','o','f','t','\\',
188 'W','i','n','d','o','w','s',' ','N','T','\\',
189 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
190 'D','e','v','i','c','e','s',0};
192 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
193 'M','i','c','r','o','s','o','f','t','\\',
194 'W','i','n','d','o','w','s',' ','N','T','\\',
195 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
196 'P','o','r','t','s',0};
198 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
199 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
200 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
201 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
202 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
203 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
204 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
205 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
206 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
208 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
209 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
211 static const WCHAR backslashW[] = {'\\',0};
212 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
213 'i','o','n',' ','F','i','l','e',0};
214 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
215 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
216 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
217 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
218 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
219 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
220 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
221 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
222 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
223 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
224 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
225 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
226 static const WCHAR NameW[] = {'N','a','m','e',0};
227 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
228 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
229 static const WCHAR PortW[] = {'P','o','r','t',0};
230 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
231 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
232 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
233 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
234 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
235 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW[] = {0};
244 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
245 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
247 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
249 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
250 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
251 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
253 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
254 'D','o','c','u','m','e','n','t',0};
256 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
257 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
258 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
259 0, sizeof(DRIVER_INFO_8W)};
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 * apd_copyfile [internal]
358 * Copy a file from the driverdirectory to the versioned directory
365 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
371 apd->src[apd->srclen] = '\0';
372 apd->dst[apd->dstlen] = '\0';
374 if (!filename || !filename[0]) {
375 /* nothing to copy */
379 ptr = strrchrW(filename, '\\');
388 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
389 /* we have an absolute Path */
395 lstrcatW(srcname, ptr);
397 lstrcatW(apd->dst, ptr);
399 TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
401 /* FIXME: handle APD_COPY_NEW_FILES */
402 res = CopyFileW(srcname, apd->dst, FALSE);
403 TRACE("got %u with %u\n", res, GetLastError());
405 /* FIXME: install of wineps.drv must be fixed, before we return the real result
412 /******************************************************************
413 * Return the number of bytes for an multi_sz string.
414 * The result includes all \0s
415 * (specifically the extra \0, that is needed as multi_sz terminator).
417 static int multi_sz_lenW(const WCHAR *str)
419 const WCHAR *ptr = str;
423 ptr += lstrlenW(ptr) + 1;
426 return (ptr - str + 1) * sizeof(WCHAR);
429 /* ################################ */
431 static int multi_sz_lenA(const char *str)
433 const char *ptr = str;
437 ptr += lstrlenA(ptr) + 1;
440 return ptr - str + 1;
444 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
447 /* If forcing, or no profile string entry for device yet, set the entry
449 * The always change entry if not WINEPS yet is discussable.
452 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
454 !strstr(qbuf,"WINEPS.DRV")
456 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
459 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
460 WriteProfileStringA("windows","device",buf);
461 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
462 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
465 HeapFree(GetProcessHeap(),0,buf);
469 static BOOL add_printer_driver(const char *name)
473 static char driver_9x[] = "wineps16.drv",
474 driver_nt[] = "wineps.drv",
475 env_9x[] = "Windows 4.0",
476 env_nt[] = "Windows NT x86",
477 data_file[] = "generic.ppd",
478 default_data_type[] = "RAW";
480 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
482 di3a.pName = (char *)name;
483 di3a.pEnvironment = env_nt;
484 di3a.pDriverPath = driver_nt;
485 di3a.pDataFile = data_file;
486 di3a.pConfigFile = driver_nt;
487 di3a.pDefaultDataType = default_data_type;
489 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
490 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
493 di3a.pEnvironment = env_9x;
494 di3a.pDriverPath = driver_9x;
495 di3a.pConfigFile = driver_9x;
496 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
497 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
502 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
503 debugstr_a(di3a.pEnvironment), GetLastError());
507 #ifdef SONAME_LIBCUPS
508 static typeof(cupsGetDests) *pcupsGetDests;
509 static typeof(cupsGetPPD) *pcupsGetPPD;
510 static typeof(cupsPrintFile) *pcupsPrintFile;
511 static void *cupshandle;
513 static BOOL CUPS_LoadPrinters(void)
516 BOOL hadprinter = FALSE, haddefault = FALSE;
518 PRINTER_INFO_2A pinfo2a;
520 HKEY hkeyPrinter, hkeyPrinters, hkey;
523 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
525 TRACE("%s\n", loaderror);
528 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
531 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
532 if (!p##x) return FALSE;
535 DYNCUPS(cupsGetDests);
536 DYNCUPS(cupsPrintFile);
539 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
541 ERR("Can't create Printers key\n");
545 nrofdests = pcupsGetDests(&dests);
546 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
547 for (i=0;i<nrofdests;i++) {
548 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
549 sprintf(port,"LPR:%s",dests[i].name);
550 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
551 sprintf(devline,"WINEPS.DRV,%s",port);
552 WriteProfileStringA("devices",dests[i].name,devline);
553 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
554 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
557 HeapFree(GetProcessHeap(),0,devline);
559 TRACE("Printer %d: %s\n", i, dests[i].name);
560 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
561 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
563 TRACE("Printer already exists\n");
564 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
565 RegCloseKey(hkeyPrinter);
567 static CHAR data_type[] = "RAW",
568 print_proc[] = "WinPrint",
569 comment[] = "WINEPS Printer using CUPS",
570 location[] = "<physical location of printer>",
571 params[] = "<parameters?>",
572 share_name[] = "<share name?>",
573 sep_file[] = "<sep file?>";
575 add_printer_driver(dests[i].name);
577 memset(&pinfo2a,0,sizeof(pinfo2a));
578 pinfo2a.pPrinterName = dests[i].name;
579 pinfo2a.pDatatype = data_type;
580 pinfo2a.pPrintProcessor = print_proc;
581 pinfo2a.pDriverName = dests[i].name;
582 pinfo2a.pComment = comment;
583 pinfo2a.pLocation = location;
584 pinfo2a.pPortName = port;
585 pinfo2a.pParameters = params;
586 pinfo2a.pShareName = share_name;
587 pinfo2a.pSepFile = sep_file;
589 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
590 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
591 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
594 HeapFree(GetProcessHeap(),0,port);
597 if (dests[i].is_default) {
598 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
602 if (hadprinter & !haddefault)
603 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
604 RegCloseKey(hkeyPrinters);
610 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
611 PRINTER_INFO_2A pinfo2a;
612 char *e,*s,*name,*prettyname,*devname;
613 BOOL ret = FALSE, set_default = FALSE;
614 char *port = NULL, *devline,*env_default;
615 HKEY hkeyPrinter, hkeyPrinters, hkey;
617 while (isspace(*pent)) pent++;
618 s = strchr(pent,':');
620 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
628 TRACE("name=%s entry=%s\n",name, pent);
630 if(ispunct(*name)) { /* a tc entry, not a real printer */
631 TRACE("skipping tc entry\n");
635 if(strstr(pent,":server")) { /* server only version so skip */
636 TRACE("skipping server entry\n");
640 /* Determine whether this is a postscript printer. */
643 env_default = getenv("PRINTER");
645 /* Get longest name, usually the one at the right for later display. */
646 while((s=strchr(prettyname,'|'))) {
649 while(isspace(*--e)) *e = '\0';
650 TRACE("\t%s\n", debugstr_a(prettyname));
651 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
652 for(prettyname = s+1; isspace(*prettyname); prettyname++)
655 e = prettyname + strlen(prettyname);
656 while(isspace(*--e)) *e = '\0';
657 TRACE("\t%s\n", debugstr_a(prettyname));
658 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
660 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
661 * if it is too long, we use it as comment below. */
662 devname = prettyname;
663 if (strlen(devname)>=CCHDEVICENAME-1)
665 if (strlen(devname)>=CCHDEVICENAME-1) {
670 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
671 sprintf(port,"LPR:%s",name);
673 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
674 sprintf(devline,"WINEPS.DRV,%s",port);
675 WriteProfileStringA("devices",devname,devline);
676 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
677 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
680 HeapFree(GetProcessHeap(),0,devline);
682 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
684 ERR("Can't create Printers key\n");
688 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
689 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
691 TRACE("Printer already exists\n");
692 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
693 RegCloseKey(hkeyPrinter);
695 static CHAR data_type[] = "RAW",
696 print_proc[] = "WinPrint",
697 comment[] = "WINEPS Printer using LPR",
698 params[] = "<parameters?>",
699 share_name[] = "<share name?>",
700 sep_file[] = "<sep file?>";
702 add_printer_driver(devname);
704 memset(&pinfo2a,0,sizeof(pinfo2a));
705 pinfo2a.pPrinterName = devname;
706 pinfo2a.pDatatype = data_type;
707 pinfo2a.pPrintProcessor = print_proc;
708 pinfo2a.pDriverName = devname;
709 pinfo2a.pComment = comment;
710 pinfo2a.pLocation = prettyname;
711 pinfo2a.pPortName = port;
712 pinfo2a.pParameters = params;
713 pinfo2a.pShareName = share_name;
714 pinfo2a.pSepFile = sep_file;
716 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
717 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
718 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
721 RegCloseKey(hkeyPrinters);
723 if (isfirst || set_default)
724 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
727 HeapFree(GetProcessHeap(), 0, port);
728 HeapFree(GetProcessHeap(), 0, name);
733 PRINTCAP_LoadPrinters(void) {
734 BOOL hadprinter = FALSE;
738 BOOL had_bash = FALSE;
740 f = fopen("/etc/printcap","r");
744 while(fgets(buf,sizeof(buf),f)) {
747 end=strchr(buf,'\n');
751 while(isspace(*start)) start++;
752 if(*start == '#' || *start == '\0')
755 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
756 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
757 HeapFree(GetProcessHeap(),0,pent);
761 if (end && *--end == '\\') {
768 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
771 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
777 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
778 HeapFree(GetProcessHeap(),0,pent);
784 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
787 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
788 (lstrlenW(value) + 1) * sizeof(WCHAR));
790 return ERROR_FILE_NOT_FOUND;
793 /*****************************************************************************
794 * enumerate the local monitors (INTERNAL)
796 * returns the needed size (in bytes) for pMonitors
797 * and *lpreturned is set to number of entries returned in pMonitors
800 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
805 LPMONITOR_INFO_2W mi;
806 WCHAR buffer[MAX_PATH];
807 WCHAR dllname[MAX_PATH];
815 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
817 numentries = *lpreturned; /* this is 0, when we scan the registry */
818 len = entrysize * numentries;
819 ptr = (LPWSTR) &pMonitors[len];
822 len = sizeof(buffer);
825 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
826 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
827 /* Scan all Monitor-Registry-Keys */
828 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
829 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
830 dllsize = sizeof(dllname);
833 /* The Monitor must have a Driver-DLL */
834 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
835 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
836 /* We found a valid DLL for this Monitor. */
837 TRACE("using Driver: %s\n", debugstr_w(dllname));
842 /* Windows returns only Port-Monitors here, but to simplify our code,
843 we do no filtering for Language-Monitors */
847 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
849 /* we install and return only monitors for "Windows NT x86" */
850 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
854 /* required size is calculated. Now fill the user-buffer */
855 if (pMonitors && (cbBuf >= needed)){
856 mi = (LPMONITOR_INFO_2W) pMonitors;
857 pMonitors += entrysize;
859 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
861 lstrcpyW(ptr, buffer); /* Name of the Monitor */
862 ptr += (len+1); /* len is lstrlenW(monitorname) */
864 mi->pEnvironment = ptr;
865 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
866 ptr += (lstrlenW(envname_x86W)+1);
869 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
870 ptr += (dllsize / sizeof(WCHAR));
875 len = sizeof(buffer);
880 *lpreturned = numentries;
881 TRACE("need %d byte for %d entries\n", needed, numentries);
885 /******************************************************************
886 * monitor_unload [internal]
888 * release a printmonitor and unload it from memory, when needed
891 static void monitor_unload(monitor_t * pm)
893 if (pm == NULL) return;
894 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
896 EnterCriticalSection(&monitor_handles_cs);
898 if (pm->refcount) pm->refcount--;
900 if (pm->refcount == 0) {
901 list_remove(&pm->entry);
902 FreeLibrary(pm->hdll);
903 HeapFree(GetProcessHeap(), 0, pm->name);
904 HeapFree(GetProcessHeap(), 0, pm->dllname);
905 HeapFree(GetProcessHeap(), 0, pm);
907 LeaveCriticalSection(&monitor_handles_cs);
910 /******************************************************************
911 * monitor_unloadall [internal]
913 * release all printmonitors and unload them from memory, when needed
916 static void monitor_unloadall(void)
921 EnterCriticalSection(&monitor_handles_cs);
922 /* iterate through the list, with safety against removal */
923 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
927 LeaveCriticalSection(&monitor_handles_cs);
930 /******************************************************************
931 * monitor_load [internal]
933 * load a printmonitor, get the dllname from the registry, when needed
934 * initialize the monitor and dump found function-pointers
936 * On failure, SetLastError() is called and NULL is returned
939 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
941 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
942 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
943 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
944 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
945 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
947 monitor_t * pm = NULL;
949 LPWSTR regroot = NULL;
950 LPWSTR driver = dllname;
952 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
953 /* Is the Monitor already loaded? */
954 EnterCriticalSection(&monitor_handles_cs);
957 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
959 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
967 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
968 if (pm == NULL) goto cleanup;
969 list_add_tail(&monitor_handles, &pm->entry);
973 if (pm->name == NULL) {
974 /* Load the monitor */
975 LPMONITOREX pmonitorEx;
979 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
980 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
984 lstrcpyW(regroot, MonitorsW);
985 lstrcatW(regroot, name);
986 /* Get the Driver from the Registry */
987 if (driver == NULL) {
990 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
991 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
992 &namesize) == ERROR_SUCCESS) {
993 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
994 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
1001 pm->name = strdupW(name);
1002 pm->dllname = strdupW(driver);
1004 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
1006 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1011 pm->hdll = LoadLibraryW(driver);
1012 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
1014 if (pm->hdll == NULL) {
1016 SetLastError(ERROR_MOD_NOT_FOUND);
1021 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
1022 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1023 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1024 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1025 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1028 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1029 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1030 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1031 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1032 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1034 if (pInitializePrintMonitorUI != NULL) {
1035 pm->monitorUI = pInitializePrintMonitorUI();
1036 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1037 if (pm->monitorUI) {
1038 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1039 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1044 if (pInitializePrintMonitor && regroot) {
1045 pmonitorEx = pInitializePrintMonitor(regroot);
1046 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1047 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1050 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1051 pm->monitor = &(pmonitorEx->Monitor);
1056 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1060 if (!pm->monitor && regroot) {
1061 if (pInitializePrintMonitor2 != NULL) {
1062 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1064 if (pInitializeMonitorEx != NULL) {
1065 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1067 if (pInitializeMonitor != NULL) {
1068 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1071 if (!pm->monitor && !pm->monitorUI) {
1073 SetLastError(ERROR_PROC_NOT_FOUND);
1078 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1082 LeaveCriticalSection(&monitor_handles_cs);
1083 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1084 HeapFree(GetProcessHeap(), 0, regroot);
1085 TRACE("=> %p\n", pm);
1089 /******************************************************************
1090 * monitor_loadall [internal]
1092 * Load all registered monitors
1095 static DWORD monitor_loadall(void)
1098 DWORD registered = 0;
1101 WCHAR buffer[MAX_PATH];
1104 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1105 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1106 NULL, NULL, NULL, NULL, NULL);
1108 TRACE("%d monitors registered\n", registered);
1110 EnterCriticalSection(&monitor_handles_cs);
1111 while (id < registered) {
1113 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1114 pm = monitor_load(buffer, NULL);
1118 LeaveCriticalSection(&monitor_handles_cs);
1119 RegCloseKey(hmonitors);
1121 TRACE("%d monitors loaded\n", loaded);
1125 /******************************************************************
1126 * monitor_loadui [internal]
1128 * load the userinterface-dll for a given portmonitor
1130 * On failure, NULL is returned
1133 static monitor_t * monitor_loadui(monitor_t * pm)
1135 monitor_t * pui = NULL;
1136 LPWSTR buffer[MAX_PATH];
1141 if (pm == NULL) return NULL;
1142 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1144 /* Try the Portmonitor first; works for many monitors */
1145 if (pm->monitorUI) {
1146 EnterCriticalSection(&monitor_handles_cs);
1148 LeaveCriticalSection(&monitor_handles_cs);
1152 /* query the userinterface-dllname from the Portmonitor */
1153 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1154 /* building (",XcvMonitor %s",pm->name) not needed yet */
1155 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1156 TRACE("got %u with %p\n", res, hXcv);
1158 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1159 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1160 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1161 pm->monitor->pfnXcvClosePort(hXcv);
1168 /******************************************************************
1169 * monitor_load_by_port [internal]
1171 * load a printmonitor for a given port
1173 * On failure, NULL is returned
1176 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1181 monitor_t * pm = NULL;
1182 DWORD registered = 0;
1186 TRACE("(%s)\n", debugstr_w(portname));
1188 /* Try the Local Monitor first */
1189 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1190 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1191 /* found the portname */
1193 return monitor_load(LocalPortW, NULL);
1198 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1199 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1200 if (buffer == NULL) return NULL;
1202 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1203 EnterCriticalSection(&monitor_handles_cs);
1204 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1206 while ((pm == NULL) && (id < registered)) {
1208 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1209 TRACE("testing %s\n", debugstr_w(buffer));
1210 len = lstrlenW(buffer);
1211 lstrcatW(buffer, bs_Ports_bsW);
1212 lstrcatW(buffer, portname);
1213 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1215 buffer[len] = '\0'; /* use only the Monitor-Name */
1216 pm = monitor_load(buffer, NULL);
1220 LeaveCriticalSection(&monitor_handles_cs);
1223 HeapFree(GetProcessHeap(), 0, buffer);
1227 /******************************************************************
1228 * enumerate the local Ports from all loaded monitors (internal)
1230 * returns the needed size (in bytes) for pPorts
1231 * and *lpreturned is set to number of entries returned in pPorts
1234 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1238 LPPORT_INFO_2W cache;
1240 LPBYTE pi_buffer = NULL;
1241 DWORD pi_allocated = 0;
1252 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1253 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1255 numentries = *lpreturned; /* this is 0, when we scan the registry */
1256 needed = entrysize * numentries;
1257 ptr = (LPWSTR) &pPorts[needed];
1262 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1264 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1267 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1268 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1269 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1270 HeapFree(GetProcessHeap(), 0, pi_buffer);
1271 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1272 pi_allocated = (pi_buffer) ? pi_needed : 0;
1273 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1275 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1276 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1278 numentries += pi_returned;
1279 needed += pi_needed;
1281 /* fill the output-buffer (pPorts), if we have one */
1282 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1284 while (pi_returned > pi_index) {
1285 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1286 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1287 out->pPortName = ptr;
1288 lstrcpyW(ptr, cache->pPortName);
1289 ptr += (lstrlenW(ptr)+1);
1291 out->pMonitorName = ptr;
1292 lstrcpyW(ptr, cache->pMonitorName);
1293 ptr += (lstrlenW(ptr)+1);
1295 out->pDescription = ptr;
1296 lstrcpyW(ptr, cache->pDescription);
1297 ptr += (lstrlenW(ptr)+1);
1298 out->fPortType = cache->fPortType;
1299 out->Reserved = cache->Reserved;
1307 /* the temporary portinfo-buffer is no longer needed */
1308 HeapFree(GetProcessHeap(), 0, pi_buffer);
1310 *lpreturned = numentries;
1311 TRACE("need %d byte for %d entries\n", needed, numentries);
1315 /******************************************************************
1316 * get_servername_from_name (internal)
1318 * for an external server, a copy of the serverpart from the full name is returned
1321 static LPWSTR get_servername_from_name(LPCWSTR name)
1325 WCHAR buffer[MAX_PATH];
1328 if (name == NULL) return NULL;
1329 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1331 server = strdupW(&name[2]); /* skip over both backslash */
1332 if (server == NULL) return NULL;
1334 /* strip '\' and the printername */
1335 ptr = strchrW(server, '\\');
1336 if (ptr) ptr[0] = '\0';
1338 TRACE("found %s\n", debugstr_w(server));
1340 len = sizeof(buffer)/sizeof(buffer[0]);
1341 if (GetComputerNameW(buffer, &len)) {
1342 if (lstrcmpW(buffer, server) == 0) {
1343 /* The requested Servername is our computername */
1344 HeapFree(GetProcessHeap(), 0, server);
1351 /******************************************************************
1352 * get_basename_from_name (internal)
1354 * skip over the serverpart from the full name
1357 static LPCWSTR get_basename_from_name(LPCWSTR name)
1359 if (name == NULL) return NULL;
1360 if ((name[0] == '\\') && (name[1] == '\\')) {
1361 /* skip over the servername and search for the following '\' */
1362 name = strchrW(&name[2], '\\');
1363 if ((name) && (name[1])) {
1364 /* found a separator ('\') followed by a name:
1365 skip over the separator and return the rest */
1370 /* no basename present (we found only a servername) */
1377 /******************************************************************
1378 * get_opened_printer_entry
1379 * Get the first place empty in the opened printer table
1382 * - pDefault is ignored
1384 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1386 UINT_PTR handle = nb_printer_handles, i;
1387 jobqueue_t *queue = NULL;
1388 opened_printer_t *printer = NULL;
1390 LPCWSTR printername;
1395 servername = get_servername_from_name(name);
1397 FIXME("server %s not supported\n", debugstr_w(servername));
1398 HeapFree(GetProcessHeap(), 0, servername);
1399 SetLastError(ERROR_INVALID_PRINTER_NAME);
1403 printername = get_basename_from_name(name);
1404 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1406 /* an empty printername is invalid */
1407 if (printername && (!printername[0])) {
1408 SetLastError(ERROR_INVALID_PARAMETER);
1412 EnterCriticalSection(&printer_handles_cs);
1414 for (i = 0; i < nb_printer_handles; i++)
1416 if (!printer_handles[i])
1418 if(handle == nb_printer_handles)
1423 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1424 queue = printer_handles[i]->queue;
1428 if (handle >= nb_printer_handles)
1430 opened_printer_t **new_array;
1431 if (printer_handles)
1432 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1433 (nb_printer_handles + 16) * sizeof(*new_array) );
1435 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1436 (nb_printer_handles + 16) * sizeof(*new_array) );
1443 printer_handles = new_array;
1444 nb_printer_handles += 16;
1447 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1454 /* clone the base name. This is NULL for the printserver */
1455 printer->printername = strdupW(printername);
1457 /* clone the full name */
1458 printer->name = strdupW(name);
1459 if (name && (!printer->name)) {
1465 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1466 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1467 /* OpenPrinter(",XcvMonitor " detected */
1468 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1469 printer->pm = monitor_load(&printername[len], NULL);
1470 if (printer->pm == NULL) {
1471 SetLastError(ERROR_UNKNOWN_PORT);
1478 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1479 if (strncmpW( printername, XcvPortW, len) == 0) {
1480 /* OpenPrinter(",XcvPort " detected */
1481 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1482 printer->pm = monitor_load_by_port(&printername[len]);
1483 if (printer->pm == NULL) {
1484 SetLastError(ERROR_UNKNOWN_PORT);
1492 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1493 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1494 pDefault ? pDefault->DesiredAccess : 0,
1497 if (printer->hXcv == NULL) {
1498 SetLastError(ERROR_INVALID_PARAMETER);
1505 /* Does the Printer exist? */
1506 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1507 ERR("Can't create Printers key\n");
1511 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1512 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1513 RegCloseKey(hkeyPrinters);
1514 SetLastError(ERROR_INVALID_PRINTER_NAME);
1518 RegCloseKey(hkeyPrinter);
1519 RegCloseKey(hkeyPrinters);
1524 TRACE("using the local printserver\n");
1528 printer->queue = queue;
1531 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1532 if (!printer->queue) {
1536 list_init(&printer->queue->jobs);
1537 printer->queue->ref = 0;
1539 InterlockedIncrement(&printer->queue->ref);
1541 printer_handles[handle] = printer;
1544 LeaveCriticalSection(&printer_handles_cs);
1545 if (!handle && printer) {
1546 /* Something failed: Free all resources */
1547 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1548 monitor_unload(printer->pm);
1549 HeapFree(GetProcessHeap(), 0, printer->printername);
1550 HeapFree(GetProcessHeap(), 0, printer->name);
1551 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1552 HeapFree(GetProcessHeap(), 0, printer);
1555 return (HANDLE)handle;
1558 /******************************************************************
1559 * get_opened_printer
1560 * Get the pointer to the opened printer referred by the handle
1562 static opened_printer_t *get_opened_printer(HANDLE hprn)
1564 UINT_PTR idx = (UINT_PTR)hprn;
1565 opened_printer_t *ret = NULL;
1567 EnterCriticalSection(&printer_handles_cs);
1569 if ((idx > 0) && (idx <= nb_printer_handles)) {
1570 ret = printer_handles[idx - 1];
1572 LeaveCriticalSection(&printer_handles_cs);
1576 /******************************************************************
1577 * get_opened_printer_name
1578 * Get the pointer to the opened printer name referred by the handle
1580 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1582 opened_printer_t *printer = get_opened_printer(hprn);
1583 if(!printer) return NULL;
1584 return printer->name;
1587 /******************************************************************
1588 * WINSPOOL_GetOpenedPrinterRegKey
1591 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1593 LPCWSTR name = get_opened_printer_name(hPrinter);
1597 if(!name) return ERROR_INVALID_HANDLE;
1599 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1603 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1605 ERR("Can't find opened printer %s in registry\n",
1607 RegCloseKey(hkeyPrinters);
1608 return ERROR_INVALID_PRINTER_NAME; /* ? */
1610 RegCloseKey(hkeyPrinters);
1611 return ERROR_SUCCESS;
1614 void WINSPOOL_LoadSystemPrinters(void)
1616 HKEY hkey, hkeyPrinters;
1618 DWORD needed, num, i;
1619 WCHAR PrinterName[256];
1622 /* This ensures that all printer entries have a valid Name value. If causes
1623 problems later if they don't. If one is found to be missed we create one
1624 and set it equal to the name of the key */
1625 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1626 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1627 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1628 for(i = 0; i < num; i++) {
1629 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1630 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1631 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1632 set_reg_szW(hkey, NameW, PrinterName);
1639 RegCloseKey(hkeyPrinters);
1642 /* We want to avoid calling AddPrinter on printers as much as
1643 possible, because on cups printers this will (eventually) lead
1644 to a call to cupsGetPPD which takes forever, even with non-cups
1645 printers AddPrinter takes a while. So we'll tag all printers that
1646 were automatically added last time around, if they still exist
1647 we'll leave them be otherwise we'll delete them. */
1648 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1650 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1651 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1652 for(i = 0; i < num; i++) {
1653 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1654 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1655 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1657 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1665 HeapFree(GetProcessHeap(), 0, pi);
1669 #ifdef SONAME_LIBCUPS
1670 done = CUPS_LoadPrinters();
1673 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1674 PRINTCAP_LoadPrinters();
1676 /* Now enumerate the list again and delete any printers that are still tagged */
1677 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1679 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1680 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1681 for(i = 0; i < num; i++) {
1682 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1683 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1684 BOOL delete_driver = FALSE;
1685 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1686 DWORD dw, type, size = sizeof(dw);
1687 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1688 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1689 DeletePrinter(hprn);
1690 delete_driver = TRUE;
1696 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1701 HeapFree(GetProcessHeap(), 0, pi);
1708 /******************************************************************
1711 * Get the pointer to the specified job.
1712 * Should hold the printer_handles_cs before calling.
1714 static job_t *get_job(HANDLE hprn, DWORD JobId)
1716 opened_printer_t *printer = get_opened_printer(hprn);
1719 if(!printer) return NULL;
1720 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1722 if(job->job_id == JobId)
1728 /***********************************************************
1731 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1734 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1737 Formname = (dmA->dmSize > off_formname);
1738 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1739 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1740 dmW->dmDeviceName, CCHDEVICENAME);
1742 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1743 dmA->dmSize - CCHDEVICENAME);
1745 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1746 off_formname - CCHDEVICENAME);
1747 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1748 dmW->dmFormName, CCHFORMNAME);
1749 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1750 (off_formname + CCHFORMNAME));
1753 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1754 dmA->dmDriverExtra);
1758 /***********************************************************
1760 * Creates an ascii copy of supplied devmode on heap
1762 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1767 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1769 if(!dmW) return NULL;
1770 Formname = (dmW->dmSize > off_formname);
1771 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1772 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1773 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1774 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1776 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1777 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1779 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1780 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1781 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1782 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1783 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1784 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1787 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1788 dmW->dmDriverExtra);
1792 /***********************************************************
1793 * PRINTER_INFO_2AtoW
1794 * Creates a unicode copy of PRINTER_INFO_2A on heap
1796 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1798 LPPRINTER_INFO_2W piW;
1799 UNICODE_STRING usBuffer;
1801 if(!piA) return NULL;
1802 piW = HeapAlloc(heap, 0, sizeof(*piW));
1803 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1805 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1806 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1807 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1808 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1809 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1810 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1811 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1812 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1813 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1814 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1815 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1816 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1820 /***********************************************************
1821 * FREE_PRINTER_INFO_2W
1822 * Free PRINTER_INFO_2W and all strings
1824 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1828 HeapFree(heap,0,piW->pServerName);
1829 HeapFree(heap,0,piW->pPrinterName);
1830 HeapFree(heap,0,piW->pShareName);
1831 HeapFree(heap,0,piW->pPortName);
1832 HeapFree(heap,0,piW->pDriverName);
1833 HeapFree(heap,0,piW->pComment);
1834 HeapFree(heap,0,piW->pLocation);
1835 HeapFree(heap,0,piW->pDevMode);
1836 HeapFree(heap,0,piW->pSepFile);
1837 HeapFree(heap,0,piW->pPrintProcessor);
1838 HeapFree(heap,0,piW->pDatatype);
1839 HeapFree(heap,0,piW->pParameters);
1840 HeapFree(heap,0,piW);
1844 /******************************************************************
1845 * DeviceCapabilities [WINSPOOL.@]
1846 * DeviceCapabilitiesA [WINSPOOL.@]
1849 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1850 LPSTR pOutput, LPDEVMODEA lpdm)
1854 if (!GDI_CallDeviceCapabilities16)
1856 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1858 if (!GDI_CallDeviceCapabilities16) return -1;
1860 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1862 /* If DC_PAPERSIZE map POINT16s to POINTs */
1863 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1864 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1865 POINT *pt = (POINT *)pOutput;
1867 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1868 for(i = 0; i < ret; i++, pt++)
1873 HeapFree( GetProcessHeap(), 0, tmp );
1879 /*****************************************************************************
1880 * DeviceCapabilitiesW [WINSPOOL.@]
1882 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1885 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1886 WORD fwCapability, LPWSTR pOutput,
1887 const DEVMODEW *pDevMode)
1889 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1890 LPSTR pDeviceA = strdupWtoA(pDevice);
1891 LPSTR pPortA = strdupWtoA(pPort);
1894 if(pOutput && (fwCapability == DC_BINNAMES ||
1895 fwCapability == DC_FILEDEPENDENCIES ||
1896 fwCapability == DC_PAPERNAMES)) {
1897 /* These need A -> W translation */
1900 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1904 switch(fwCapability) {
1909 case DC_FILEDEPENDENCIES:
1913 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1914 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1916 for(i = 0; i < ret; i++)
1917 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1918 pOutput + (i * size), size);
1919 HeapFree(GetProcessHeap(), 0, pOutputA);
1921 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1922 (LPSTR)pOutput, dmA);
1924 HeapFree(GetProcessHeap(),0,pPortA);
1925 HeapFree(GetProcessHeap(),0,pDeviceA);
1926 HeapFree(GetProcessHeap(),0,dmA);
1930 /******************************************************************
1931 * DocumentPropertiesA [WINSPOOL.@]
1933 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1935 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1936 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1937 LPDEVMODEA pDevModeInput,DWORD fMode )
1939 LPSTR lpName = pDeviceName;
1940 static CHAR port[] = "LPT1:";
1943 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1944 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1948 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1950 ERR("no name from hPrinter?\n");
1951 SetLastError(ERROR_INVALID_HANDLE);
1954 lpName = strdupWtoA(lpNameW);
1957 if (!GDI_CallExtDeviceMode16)
1959 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1961 if (!GDI_CallExtDeviceMode16) {
1962 ERR("No CallExtDeviceMode16?\n");
1966 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1967 pDevModeInput, NULL, fMode);
1970 HeapFree(GetProcessHeap(),0,lpName);
1975 /*****************************************************************************
1976 * DocumentPropertiesW (WINSPOOL.@)
1978 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1980 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1982 LPDEVMODEW pDevModeOutput,
1983 LPDEVMODEW pDevModeInput, DWORD fMode)
1986 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1987 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1988 LPDEVMODEA pDevModeOutputA = NULL;
1991 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1992 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1994 if(pDevModeOutput) {
1995 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1996 if(ret < 0) return ret;
1997 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1999 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2000 pDevModeInputA, fMode);
2001 if(pDevModeOutput) {
2002 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2003 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2005 if(fMode == 0 && ret > 0)
2006 ret += (CCHDEVICENAME + CCHFORMNAME);
2007 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2008 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2012 /******************************************************************
2013 * OpenPrinterA [WINSPOOL.@]
2018 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2019 LPPRINTER_DEFAULTSA pDefault)
2021 UNICODE_STRING lpPrinterNameW;
2022 UNICODE_STRING usBuffer;
2023 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2024 PWSTR pwstrPrinterNameW;
2027 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2030 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2031 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2032 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2033 pDefaultW = &DefaultW;
2035 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2037 RtlFreeUnicodeString(&usBuffer);
2038 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2040 RtlFreeUnicodeString(&lpPrinterNameW);
2044 /******************************************************************
2045 * OpenPrinterW [WINSPOOL.@]
2047 * Open a Printer / Printserver or a Printer-Object
2050 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2051 * phPrinter [O] The resulting Handle is stored here
2052 * pDefault [I] PTR to Default Printer Settings or NULL
2059 * lpPrinterName is one of:
2060 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2061 *| Printer: "PrinterName"
2062 *| Printer-Object: "PrinterName,Job xxx"
2063 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2064 *| XcvPort: "Servername,XcvPort PortName"
2067 *| Printer-Object not supported
2068 *| pDefaults is ignored
2071 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2074 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2076 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2077 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2081 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2082 SetLastError(ERROR_INVALID_PARAMETER);
2086 /* Get the unique handle of the printer or Printserver */
2087 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2088 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2089 return (*phPrinter != 0);
2092 /******************************************************************
2093 * AddMonitorA [WINSPOOL.@]
2098 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2100 LPWSTR nameW = NULL;
2103 LPMONITOR_INFO_2A mi2a;
2104 MONITOR_INFO_2W mi2w;
2106 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2107 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2108 mi2a ? debugstr_a(mi2a->pName) : NULL,
2109 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2110 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2113 SetLastError(ERROR_INVALID_LEVEL);
2117 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2123 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2124 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2125 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2128 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2130 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2131 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2132 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2134 if (mi2a->pEnvironment) {
2135 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2136 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2137 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2139 if (mi2a->pDLLName) {
2140 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2141 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2142 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2145 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2147 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2148 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2149 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2151 HeapFree(GetProcessHeap(), 0, nameW);
2155 /******************************************************************************
2156 * AddMonitorW [WINSPOOL.@]
2158 * Install a Printmonitor
2161 * pName [I] Servername or NULL (local Computer)
2162 * Level [I] Structure-Level (Must be 2)
2163 * pMonitors [I] PTR to MONITOR_INFO_2
2170 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2173 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2175 monitor_t * pm = NULL;
2176 LPMONITOR_INFO_2W mi2w;
2182 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2183 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2184 mi2w ? debugstr_w(mi2w->pName) : NULL,
2185 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2186 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2189 SetLastError(ERROR_INVALID_LEVEL);
2193 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2198 if (pName && (pName[0])) {
2199 FIXME("for server %s not implemented\n", debugstr_w(pName));
2200 SetLastError(ERROR_ACCESS_DENIED);
2205 if (!mi2w->pName || (! mi2w->pName[0])) {
2206 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2207 SetLastError(ERROR_INVALID_PARAMETER);
2210 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2211 WARN("Environment %s requested (we support only %s)\n",
2212 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2213 SetLastError(ERROR_INVALID_ENVIRONMENT);
2217 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2218 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2219 SetLastError(ERROR_INVALID_PARAMETER);
2223 /* Load and initialize the monitor. SetLastError() is called on failure */
2224 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2229 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2230 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2234 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2235 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2236 &disposition) == ERROR_SUCCESS) {
2238 /* Some installers set options for the port before calling AddMonitor.
2239 We query the "Driver" entry to verify that the monitor is installed,
2240 before we return an error.
2241 When a user installs two print monitors at the same time with the
2242 same name but with a different driver DLL and a task switch comes
2243 between RegQueryValueExW and RegSetValueExW, a race condition
2244 is possible but silently ignored. */
2248 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2249 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2250 &namesize) == ERROR_SUCCESS)) {
2251 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2252 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2253 9x: ERROR_ALREADY_EXISTS (183) */
2254 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2259 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2260 res = (RegSetValueExW(hentry, DriverW, 0,
2261 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2263 RegCloseKey(hentry);
2270 /******************************************************************
2271 * DeletePrinterDriverA [WINSPOOL.@]
2274 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2276 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2279 /******************************************************************
2280 * DeletePrinterDriverW [WINSPOOL.@]
2283 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2285 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2288 /******************************************************************
2289 * DeleteMonitorA [WINSPOOL.@]
2291 * See DeleteMonitorW.
2294 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2296 LPWSTR nameW = NULL;
2297 LPWSTR EnvironmentW = NULL;
2298 LPWSTR MonitorNameW = NULL;
2303 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2304 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2305 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2309 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2310 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2311 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2314 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2315 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2316 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2319 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2321 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2322 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2323 HeapFree(GetProcessHeap(), 0, nameW);
2327 /******************************************************************
2328 * DeleteMonitorW [WINSPOOL.@]
2330 * Delete a specific Printmonitor from a Printing-Environment
2333 * pName [I] Servername or NULL (local Computer)
2334 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2335 * pMonitorName [I] Name of the Monitor, that should be deleted
2342 * pEnvironment is ignored in Windows for the local Computer.
2346 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2350 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2351 debugstr_w(pMonitorName));
2353 if (pName && (pName[0])) {
2354 FIXME("for server %s not implemented\n", debugstr_w(pName));
2355 SetLastError(ERROR_ACCESS_DENIED);
2359 /* pEnvironment is ignored in Windows for the local Computer */
2361 if (!pMonitorName || !pMonitorName[0]) {
2362 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2363 SetLastError(ERROR_INVALID_PARAMETER);
2367 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2368 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2372 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2373 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2378 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2381 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2382 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2386 /******************************************************************
2387 * DeletePortA [WINSPOOL.@]
2392 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2394 LPWSTR nameW = NULL;
2395 LPWSTR portW = NULL;
2399 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2401 /* convert servername to unicode */
2403 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2404 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2405 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2408 /* convert portname to unicode */
2410 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2411 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2412 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2415 res = DeletePortW(nameW, hWnd, portW);
2416 HeapFree(GetProcessHeap(), 0, nameW);
2417 HeapFree(GetProcessHeap(), 0, portW);
2421 /******************************************************************
2422 * DeletePortW [WINSPOOL.@]
2424 * Delete a specific Port
2427 * pName [I] Servername or NULL (local Computer)
2428 * hWnd [I] Handle to parent Window for the Dialog-Box
2429 * pPortName [I] Name of the Port, that should be deleted
2436 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2442 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2444 if (pName && pName[0]) {
2445 SetLastError(ERROR_INVALID_PARAMETER);
2450 SetLastError(RPC_X_NULL_REF_POINTER);
2454 /* an empty Portname is Invalid */
2455 if (!pPortName[0]) {
2456 SetLastError(ERROR_NOT_SUPPORTED);
2460 pm = monitor_load_by_port(pPortName);
2461 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2462 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2463 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2464 TRACE("got %d with %u\n", res, GetLastError());
2468 pui = monitor_loadui(pm);
2469 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2470 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2471 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2472 TRACE("got %d with %u\n", res, GetLastError());
2476 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2477 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2479 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2480 SetLastError(ERROR_NOT_SUPPORTED);
2483 monitor_unload(pui);
2487 TRACE("returning %d with %u\n", res, GetLastError());
2491 /******************************************************************************
2492 * SetPrinterW [WINSPOOL.@]
2494 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2496 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2497 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2501 /******************************************************************************
2502 * WritePrinter [WINSPOOL.@]
2504 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2506 opened_printer_t *printer;
2509 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2511 EnterCriticalSection(&printer_handles_cs);
2512 printer = get_opened_printer(hPrinter);
2515 SetLastError(ERROR_INVALID_HANDLE);
2521 SetLastError(ERROR_SPL_NO_STARTDOC);
2525 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2527 LeaveCriticalSection(&printer_handles_cs);
2531 /*****************************************************************************
2532 * AddFormA [WINSPOOL.@]
2534 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2536 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2540 /*****************************************************************************
2541 * AddFormW [WINSPOOL.@]
2543 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2545 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2549 /*****************************************************************************
2550 * AddJobA [WINSPOOL.@]
2552 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2555 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2559 SetLastError(ERROR_INVALID_LEVEL);
2563 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2566 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2567 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2568 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2569 if(*pcbNeeded > cbBuf) {
2570 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2573 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2574 addjobA->JobId = addjobW->JobId;
2575 addjobA->Path = (char *)(addjobA + 1);
2576 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2582 /*****************************************************************************
2583 * AddJobW [WINSPOOL.@]
2585 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2587 opened_printer_t *printer;
2590 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2591 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2592 WCHAR path[MAX_PATH], filename[MAX_PATH];
2594 ADDJOB_INFO_1W *addjob;
2596 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2598 EnterCriticalSection(&printer_handles_cs);
2600 printer = get_opened_printer(hPrinter);
2603 SetLastError(ERROR_INVALID_HANDLE);
2608 SetLastError(ERROR_INVALID_LEVEL);
2612 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2616 job->job_id = InterlockedIncrement(&next_job_id);
2618 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2619 if(path[len - 1] != '\\')
2621 memcpy(path + len, spool_path, sizeof(spool_path));
2622 sprintfW(filename, fmtW, path, job->job_id);
2624 len = strlenW(filename);
2625 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2626 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2627 job->document_title = strdupW(default_doc_title);
2628 list_add_tail(&printer->queue->jobs, &job->entry);
2630 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2631 if(*pcbNeeded <= cbBuf) {
2632 addjob = (ADDJOB_INFO_1W*)pData;
2633 addjob->JobId = job->job_id;
2634 addjob->Path = (WCHAR *)(addjob + 1);
2635 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2638 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2641 LeaveCriticalSection(&printer_handles_cs);
2645 /*****************************************************************************
2646 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2648 * Return the PATH for the Print-Processors
2650 * See GetPrintProcessorDirectoryW.
2654 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2655 DWORD level, LPBYTE Info,
2656 DWORD cbBuf, LPDWORD pcbNeeded)
2658 LPWSTR serverW = NULL;
2663 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2664 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2668 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2669 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2670 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2674 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2675 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2676 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2679 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2680 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2682 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2685 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2686 cbBuf, NULL, NULL) > 0;
2689 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2690 HeapFree(GetProcessHeap(), 0, envW);
2691 HeapFree(GetProcessHeap(), 0, serverW);
2695 /*****************************************************************************
2696 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2698 * Return the PATH for the Print-Processors
2701 * server [I] Servername (NT only) or NULL (local Computer)
2702 * env [I] Printing-Environment (see below) or NULL (Default)
2703 * level [I] Structure-Level (must be 1)
2704 * Info [O] PTR to Buffer that receives the Result
2705 * cbBuf [I] Size of Buffer at "Info"
2706 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2707 * required for the Buffer at "Info"
2710 * Success: TRUE and in pcbNeeded the Bytes used in Info
2711 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2712 * if cbBuf is too small
2714 * Native Values returned in Info on Success:
2715 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2716 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2717 *| win9x(Windows 4.0): "%winsysdir%"
2719 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2722 * Only NULL or "" is supported for server
2725 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2726 DWORD level, LPBYTE Info,
2727 DWORD cbBuf, LPDWORD pcbNeeded)
2730 const printenv_t * env_t;
2732 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2733 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2735 if(server != NULL && server[0]) {
2736 FIXME("server not supported: %s\n", debugstr_w(server));
2737 SetLastError(ERROR_INVALID_PARAMETER);
2741 env_t = validate_envW(env);
2742 if(!env_t) return FALSE; /* environment invalid or unsupported */
2745 WARN("(Level: %d) is ignored in win9x\n", level);
2746 SetLastError(ERROR_INVALID_LEVEL);
2750 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2751 needed = GetSystemDirectoryW(NULL, 0);
2752 /* add the Size for the Subdirectories */
2753 needed += lstrlenW(spoolprtprocsW);
2754 needed += lstrlenW(env_t->subdir);
2755 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2757 if(pcbNeeded) *pcbNeeded = needed;
2758 TRACE ("required: 0x%x/%d\n", needed, needed);
2759 if (needed > cbBuf) {
2760 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2763 if(pcbNeeded == NULL) {
2764 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2765 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2766 SetLastError(RPC_X_NULL_REF_POINTER);
2770 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2771 SetLastError(RPC_X_NULL_REF_POINTER);
2775 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2776 /* add the Subdirectories */
2777 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2778 lstrcatW((LPWSTR) Info, env_t->subdir);
2779 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2783 /*****************************************************************************
2784 * WINSPOOL_OpenDriverReg [internal]
2786 * opens the registry for the printer drivers depending on the given input
2787 * variable pEnvironment
2790 * the opened hkey on success
2793 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2797 const printenv_t * env;
2800 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2802 if (!pEnvironment || unicode) {
2803 /* pEnvironment was NULL or an Unicode-String: use it direct */
2804 env = validate_envW(pEnvironment);
2808 /* pEnvironment was an ANSI-String: convert to unicode first */
2810 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2811 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2812 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2813 env = validate_envW(buffer);
2814 HeapFree(GetProcessHeap(), 0, buffer);
2816 if (!env) return NULL;
2818 buffer = HeapAlloc( GetProcessHeap(), 0,
2819 (strlenW(DriversW) + strlenW(env->envname) +
2820 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2822 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2823 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2824 HeapFree(GetProcessHeap(), 0, buffer);
2829 /*****************************************************************************
2830 * AddPrinterW [WINSPOOL.@]
2832 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2834 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2838 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2840 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2841 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2842 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2843 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2844 statusW[] = {'S','t','a','t','u','s',0},
2845 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2847 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2850 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2851 SetLastError(ERROR_INVALID_PARAMETER);
2855 ERR("Level = %d, unsupported!\n", Level);
2856 SetLastError(ERROR_INVALID_LEVEL);
2860 SetLastError(ERROR_INVALID_PARAMETER);
2863 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2865 ERR("Can't create Printers key\n");
2868 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2869 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2870 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2871 RegCloseKey(hkeyPrinter);
2872 RegCloseKey(hkeyPrinters);
2875 RegCloseKey(hkeyPrinter);
2877 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2879 ERR("Can't create Drivers key\n");
2880 RegCloseKey(hkeyPrinters);
2883 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2885 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2886 RegCloseKey(hkeyPrinters);
2887 RegCloseKey(hkeyDrivers);
2888 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2891 RegCloseKey(hkeyDriver);
2892 RegCloseKey(hkeyDrivers);
2894 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2895 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2896 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2897 RegCloseKey(hkeyPrinters);
2901 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2903 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2904 SetLastError(ERROR_INVALID_PRINTER_NAME);
2905 RegCloseKey(hkeyPrinters);
2908 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2909 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2910 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2912 /* See if we can load the driver. We may need the devmode structure anyway
2915 * Note that DocumentPropertiesW will briefly try to open the printer we
2916 * just create to find a DEVMODEA struct (it will use the WINEPS default
2917 * one in case it is not there, so we are ok).
2919 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2922 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2923 size = sizeof(DEVMODEW);
2929 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2931 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2933 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2934 HeapFree(GetProcessHeap(),0,dmW);
2939 /* set devmode to printer name */
2940 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2944 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2945 and we support these drivers. NT writes DEVMODEW so somehow
2946 we'll need to distinguish between these when we support NT
2950 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2951 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2952 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2953 HeapFree(GetProcessHeap(), 0, dmA);
2955 HeapFree(GetProcessHeap(), 0, dmW);
2957 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2958 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2959 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2960 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2962 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2963 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2964 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2965 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2966 (LPBYTE)&pi->Priority, sizeof(DWORD));
2967 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2968 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2969 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2970 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2971 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2972 (LPBYTE)&pi->Status, sizeof(DWORD));
2973 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2974 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2976 RegCloseKey(hkeyPrinter);
2977 RegCloseKey(hkeyPrinters);
2978 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2979 ERR("OpenPrinter failing\n");
2985 /*****************************************************************************
2986 * AddPrinterA [WINSPOOL.@]
2988 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2990 UNICODE_STRING pNameW;
2992 PRINTER_INFO_2W *piW;
2993 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2996 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2998 ERR("Level = %d, unsupported!\n", Level);
2999 SetLastError(ERROR_INVALID_LEVEL);
3002 pwstrNameW = asciitounicode(&pNameW,pName);
3003 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3005 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3007 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3008 RtlFreeUnicodeString(&pNameW);
3013 /*****************************************************************************
3014 * ClosePrinter [WINSPOOL.@]
3016 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3018 UINT_PTR i = (UINT_PTR)hPrinter;
3019 opened_printer_t *printer = NULL;
3022 TRACE("(%p)\n", hPrinter);
3024 EnterCriticalSection(&printer_handles_cs);
3026 if ((i > 0) && (i <= nb_printer_handles))
3027 printer = printer_handles[i - 1];
3032 struct list *cursor, *cursor2;
3034 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3035 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3036 printer->hXcv, debugstr_w(printer->name), printer->doc );
3039 EndDocPrinter(hPrinter);
3041 if(InterlockedDecrement(&printer->queue->ref) == 0)
3043 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3045 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3046 ScheduleJob(hPrinter, job->job_id);
3048 HeapFree(GetProcessHeap(), 0, printer->queue);
3050 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3051 monitor_unload(printer->pm);
3052 HeapFree(GetProcessHeap(), 0, printer->printername);
3053 HeapFree(GetProcessHeap(), 0, printer->name);
3054 HeapFree(GetProcessHeap(), 0, printer);
3055 printer_handles[i - 1] = NULL;
3058 LeaveCriticalSection(&printer_handles_cs);
3062 /*****************************************************************************
3063 * DeleteFormA [WINSPOOL.@]
3065 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3067 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3071 /*****************************************************************************
3072 * DeleteFormW [WINSPOOL.@]
3074 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3076 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3080 /*****************************************************************************
3081 * DeletePrinter [WINSPOOL.@]
3083 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3085 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3086 HKEY hkeyPrinters, hkey;
3089 SetLastError(ERROR_INVALID_HANDLE);
3092 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3093 RegDeleteTreeW(hkeyPrinters, lpNameW);
3094 RegCloseKey(hkeyPrinters);
3096 WriteProfileStringW(devicesW, lpNameW, NULL);
3097 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3098 RegDeleteValueW(hkey, lpNameW);
3104 /*****************************************************************************
3105 * SetPrinterA [WINSPOOL.@]
3107 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3110 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3114 /*****************************************************************************
3115 * SetJobA [WINSPOOL.@]
3117 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3118 LPBYTE pJob, DWORD Command)
3122 UNICODE_STRING usBuffer;
3124 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3126 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3127 are all ignored by SetJob, so we don't bother copying them */
3135 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3136 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3138 JobW = (LPBYTE)info1W;
3139 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3140 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3141 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3142 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3143 info1W->Status = info1A->Status;
3144 info1W->Priority = info1A->Priority;
3145 info1W->Position = info1A->Position;
3146 info1W->PagesPrinted = info1A->PagesPrinted;
3151 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3152 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3154 JobW = (LPBYTE)info2W;
3155 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3156 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3157 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3158 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3159 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3160 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3161 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3162 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3163 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3164 info2W->Status = info2A->Status;
3165 info2W->Priority = info2A->Priority;
3166 info2W->Position = info2A->Position;
3167 info2W->StartTime = info2A->StartTime;
3168 info2W->UntilTime = info2A->UntilTime;
3169 info2W->PagesPrinted = info2A->PagesPrinted;
3173 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3174 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3177 SetLastError(ERROR_INVALID_LEVEL);
3181 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3187 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3188 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3189 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3190 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3191 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3196 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3197 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3198 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3199 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3200 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3201 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3202 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3203 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3204 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3208 HeapFree(GetProcessHeap(), 0, JobW);
3213 /*****************************************************************************
3214 * SetJobW [WINSPOOL.@]
3216 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3217 LPBYTE pJob, DWORD Command)
3222 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3223 FIXME("Ignoring everything other than document title\n");
3225 EnterCriticalSection(&printer_handles_cs);
3226 job = get_job(hPrinter, JobId);
3236 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3237 HeapFree(GetProcessHeap(), 0, job->document_title);
3238 job->document_title = strdupW(info1->pDocument);
3243 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3244 HeapFree(GetProcessHeap(), 0, job->document_title);
3245 job->document_title = strdupW(info2->pDocument);
3251 SetLastError(ERROR_INVALID_LEVEL);
3256 LeaveCriticalSection(&printer_handles_cs);
3260 /*****************************************************************************
3261 * EndDocPrinter [WINSPOOL.@]
3263 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3265 opened_printer_t *printer;
3267 TRACE("(%p)\n", hPrinter);
3269 EnterCriticalSection(&printer_handles_cs);
3271 printer = get_opened_printer(hPrinter);
3274 SetLastError(ERROR_INVALID_HANDLE);
3280 SetLastError(ERROR_SPL_NO_STARTDOC);
3284 CloseHandle(printer->doc->hf);
3285 ScheduleJob(hPrinter, printer->doc->job_id);
3286 HeapFree(GetProcessHeap(), 0, printer->doc);
3287 printer->doc = NULL;
3290 LeaveCriticalSection(&printer_handles_cs);
3294 /*****************************************************************************
3295 * EndPagePrinter [WINSPOOL.@]
3297 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3299 FIXME("(%p): stub\n", hPrinter);
3303 /*****************************************************************************
3304 * StartDocPrinterA [WINSPOOL.@]
3306 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3308 UNICODE_STRING usBuffer;
3310 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3313 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3314 or one (DOC_INFO_3) extra DWORDs */
3318 doc2W.JobId = doc2->JobId;
3321 doc2W.dwMode = doc2->dwMode;
3324 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3325 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3326 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3330 SetLastError(ERROR_INVALID_LEVEL);
3334 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3336 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3337 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3338 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3343 /*****************************************************************************
3344 * StartDocPrinterW [WINSPOOL.@]
3346 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3348 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3349 opened_printer_t *printer;
3350 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3351 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3352 JOB_INFO_1W job_info;
3353 DWORD needed, ret = 0;
3357 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3358 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3359 debugstr_w(doc->pDatatype));
3361 if(Level < 1 || Level > 3)
3363 SetLastError(ERROR_INVALID_LEVEL);
3367 EnterCriticalSection(&printer_handles_cs);
3368 printer = get_opened_printer(hPrinter);
3371 SetLastError(ERROR_INVALID_HANDLE);
3377 SetLastError(ERROR_INVALID_PRINTER_STATE);
3381 /* Even if we're printing to a file we still add a print job, we'll
3382 just ignore the spool file name */
3384 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3386 ERR("AddJob failed gle %u\n", GetLastError());
3390 if(doc->pOutputFile)
3391 filename = doc->pOutputFile;
3393 filename = addjob->Path;
3395 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3396 if(hf == INVALID_HANDLE_VALUE)
3399 memset(&job_info, 0, sizeof(job_info));
3400 job_info.pDocument = doc->pDocName;
3401 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3403 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3404 printer->doc->hf = hf;
3405 ret = printer->doc->job_id = addjob->JobId;
3407 LeaveCriticalSection(&printer_handles_cs);
3412 /*****************************************************************************
3413 * StartPagePrinter [WINSPOOL.@]
3415 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3417 FIXME("(%p): stub\n", hPrinter);
3421 /*****************************************************************************
3422 * GetFormA [WINSPOOL.@]
3424 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3425 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3427 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3428 Level,pForm,cbBuf,pcbNeeded);
3432 /*****************************************************************************
3433 * GetFormW [WINSPOOL.@]
3435 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3436 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3438 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3439 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3443 /*****************************************************************************
3444 * SetFormA [WINSPOOL.@]
3446 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3449 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3453 /*****************************************************************************
3454 * SetFormW [WINSPOOL.@]
3456 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3459 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3463 /*****************************************************************************
3464 * ReadPrinter [WINSPOOL.@]
3466 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3467 LPDWORD pNoBytesRead)
3469 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3473 /*****************************************************************************
3474 * ResetPrinterA [WINSPOOL.@]
3476 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3478 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3482 /*****************************************************************************
3483 * ResetPrinterW [WINSPOOL.@]
3485 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3487 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3491 /*****************************************************************************
3492 * WINSPOOL_GetDWORDFromReg
3494 * Return DWORD associated with ValueName from hkey.
3496 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3498 DWORD sz = sizeof(DWORD), type, value = 0;
3501 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3503 if(ret != ERROR_SUCCESS) {
3504 WARN("Got ret = %d on name %s\n", ret, ValueName);
3507 if(type != REG_DWORD) {
3508 ERR("Got type %d\n", type);
3515 /*****************************************************************************
3516 * get_filename_from_reg [internal]
3518 * Get ValueName from hkey storing result in out
3519 * when the Value in the registry has only a filename, use driverdir as prefix
3520 * outlen is space left in out
3521 * String is stored either as unicode or ascii
3525 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3526 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3528 WCHAR filename[MAX_PATH];
3532 LPWSTR buffer = filename;
3536 size = sizeof(filename);
3538 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3539 if (ret == ERROR_MORE_DATA) {
3540 TRACE("need dynamic buffer: %u\n", size);
3541 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3543 /* No Memory is bad */
3547 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3550 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3551 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3557 /* do we have a full path ? */
3558 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3559 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3562 /* we must build the full Path */
3564 if ((out) && (outlen > dirlen)) {
3566 lstrcpyW((LPWSTR)out, driverdir);
3570 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3579 /* write the filename */
3581 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3582 if ((out) && (outlen >= size)) {
3583 lstrcpyW((LPWSTR)out, ptr);
3592 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3593 if ((out) && (outlen >= size)) {
3594 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3602 ptr += lstrlenW(ptr)+1;
3603 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3606 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3608 /* write the multisz-termination */
3609 if (type == REG_MULTI_SZ) {
3610 size = (unicode) ? sizeof(WCHAR) : 1;
3613 if (out && (outlen >= size)) {
3614 memset (out, 0, size);
3620 /*****************************************************************************
3621 * WINSPOOL_GetStringFromReg
3623 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3624 * String is stored either as unicode or ascii.
3625 * Bit of a hack here to get the ValueName if we want ascii.
3627 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3628 DWORD buflen, DWORD *needed,
3631 DWORD sz = buflen, type;
3635 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3637 LPSTR ValueNameA = strdupWtoA(ValueName);
3638 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3639 HeapFree(GetProcessHeap(),0,ValueNameA);
3641 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3642 WARN("Got ret = %d\n", ret);
3646 /* add space for terminating '\0' */
3647 sz += unicode ? sizeof(WCHAR) : 1;
3651 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3656 /*****************************************************************************
3657 * WINSPOOL_GetDefaultDevMode
3659 * Get a default DevMode values for wineps.
3663 static void WINSPOOL_GetDefaultDevMode(
3665 DWORD buflen, DWORD *needed,
3669 static const char szwps[] = "wineps.drv";
3671 /* fill default DEVMODE - should be read from ppd... */
3672 ZeroMemory( &dm, sizeof(dm) );
3673 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3674 dm.dmSpecVersion = DM_SPECVERSION;
3675 dm.dmDriverVersion = 1;
3676 dm.dmSize = sizeof(DEVMODEA);
3677 dm.dmDriverExtra = 0;
3679 DM_ORIENTATION | DM_PAPERSIZE |
3680 DM_PAPERLENGTH | DM_PAPERWIDTH |
3683 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3684 DM_YRESOLUTION | DM_TTOPTION;
3686 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3687 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3688 dm.u1.s1.dmPaperLength = 2970;
3689 dm.u1.s1.dmPaperWidth = 2100;
3691 dm.u1.s1.dmScale = 100;
3692 dm.u1.s1.dmCopies = 1;
3693 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3694 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3697 dm.dmYResolution = 300; /* 300dpi */
3698 dm.dmTTOption = DMTT_BITMAP;
3701 /* dm.dmLogPixels */
3702 /* dm.dmBitsPerPel */
3703 /* dm.dmPelsWidth */
3704 /* dm.dmPelsHeight */
3705 /* dm.u2.dmDisplayFlags */
3706 /* dm.dmDisplayFrequency */
3707 /* dm.dmICMMethod */
3708 /* dm.dmICMIntent */
3709 /* dm.dmMediaType */
3710 /* dm.dmDitherType */
3711 /* dm.dmReserved1 */
3712 /* dm.dmReserved2 */
3713 /* dm.dmPanningWidth */
3714 /* dm.dmPanningHeight */
3717 if(buflen >= sizeof(DEVMODEW)) {
3718 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3719 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3720 HeapFree(GetProcessHeap(),0,pdmW);
3722 *needed = sizeof(DEVMODEW);
3726 if(buflen >= sizeof(DEVMODEA)) {
3727 memcpy(ptr, &dm, sizeof(DEVMODEA));
3729 *needed = sizeof(DEVMODEA);
3733 /*****************************************************************************
3734 * WINSPOOL_GetDevModeFromReg
3736 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3737 * DevMode is stored either as unicode or ascii.
3739 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3741 DWORD buflen, DWORD *needed,
3744 DWORD sz = buflen, type;
3747 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3748 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3749 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3750 if (sz < sizeof(DEVMODEA))
3752 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3755 /* ensures that dmSize is not erratically bogus if registry is invalid */
3756 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3757 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3759 sz += (CCHDEVICENAME + CCHFORMNAME);
3761 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3762 memcpy(ptr, dmW, sz);
3763 HeapFree(GetProcessHeap(),0,dmW);
3770 /*********************************************************************
3771 * WINSPOOL_GetPrinter_1
3773 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3774 * The strings are either stored as unicode or ascii.
3776 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3777 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3780 DWORD size, left = cbBuf;
3781 BOOL space = (cbBuf > 0);
3786 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3788 if(space && size <= left) {
3789 pi1->pName = (LPWSTR)ptr;
3797 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3798 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3800 if(space && size <= left) {
3801 pi1->pDescription = (LPWSTR)ptr;
3809 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3811 if(space && size <= left) {
3812 pi1->pComment = (LPWSTR)ptr;
3820 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3822 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3823 memset(pi1, 0, sizeof(*pi1));
3827 /*********************************************************************
3828 * WINSPOOL_GetPrinter_2
3830 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3831 * The strings are either stored as unicode or ascii.
3833 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3834 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3837 DWORD size, left = cbBuf;
3838 BOOL space = (cbBuf > 0);
3843 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3845 if(space && size <= left) {
3846 pi2->pPrinterName = (LPWSTR)ptr;
3853 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3855 if(space && size <= left) {
3856 pi2->pShareName = (LPWSTR)ptr;
3863 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3865 if(space && size <= left) {
3866 pi2->pPortName = (LPWSTR)ptr;
3873 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3875 if(space && size <= left) {
3876 pi2->pDriverName = (LPWSTR)ptr;
3883 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3885 if(space && size <= left) {
3886 pi2->pComment = (LPWSTR)ptr;
3893 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3895 if(space && size <= left) {
3896 pi2->pLocation = (LPWSTR)ptr;
3903 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3905 if(space && size <= left) {
3906 pi2->pDevMode = (LPDEVMODEW)ptr;
3915 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3916 if(space && size <= left) {
3917 pi2->pDevMode = (LPDEVMODEW)ptr;
3924 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3926 if(space && size <= left) {
3927 pi2->pSepFile = (LPWSTR)ptr;
3934 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3936 if(space && size <= left) {
3937 pi2->pPrintProcessor = (LPWSTR)ptr;
3944 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3946 if(space && size <= left) {
3947 pi2->pDatatype = (LPWSTR)ptr;
3954 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3956 if(space && size <= left) {
3957 pi2->pParameters = (LPWSTR)ptr;
3965 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3966 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3967 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3968 "Default Priority");
3969 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3970 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3973 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3974 memset(pi2, 0, sizeof(*pi2));
3979 /*********************************************************************
3980 * WINSPOOL_GetPrinter_4
3982 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3984 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3985 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3988 DWORD size, left = cbBuf;
3989 BOOL space = (cbBuf > 0);
3994 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3996 if(space && size <= left) {
3997 pi4->pPrinterName = (LPWSTR)ptr;
4005 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4008 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4009 memset(pi4, 0, sizeof(*pi4));
4014 /*********************************************************************
4015 * WINSPOOL_GetPrinter_5
4017 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4019 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4020 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4023 DWORD size, left = cbBuf;
4024 BOOL space = (cbBuf > 0);
4029 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4031 if(space && size <= left) {
4032 pi5->pPrinterName = (LPWSTR)ptr;
4039 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4041 if(space && size <= left) {
4042 pi5->pPortName = (LPWSTR)ptr;
4050 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4051 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4053 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4057 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4058 memset(pi5, 0, sizeof(*pi5));
4063 /*****************************************************************************
4064 * WINSPOOL_GetPrinter
4066 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4067 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4068 * just a collection of pointers to strings.
4070 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4071 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4074 DWORD size, needed = 0;
4076 HKEY hkeyPrinter, hkeyPrinters;
4079 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4081 if (!(name = get_opened_printer_name(hPrinter))) {
4082 SetLastError(ERROR_INVALID_HANDLE);
4086 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4088 ERR("Can't create Printers key\n");
4091 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4093 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4094 RegCloseKey(hkeyPrinters);
4095 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4102 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4104 size = sizeof(PRINTER_INFO_2W);
4106 ptr = pPrinter + size;
4108 memset(pPrinter, 0, size);
4113 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4121 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4123 size = sizeof(PRINTER_INFO_4W);
4125 ptr = pPrinter + size;
4127 memset(pPrinter, 0, size);
4132 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4141 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4143 size = sizeof(PRINTER_INFO_5W);
4145 ptr = pPrinter + size;
4147 memset(pPrinter, 0, size);
4153 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4160 FIXME("Unimplemented level %d\n", Level);
4161 SetLastError(ERROR_INVALID_LEVEL);
4162 RegCloseKey(hkeyPrinters);
4163 RegCloseKey(hkeyPrinter);
4167 RegCloseKey(hkeyPrinter);
4168 RegCloseKey(hkeyPrinters);
4170 TRACE("returning %d needed = %d\n", ret, needed);
4171 if(pcbNeeded) *pcbNeeded = needed;
4173 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4177 /*****************************************************************************
4178 * GetPrinterW [WINSPOOL.@]
4180 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4181 DWORD cbBuf, LPDWORD pcbNeeded)
4183 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4187 /*****************************************************************************
4188 * GetPrinterA [WINSPOOL.@]
4190 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4191 DWORD cbBuf, LPDWORD pcbNeeded)
4193 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4197 /*****************************************************************************
4198 * WINSPOOL_EnumPrinters
4200 * Implementation of EnumPrintersA|W
4202 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4203 DWORD dwLevel, LPBYTE lpbPrinters,
4204 DWORD cbBuf, LPDWORD lpdwNeeded,
4205 LPDWORD lpdwReturned, BOOL unicode)
4208 HKEY hkeyPrinters, hkeyPrinter;
4209 WCHAR PrinterName[255];
4210 DWORD needed = 0, number = 0;
4211 DWORD used, i, left;
4215 memset(lpbPrinters, 0, cbBuf);
4221 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4222 if(dwType == PRINTER_ENUM_DEFAULT)
4225 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4226 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4227 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4229 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4237 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4238 FIXME("dwType = %08x\n", dwType);
4239 SetLastError(ERROR_INVALID_FLAGS);
4243 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4245 ERR("Can't create Printers key\n");
4249 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4250 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4251 RegCloseKey(hkeyPrinters);
4252 ERR("Can't query Printers key\n");
4255 TRACE("Found %d printers\n", number);
4259 used = number * sizeof(PRINTER_INFO_1W);
4262 used = number * sizeof(PRINTER_INFO_2W);
4265 used = number * sizeof(PRINTER_INFO_4W);
4268 used = number * sizeof(PRINTER_INFO_5W);
4272 SetLastError(ERROR_INVALID_LEVEL);
4273 RegCloseKey(hkeyPrinters);
4276 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4278 for(i = 0; i < number; i++) {
4279 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4281 ERR("Can't enum key number %d\n", i);
4282 RegCloseKey(hkeyPrinters);
4285 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4286 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4288 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4289 RegCloseKey(hkeyPrinters);
4294 buf = lpbPrinters + used;
4295 left = cbBuf - used;
4303 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4304 left, &needed, unicode);
4306 if(pi) pi += sizeof(PRINTER_INFO_1W);
4309 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4310 left, &needed, unicode);
4312 if(pi) pi += sizeof(PRINTER_INFO_2W);
4315 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4316 left, &needed, unicode);
4318 if(pi) pi += sizeof(PRINTER_INFO_4W);
4321 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4322 left, &needed, unicode);
4324 if(pi) pi += sizeof(PRINTER_INFO_5W);
4327 ERR("Shouldn't be here!\n");
4328 RegCloseKey(hkeyPrinter);
4329 RegCloseKey(hkeyPrinters);
4332 RegCloseKey(hkeyPrinter);
4334 RegCloseKey(hkeyPrinters);
4341 memset(lpbPrinters, 0, cbBuf);
4342 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4346 *lpdwReturned = number;
4347 SetLastError(ERROR_SUCCESS);
4352 /******************************************************************
4353 * EnumPrintersW [WINSPOOL.@]
4355 * Enumerates the available printers, print servers and print
4356 * providers, depending on the specified flags, name and level.
4360 * If level is set to 1:
4361 * Returns an array of PRINTER_INFO_1 data structures in the
4362 * lpbPrinters buffer.
4364 * If level is set to 2:
4365 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4366 * Returns an array of PRINTER_INFO_2 data structures in the
4367 * lpbPrinters buffer. Note that according to MSDN also an
4368 * OpenPrinter should be performed on every remote printer.
4370 * If level is set to 4 (officially WinNT only):
4371 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4372 * Fast: Only the registry is queried to retrieve printer names,
4373 * no connection to the driver is made.
4374 * Returns an array of PRINTER_INFO_4 data structures in the
4375 * lpbPrinters buffer.
4377 * If level is set to 5 (officially WinNT4/Win9x only):
4378 * Fast: Only the registry is queried to retrieve printer names,
4379 * no connection to the driver is made.
4380 * Returns an array of PRINTER_INFO_5 data structures in the
4381 * lpbPrinters buffer.
4383 * If level set to 3 or 6+:
4384 * returns zero (failure!)
4386 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4390 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4391 * - Only levels 2, 4 and 5 are implemented at the moment.
4392 * - 16-bit printer drivers are not enumerated.
4393 * - Returned amount of bytes used/needed does not match the real Windoze
4394 * implementation (as in this implementation, all strings are part
4395 * of the buffer, whereas Win32 keeps them somewhere else)
4396 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4399 * - In a regular Wine installation, no registry settings for printers
4400 * exist, which makes this function return an empty list.
4402 BOOL WINAPI EnumPrintersW(
4403 DWORD dwType, /* [in] Types of print objects to enumerate */
4404 LPWSTR lpszName, /* [in] name of objects to enumerate */
4405 DWORD dwLevel, /* [in] type of printer info structure */
4406 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4407 DWORD cbBuf, /* [in] max size of buffer in bytes */
4408 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4409 LPDWORD lpdwReturned /* [out] number of entries returned */
4412 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4413 lpdwNeeded, lpdwReturned, TRUE);
4416 /******************************************************************
4417 * EnumPrintersA [WINSPOOL.@]
4420 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4421 DWORD dwLevel, LPBYTE lpbPrinters,
4422 DWORD cbBuf, LPDWORD lpdwNeeded,
4423 LPDWORD lpdwReturned)
4425 BOOL ret, unicode = FALSE;
4426 UNICODE_STRING lpszNameW;
4429 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4430 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4431 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4432 lpdwNeeded, lpdwReturned, unicode);
4433 RtlFreeUnicodeString(&lpszNameW);
4437 /*****************************************************************************
4438 * WINSPOOL_GetDriverInfoFromReg [internal]
4440 * Enters the information from the registry into the DRIVER_INFO struct
4443 * zero if the printer driver does not exist in the registry
4444 * (only if Level > 1) otherwise nonzero
4446 static BOOL WINSPOOL_GetDriverInfoFromReg(
4449 const printenv_t * env,
4451 LPBYTE ptr, /* DRIVER_INFO */
4452 LPBYTE pDriverStrings, /* strings buffer */
4453 DWORD cbBuf, /* size of string buffer */
4454 LPDWORD pcbNeeded, /* space needed for str. */
4455 BOOL unicode) /* type of strings */
4459 WCHAR driverdir[MAX_PATH];
4461 LPBYTE strPtr = pDriverStrings;
4462 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4464 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4465 debugstr_w(DriverName), env,
4466 Level, di, pDriverStrings, cbBuf, unicode);
4468 if (di) ZeroMemory(di, di_sizeof[Level]);
4471 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4472 if (*pcbNeeded <= cbBuf)
4473 strcpyW((LPWSTR)strPtr, DriverName);
4477 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4478 if (*pcbNeeded <= cbBuf)
4479 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4482 /* pName for level 1 has a different offset! */
4484 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4488 /* .cVersion and .pName for level > 1 */
4490 di->cVersion = env->driverversion;
4491 di->pName = (LPWSTR) strPtr;
4492 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4495 /* Reserve Space for the largest subdir and a Backslash*/
4496 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4497 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4498 /* Should never Fail */
4501 lstrcatW(driverdir, env->versionsubdir);
4502 lstrcatW(driverdir, backslashW);
4504 /* dirlen must not include the terminating zero */
4505 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4506 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4508 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4509 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4510 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4516 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4518 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4521 if (*pcbNeeded <= cbBuf) {
4523 lstrcpyW((LPWSTR)strPtr, env->envname);
4527 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4529 if (di) di->pEnvironment = (LPWSTR)strPtr;
4530 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4533 /* .pDriverPath is the Graphics rendering engine.
4534 The full Path is required to avoid a crash in some apps */
4535 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4537 if (*pcbNeeded <= cbBuf)
4538 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4540 if (di) di->pDriverPath = (LPWSTR)strPtr;
4541 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4544 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4545 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4547 if (*pcbNeeded <= cbBuf)
4548 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4550 if (di) di->pDataFile = (LPWSTR)strPtr;
4551 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4554 /* .pConfigFile is the Driver user Interface */
4555 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4557 if (*pcbNeeded <= cbBuf)
4558 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4560 if (di) di->pConfigFile = (LPWSTR)strPtr;
4561 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4565 RegCloseKey(hkeyDriver);
4566 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4571 RegCloseKey(hkeyDriver);
4572 FIXME("level 5: incomplete\n");
4577 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4579 if (*pcbNeeded <= cbBuf)
4580 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4582 if (di) di->pHelpFile = (LPWSTR)strPtr;
4583 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4586 /* .pDependentFiles */
4587 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4589 if (*pcbNeeded <= cbBuf)
4590 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4592 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4593 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4595 else if (GetVersion() & 0x80000000) {
4596 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4597 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4599 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4601 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4602 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4605 /* .pMonitorName is the optional Language Monitor */
4606 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4608 if (*pcbNeeded <= cbBuf)
4609 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4611 if (di) di->pMonitorName = (LPWSTR)strPtr;
4612 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4615 /* .pDefaultDataType */
4616 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4618 if(*pcbNeeded <= cbBuf)
4619 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4621 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4622 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4626 RegCloseKey(hkeyDriver);
4627 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4631 /* .pszzPreviousNames */
4632 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4634 if(*pcbNeeded <= cbBuf)
4635 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4637 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4638 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4642 RegCloseKey(hkeyDriver);
4643 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4647 /* support is missing, but not important enough for a FIXME */
4648 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4651 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4653 if(*pcbNeeded <= cbBuf)
4654 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4656 if (di) di->pszMfgName = (LPWSTR)strPtr;
4657 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4661 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4663 if(*pcbNeeded <= cbBuf)
4664 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4666 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4667 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4670 /* .pszHardwareID */
4671 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4673 if(*pcbNeeded <= cbBuf)
4674 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4676 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4677 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4681 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4683 if(*pcbNeeded <= cbBuf)
4684 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4686 if (di) di->pszProvider = (LPWSTR)strPtr;
4687 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4691 RegCloseKey(hkeyDriver);
4695 /* support is missing, but not important enough for a FIXME */
4696 TRACE("level 8: incomplete\n");
4698 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4699 RegCloseKey(hkeyDriver);
4703 /*****************************************************************************
4704 * WINSPOOL_GetPrinterDriver
4706 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4707 DWORD Level, LPBYTE pDriverInfo,
4708 DWORD cbBuf, LPDWORD pcbNeeded,
4712 WCHAR DriverName[100];
4713 DWORD ret, type, size, needed = 0;
4715 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4716 const printenv_t * env;
4718 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4719 Level,pDriverInfo,cbBuf, pcbNeeded);
4722 if (!(name = get_opened_printer_name(hPrinter))) {
4723 SetLastError(ERROR_INVALID_HANDLE);
4727 if (Level < 1 || Level == 7 || Level > 8) {
4728 SetLastError(ERROR_INVALID_LEVEL);
4732 env = validate_envW(pEnvironment);
4733 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4735 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4737 ERR("Can't create Printers key\n");
4740 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4742 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4743 RegCloseKey(hkeyPrinters);
4744 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4747 size = sizeof(DriverName);
4749 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4750 (LPBYTE)DriverName, &size);
4751 RegCloseKey(hkeyPrinter);
4752 RegCloseKey(hkeyPrinters);
4753 if(ret != ERROR_SUCCESS) {
4754 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4758 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4760 ERR("Can't create Drivers key\n");
4764 size = di_sizeof[Level];
4765 if ((size <= cbBuf) && pDriverInfo)
4766 ptr = pDriverInfo + size;
4768 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4769 env, Level, pDriverInfo, ptr,
4770 (cbBuf < size) ? 0 : cbBuf - size,
4771 &needed, unicode)) {
4772 RegCloseKey(hkeyDrivers);
4776 RegCloseKey(hkeyDrivers);
4778 if(pcbNeeded) *pcbNeeded = size + needed;
4779 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4780 if(cbBuf >= needed) return TRUE;
4781 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4785 /*****************************************************************************
4786 * GetPrinterDriverA [WINSPOOL.@]
4788 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4789 DWORD Level, LPBYTE pDriverInfo,
4790 DWORD cbBuf, LPDWORD pcbNeeded)
4793 UNICODE_STRING pEnvW;
4796 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4797 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4798 cbBuf, pcbNeeded, FALSE);
4799 RtlFreeUnicodeString(&pEnvW);
4802 /*****************************************************************************
4803 * GetPrinterDriverW [WINSPOOL.@]
4805 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4806 DWORD Level, LPBYTE pDriverInfo,
4807 DWORD cbBuf, LPDWORD pcbNeeded)
4809 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4810 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4813 /*****************************************************************************
4814 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4816 * Return the PATH for the Printer-Drivers (UNICODE)
4819 * pName [I] Servername (NT only) or NULL (local Computer)
4820 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4821 * Level [I] Structure-Level (must be 1)
4822 * pDriverDirectory [O] PTR to Buffer that receives the Result
4823 * cbBuf [I] Size of Buffer at pDriverDirectory
4824 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4825 * required for pDriverDirectory
4828 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4829 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4830 * if cbBuf is too small
4832 * Native Values returned in pDriverDirectory on Success:
4833 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4834 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4835 *| win9x(Windows 4.0): "%winsysdir%"
4837 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4840 *- Only NULL or "" is supported for pName
4843 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4844 DWORD Level, LPBYTE pDriverDirectory,
4845 DWORD cbBuf, LPDWORD pcbNeeded)
4848 const printenv_t * env;
4850 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4851 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4852 if(pName != NULL && pName[0]) {
4853 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4854 SetLastError(ERROR_INVALID_PARAMETER);
4858 env = validate_envW(pEnvironment);
4859 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4862 WARN("(Level: %d) is ignored in win9x\n", Level);
4863 SetLastError(ERROR_INVALID_LEVEL);
4867 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4868 needed = GetSystemDirectoryW(NULL, 0);
4869 /* add the Size for the Subdirectories */
4870 needed += lstrlenW(spooldriversW);
4871 needed += lstrlenW(env->subdir);
4872 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4875 *pcbNeeded = needed;
4876 TRACE("required: 0x%x/%d\n", needed, needed);
4877 if(needed > cbBuf) {
4878 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4881 if(pcbNeeded == NULL) {
4882 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4883 SetLastError(RPC_X_NULL_REF_POINTER);
4886 if(pDriverDirectory == NULL) {
4887 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4888 SetLastError(ERROR_INVALID_USER_BUFFER);
4892 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4893 /* add the Subdirectories */
4894 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4895 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4896 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4901 /*****************************************************************************
4902 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4904 * Return the PATH for the Printer-Drivers (ANSI)
4906 * See GetPrinterDriverDirectoryW.
4909 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4912 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4913 DWORD Level, LPBYTE pDriverDirectory,
4914 DWORD cbBuf, LPDWORD pcbNeeded)
4916 UNICODE_STRING nameW, environmentW;
4919 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4920 WCHAR *driverDirectoryW = NULL;
4922 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4923 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4925 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4927 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4928 else nameW.Buffer = NULL;
4929 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4930 else environmentW.Buffer = NULL;
4932 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4933 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4936 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4937 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4939 *pcbNeeded = needed;
4940 ret = (needed <= cbBuf) ? TRUE : FALSE;
4942 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4944 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4946 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4947 RtlFreeUnicodeString(&environmentW);
4948 RtlFreeUnicodeString(&nameW);
4953 /*****************************************************************************
4954 * AddPrinterDriverA [WINSPOOL.@]
4956 * See AddPrinterDriverW.
4959 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4961 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4962 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4965 /******************************************************************************
4966 * AddPrinterDriverW (WINSPOOL.@)
4968 * Install a Printer Driver
4971 * pName [I] Servername or NULL (local Computer)
4972 * level [I] Level for the supplied DRIVER_INFO_*W struct
4973 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4980 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4982 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4983 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4986 /*****************************************************************************
4987 * AddPrintProcessorA [WINSPOOL.@]
4989 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4990 LPSTR pPrintProcessorName)
4992 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4993 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4997 /*****************************************************************************
4998 * AddPrintProcessorW [WINSPOOL.@]
5000 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5001 LPWSTR pPrintProcessorName)
5003 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5004 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5008 /*****************************************************************************
5009 * AddPrintProvidorA [WINSPOOL.@]
5011 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5013 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5017 /*****************************************************************************
5018 * AddPrintProvidorW [WINSPOOL.@]
5020 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5022 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5026 /*****************************************************************************
5027 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5029 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5030 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5032 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5033 pDevModeOutput, pDevModeInput);
5037 /*****************************************************************************
5038 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5040 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5041 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5043 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5044 pDevModeOutput, pDevModeInput);
5048 /*****************************************************************************
5049 * PrinterProperties [WINSPOOL.@]
5051 * Displays a dialog to set the properties of the printer.
5054 * nonzero on success or zero on failure
5057 * implemented as stub only
5059 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5060 HANDLE hPrinter /* [in] handle to printer object */
5062 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5063 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5067 /*****************************************************************************
5068 * EnumJobsA [WINSPOOL.@]
5071 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5072 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5075 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5076 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5078 if(pcbNeeded) *pcbNeeded = 0;
5079 if(pcReturned) *pcReturned = 0;
5084 /*****************************************************************************
5085 * EnumJobsW [WINSPOOL.@]
5088 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5089 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5092 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5093 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5095 if(pcbNeeded) *pcbNeeded = 0;
5096 if(pcReturned) *pcReturned = 0;
5100 /*****************************************************************************
5101 * WINSPOOL_EnumPrinterDrivers [internal]
5103 * Delivers information about all printer drivers installed on the
5104 * localhost or a given server
5107 * nonzero on success or zero on failure. If the buffer for the returned
5108 * information is too small the function will return an error
5111 * - only implemented for localhost, foreign hosts will return an error
5113 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5114 DWORD Level, LPBYTE pDriverInfo,
5115 DWORD cbBuf, LPDWORD pcbNeeded,
5116 LPDWORD pcReturned, BOOL unicode)
5119 DWORD i, needed, number = 0, size = 0;
5120 WCHAR DriverNameW[255];
5122 const printenv_t * env;
5124 TRACE("%s,%s,%d,%p,%d,%d\n",
5125 debugstr_w(pName), debugstr_w(pEnvironment),
5126 Level, pDriverInfo, cbBuf, unicode);
5128 /* check for local drivers */
5129 if((pName) && (pName[0])) {
5130 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5131 SetLastError(ERROR_ACCESS_DENIED);
5135 env = validate_envW(pEnvironment);
5136 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5138 /* check input parameter */
5139 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5140 SetLastError(ERROR_INVALID_LEVEL);
5144 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5145 SetLastError(RPC_X_NULL_REF_POINTER);
5149 /* initialize return values */
5151 memset( pDriverInfo, 0, cbBuf);
5155 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5157 ERR("Can't open Drivers key\n");
5161 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5162 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5163 RegCloseKey(hkeyDrivers);
5164 ERR("Can't query Drivers key\n");
5167 TRACE("Found %d Drivers\n", number);
5169 /* get size of single struct
5170 * unicode and ascii structure have the same size
5172 size = di_sizeof[Level];
5174 /* calculate required buffer size */
5175 *pcbNeeded = size * number;
5177 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5179 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5180 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5182 ERR("Can't enum key number %d\n", i);
5183 RegCloseKey(hkeyDrivers);
5186 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5188 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5189 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5190 &needed, unicode)) {
5191 RegCloseKey(hkeyDrivers);
5194 (*pcbNeeded) += needed;
5197 RegCloseKey(hkeyDrivers);
5199 if(cbBuf < *pcbNeeded){
5200 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5204 *pcReturned = number;
5208 /*****************************************************************************
5209 * EnumPrinterDriversW [WINSPOOL.@]
5211 * see function EnumPrinterDrivers for RETURNS, BUGS
5213 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5214 LPBYTE pDriverInfo, DWORD cbBuf,
5215 LPDWORD pcbNeeded, LPDWORD pcReturned)
5217 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5218 cbBuf, pcbNeeded, pcReturned, TRUE);
5221 /*****************************************************************************
5222 * EnumPrinterDriversA [WINSPOOL.@]
5224 * see function EnumPrinterDrivers for RETURNS, BUGS
5226 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5227 LPBYTE pDriverInfo, DWORD cbBuf,
5228 LPDWORD pcbNeeded, LPDWORD pcReturned)
5230 UNICODE_STRING pNameW, pEnvironmentW;
5231 PWSTR pwstrNameW, pwstrEnvironmentW;
5233 pwstrNameW = asciitounicode(&pNameW, pName);
5234 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5236 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5237 Level, pDriverInfo, cbBuf, pcbNeeded,
5239 RtlFreeUnicodeString(&pNameW);
5240 RtlFreeUnicodeString(&pEnvironmentW);
5245 /******************************************************************************
5246 * EnumPortsA (WINSPOOL.@)
5251 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5252 LPDWORD pcbNeeded, LPDWORD pcReturned)
5255 LPBYTE bufferW = NULL;
5256 LPWSTR nameW = NULL;
5258 DWORD numentries = 0;
5261 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5262 cbBuf, pcbNeeded, pcReturned);
5264 /* convert servername to unicode */
5266 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5267 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5268 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5270 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5271 needed = cbBuf * sizeof(WCHAR);
5272 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5273 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5275 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5276 if (pcbNeeded) needed = *pcbNeeded;
5277 /* HeapReAlloc return NULL, when bufferW was NULL */
5278 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5279 HeapAlloc(GetProcessHeap(), 0, needed);
5281 /* Try again with the large Buffer */
5282 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5284 needed = pcbNeeded ? *pcbNeeded : 0;
5285 numentries = pcReturned ? *pcReturned : 0;
5288 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5289 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5292 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5293 DWORD entrysize = 0;
5296 LPPORT_INFO_2W pi2w;
5297 LPPORT_INFO_2A pi2a;
5300 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5302 /* First pass: calculate the size for all Entries */
5303 pi2w = (LPPORT_INFO_2W) bufferW;
5304 pi2a = (LPPORT_INFO_2A) pPorts;
5306 while (index < numentries) {
5308 needed += entrysize; /* PORT_INFO_?A */
5309 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5311 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5312 NULL, 0, NULL, NULL);
5314 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5315 NULL, 0, NULL, NULL);
5316 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5317 NULL, 0, NULL, NULL);
5319 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5320 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5321 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5324 /* check for errors and quit on failure */
5325 if (cbBuf < needed) {
5326 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5330 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5331 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5332 cbBuf -= len ; /* free Bytes in the user-Buffer */
5333 pi2w = (LPPORT_INFO_2W) bufferW;
5334 pi2a = (LPPORT_INFO_2A) pPorts;
5336 /* Second Pass: Fill the User Buffer (if we have one) */
5337 while ((index < numentries) && pPorts) {
5339 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5340 pi2a->pPortName = ptr;
5341 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5342 ptr, cbBuf , NULL, NULL);
5346 pi2a->pMonitorName = ptr;
5347 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5348 ptr, cbBuf, NULL, NULL);
5352 pi2a->pDescription = ptr;
5353 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5354 ptr, cbBuf, NULL, NULL);
5358 pi2a->fPortType = pi2w->fPortType;
5359 pi2a->Reserved = 0; /* documented: "must be zero" */
5362 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5363 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5364 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5369 if (pcbNeeded) *pcbNeeded = needed;
5370 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5372 HeapFree(GetProcessHeap(), 0, nameW);
5373 HeapFree(GetProcessHeap(), 0, bufferW);
5375 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5376 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5382 /******************************************************************************
5383 * EnumPortsW (WINSPOOL.@)
5385 * Enumerate available Ports
5388 * name [I] Servername or NULL (local Computer)
5389 * level [I] Structure-Level (1 or 2)
5390 * buffer [O] PTR to Buffer that receives the Result
5391 * bufsize [I] Size of Buffer at buffer
5392 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5393 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5397 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5401 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5404 DWORD numentries = 0;
5407 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5408 cbBuf, pcbNeeded, pcReturned);
5410 if (pName && (pName[0])) {
5411 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5412 SetLastError(ERROR_ACCESS_DENIED);
5416 /* Level is not checked in win9x */
5417 if (!Level || (Level > 2)) {
5418 WARN("level (%d) is ignored in win9x\n", Level);
5419 SetLastError(ERROR_INVALID_LEVEL);
5423 SetLastError(RPC_X_NULL_REF_POINTER);
5427 EnterCriticalSection(&monitor_handles_cs);
5430 /* Scan all local Ports */
5432 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5434 /* we calculated the needed buffersize. now do the error-checks */
5435 if (cbBuf < needed) {
5436 monitor_unloadall();
5437 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5438 goto emP_cleanup_cs;
5440 else if (!pPorts || !pcReturned) {
5441 monitor_unloadall();
5442 SetLastError(RPC_X_NULL_REF_POINTER);
5443 goto emP_cleanup_cs;
5446 /* Fill the Buffer */
5447 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5449 monitor_unloadall();
5452 LeaveCriticalSection(&monitor_handles_cs);
5455 if (pcbNeeded) *pcbNeeded = needed;
5456 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5458 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5459 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5464 /******************************************************************************
5465 * GetDefaultPrinterW (WINSPOOL.@)
5468 * This function must read the value from data 'device' of key
5469 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5471 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5475 WCHAR *buffer, *ptr;
5479 SetLastError(ERROR_INVALID_PARAMETER);
5483 /* make the buffer big enough for the stuff from the profile/registry,
5484 * the content must fit into the local buffer to compute the correct
5485 * size even if the extern buffer is too small or not given.
5486 * (20 for ,driver,port) */
5488 len = max(100, (insize + 20));
5489 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5491 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5493 SetLastError (ERROR_FILE_NOT_FOUND);
5497 TRACE("%s\n", debugstr_w(buffer));
5499 if ((ptr = strchrW(buffer, ',')) == NULL)
5501 SetLastError(ERROR_INVALID_NAME);
5507 *namesize = strlenW(buffer) + 1;
5508 if(!name || (*namesize > insize))
5510 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5514 strcpyW(name, buffer);
5517 HeapFree( GetProcessHeap(), 0, buffer);
5522 /******************************************************************************
5523 * GetDefaultPrinterA (WINSPOOL.@)
5525 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5529 WCHAR *bufferW = NULL;
5533 SetLastError(ERROR_INVALID_PARAMETER);
5537 if(name && *namesize) {
5539 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5542 if(!GetDefaultPrinterW( bufferW, namesize)) {
5547 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5551 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5554 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5557 HeapFree( GetProcessHeap(), 0, bufferW);
5562 /******************************************************************************
5563 * SetDefaultPrinterW (WINSPOOL.204)
5565 * Set the Name of the Default Printer
5568 * pszPrinter [I] Name of the Printer or NULL
5575 * When the Parameter is NULL or points to an Empty String and
5576 * a Default Printer was already present, then this Function changes nothing.
5577 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5578 * the First enumerated local Printer is used.
5581 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5584 TRACE("(%s)\n", debugstr_w(pszPrinter));
5586 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5590 /******************************************************************************
5591 * SetDefaultPrinterA (WINSPOOL.202)
5593 * See SetDefaultPrinterW.
5596 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5599 TRACE("(%s)\n", debugstr_a(pszPrinter));
5601 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5606 /******************************************************************************
5607 * SetPrinterDataExA (WINSPOOL.@)
5609 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5610 LPCSTR pValueName, DWORD Type,
5611 LPBYTE pData, DWORD cbData)
5613 HKEY hkeyPrinter, hkeySubkey;
5616 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5617 debugstr_a(pValueName), Type, pData, cbData);
5619 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5623 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5625 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5626 RegCloseKey(hkeyPrinter);
5629 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5630 RegCloseKey(hkeySubkey);
5631 RegCloseKey(hkeyPrinter);
5635 /******************************************************************************
5636 * SetPrinterDataExW (WINSPOOL.@)
5638 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5639 LPCWSTR pValueName, DWORD Type,
5640 LPBYTE pData, DWORD cbData)
5642 HKEY hkeyPrinter, hkeySubkey;
5645 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5646 debugstr_w(pValueName), Type, pData, cbData);
5648 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5652 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5654 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5655 RegCloseKey(hkeyPrinter);
5658 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5659 RegCloseKey(hkeySubkey);
5660 RegCloseKey(hkeyPrinter);
5664 /******************************************************************************
5665 * SetPrinterDataA (WINSPOOL.@)
5667 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5668 LPBYTE pData, DWORD cbData)
5670 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5674 /******************************************************************************
5675 * SetPrinterDataW (WINSPOOL.@)
5677 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5678 LPBYTE pData, DWORD cbData)
5680 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5684 /******************************************************************************
5685 * GetPrinterDataExA (WINSPOOL.@)
5687 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5688 LPCSTR pValueName, LPDWORD pType,
5689 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5691 HKEY hkeyPrinter, hkeySubkey;
5694 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5695 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5698 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5702 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5704 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5705 RegCloseKey(hkeyPrinter);
5709 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5710 RegCloseKey(hkeySubkey);
5711 RegCloseKey(hkeyPrinter);
5715 /******************************************************************************
5716 * GetPrinterDataExW (WINSPOOL.@)
5718 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5719 LPCWSTR pValueName, LPDWORD pType,
5720 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5722 HKEY hkeyPrinter, hkeySubkey;
5725 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5726 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5729 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5733 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5735 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5736 RegCloseKey(hkeyPrinter);
5740 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5741 RegCloseKey(hkeySubkey);
5742 RegCloseKey(hkeyPrinter);
5746 /******************************************************************************
5747 * GetPrinterDataA (WINSPOOL.@)
5749 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5750 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5752 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5753 pData, nSize, pcbNeeded);
5756 /******************************************************************************
5757 * GetPrinterDataW (WINSPOOL.@)
5759 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5760 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5762 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5763 pData, nSize, pcbNeeded);
5766 /*******************************************************************************
5767 * EnumPrinterDataExW [WINSPOOL.@]
5769 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5770 LPBYTE pEnumValues, DWORD cbEnumValues,
5771 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5773 HKEY hkPrinter, hkSubKey;
5774 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5775 cbValueNameLen, cbMaxValueLen, cbValueLen,
5780 PPRINTER_ENUM_VALUESW ppev;
5782 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5784 if (pKeyName == NULL || *pKeyName == 0)
5785 return ERROR_INVALID_PARAMETER;
5787 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5788 if (ret != ERROR_SUCCESS)
5790 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5795 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5796 if (ret != ERROR_SUCCESS)
5798 r = RegCloseKey (hkPrinter);
5799 if (r != ERROR_SUCCESS)
5800 WARN ("RegCloseKey returned %i\n", r);
5801 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5802 debugstr_w (pKeyName), ret);
5806 ret = RegCloseKey (hkPrinter);
5807 if (ret != ERROR_SUCCESS)
5809 ERR ("RegCloseKey returned %i\n", ret);
5810 r = RegCloseKey (hkSubKey);
5811 if (r != ERROR_SUCCESS)
5812 WARN ("RegCloseKey returned %i\n", r);
5816 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5817 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5818 if (ret != ERROR_SUCCESS)
5820 r = RegCloseKey (hkSubKey);
5821 if (r != ERROR_SUCCESS)
5822 WARN ("RegCloseKey returned %i\n", r);
5823 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5827 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5828 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5830 if (cValues == 0) /* empty key */
5832 r = RegCloseKey (hkSubKey);
5833 if (r != ERROR_SUCCESS)
5834 WARN ("RegCloseKey returned %i\n", r);
5835 *pcbEnumValues = *pnEnumValues = 0;
5836 return ERROR_SUCCESS;
5839 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5841 hHeap = GetProcessHeap ();
5844 ERR ("GetProcessHeap failed\n");
5845 r = RegCloseKey (hkSubKey);
5846 if (r != ERROR_SUCCESS)
5847 WARN ("RegCloseKey returned %i\n", r);
5848 return ERROR_OUTOFMEMORY;
5851 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5852 if (lpValueName == NULL)
5854 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5855 r = RegCloseKey (hkSubKey);
5856 if (r != ERROR_SUCCESS)
5857 WARN ("RegCloseKey returned %i\n", r);
5858 return ERROR_OUTOFMEMORY;
5861 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5862 if (lpValue == NULL)
5864 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5865 if (HeapFree (hHeap, 0, lpValueName) == 0)
5866 WARN ("HeapFree failed with code %i\n", GetLastError ());
5867 r = RegCloseKey (hkSubKey);
5868 if (r != ERROR_SUCCESS)
5869 WARN ("RegCloseKey returned %i\n", r);
5870 return ERROR_OUTOFMEMORY;
5873 TRACE ("pass 1: calculating buffer required for all names and values\n");
5875 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5877 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5879 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5881 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5882 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5883 NULL, NULL, lpValue, &cbValueLen);
5884 if (ret != ERROR_SUCCESS)
5886 if (HeapFree (hHeap, 0, lpValue) == 0)
5887 WARN ("HeapFree failed with code %i\n", GetLastError ());
5888 if (HeapFree (hHeap, 0, lpValueName) == 0)
5889 WARN ("HeapFree failed with code %i\n", GetLastError ());
5890 r = RegCloseKey (hkSubKey);
5891 if (r != ERROR_SUCCESS)
5892 WARN ("RegCloseKey returned %i\n", r);
5893 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5897 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5898 debugstr_w (lpValueName), dwIndex,
5899 cbValueNameLen + 1, cbValueLen);
5901 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5902 cbBufSize += cbValueLen;
5905 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5907 *pcbEnumValues = cbBufSize;
5908 *pnEnumValues = cValues;
5910 if (cbEnumValues < cbBufSize) /* buffer too small */
5912 if (HeapFree (hHeap, 0, lpValue) == 0)
5913 WARN ("HeapFree failed with code %i\n", GetLastError ());
5914 if (HeapFree (hHeap, 0, lpValueName) == 0)
5915 WARN ("HeapFree failed with code %i\n", GetLastError ());
5916 r = RegCloseKey (hkSubKey);
5917 if (r != ERROR_SUCCESS)
5918 WARN ("RegCloseKey returned %i\n", r);
5919 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5920 return ERROR_MORE_DATA;
5923 TRACE ("pass 2: copying all names and values to buffer\n");
5925 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5926 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5928 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5930 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5931 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5932 NULL, &dwType, lpValue, &cbValueLen);
5933 if (ret != ERROR_SUCCESS)
5935 if (HeapFree (hHeap, 0, lpValue) == 0)
5936 WARN ("HeapFree failed with code %i\n", GetLastError ());
5937 if (HeapFree (hHeap, 0, lpValueName) == 0)
5938 WARN ("HeapFree failed with code %i\n", GetLastError ());
5939 r = RegCloseKey (hkSubKey);
5940 if (r != ERROR_SUCCESS)
5941 WARN ("RegCloseKey returned %i\n", r);
5942 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5946 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5947 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5948 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5949 pEnumValues += cbValueNameLen;
5951 /* return # of *bytes* (including trailing \0), not # of chars */
5952 ppev[dwIndex].cbValueName = cbValueNameLen;
5954 ppev[dwIndex].dwType = dwType;
5956 memcpy (pEnumValues, lpValue, cbValueLen);
5957 ppev[dwIndex].pData = pEnumValues;
5958 pEnumValues += cbValueLen;
5960 ppev[dwIndex].cbData = cbValueLen;
5962 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5963 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5966 if (HeapFree (hHeap, 0, lpValue) == 0)
5968 ret = GetLastError ();
5969 ERR ("HeapFree failed with code %i\n", ret);
5970 if (HeapFree (hHeap, 0, lpValueName) == 0)
5971 WARN ("HeapFree failed with code %i\n", GetLastError ());
5972 r = RegCloseKey (hkSubKey);
5973 if (r != ERROR_SUCCESS)
5974 WARN ("RegCloseKey returned %i\n", r);
5978 if (HeapFree (hHeap, 0, lpValueName) == 0)
5980 ret = GetLastError ();
5981 ERR ("HeapFree failed with code %i\n", ret);
5982 r = RegCloseKey (hkSubKey);
5983 if (r != ERROR_SUCCESS)
5984 WARN ("RegCloseKey returned %i\n", r);
5988 ret = RegCloseKey (hkSubKey);
5989 if (ret != ERROR_SUCCESS)
5991 ERR ("RegCloseKey returned %i\n", ret);
5995 return ERROR_SUCCESS;
5998 /*******************************************************************************
5999 * EnumPrinterDataExA [WINSPOOL.@]
6001 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6002 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6003 * what Windows 2000 SP1 does.
6006 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6007 LPBYTE pEnumValues, DWORD cbEnumValues,
6008 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6012 DWORD ret, dwIndex, dwBufSize;
6016 TRACE ("%p %s\n", hPrinter, pKeyName);
6018 if (pKeyName == NULL || *pKeyName == 0)
6019 return ERROR_INVALID_PARAMETER;
6021 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6024 ret = GetLastError ();
6025 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6029 hHeap = GetProcessHeap ();
6032 ERR ("GetProcessHeap failed\n");
6033 return ERROR_OUTOFMEMORY;
6036 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6037 if (pKeyNameW == NULL)
6039 ERR ("Failed to allocate %i bytes from process heap\n",
6040 (LONG)(len * sizeof (WCHAR)));
6041 return ERROR_OUTOFMEMORY;
6044 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6046 ret = GetLastError ();
6047 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6048 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6049 WARN ("HeapFree failed with code %i\n", GetLastError ());
6053 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6054 pcbEnumValues, pnEnumValues);
6055 if (ret != ERROR_SUCCESS)
6057 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6058 WARN ("HeapFree failed with code %i\n", GetLastError ());
6059 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6063 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6065 ret = GetLastError ();
6066 ERR ("HeapFree failed with code %i\n", ret);
6070 if (*pnEnumValues == 0) /* empty key */
6071 return ERROR_SUCCESS;
6074 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6076 PPRINTER_ENUM_VALUESW ppev =
6077 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6079 if (dwBufSize < ppev->cbValueName)
6080 dwBufSize = ppev->cbValueName;
6082 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6083 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6084 dwBufSize = ppev->cbData;
6087 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6089 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6090 if (pBuffer == NULL)
6092 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6093 return ERROR_OUTOFMEMORY;
6096 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6098 PPRINTER_ENUM_VALUESW ppev =
6099 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6101 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6102 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6106 ret = GetLastError ();
6107 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6108 if (HeapFree (hHeap, 0, pBuffer) == 0)
6109 WARN ("HeapFree failed with code %i\n", GetLastError ());
6113 memcpy (ppev->pValueName, pBuffer, len);
6115 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6117 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6118 ppev->dwType != REG_MULTI_SZ)
6121 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6122 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6125 ret = GetLastError ();
6126 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6127 if (HeapFree (hHeap, 0, pBuffer) == 0)
6128 WARN ("HeapFree failed with code %i\n", GetLastError ());
6132 memcpy (ppev->pData, pBuffer, len);
6134 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6135 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6138 if (HeapFree (hHeap, 0, pBuffer) == 0)
6140 ret = GetLastError ();
6141 ERR ("HeapFree failed with code %i\n", ret);
6145 return ERROR_SUCCESS;
6148 /******************************************************************************
6149 * AbortPrinter (WINSPOOL.@)
6151 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6153 FIXME("(%p), stub!\n", hPrinter);
6157 /******************************************************************************
6158 * AddPortA (WINSPOOL.@)
6163 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6165 LPWSTR nameW = NULL;
6166 LPWSTR monitorW = NULL;
6170 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6173 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6174 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6175 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6179 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6180 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6181 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6183 res = AddPortW(nameW, hWnd, monitorW);
6184 HeapFree(GetProcessHeap(), 0, nameW);
6185 HeapFree(GetProcessHeap(), 0, monitorW);
6189 /******************************************************************************
6190 * AddPortW (WINSPOOL.@)
6192 * Add a Port for a specific Monitor
6195 * pName [I] Servername or NULL (local Computer)
6196 * hWnd [I] Handle to parent Window for the Dialog-Box
6197 * pMonitorName [I] Name of the Monitor that manage the Port
6204 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6210 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6212 if (pName && pName[0]) {
6213 SetLastError(ERROR_INVALID_PARAMETER);
6217 if (!pMonitorName) {
6218 SetLastError(RPC_X_NULL_REF_POINTER);
6222 /* an empty Monitorname is Invalid */
6223 if (!pMonitorName[0]) {
6224 SetLastError(ERROR_NOT_SUPPORTED);
6228 pm = monitor_load(pMonitorName, NULL);
6229 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6230 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6231 TRACE("got %d with %u\n", res, GetLastError());
6236 pui = monitor_loadui(pm);
6237 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6238 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6239 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6240 TRACE("got %d with %u\n", res, GetLastError());
6245 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6246 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6248 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6249 SetLastError(ERROR_NOT_SUPPORTED);
6252 monitor_unload(pui);
6255 TRACE("returning %d with %u\n", res, GetLastError());
6259 /******************************************************************************
6260 * AddPortExA (WINSPOOL.@)
6265 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6268 PORT_INFO_2A * pi2A;
6269 LPWSTR nameW = NULL;
6270 LPWSTR monitorW = NULL;
6274 pi2A = (PORT_INFO_2A *) pBuffer;
6276 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6277 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6279 if ((level < 1) || (level > 2)) {
6280 SetLastError(ERROR_INVALID_LEVEL);
6285 SetLastError(ERROR_INVALID_PARAMETER);
6290 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6291 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6292 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6296 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6297 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6298 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6301 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6303 if (pi2A->pPortName) {
6304 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6305 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6306 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6310 if (pi2A->pMonitorName) {
6311 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6312 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6313 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6316 if (pi2A->pDescription) {
6317 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6318 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6319 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6321 pi2W.fPortType = pi2A->fPortType;
6322 pi2W.Reserved = pi2A->Reserved;
6325 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6327 HeapFree(GetProcessHeap(), 0, nameW);
6328 HeapFree(GetProcessHeap(), 0, monitorW);
6329 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6330 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6331 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6336 /******************************************************************************
6337 * AddPortExW (WINSPOOL.@)
6339 * Add a Port for a specific Monitor, without presenting a user interface
6342 * pName [I] Servername or NULL (local Computer)
6343 * level [I] Structure-Level (1 or 2) for pBuffer
6344 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6345 * pMonitorName [I] Name of the Monitor that manage the Port
6352 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6358 pi2 = (PORT_INFO_2W *) pBuffer;
6360 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6361 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6362 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6363 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6366 if ((level < 1) || (level > 2)) {
6367 SetLastError(ERROR_INVALID_LEVEL);
6371 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6372 SetLastError(ERROR_INVALID_PARAMETER);
6376 /* load the Monitor */
6377 pm = monitor_load(pMonitorName, NULL);
6379 SetLastError(ERROR_INVALID_PARAMETER);
6383 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6384 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6385 TRACE("got %u with %u\n", res, GetLastError());
6389 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6395 /******************************************************************************
6396 * AddPrinterConnectionA (WINSPOOL.@)
6398 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6400 FIXME("%s\n", debugstr_a(pName));
6404 /******************************************************************************
6405 * AddPrinterConnectionW (WINSPOOL.@)
6407 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6409 FIXME("%s\n", debugstr_w(pName));
6413 /******************************************************************************
6414 * AddPrinterDriverExW (WINSPOOL.@)
6416 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6419 * pName [I] Servername or NULL (local Computer)
6420 * level [I] Level for the supplied DRIVER_INFO_*W struct
6421 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6422 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6429 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6431 const printenv_t *env;
6441 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6443 if (level < 2 || level == 5 || level == 7 || level > 8) {
6444 SetLastError(ERROR_INVALID_LEVEL);
6449 SetLastError(ERROR_INVALID_PARAMETER);
6453 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
6454 FIXME("Flags 0x%x ignored (Fallback to APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
6457 ptr = get_servername_from_name(pName);
6458 HeapFree(GetProcessHeap(), 0, ptr);
6460 FIXME("not supported for server: %s\n", debugstr_w(pName));
6461 SetLastError(ERROR_ACCESS_DENIED);
6465 /* we need to set all entries in the Registry, independent from the Level of
6466 DRIVER_INFO, that the caller supplied */
6468 ZeroMemory(&di, sizeof(di));
6469 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
6470 memcpy(&di, pDriverInfo, di_sizeof[level]);
6473 /* dump the most used infos */
6474 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
6475 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
6476 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
6477 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
6478 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
6479 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
6480 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
6481 /* dump only the first of the additional Files */
6482 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
6485 /* check environment */
6486 env = validate_envW(di.pEnvironment);
6487 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
6489 /* fill the copy-data / get the driverdir */
6490 len = sizeof(apd.src) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
6491 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1,
6492 (LPBYTE) apd.src, len, &len)) {
6493 /* Should never Fail */
6496 memcpy(apd.dst, apd.src, len);
6497 lstrcatW(apd.src, backslashW);
6498 apd.srclen = lstrlenW(apd.src);
6499 lstrcatW(apd.dst, env->versionsubdir);
6500 lstrcatW(apd.dst, backslashW);
6501 apd.dstlen = lstrlenW(apd.dst);
6502 apd.copyflags = dwFileCopyFlags;
6503 CreateDirectoryW(apd.src, NULL);
6504 CreateDirectoryW(apd.dst, NULL);
6506 /* Fill the Registry for the Driver */
6507 hroot = WINSPOOL_OpenDriverReg(env->envname, TRUE);
6509 ERR("Can't create Drivers key\n");
6513 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
6514 KEY_WRITE | KEY_QUERY_VALUE, NULL,
6515 &hdrv, &disposition)) != ERROR_SUCCESS) {
6517 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
6524 if (disposition == REG_OPENED_EXISTING_KEY) {
6525 TRACE("driver %s already installed\n", debugstr_w(di.pName));
6527 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
6531 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
6532 RegSetValueExW(hdrv, VersionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
6535 RegSetValueExW(hdrv, DriverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
6536 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
6537 apd_copyfile(di.pDriverPath, &apd);
6539 RegSetValueExW(hdrv, Data_FileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
6540 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
6541 apd_copyfile(di.pDataFile, &apd);
6543 RegSetValueExW(hdrv, Configuration_FileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
6544 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
6545 apd_copyfile(di.pConfigFile, &apd);
6547 /* settings for level 3 */
6548 RegSetValueExW(hdrv, Help_FileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
6549 di.pHelpFile ? (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR) : 0);
6550 apd_copyfile(di.pHelpFile, &apd);
6553 ptr = di.pDependentFiles;
6554 RegSetValueExW(hdrv, Dependent_FilesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
6555 di.pDependentFiles ? multi_sz_lenW(di.pDependentFiles) : 0);
6556 while ((ptr != NULL) && (ptr[0])) {
6557 if (apd_copyfile(ptr, &apd)) {
6558 ptr += lstrlenW(ptr) + 1;
6562 WARN("Failed to copy %s\n", debugstr_w(ptr));
6567 /* The language-Monitor was already copied to "%SystemRoot%\system32" */
6568 RegSetValueExW(hdrv, MonitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
6569 di.pMonitorName ? (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR) : 0);
6571 RegSetValueExW(hdrv, DatatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
6572 di.pDefaultDataType ? (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR) : 0);
6574 /* settings for level 4 */
6575 RegSetValueExW(hdrv, Previous_NamesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
6576 di.pszzPreviousNames ? multi_sz_lenW(di.pszzPreviousNames) : 0);
6578 if (level > 5) FIXME("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
6582 FIXME("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
6585 TRACE("=> TRUE with %u\n", GetLastError());
6590 /******************************************************************************
6591 * AddPrinterDriverExA (WINSPOOL.@)
6593 * See AddPrinterDriverExW.
6596 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6598 DRIVER_INFO_8A *diA;
6600 LPWSTR nameW = NULL;
6605 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6607 diA = (DRIVER_INFO_8A *) pDriverInfo;
6608 ZeroMemory(&diW, sizeof(diW));
6610 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6611 SetLastError(ERROR_INVALID_LEVEL);
6616 SetLastError(ERROR_INVALID_PARAMETER);
6620 /* convert servername to unicode */
6622 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6623 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6624 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6628 diW.cVersion = diA->cVersion;
6631 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6632 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6633 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6636 if (diA->pEnvironment) {
6637 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6638 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6639 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6642 if (diA->pDriverPath) {
6643 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6644 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6645 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6648 if (diA->pDataFile) {
6649 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6650 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6651 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6654 if (diA->pConfigFile) {
6655 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6656 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6657 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6660 if ((Level > 2) && diA->pDependentFiles) {
6661 lenA = multi_sz_lenA(diA->pDependentFiles);
6662 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6663 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6664 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6667 if ((Level > 2) && diA->pMonitorName) {
6668 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6669 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6670 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6673 if ((Level > 3) && diA->pDefaultDataType) {
6674 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6675 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6676 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6679 if ((Level > 3) && diA->pszzPreviousNames) {
6680 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6681 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6682 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6683 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6686 if ((Level > 5) && diA->pszMfgName) {
6687 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6688 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6689 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6692 if ((Level > 5) && diA->pszOEMUrl) {
6693 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6694 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6695 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6698 if ((Level > 5) && diA->pszHardwareID) {
6699 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6700 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6701 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6704 if ((Level > 5) && diA->pszProvider) {
6705 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6706 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6707 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6711 FIXME("level %u is incomplete\n", Level);
6714 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6715 TRACE("got %u with %u\n", res, GetLastError());
6716 HeapFree(GetProcessHeap(), 0, nameW);
6717 HeapFree(GetProcessHeap(), 0, diW.pName);
6718 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6719 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6720 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6721 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6722 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6723 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6724 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6725 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6726 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6727 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6728 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6729 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6731 TRACE("=> %u with %u\n", res, GetLastError());
6735 /******************************************************************************
6736 * ConfigurePortA (WINSPOOL.@)
6738 * See ConfigurePortW.
6741 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6743 LPWSTR nameW = NULL;
6744 LPWSTR portW = NULL;
6748 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6750 /* convert servername to unicode */
6752 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6753 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6754 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6757 /* convert portname to unicode */
6759 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6760 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6761 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6764 res = ConfigurePortW(nameW, hWnd, portW);
6765 HeapFree(GetProcessHeap(), 0, nameW);
6766 HeapFree(GetProcessHeap(), 0, portW);
6770 /******************************************************************************
6771 * ConfigurePortW (WINSPOOL.@)
6773 * Display the Configuration-Dialog for a specific Port
6776 * pName [I] Servername or NULL (local Computer)
6777 * hWnd [I] Handle to parent Window for the Dialog-Box
6778 * pPortName [I] Name of the Port, that should be configured
6785 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6791 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6793 if (pName && pName[0]) {
6794 SetLastError(ERROR_INVALID_PARAMETER);
6799 SetLastError(RPC_X_NULL_REF_POINTER);
6803 /* an empty Portname is Invalid, but can popup a Dialog */
6804 if (!pPortName[0]) {
6805 SetLastError(ERROR_NOT_SUPPORTED);
6809 pm = monitor_load_by_port(pPortName);
6810 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6811 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6812 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6813 TRACE("got %d with %u\n", res, GetLastError());
6817 pui = monitor_loadui(pm);
6818 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6819 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6820 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6821 TRACE("got %d with %u\n", res, GetLastError());
6825 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6826 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6828 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6829 SetLastError(ERROR_NOT_SUPPORTED);
6832 monitor_unload(pui);
6836 TRACE("returning %d with %u\n", res, GetLastError());
6840 /******************************************************************************
6841 * ConnectToPrinterDlg (WINSPOOL.@)
6843 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6845 FIXME("%p %x\n", hWnd, Flags);
6849 /******************************************************************************
6850 * DeletePrinterConnectionA (WINSPOOL.@)
6852 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6854 FIXME("%s\n", debugstr_a(pName));
6858 /******************************************************************************
6859 * DeletePrinterConnectionW (WINSPOOL.@)
6861 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6863 FIXME("%s\n", debugstr_w(pName));
6867 /******************************************************************************
6868 * DeletePrinterDriverExW (WINSPOOL.@)
6870 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6871 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6876 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6877 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6879 if(pName && pName[0])
6881 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6882 SetLastError(ERROR_INVALID_PARAMETER);
6888 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6889 SetLastError(ERROR_INVALID_PARAMETER);
6893 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6897 ERR("Can't open drivers key\n");
6901 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6904 RegCloseKey(hkey_drivers);
6909 /******************************************************************************
6910 * DeletePrinterDriverExA (WINSPOOL.@)
6912 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6913 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6915 UNICODE_STRING NameW, EnvW, DriverW;
6918 asciitounicode(&NameW, pName);
6919 asciitounicode(&EnvW, pEnvironment);
6920 asciitounicode(&DriverW, pDriverName);
6922 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6924 RtlFreeUnicodeString(&DriverW);
6925 RtlFreeUnicodeString(&EnvW);
6926 RtlFreeUnicodeString(&NameW);
6931 /******************************************************************************
6932 * DeletePrinterDataExW (WINSPOOL.@)
6934 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6937 FIXME("%p %s %s\n", hPrinter,
6938 debugstr_w(pKeyName), debugstr_w(pValueName));
6939 return ERROR_INVALID_PARAMETER;
6942 /******************************************************************************
6943 * DeletePrinterDataExA (WINSPOOL.@)
6945 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6948 FIXME("%p %s %s\n", hPrinter,
6949 debugstr_a(pKeyName), debugstr_a(pValueName));
6950 return ERROR_INVALID_PARAMETER;
6953 /******************************************************************************
6954 * DeletePrintProcessorA (WINSPOOL.@)
6956 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6958 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6959 debugstr_a(pPrintProcessorName));
6963 /******************************************************************************
6964 * DeletePrintProcessorW (WINSPOOL.@)
6966 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6968 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6969 debugstr_w(pPrintProcessorName));
6973 /******************************************************************************
6974 * DeletePrintProvidorA (WINSPOOL.@)
6976 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6978 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6979 debugstr_a(pPrintProviderName));
6983 /******************************************************************************
6984 * DeletePrintProvidorW (WINSPOOL.@)
6986 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6988 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6989 debugstr_w(pPrintProviderName));
6993 /******************************************************************************
6994 * EnumFormsA (WINSPOOL.@)
6996 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6997 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6999 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7000 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7004 /******************************************************************************
7005 * EnumFormsW (WINSPOOL.@)
7007 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7008 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7010 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7011 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7015 /*****************************************************************************
7016 * EnumMonitorsA [WINSPOOL.@]
7018 * See EnumMonitorsW.
7021 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7022 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7025 LPBYTE bufferW = NULL;
7026 LPWSTR nameW = NULL;
7028 DWORD numentries = 0;
7031 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7032 cbBuf, pcbNeeded, pcReturned);
7034 /* convert servername to unicode */
7036 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7037 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7038 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7040 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7041 needed = cbBuf * sizeof(WCHAR);
7042 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7043 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7045 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7046 if (pcbNeeded) needed = *pcbNeeded;
7047 /* HeapReAlloc return NULL, when bufferW was NULL */
7048 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7049 HeapAlloc(GetProcessHeap(), 0, needed);
7051 /* Try again with the large Buffer */
7052 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7054 numentries = pcReturned ? *pcReturned : 0;
7057 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7058 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7061 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7062 DWORD entrysize = 0;
7065 LPMONITOR_INFO_2W mi2w;
7066 LPMONITOR_INFO_2A mi2a;
7068 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7069 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7071 /* First pass: calculate the size for all Entries */
7072 mi2w = (LPMONITOR_INFO_2W) bufferW;
7073 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7075 while (index < numentries) {
7077 needed += entrysize; /* MONITOR_INFO_?A */
7078 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7080 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7081 NULL, 0, NULL, NULL);
7083 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7084 NULL, 0, NULL, NULL);
7085 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7086 NULL, 0, NULL, NULL);
7088 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7089 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7090 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7093 /* check for errors and quit on failure */
7094 if (cbBuf < needed) {
7095 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7099 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7100 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7101 cbBuf -= len ; /* free Bytes in the user-Buffer */
7102 mi2w = (LPMONITOR_INFO_2W) bufferW;
7103 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7105 /* Second Pass: Fill the User Buffer (if we have one) */
7106 while ((index < numentries) && pMonitors) {
7108 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7110 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7111 ptr, cbBuf , NULL, NULL);
7115 mi2a->pEnvironment = ptr;
7116 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7117 ptr, cbBuf, NULL, NULL);
7121 mi2a->pDLLName = ptr;
7122 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7123 ptr, cbBuf, NULL, NULL);
7127 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7128 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7129 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7133 if (pcbNeeded) *pcbNeeded = needed;
7134 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7136 HeapFree(GetProcessHeap(), 0, nameW);
7137 HeapFree(GetProcessHeap(), 0, bufferW);
7139 TRACE("returning %d with %d (%d byte for %d entries)\n",
7140 (res), GetLastError(), needed, numentries);
7146 /*****************************************************************************
7147 * EnumMonitorsW [WINSPOOL.@]
7149 * Enumerate available Port-Monitors
7152 * pName [I] Servername or NULL (local Computer)
7153 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7154 * pMonitors [O] PTR to Buffer that receives the Result
7155 * cbBuf [I] Size of Buffer at pMonitors
7156 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7157 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7161 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7164 * Windows reads the Registry once and cache the Results.
7166 *| Language-Monitors are also installed in the same Registry-Location but
7167 *| they are filtered in Windows (not returned by EnumMonitors).
7168 *| We do no filtering to simplify our Code.
7171 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7172 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7175 DWORD numentries = 0;
7178 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7179 cbBuf, pcbNeeded, pcReturned);
7181 if (pName && (lstrlenW(pName))) {
7182 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7183 SetLastError(ERROR_ACCESS_DENIED);
7187 /* Level is not checked in win9x */
7188 if (!Level || (Level > 2)) {
7189 WARN("level (%d) is ignored in win9x\n", Level);
7190 SetLastError(ERROR_INVALID_LEVEL);
7194 SetLastError(RPC_X_NULL_REF_POINTER);
7198 /* Scan all Monitor-Keys */
7200 needed = get_local_monitors(Level, NULL, 0, &numentries);
7202 /* we calculated the needed buffersize. now do the error-checks */
7203 if (cbBuf < needed) {
7204 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7207 else if (!pMonitors || !pcReturned) {
7208 SetLastError(RPC_X_NULL_REF_POINTER);
7212 /* fill the Buffer with the Monitor-Keys */
7213 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7217 if (pcbNeeded) *pcbNeeded = needed;
7218 if (pcReturned) *pcReturned = numentries;
7220 TRACE("returning %d with %d (%d byte for %d entries)\n",
7221 res, GetLastError(), needed, numentries);
7226 /******************************************************************************
7227 * XcvDataW (WINSPOOL.@)
7229 * Execute commands in the Printmonitor DLL
7232 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7233 * pszDataName [i] Name of the command to execute
7234 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7235 * cbInputData [i] Size in Bytes of Buffer at pInputData
7236 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7237 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7238 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7239 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7246 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7247 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7249 * Minimal List of commands, that a Printmonitor DLL should support:
7251 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7252 *| "AddPort" : Add a Port
7253 *| "DeletePort": Delete a Port
7255 * Many Printmonitors support additional commands. Examples for localspl.dll:
7256 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7257 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7260 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7261 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7262 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7264 opened_printer_t *printer;
7266 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7267 pInputData, cbInputData, pOutputData,
7268 cbOutputData, pcbOutputNeeded, pdwStatus);
7270 printer = get_opened_printer(hXcv);
7271 if (!printer || (!printer->hXcv)) {
7272 SetLastError(ERROR_INVALID_HANDLE);
7276 if (!pcbOutputNeeded) {
7277 SetLastError(ERROR_INVALID_PARAMETER);
7281 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7282 SetLastError(RPC_X_NULL_REF_POINTER);
7286 *pcbOutputNeeded = 0;
7288 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7289 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7294 /*****************************************************************************
7295 * EnumPrinterDataA [WINSPOOL.@]
7298 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7299 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7300 DWORD cbData, LPDWORD pcbData )
7302 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7303 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7304 return ERROR_NO_MORE_ITEMS;
7307 /*****************************************************************************
7308 * EnumPrinterDataW [WINSPOOL.@]
7311 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7312 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7313 DWORD cbData, LPDWORD pcbData )
7315 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7316 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7317 return ERROR_NO_MORE_ITEMS;
7320 /*****************************************************************************
7321 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7324 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7325 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7326 LPDWORD pcbNeeded, LPDWORD pcReturned)
7328 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7329 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7330 pcbNeeded, pcReturned);
7334 /*****************************************************************************
7335 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7338 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7339 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7340 LPDWORD pcbNeeded, LPDWORD pcReturned)
7342 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7343 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7344 pcbNeeded, pcReturned);
7348 /*****************************************************************************
7349 * EnumPrintProcessorsA [WINSPOOL.@]
7352 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7353 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7355 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7356 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7360 /*****************************************************************************
7361 * EnumPrintProcessorsW [WINSPOOL.@]
7364 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7365 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7367 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7368 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7369 cbBuf, pcbNeeded, pcbReturned);
7373 /*****************************************************************************
7374 * ExtDeviceMode [WINSPOOL.@]
7377 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7378 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7381 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7382 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7383 debugstr_a(pProfile), fMode);
7387 /*****************************************************************************
7388 * FindClosePrinterChangeNotification [WINSPOOL.@]
7391 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7393 FIXME("Stub: %p\n", hChange);
7397 /*****************************************************************************
7398 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7401 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7402 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7404 FIXME("Stub: %p %x %x %p\n",
7405 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7406 return INVALID_HANDLE_VALUE;
7409 /*****************************************************************************
7410 * FindNextPrinterChangeNotification [WINSPOOL.@]
7413 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7414 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7416 FIXME("Stub: %p %p %p %p\n",
7417 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7421 /*****************************************************************************
7422 * FreePrinterNotifyInfo [WINSPOOL.@]
7425 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7427 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7431 /*****************************************************************************
7434 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7435 * ansi depending on the unicode parameter.
7437 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7447 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7450 memcpy(ptr, str, *size);
7457 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7460 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7467 /*****************************************************************************
7470 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7471 LPDWORD pcbNeeded, BOOL unicode)
7473 DWORD size, left = cbBuf;
7474 BOOL space = (cbBuf > 0);
7481 ji1->JobId = job->job_id;
7484 string_to_buf(job->document_title, ptr, left, &size, unicode);
7485 if(space && size <= left)
7487 ji1->pDocument = (LPWSTR)ptr;
7498 /*****************************************************************************
7501 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7502 LPDWORD pcbNeeded, BOOL unicode)
7504 DWORD size, left = cbBuf;
7505 BOOL space = (cbBuf > 0);
7512 ji2->JobId = job->job_id;
7515 string_to_buf(job->document_title, ptr, left, &size, unicode);
7516 if(space && size <= left)
7518 ji2->pDocument = (LPWSTR)ptr;
7529 /*****************************************************************************
7532 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7533 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7536 DWORD needed = 0, size;
7540 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7542 EnterCriticalSection(&printer_handles_cs);
7543 job = get_job(hPrinter, JobId);
7550 size = sizeof(JOB_INFO_1W);
7555 memset(pJob, 0, size);
7559 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7564 size = sizeof(JOB_INFO_2W);
7569 memset(pJob, 0, size);
7573 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7578 size = sizeof(JOB_INFO_3);
7582 memset(pJob, 0, size);
7591 SetLastError(ERROR_INVALID_LEVEL);
7595 *pcbNeeded = needed;
7597 LeaveCriticalSection(&printer_handles_cs);
7601 /*****************************************************************************
7602 * GetJobA [WINSPOOL.@]
7605 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7606 DWORD cbBuf, LPDWORD pcbNeeded)
7608 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7611 /*****************************************************************************
7612 * GetJobW [WINSPOOL.@]
7615 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7616 DWORD cbBuf, LPDWORD pcbNeeded)
7618 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7621 /*****************************************************************************
7624 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7626 char *unixname, *queue, *cmd;
7627 char fmt[] = "lpr -P%s %s";
7630 if(!(unixname = wine_get_unix_file_name(filename)))
7633 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7634 queue = HeapAlloc(GetProcessHeap(), 0, len);
7635 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7637 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7638 sprintf(cmd, fmt, queue, unixname);
7640 TRACE("printing with: %s\n", cmd);
7643 HeapFree(GetProcessHeap(), 0, cmd);
7644 HeapFree(GetProcessHeap(), 0, queue);
7645 HeapFree(GetProcessHeap(), 0, unixname);
7649 /*****************************************************************************
7652 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7654 #ifdef SONAME_LIBCUPS
7657 char *unixname, *queue, *doc_titleA;
7661 if(!(unixname = wine_get_unix_file_name(filename)))
7664 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7665 queue = HeapAlloc(GetProcessHeap(), 0, len);
7666 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7668 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7669 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7670 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7672 TRACE("printing via cups\n");
7673 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7674 HeapFree(GetProcessHeap(), 0, doc_titleA);
7675 HeapFree(GetProcessHeap(), 0, queue);
7676 HeapFree(GetProcessHeap(), 0, unixname);
7682 return schedule_lpr(printer_name, filename);
7686 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7693 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7697 if(HIWORD(wparam) == BN_CLICKED)
7699 if(LOWORD(wparam) == IDOK)
7702 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7705 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7706 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7708 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7710 WCHAR caption[200], message[200];
7713 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7714 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7715 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7716 if(mb_ret == IDCANCEL)
7718 HeapFree(GetProcessHeap(), 0, filename);
7722 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7723 if(hf == INVALID_HANDLE_VALUE)
7725 WCHAR caption[200], message[200];
7727 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7728 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7729 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7730 HeapFree(GetProcessHeap(), 0, filename);
7734 DeleteFileW(filename);
7735 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7737 EndDialog(hwnd, IDOK);
7740 if(LOWORD(wparam) == IDCANCEL)
7742 EndDialog(hwnd, IDCANCEL);
7751 /*****************************************************************************
7754 static BOOL get_filename(LPWSTR *filename)
7756 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7757 file_dlg_proc, (LPARAM)filename) == IDOK;
7760 /*****************************************************************************
7763 static BOOL schedule_file(LPCWSTR filename)
7765 LPWSTR output = NULL;
7767 if(get_filename(&output))
7769 TRACE("copy to %s\n", debugstr_w(output));
7770 CopyFileW(filename, output, FALSE);
7771 HeapFree(GetProcessHeap(), 0, output);
7777 /*****************************************************************************
7780 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7783 char *unixname, *cmdA;
7785 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7789 if(!(unixname = wine_get_unix_file_name(filename)))
7792 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7793 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7794 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7796 TRACE("printing with: %s\n", cmdA);
7798 if((file_fd = open(unixname, O_RDONLY)) == -1)
7803 ERR("pipe() failed!\n");
7813 /* reset signals that we previously set to SIG_IGN */
7814 signal(SIGPIPE, SIG_DFL);
7815 signal(SIGCHLD, SIG_DFL);
7817 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7821 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7822 write(fds[1], buf, no_read);
7827 if(file_fd != -1) close(file_fd);
7828 if(fds[0] != -1) close(fds[0]);
7829 if(fds[1] != -1) close(fds[1]);
7831 HeapFree(GetProcessHeap(), 0, cmdA);
7832 HeapFree(GetProcessHeap(), 0, unixname);
7839 /*****************************************************************************
7842 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7844 int in_fd, out_fd, no_read;
7847 char *unixname, *outputA;
7850 if(!(unixname = wine_get_unix_file_name(filename)))
7853 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7854 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7855 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7857 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7858 in_fd = open(unixname, O_RDONLY);
7859 if(out_fd == -1 || in_fd == -1)
7862 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7863 write(out_fd, buf, no_read);
7867 if(in_fd != -1) close(in_fd);
7868 if(out_fd != -1) close(out_fd);
7869 HeapFree(GetProcessHeap(), 0, outputA);
7870 HeapFree(GetProcessHeap(), 0, unixname);
7874 /*****************************************************************************
7875 * ScheduleJob [WINSPOOL.@]
7878 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7880 opened_printer_t *printer;
7882 struct list *cursor, *cursor2;
7884 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7885 EnterCriticalSection(&printer_handles_cs);
7886 printer = get_opened_printer(hPrinter);
7890 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7892 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7895 if(job->job_id != dwJobID) continue;
7897 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7898 if(hf != INVALID_HANDLE_VALUE)
7900 PRINTER_INFO_5W *pi5;
7904 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7905 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7907 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7908 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7909 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7910 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7911 debugstr_w(pi5->pPortName));
7915 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7916 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7918 DWORD type, count = sizeof(output);
7919 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7922 if(output[0] == '|')
7924 schedule_pipe(output + 1, job->filename);
7928 schedule_unixfile(output, job->filename);
7930 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7932 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7934 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7936 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7938 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7940 schedule_file(job->filename);
7944 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7946 HeapFree(GetProcessHeap(), 0, pi5);
7948 DeleteFileW(job->filename);
7950 list_remove(cursor);
7951 HeapFree(GetProcessHeap(), 0, job->document_title);
7952 HeapFree(GetProcessHeap(), 0, job->filename);
7953 HeapFree(GetProcessHeap(), 0, job);
7958 LeaveCriticalSection(&printer_handles_cs);
7962 /*****************************************************************************
7963 * StartDocDlgA [WINSPOOL.@]
7965 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7967 UNICODE_STRING usBuffer;
7970 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7973 docW.cbSize = sizeof(docW);
7974 if (doc->lpszDocName)
7976 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7977 if (!(docW.lpszDocName = docnameW)) return NULL;
7979 if (doc->lpszOutput)
7981 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7982 if (!(docW.lpszOutput = outputW)) return NULL;
7984 if (doc->lpszDatatype)
7986 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7987 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7989 docW.fwType = doc->fwType;
7991 retW = StartDocDlgW(hPrinter, &docW);
7995 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7996 ret = HeapAlloc(GetProcessHeap(), 0, len);
7997 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7998 HeapFree(GetProcessHeap(), 0, retW);
8001 HeapFree(GetProcessHeap(), 0, datatypeW);
8002 HeapFree(GetProcessHeap(), 0, outputW);
8003 HeapFree(GetProcessHeap(), 0, docnameW);
8008 /*****************************************************************************
8009 * StartDocDlgW [WINSPOOL.@]
8011 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8012 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8013 * port is "FILE:". Also returns the full path if passed a relative path.
8015 * The caller should free the returned string from the process heap.
8017 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8022 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8024 PRINTER_INFO_5W *pi5;
8025 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8026 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8028 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8029 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8030 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8032 HeapFree(GetProcessHeap(), 0, pi5);
8035 HeapFree(GetProcessHeap(), 0, pi5);
8038 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8042 if (get_filename(&name))
8044 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8046 HeapFree(GetProcessHeap(), 0, name);
8049 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8050 GetFullPathNameW(name, len, ret, NULL);
8051 HeapFree(GetProcessHeap(), 0, name);
8056 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8059 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8060 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8062 attr = GetFileAttributesW(ret);
8063 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8065 HeapFree(GetProcessHeap(), 0, ret);