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 int 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_path[] = "wineps16",
474 data_file[] = "<datafile?>",
475 config_file[] = "wineps16",
476 help_file[] = "<helpfile?>",
477 dep_file[] = "<dependent files?>\0",
478 monitor_name[] = "<monitor name?>",
479 default_data_type[] = "RAW";
481 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
482 di3a.pName = (char *)name;
483 di3a.pEnvironment = NULL; /* NULL means auto */
484 di3a.pDriverPath = driver_path;
485 di3a.pDataFile = data_file;
486 di3a.pConfigFile = config_file;
487 di3a.pHelpFile = help_file;
488 di3a.pDependentFiles = dep_file;
489 di3a.pMonitorName = monitor_name;
490 di3a.pDefaultDataType = default_data_type;
492 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
494 ERR("Failed adding driver (%d)\n", GetLastError());
500 #ifdef SONAME_LIBCUPS
501 static typeof(cupsGetDests) *pcupsGetDests;
502 static typeof(cupsGetPPD) *pcupsGetPPD;
503 static typeof(cupsPrintFile) *pcupsPrintFile;
504 static void *cupshandle;
506 static BOOL CUPS_LoadPrinters(void)
509 BOOL hadprinter = FALSE, haddefault = FALSE;
511 PRINTER_INFO_2A pinfo2a;
513 HKEY hkeyPrinter, hkeyPrinters, hkey;
516 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
518 TRACE("%s\n", loaderror);
521 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
524 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
525 if (!p##x) return FALSE;
528 DYNCUPS(cupsGetDests);
529 DYNCUPS(cupsPrintFile);
532 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
534 ERR("Can't create Printers key\n");
538 nrofdests = pcupsGetDests(&dests);
539 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
540 for (i=0;i<nrofdests;i++) {
541 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
542 sprintf(port,"LPR:%s",dests[i].name);
543 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
544 sprintf(devline,"WINEPS.DRV,%s",port);
545 WriteProfileStringA("devices",dests[i].name,devline);
546 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
547 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
550 HeapFree(GetProcessHeap(),0,devline);
552 TRACE("Printer %d: %s\n", i, dests[i].name);
553 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
554 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
556 TRACE("Printer already exists\n");
557 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
558 RegCloseKey(hkeyPrinter);
560 static CHAR data_type[] = "RAW",
561 print_proc[] = "WinPrint",
562 comment[] = "WINEPS Printer using CUPS",
563 location[] = "<physical location of printer>",
564 params[] = "<parameters?>",
565 share_name[] = "<share name?>",
566 sep_file[] = "<sep file?>";
568 add_printer_driver(dests[i].name);
570 memset(&pinfo2a,0,sizeof(pinfo2a));
571 pinfo2a.pPrinterName = dests[i].name;
572 pinfo2a.pDatatype = data_type;
573 pinfo2a.pPrintProcessor = print_proc;
574 pinfo2a.pDriverName = dests[i].name;
575 pinfo2a.pComment = comment;
576 pinfo2a.pLocation = location;
577 pinfo2a.pPortName = port;
578 pinfo2a.pParameters = params;
579 pinfo2a.pShareName = share_name;
580 pinfo2a.pSepFile = sep_file;
582 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
583 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
584 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
587 HeapFree(GetProcessHeap(),0,port);
590 if (dests[i].is_default) {
591 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
595 if (hadprinter & !haddefault)
596 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
597 RegCloseKey(hkeyPrinters);
603 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
604 PRINTER_INFO_2A pinfo2a;
605 char *e,*s,*name,*prettyname,*devname;
606 BOOL ret = FALSE, set_default = FALSE;
607 char *port,*devline,*env_default;
608 HKEY hkeyPrinter, hkeyPrinters, hkey;
610 while (isspace(*pent)) pent++;
611 s = strchr(pent,':');
613 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
621 TRACE("name=%s entry=%s\n",name, pent);
623 if(ispunct(*name)) { /* a tc entry, not a real printer */
624 TRACE("skipping tc entry\n");
628 if(strstr(pent,":server")) { /* server only version so skip */
629 TRACE("skipping server entry\n");
633 /* Determine whether this is a postscript printer. */
636 env_default = getenv("PRINTER");
638 /* Get longest name, usually the one at the right for later display. */
639 while((s=strchr(prettyname,'|'))) {
642 while(isspace(*--e)) *e = '\0';
643 TRACE("\t%s\n", debugstr_a(prettyname));
644 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
645 for(prettyname = s+1; isspace(*prettyname); prettyname++)
648 e = prettyname + strlen(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;
653 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
654 * if it is too long, we use it as comment below. */
655 devname = prettyname;
656 if (strlen(devname)>=CCHDEVICENAME-1)
658 if (strlen(devname)>=CCHDEVICENAME-1) {
663 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
664 sprintf(port,"LPR:%s",name);
666 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
667 sprintf(devline,"WINEPS.DRV,%s",port);
668 WriteProfileStringA("devices",devname,devline);
669 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
670 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
673 HeapFree(GetProcessHeap(),0,devline);
675 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
677 ERR("Can't create Printers key\n");
681 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
682 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
684 TRACE("Printer already exists\n");
685 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
686 RegCloseKey(hkeyPrinter);
688 static CHAR data_type[] = "RAW",
689 print_proc[] = "WinPrint",
690 comment[] = "WINEPS Printer using LPR",
691 params[] = "<parameters?>",
692 share_name[] = "<share name?>",
693 sep_file[] = "<sep file?>";
695 add_printer_driver(devname);
697 memset(&pinfo2a,0,sizeof(pinfo2a));
698 pinfo2a.pPrinterName = devname;
699 pinfo2a.pDatatype = data_type;
700 pinfo2a.pPrintProcessor = print_proc;
701 pinfo2a.pDriverName = devname;
702 pinfo2a.pComment = comment;
703 pinfo2a.pLocation = prettyname;
704 pinfo2a.pPortName = port;
705 pinfo2a.pParameters = params;
706 pinfo2a.pShareName = share_name;
707 pinfo2a.pSepFile = sep_file;
709 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
710 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
711 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
714 RegCloseKey(hkeyPrinters);
716 if (isfirst || set_default)
717 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
719 HeapFree(GetProcessHeap(), 0, port);
721 HeapFree(GetProcessHeap(), 0, name);
726 PRINTCAP_LoadPrinters(void) {
727 BOOL hadprinter = FALSE;
731 BOOL had_bash = FALSE;
733 f = fopen("/etc/printcap","r");
737 while(fgets(buf,sizeof(buf),f)) {
740 end=strchr(buf,'\n');
744 while(isspace(*start)) start++;
745 if(*start == '#' || *start == '\0')
748 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
749 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
750 HeapFree(GetProcessHeap(),0,pent);
754 if (end && *--end == '\\') {
761 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
764 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
770 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
771 HeapFree(GetProcessHeap(),0,pent);
777 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
780 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
781 (lstrlenW(value) + 1) * sizeof(WCHAR));
783 return ERROR_FILE_NOT_FOUND;
786 /*****************************************************************************
787 * enumerate the local monitors (INTERNAL)
789 * returns the needed size (in bytes) for pMonitors
790 * and *lpreturned is set to number of entries returned in pMonitors
793 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
798 LPMONITOR_INFO_2W mi;
799 WCHAR buffer[MAX_PATH];
800 WCHAR dllname[MAX_PATH];
808 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
810 numentries = *lpreturned; /* this is 0, when we scan the registry */
811 len = entrysize * numentries;
812 ptr = (LPWSTR) &pMonitors[len];
815 len = sizeof(buffer);
818 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
819 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
820 /* Scan all Monitor-Registry-Keys */
821 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
822 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
823 dllsize = sizeof(dllname);
826 /* The Monitor must have a Driver-DLL */
827 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
828 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
829 /* We found a valid DLL for this Monitor. */
830 TRACE("using Driver: %s\n", debugstr_w(dllname));
835 /* Windows returns only Port-Monitors here, but to simplify our code,
836 we do no filtering for Language-Monitors */
840 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
842 /* we install and return only monitors for "Windows NT x86" */
843 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
847 /* required size is calculated. Now fill the user-buffer */
848 if (pMonitors && (cbBuf >= needed)){
849 mi = (LPMONITOR_INFO_2W) pMonitors;
850 pMonitors += entrysize;
852 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
854 lstrcpyW(ptr, buffer); /* Name of the Monitor */
855 ptr += (len+1); /* len is lstrlenW(monitorname) */
857 mi->pEnvironment = ptr;
858 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
859 ptr += (lstrlenW(envname_x86W)+1);
862 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
863 ptr += (dllsize / sizeof(WCHAR));
868 len = sizeof(buffer);
873 *lpreturned = numentries;
874 TRACE("need %d byte for %d entries\n", needed, numentries);
878 /******************************************************************
879 * monitor_unload [internal]
881 * release a printmonitor and unload it from memory, when needed
884 static void monitor_unload(monitor_t * pm)
886 if (pm == NULL) return;
887 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
889 EnterCriticalSection(&monitor_handles_cs);
891 if (pm->refcount) pm->refcount--;
893 if (pm->refcount == 0) {
894 list_remove(&pm->entry);
895 FreeLibrary(pm->hdll);
896 HeapFree(GetProcessHeap(), 0, pm->name);
897 HeapFree(GetProcessHeap(), 0, pm->dllname);
898 HeapFree(GetProcessHeap(), 0, pm);
900 LeaveCriticalSection(&monitor_handles_cs);
903 /******************************************************************
904 * monitor_unloadall [internal]
906 * release all printmonitors and unload them from memory, when needed
909 static void monitor_unloadall(void)
914 EnterCriticalSection(&monitor_handles_cs);
915 /* iterate through the list, with safety against removal */
916 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
920 LeaveCriticalSection(&monitor_handles_cs);
923 /******************************************************************
924 * monitor_load [internal]
926 * load a printmonitor, get the dllname from the registry, when needed
927 * initialize the monitor and dump found function-pointers
929 * On failure, SetLastError() is called and NULL is returned
932 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
934 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
935 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
936 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
937 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
938 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
940 monitor_t * pm = NULL;
942 LPWSTR regroot = NULL;
943 LPWSTR driver = dllname;
945 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
946 /* Is the Monitor already loaded? */
947 EnterCriticalSection(&monitor_handles_cs);
950 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
952 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
960 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
961 if (pm == NULL) goto cleanup;
962 list_add_tail(&monitor_handles, &pm->entry);
966 if (pm->name == NULL) {
967 /* Load the monitor */
968 LPMONITOREX pmonitorEx;
972 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
973 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
977 lstrcpyW(regroot, MonitorsW);
978 lstrcatW(regroot, name);
979 /* Get the Driver from the Registry */
980 if (driver == NULL) {
983 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
984 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
985 &namesize) == ERROR_SUCCESS) {
986 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
987 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
994 pm->name = strdupW(name);
995 pm->dllname = strdupW(driver);
997 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
999 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1004 pm->hdll = LoadLibraryW(driver);
1005 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
1007 if (pm->hdll == NULL) {
1009 SetLastError(ERROR_MOD_NOT_FOUND);
1014 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
1015 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1016 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1017 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1018 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1021 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1022 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1023 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1024 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1025 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1027 if (pInitializePrintMonitorUI != NULL) {
1028 pm->monitorUI = pInitializePrintMonitorUI();
1029 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1030 if (pm->monitorUI) {
1031 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1032 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1037 if (pInitializePrintMonitor && regroot) {
1038 pmonitorEx = pInitializePrintMonitor(regroot);
1039 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1040 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1043 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1044 pm->monitor = &(pmonitorEx->Monitor);
1049 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1053 if (!pm->monitor && regroot) {
1054 if (pInitializePrintMonitor2 != NULL) {
1055 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1057 if (pInitializeMonitorEx != NULL) {
1058 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1060 if (pInitializeMonitor != NULL) {
1061 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1064 if (!pm->monitor && !pm->monitorUI) {
1066 SetLastError(ERROR_PROC_NOT_FOUND);
1071 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1075 LeaveCriticalSection(&monitor_handles_cs);
1076 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1077 HeapFree(GetProcessHeap(), 0, regroot);
1078 TRACE("=> %p\n", pm);
1082 /******************************************************************
1083 * monitor_loadall [internal]
1085 * Load all registered monitors
1088 static DWORD monitor_loadall(void)
1091 DWORD registered = 0;
1094 WCHAR buffer[MAX_PATH];
1097 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1098 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1099 NULL, NULL, NULL, NULL, NULL);
1101 TRACE("%d monitors registered\n", registered);
1103 EnterCriticalSection(&monitor_handles_cs);
1104 while (id < registered) {
1106 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1107 pm = monitor_load(buffer, NULL);
1111 LeaveCriticalSection(&monitor_handles_cs);
1112 RegCloseKey(hmonitors);
1114 TRACE("%d monitors loaded\n", loaded);
1118 /******************************************************************
1119 * monitor_loadui [internal]
1121 * load the userinterface-dll for a given portmonitor
1123 * On failure, NULL is returned
1126 static monitor_t * monitor_loadui(monitor_t * pm)
1128 monitor_t * pui = NULL;
1129 LPWSTR buffer[MAX_PATH];
1134 if (pm == NULL) return NULL;
1135 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1137 /* Try the Portmonitor first; works for many monitors */
1138 if (pm->monitorUI) {
1139 EnterCriticalSection(&monitor_handles_cs);
1141 LeaveCriticalSection(&monitor_handles_cs);
1145 /* query the userinterface-dllname from the Portmonitor */
1146 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1147 /* building (",XcvMonitor %s",pm->name) not needed yet */
1148 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1149 TRACE("got %u with %p\n", res, hXcv);
1151 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1152 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1153 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1154 pm->monitor->pfnXcvClosePort(hXcv);
1161 /******************************************************************
1162 * monitor_load_by_port [internal]
1164 * load a printmonitor for a given port
1166 * On failure, NULL is returned
1169 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1174 monitor_t * pm = NULL;
1175 DWORD registered = 0;
1179 TRACE("(%s)\n", debugstr_w(portname));
1181 /* Try the Local Monitor first */
1182 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1183 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1184 /* found the portname */
1186 return monitor_load(LocalPortW, NULL);
1191 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1192 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1193 if (buffer == NULL) return NULL;
1195 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1196 EnterCriticalSection(&monitor_handles_cs);
1197 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1199 while ((pm == NULL) && (id < registered)) {
1201 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1202 TRACE("testing %s\n", debugstr_w(buffer));
1203 len = lstrlenW(buffer);
1204 lstrcatW(buffer, bs_Ports_bsW);
1205 lstrcatW(buffer, portname);
1206 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1208 buffer[len] = '\0'; /* use only the Monitor-Name */
1209 pm = monitor_load(buffer, NULL);
1213 LeaveCriticalSection(&monitor_handles_cs);
1216 HeapFree(GetProcessHeap(), 0, buffer);
1220 /******************************************************************
1221 * enumerate the local Ports from all loaded monitors (internal)
1223 * returns the needed size (in bytes) for pPorts
1224 * and *lpreturned is set to number of entries returned in pPorts
1227 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1231 LPPORT_INFO_2W cache;
1233 LPBYTE pi_buffer = NULL;
1234 DWORD pi_allocated = 0;
1245 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1246 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1248 numentries = *lpreturned; /* this is 0, when we scan the registry */
1249 needed = entrysize * numentries;
1250 ptr = (LPWSTR) &pPorts[needed];
1255 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1257 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1260 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1261 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1262 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1263 HeapFree(GetProcessHeap(), 0, pi_buffer);
1264 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1265 pi_allocated = (pi_buffer) ? pi_needed : 0;
1266 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1268 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1269 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1271 numentries += pi_returned;
1272 needed += pi_needed;
1274 /* fill the output-buffer (pPorts), if we have one */
1275 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1277 while (pi_returned > pi_index) {
1278 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1279 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1280 out->pPortName = ptr;
1281 lstrcpyW(ptr, cache->pPortName);
1282 ptr += (lstrlenW(ptr)+1);
1284 out->pMonitorName = ptr;
1285 lstrcpyW(ptr, cache->pMonitorName);
1286 ptr += (lstrlenW(ptr)+1);
1288 out->pDescription = ptr;
1289 lstrcpyW(ptr, cache->pDescription);
1290 ptr += (lstrlenW(ptr)+1);
1291 out->fPortType = cache->fPortType;
1292 out->Reserved = cache->Reserved;
1300 /* the temporary portinfo-buffer is no longer needed */
1301 HeapFree(GetProcessHeap(), 0, pi_buffer);
1303 *lpreturned = numentries;
1304 TRACE("need %d byte for %d entries\n", needed, numentries);
1308 /******************************************************************
1309 * get_servername_from_name (internal)
1311 * for an external server, a copy of the serverpart from the full name is returned
1314 static LPWSTR get_servername_from_name(LPCWSTR name)
1318 WCHAR buffer[MAX_PATH];
1321 if (name == NULL) return NULL;
1322 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1324 server = strdupW(&name[2]); /* skip over both backslash */
1325 if (server == NULL) return NULL;
1327 /* strip '\' and the printername */
1328 ptr = strchrW(server, '\\');
1329 if (ptr) ptr[0] = '\0';
1331 TRACE("found %s\n", debugstr_w(server));
1333 len = sizeof(buffer)/sizeof(buffer[0]);
1334 if (GetComputerNameW(buffer, &len)) {
1335 if (lstrcmpW(buffer, server) == 0) {
1336 /* The requested Servername is our computername */
1337 HeapFree(GetProcessHeap(), 0, server);
1344 /******************************************************************
1345 * get_basename_from_name (internal)
1347 * skip over the serverpart from the full name
1350 static LPCWSTR get_basename_from_name(LPCWSTR name)
1352 if (name == NULL) return NULL;
1353 if ((name[0] == '\\') && (name[1] == '\\')) {
1354 /* skip over the servername and search for the following '\' */
1355 name = strchrW(&name[2], '\\');
1356 if ((name) && (name[1])) {
1357 /* found a separator ('\') followed by a name:
1358 skip over the separator and return the rest */
1363 /* no basename present (we found only a servername) */
1370 /******************************************************************
1371 * get_opened_printer_entry
1372 * Get the first place empty in the opened printer table
1375 * - pDefault is ignored
1377 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1379 UINT_PTR handle = nb_printer_handles, i;
1380 jobqueue_t *queue = NULL;
1381 opened_printer_t *printer = NULL;
1383 LPCWSTR printername;
1388 servername = get_servername_from_name(name);
1390 FIXME("server %s not supported\n", debugstr_w(servername));
1391 HeapFree(GetProcessHeap(), 0, servername);
1392 SetLastError(ERROR_INVALID_PRINTER_NAME);
1396 printername = get_basename_from_name(name);
1397 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1399 /* an empty printername is invalid */
1400 if (printername && (!printername[0])) {
1401 SetLastError(ERROR_INVALID_PARAMETER);
1405 EnterCriticalSection(&printer_handles_cs);
1407 for (i = 0; i < nb_printer_handles; i++)
1409 if (!printer_handles[i])
1411 if(handle == nb_printer_handles)
1416 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1417 queue = printer_handles[i]->queue;
1421 if (handle >= nb_printer_handles)
1423 opened_printer_t **new_array;
1424 if (printer_handles)
1425 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1426 (nb_printer_handles + 16) * sizeof(*new_array) );
1428 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1429 (nb_printer_handles + 16) * sizeof(*new_array) );
1436 printer_handles = new_array;
1437 nb_printer_handles += 16;
1440 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1447 /* clone the base name. This is NULL for the printserver */
1448 printer->printername = strdupW(printername);
1450 /* clone the full name */
1451 printer->name = strdupW(name);
1452 if (name && (!printer->name)) {
1458 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1459 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1460 /* OpenPrinter(",XcvMonitor " detected */
1461 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1462 printer->pm = monitor_load(&printername[len], NULL);
1463 if (printer->pm == NULL) {
1464 SetLastError(ERROR_UNKNOWN_PORT);
1471 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1472 if (strncmpW( printername, XcvPortW, len) == 0) {
1473 /* OpenPrinter(",XcvPort " detected */
1474 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1475 printer->pm = monitor_load_by_port(&printername[len]);
1476 if (printer->pm == NULL) {
1477 SetLastError(ERROR_UNKNOWN_PORT);
1485 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1486 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1487 pDefault ? pDefault->DesiredAccess : 0,
1490 if (printer->hXcv == NULL) {
1491 SetLastError(ERROR_INVALID_PARAMETER);
1498 /* Does the Printer exist? */
1499 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1500 ERR("Can't create Printers key\n");
1504 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1505 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1506 RegCloseKey(hkeyPrinters);
1507 SetLastError(ERROR_INVALID_PRINTER_NAME);
1511 RegCloseKey(hkeyPrinter);
1512 RegCloseKey(hkeyPrinters);
1517 TRACE("using the local printserver\n");
1521 printer->queue = queue;
1524 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1525 if (!printer->queue) {
1529 list_init(&printer->queue->jobs);
1530 printer->queue->ref = 0;
1532 InterlockedIncrement(&printer->queue->ref);
1534 printer_handles[handle] = printer;
1537 LeaveCriticalSection(&printer_handles_cs);
1538 if (!handle && printer) {
1539 /* Something failed: Free all resources */
1540 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1541 monitor_unload(printer->pm);
1542 HeapFree(GetProcessHeap(), 0, printer->printername);
1543 HeapFree(GetProcessHeap(), 0, printer->name);
1544 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1545 HeapFree(GetProcessHeap(), 0, printer);
1548 return (HANDLE)handle;
1551 /******************************************************************
1552 * get_opened_printer
1553 * Get the pointer to the opened printer referred by the handle
1555 static opened_printer_t *get_opened_printer(HANDLE hprn)
1557 UINT_PTR idx = (UINT_PTR)hprn;
1558 opened_printer_t *ret = NULL;
1560 EnterCriticalSection(&printer_handles_cs);
1562 if ((idx <= 0) || (idx > nb_printer_handles))
1565 ret = printer_handles[idx - 1];
1567 LeaveCriticalSection(&printer_handles_cs);
1571 /******************************************************************
1572 * get_opened_printer_name
1573 * Get the pointer to the opened printer name referred by the handle
1575 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1577 opened_printer_t *printer = get_opened_printer(hprn);
1578 if(!printer) return NULL;
1579 return printer->name;
1582 /******************************************************************
1583 * WINSPOOL_GetOpenedPrinterRegKey
1586 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1588 LPCWSTR name = get_opened_printer_name(hPrinter);
1592 if(!name) return ERROR_INVALID_HANDLE;
1594 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1598 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1600 ERR("Can't find opened printer %s in registry\n",
1602 RegCloseKey(hkeyPrinters);
1603 return ERROR_INVALID_PRINTER_NAME; /* ? */
1605 RegCloseKey(hkeyPrinters);
1606 return ERROR_SUCCESS;
1609 void WINSPOOL_LoadSystemPrinters(void)
1611 HKEY hkey, hkeyPrinters;
1613 DWORD needed, num, i;
1614 WCHAR PrinterName[256];
1617 /* This ensures that all printer entries have a valid Name value. If causes
1618 problems later if they don't. If one is found to be missed we create one
1619 and set it equal to the name of the key */
1620 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1621 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1622 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1623 for(i = 0; i < num; i++) {
1624 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
1625 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1626 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1627 set_reg_szW(hkey, NameW, PrinterName);
1634 RegCloseKey(hkeyPrinters);
1637 /* We want to avoid calling AddPrinter on printers as much as
1638 possible, because on cups printers this will (eventually) lead
1639 to a call to cupsGetPPD which takes forever, even with non-cups
1640 printers AddPrinter takes a while. So we'll tag all printers that
1641 were automatically added last time around, if they still exist
1642 we'll leave them be otherwise we'll delete them. */
1643 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1645 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1646 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1647 for(i = 0; i < num; i++) {
1648 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1649 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1650 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1652 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1660 HeapFree(GetProcessHeap(), 0, pi);
1664 #ifdef SONAME_LIBCUPS
1665 done = CUPS_LoadPrinters();
1668 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1669 PRINTCAP_LoadPrinters();
1671 /* Now enumerate the list again and delete any printers that a still tagged */
1672 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1674 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1675 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1676 for(i = 0; i < num; i++) {
1677 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1678 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1679 BOOL delete_driver = FALSE;
1680 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1681 DWORD dw, type, size = sizeof(dw);
1682 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1683 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1684 DeletePrinter(hprn);
1685 delete_driver = TRUE;
1691 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1696 HeapFree(GetProcessHeap(), 0, pi);
1703 /******************************************************************
1706 * Get the pointer to the specified job.
1707 * Should hold the printer_handles_cs before calling.
1709 static job_t *get_job(HANDLE hprn, DWORD JobId)
1711 opened_printer_t *printer = get_opened_printer(hprn);
1714 if(!printer) return NULL;
1715 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1717 if(job->job_id == JobId)
1723 /***********************************************************
1726 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1729 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1732 Formname = (dmA->dmSize > off_formname);
1733 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1734 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1735 dmW->dmDeviceName, CCHDEVICENAME);
1737 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1738 dmA->dmSize - CCHDEVICENAME);
1740 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1741 off_formname - CCHDEVICENAME);
1742 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1743 dmW->dmFormName, CCHFORMNAME);
1744 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1745 (off_formname + CCHFORMNAME));
1748 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1749 dmA->dmDriverExtra);
1753 /***********************************************************
1755 * Creates an ascii copy of supplied devmode on heap
1757 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1762 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1764 if(!dmW) return NULL;
1765 Formname = (dmW->dmSize > off_formname);
1766 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1767 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1768 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1769 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1771 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1772 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1774 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1775 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1776 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1777 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1778 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1779 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1782 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1783 dmW->dmDriverExtra);
1787 /***********************************************************
1788 * PRINTER_INFO_2AtoW
1789 * Creates a unicode copy of PRINTER_INFO_2A on heap
1791 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1793 LPPRINTER_INFO_2W piW;
1794 UNICODE_STRING usBuffer;
1796 if(!piA) return NULL;
1797 piW = HeapAlloc(heap, 0, sizeof(*piW));
1798 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1800 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1801 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1802 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1803 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1804 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1805 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1806 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1807 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1808 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1809 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1810 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1811 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1815 /***********************************************************
1816 * FREE_PRINTER_INFO_2W
1817 * Free PRINTER_INFO_2W and all strings
1819 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1823 HeapFree(heap,0,piW->pServerName);
1824 HeapFree(heap,0,piW->pPrinterName);
1825 HeapFree(heap,0,piW->pShareName);
1826 HeapFree(heap,0,piW->pPortName);
1827 HeapFree(heap,0,piW->pDriverName);
1828 HeapFree(heap,0,piW->pComment);
1829 HeapFree(heap,0,piW->pLocation);
1830 HeapFree(heap,0,piW->pDevMode);
1831 HeapFree(heap,0,piW->pSepFile);
1832 HeapFree(heap,0,piW->pPrintProcessor);
1833 HeapFree(heap,0,piW->pDatatype);
1834 HeapFree(heap,0,piW->pParameters);
1835 HeapFree(heap,0,piW);
1839 /******************************************************************
1840 * DeviceCapabilities [WINSPOOL.@]
1841 * DeviceCapabilitiesA [WINSPOOL.@]
1844 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1845 LPSTR pOutput, LPDEVMODEA lpdm)
1849 if (!GDI_CallDeviceCapabilities16)
1851 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1853 if (!GDI_CallDeviceCapabilities16) return -1;
1855 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1857 /* If DC_PAPERSIZE map POINT16s to POINTs */
1858 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1859 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1860 POINT *pt = (POINT *)pOutput;
1862 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1863 for(i = 0; i < ret; i++, pt++)
1868 HeapFree( GetProcessHeap(), 0, tmp );
1874 /*****************************************************************************
1875 * DeviceCapabilitiesW [WINSPOOL.@]
1877 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1880 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1881 WORD fwCapability, LPWSTR pOutput,
1882 const DEVMODEW *pDevMode)
1884 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1885 LPSTR pDeviceA = strdupWtoA(pDevice);
1886 LPSTR pPortA = strdupWtoA(pPort);
1889 if(pOutput && (fwCapability == DC_BINNAMES ||
1890 fwCapability == DC_FILEDEPENDENCIES ||
1891 fwCapability == DC_PAPERNAMES)) {
1892 /* These need A -> W translation */
1895 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1899 switch(fwCapability) {
1904 case DC_FILEDEPENDENCIES:
1908 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1909 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1911 for(i = 0; i < ret; i++)
1912 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1913 pOutput + (i * size), size);
1914 HeapFree(GetProcessHeap(), 0, pOutputA);
1916 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1917 (LPSTR)pOutput, dmA);
1919 HeapFree(GetProcessHeap(),0,pPortA);
1920 HeapFree(GetProcessHeap(),0,pDeviceA);
1921 HeapFree(GetProcessHeap(),0,dmA);
1925 /******************************************************************
1926 * DocumentPropertiesA [WINSPOOL.@]
1928 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1930 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1931 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1932 LPDEVMODEA pDevModeInput,DWORD fMode )
1934 LPSTR lpName = pDeviceName;
1935 static CHAR port[] = "LPT1:";
1938 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1939 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1943 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1945 ERR("no name from hPrinter?\n");
1946 SetLastError(ERROR_INVALID_HANDLE);
1949 lpName = strdupWtoA(lpNameW);
1952 if (!GDI_CallExtDeviceMode16)
1954 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1956 if (!GDI_CallExtDeviceMode16) {
1957 ERR("No CallExtDeviceMode16?\n");
1961 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1962 pDevModeInput, NULL, fMode);
1965 HeapFree(GetProcessHeap(),0,lpName);
1970 /*****************************************************************************
1971 * DocumentPropertiesW (WINSPOOL.@)
1973 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1975 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1977 LPDEVMODEW pDevModeOutput,
1978 LPDEVMODEW pDevModeInput, DWORD fMode)
1981 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1982 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1983 LPDEVMODEA pDevModeOutputA = NULL;
1986 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1987 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1989 if(pDevModeOutput) {
1990 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1991 if(ret < 0) return ret;
1992 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1994 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1995 pDevModeInputA, fMode);
1996 if(pDevModeOutput) {
1997 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1998 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2000 if(fMode == 0 && ret > 0)
2001 ret += (CCHDEVICENAME + CCHFORMNAME);
2002 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2003 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2007 /******************************************************************
2008 * OpenPrinterA [WINSPOOL.@]
2013 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2014 LPPRINTER_DEFAULTSA pDefault)
2016 UNICODE_STRING lpPrinterNameW;
2017 UNICODE_STRING usBuffer;
2018 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2019 PWSTR pwstrPrinterNameW;
2022 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2025 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2026 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2027 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2028 pDefaultW = &DefaultW;
2030 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2032 RtlFreeUnicodeString(&usBuffer);
2033 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2035 RtlFreeUnicodeString(&lpPrinterNameW);
2039 /******************************************************************
2040 * OpenPrinterW [WINSPOOL.@]
2042 * Open a Printer / Printserver or a Printer-Object
2045 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2046 * phPrinter [O] The resulting Handle is stored here
2047 * pDefault [I] PTR to Default Printer Settings or NULL
2054 * lpPrinterName is one of:
2055 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2056 *| Printer: "PrinterName"
2057 *| Printer-Object: "PrinterName,Job xxx"
2058 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2059 *| XcvPort: "Servername,XcvPort PortName"
2062 *| Printer-Object not supported
2063 *| pDefaults is ignored
2066 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2069 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2071 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2072 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2076 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2077 SetLastError(ERROR_INVALID_PARAMETER);
2081 /* Get the unique handle of the printer or Printserver */
2082 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2083 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2084 return (*phPrinter != 0);
2087 /******************************************************************
2088 * AddMonitorA [WINSPOOL.@]
2093 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2095 LPWSTR nameW = NULL;
2098 LPMONITOR_INFO_2A mi2a;
2099 MONITOR_INFO_2W mi2w;
2101 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2102 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2103 mi2a ? debugstr_a(mi2a->pName) : NULL,
2104 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2105 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2108 SetLastError(ERROR_INVALID_LEVEL);
2112 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2118 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2119 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2120 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2123 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2125 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2126 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2127 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2129 if (mi2a->pEnvironment) {
2130 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2131 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2132 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2134 if (mi2a->pDLLName) {
2135 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2136 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2137 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2140 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2142 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2143 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2144 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2146 HeapFree(GetProcessHeap(), 0, nameW);
2150 /******************************************************************************
2151 * AddMonitorW [WINSPOOL.@]
2153 * Install a Printmonitor
2156 * pName [I] Servername or NULL (local Computer)
2157 * Level [I] Structure-Level (Must be 2)
2158 * pMonitors [I] PTR to MONITOR_INFO_2
2165 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2168 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2170 monitor_t * pm = NULL;
2171 LPMONITOR_INFO_2W mi2w;
2177 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2178 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2179 mi2w ? debugstr_w(mi2w->pName) : NULL,
2180 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2181 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2184 SetLastError(ERROR_INVALID_LEVEL);
2188 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2193 if (pName && (pName[0])) {
2194 FIXME("for server %s not implemented\n", debugstr_w(pName));
2195 SetLastError(ERROR_ACCESS_DENIED);
2200 if (!mi2w->pName || (! mi2w->pName[0])) {
2201 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2202 SetLastError(ERROR_INVALID_PARAMETER);
2205 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2206 WARN("Environment %s requested (we support only %s)\n",
2207 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2208 SetLastError(ERROR_INVALID_ENVIRONMENT);
2212 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2213 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2214 SetLastError(ERROR_INVALID_PARAMETER);
2218 /* Load and initialize the monitor. SetLastError() is called on failure */
2219 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2224 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2225 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2229 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2230 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2231 &disposition) == ERROR_SUCCESS) {
2233 /* Some installers set options for the port before calling AddMonitor.
2234 We query the "Driver" entry to verify that the monitor is installed,
2235 before we return an error.
2236 When a user installs two print monitors at the same time with the
2237 same name but with a different driver DLL and a task switch comes
2238 between RegQueryValueExW and RegSetValueExW, a race condition
2239 is possible but silently ignored. */
2243 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2244 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2245 &namesize) == ERROR_SUCCESS)) {
2246 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2247 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2248 9x: ERROR_ALREADY_EXISTS (183) */
2249 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2254 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2255 res = (RegSetValueExW(hentry, DriverW, 0,
2256 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2258 RegCloseKey(hentry);
2265 /******************************************************************
2266 * DeletePrinterDriverA [WINSPOOL.@]
2269 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2271 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2274 /******************************************************************
2275 * DeletePrinterDriverW [WINSPOOL.@]
2278 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2280 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2283 /******************************************************************
2284 * DeleteMonitorA [WINSPOOL.@]
2286 * See DeleteMonitorW.
2289 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2291 LPWSTR nameW = NULL;
2292 LPWSTR EnvironmentW = NULL;
2293 LPWSTR MonitorNameW = NULL;
2298 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2299 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2300 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2304 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2305 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2306 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2309 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2310 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2311 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2314 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2316 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2317 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2318 HeapFree(GetProcessHeap(), 0, nameW);
2322 /******************************************************************
2323 * DeleteMonitorW [WINSPOOL.@]
2325 * Delete a specific Printmonitor from a Printing-Environment
2328 * pName [I] Servername or NULL (local Computer)
2329 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2330 * pMonitorName [I] Name of the Monitor, that should be deleted
2337 * pEnvironment is ignored in Windows for the local Computer.
2341 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2345 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2346 debugstr_w(pMonitorName));
2348 if (pName && (pName[0])) {
2349 FIXME("for server %s not implemented\n", debugstr_w(pName));
2350 SetLastError(ERROR_ACCESS_DENIED);
2354 /* pEnvironment is ignored in Windows for the local Computer */
2356 if (!pMonitorName || !pMonitorName[0]) {
2357 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2358 SetLastError(ERROR_INVALID_PARAMETER);
2362 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2363 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2367 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2368 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2373 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2376 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2377 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2381 /******************************************************************
2382 * DeletePortA [WINSPOOL.@]
2387 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2389 LPWSTR nameW = NULL;
2390 LPWSTR portW = NULL;
2394 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2396 /* convert servername to unicode */
2398 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2399 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2400 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2403 /* convert portname to unicode */
2405 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2406 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2407 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2410 res = DeletePortW(nameW, hWnd, portW);
2411 HeapFree(GetProcessHeap(), 0, nameW);
2412 HeapFree(GetProcessHeap(), 0, portW);
2416 /******************************************************************
2417 * DeletePortW [WINSPOOL.@]
2419 * Delete a specific Port
2422 * pName [I] Servername or NULL (local Computer)
2423 * hWnd [I] Handle to parent Window for the Dialog-Box
2424 * pPortName [I] Name of the Port, that should be deleted
2431 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2437 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2439 if (pName && pName[0]) {
2440 SetLastError(ERROR_INVALID_PARAMETER);
2445 SetLastError(RPC_X_NULL_REF_POINTER);
2449 /* an empty Portname is Invalid */
2450 if (!pPortName[0]) {
2451 SetLastError(ERROR_NOT_SUPPORTED);
2455 pm = monitor_load_by_port(pPortName);
2456 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2457 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2458 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2459 TRACE("got %d with %u\n", res, GetLastError());
2463 pui = monitor_loadui(pm);
2464 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2465 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2466 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2467 TRACE("got %d with %u\n", res, GetLastError());
2471 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2472 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2474 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2475 SetLastError(ERROR_NOT_SUPPORTED);
2478 monitor_unload(pui);
2482 TRACE("returning %d with %u\n", res, GetLastError());
2486 /******************************************************************************
2487 * SetPrinterW [WINSPOOL.@]
2489 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2491 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2492 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2496 /******************************************************************************
2497 * WritePrinter [WINSPOOL.@]
2499 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2501 opened_printer_t *printer;
2504 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2506 EnterCriticalSection(&printer_handles_cs);
2507 printer = get_opened_printer(hPrinter);
2510 SetLastError(ERROR_INVALID_HANDLE);
2516 SetLastError(ERROR_SPL_NO_STARTDOC);
2520 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2522 LeaveCriticalSection(&printer_handles_cs);
2526 /*****************************************************************************
2527 * AddFormA [WINSPOOL.@]
2529 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2531 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2535 /*****************************************************************************
2536 * AddFormW [WINSPOOL.@]
2538 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2540 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2544 /*****************************************************************************
2545 * AddJobA [WINSPOOL.@]
2547 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2550 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2554 SetLastError(ERROR_INVALID_LEVEL);
2558 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2561 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2562 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2563 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2564 if(*pcbNeeded > cbBuf) {
2565 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2568 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2569 addjobA->JobId = addjobW->JobId;
2570 addjobA->Path = (char *)(addjobA + 1);
2571 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2577 /*****************************************************************************
2578 * AddJobW [WINSPOOL.@]
2580 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2582 opened_printer_t *printer;
2585 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2586 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2587 WCHAR path[MAX_PATH], filename[MAX_PATH];
2589 ADDJOB_INFO_1W *addjob;
2591 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2593 EnterCriticalSection(&printer_handles_cs);
2595 printer = get_opened_printer(hPrinter);
2598 SetLastError(ERROR_INVALID_HANDLE);
2603 SetLastError(ERROR_INVALID_LEVEL);
2607 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2611 job->job_id = InterlockedIncrement(&next_job_id);
2613 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2614 if(path[len - 1] != '\\')
2616 memcpy(path + len, spool_path, sizeof(spool_path));
2617 sprintfW(filename, fmtW, path, job->job_id);
2619 len = strlenW(filename);
2620 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2621 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2622 job->document_title = strdupW(default_doc_title);
2623 list_add_tail(&printer->queue->jobs, &job->entry);
2625 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2626 if(*pcbNeeded <= cbBuf) {
2627 addjob = (ADDJOB_INFO_1W*)pData;
2628 addjob->JobId = job->job_id;
2629 addjob->Path = (WCHAR *)(addjob + 1);
2630 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2633 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2636 LeaveCriticalSection(&printer_handles_cs);
2640 /*****************************************************************************
2641 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2643 * Return the PATH for the Print-Processors
2645 * See GetPrintProcessorDirectoryW.
2649 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2650 DWORD level, LPBYTE Info,
2651 DWORD cbBuf, LPDWORD pcbNeeded)
2653 LPWSTR serverW = NULL;
2658 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2659 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2663 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2664 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2665 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2669 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2670 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2671 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2674 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2675 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2677 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2680 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2681 cbBuf, NULL, NULL) > 0;
2684 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2685 HeapFree(GetProcessHeap(), 0, envW);
2686 HeapFree(GetProcessHeap(), 0, serverW);
2690 /*****************************************************************************
2691 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2693 * Return the PATH for the Print-Processors
2696 * server [I] Servername (NT only) or NULL (local Computer)
2697 * env [I] Printing-Environment (see below) or NULL (Default)
2698 * level [I] Structure-Level (must be 1)
2699 * Info [O] PTR to Buffer that receives the Result
2700 * cbBuf [I] Size of Buffer at "Info"
2701 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2702 * required for the Buffer at "Info"
2705 * Success: TRUE and in pcbNeeded the Bytes used in Info
2706 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2707 * if cbBuf is too small
2709 * Native Values returned in Info on Success:
2710 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2711 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2712 *| win9x(Windows 4.0): "%winsysdir%"
2714 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2717 * Only NULL or "" is supported for server
2720 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2721 DWORD level, LPBYTE Info,
2722 DWORD cbBuf, LPDWORD pcbNeeded)
2725 const printenv_t * env_t;
2727 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2728 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2730 if(server != NULL && server[0]) {
2731 FIXME("server not supported: %s\n", debugstr_w(server));
2732 SetLastError(ERROR_INVALID_PARAMETER);
2736 env_t = validate_envW(env);
2737 if(!env_t) return FALSE; /* environment invalid or unsupported */
2740 WARN("(Level: %d) is ignored in win9x\n", level);
2741 SetLastError(ERROR_INVALID_LEVEL);
2745 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2746 needed = GetSystemDirectoryW(NULL, 0);
2747 /* add the Size for the Subdirectories */
2748 needed += lstrlenW(spoolprtprocsW);
2749 needed += lstrlenW(env_t->subdir);
2750 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2752 if(pcbNeeded) *pcbNeeded = needed;
2753 TRACE ("required: 0x%x/%d\n", needed, needed);
2754 if (needed > cbBuf) {
2755 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2758 if(pcbNeeded == NULL) {
2759 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2760 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2761 SetLastError(RPC_X_NULL_REF_POINTER);
2765 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2766 SetLastError(RPC_X_NULL_REF_POINTER);
2770 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2771 /* add the Subdirectories */
2772 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2773 lstrcatW((LPWSTR) Info, env_t->subdir);
2774 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2778 /*****************************************************************************
2779 * WINSPOOL_OpenDriverReg [internal]
2781 * opens the registry for the printer drivers depending on the given input
2782 * variable pEnvironment
2785 * the opened hkey on success
2788 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2792 const printenv_t * env;
2795 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2797 if (!pEnvironment || unicode) {
2798 /* pEnvironment was NULL or an Unicode-String: use it direct */
2799 env = validate_envW(pEnvironment);
2803 /* pEnvironment was an ANSI-String: convert to unicode first */
2805 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2806 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2807 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2808 env = validate_envW(buffer);
2809 HeapFree(GetProcessHeap(), 0, buffer);
2811 if (!env) return NULL;
2813 buffer = HeapAlloc( GetProcessHeap(), 0,
2814 (strlenW(DriversW) + strlenW(env->envname) +
2815 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2817 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2818 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2819 HeapFree(GetProcessHeap(), 0, buffer);
2824 /*****************************************************************************
2825 * AddPrinterW [WINSPOOL.@]
2827 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2829 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2833 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2835 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2836 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2837 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2838 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2839 statusW[] = {'S','t','a','t','u','s',0},
2840 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2842 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2845 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2846 SetLastError(ERROR_INVALID_PARAMETER);
2850 ERR("Level = %d, unsupported!\n", Level);
2851 SetLastError(ERROR_INVALID_LEVEL);
2855 SetLastError(ERROR_INVALID_PARAMETER);
2858 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2860 ERR("Can't create Printers key\n");
2863 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2864 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2865 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2866 RegCloseKey(hkeyPrinter);
2867 RegCloseKey(hkeyPrinters);
2870 RegCloseKey(hkeyPrinter);
2872 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2874 ERR("Can't create Drivers key\n");
2875 RegCloseKey(hkeyPrinters);
2878 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2880 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2881 RegCloseKey(hkeyPrinters);
2882 RegCloseKey(hkeyDrivers);
2883 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2886 RegCloseKey(hkeyDriver);
2887 RegCloseKey(hkeyDrivers);
2889 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2890 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2891 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2892 RegCloseKey(hkeyPrinters);
2896 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2898 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2899 SetLastError(ERROR_INVALID_PRINTER_NAME);
2900 RegCloseKey(hkeyPrinters);
2903 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2904 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2905 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2907 /* See if we can load the driver. We may need the devmode structure anyway
2910 * Note that DocumentPropertiesW will briefly try to open the printer we
2911 * just create to find a DEVMODEA struct (it will use the WINEPS default
2912 * one in case it is not there, so we are ok).
2914 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2917 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2918 size = sizeof(DEVMODEW);
2924 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2926 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2928 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2929 HeapFree(GetProcessHeap(),0,dmW);
2934 /* set devmode to printer name */
2935 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2939 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2940 and we support these drivers. NT writes DEVMODEW so somehow
2941 we'll need to distinguish between these when we support NT
2945 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2946 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2947 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2948 HeapFree(GetProcessHeap(), 0, dmA);
2950 HeapFree(GetProcessHeap(), 0, dmW);
2952 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2953 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2954 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2955 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2957 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2958 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2959 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2960 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2961 (LPBYTE)&pi->Priority, sizeof(DWORD));
2962 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2963 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2964 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2965 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2966 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2967 (LPBYTE)&pi->Status, sizeof(DWORD));
2968 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2969 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2971 RegCloseKey(hkeyPrinter);
2972 RegCloseKey(hkeyPrinters);
2973 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2974 ERR("OpenPrinter failing\n");
2980 /*****************************************************************************
2981 * AddPrinterA [WINSPOOL.@]
2983 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2985 UNICODE_STRING pNameW;
2987 PRINTER_INFO_2W *piW;
2988 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2991 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2993 ERR("Level = %d, unsupported!\n", Level);
2994 SetLastError(ERROR_INVALID_LEVEL);
2997 pwstrNameW = asciitounicode(&pNameW,pName);
2998 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3000 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3002 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3003 RtlFreeUnicodeString(&pNameW);
3008 /*****************************************************************************
3009 * ClosePrinter [WINSPOOL.@]
3011 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3013 UINT_PTR i = (UINT_PTR)hPrinter;
3014 opened_printer_t *printer = NULL;
3017 TRACE("(%p)\n", hPrinter);
3019 EnterCriticalSection(&printer_handles_cs);
3021 if ((i > 0) && (i <= nb_printer_handles))
3022 printer = printer_handles[i - 1];
3027 struct list *cursor, *cursor2;
3029 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3030 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3031 printer->hXcv, debugstr_w(printer->name), printer->doc );
3034 EndDocPrinter(hPrinter);
3036 if(InterlockedDecrement(&printer->queue->ref) == 0)
3038 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3040 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3041 ScheduleJob(hPrinter, job->job_id);
3043 HeapFree(GetProcessHeap(), 0, printer->queue);
3045 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3046 monitor_unload(printer->pm);
3047 HeapFree(GetProcessHeap(), 0, printer->printername);
3048 HeapFree(GetProcessHeap(), 0, printer->name);
3049 HeapFree(GetProcessHeap(), 0, printer);
3050 printer_handles[i - 1] = NULL;
3053 LeaveCriticalSection(&printer_handles_cs);
3057 /*****************************************************************************
3058 * DeleteFormA [WINSPOOL.@]
3060 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3062 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3066 /*****************************************************************************
3067 * DeleteFormW [WINSPOOL.@]
3069 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3071 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3075 /*****************************************************************************
3076 * DeletePrinter [WINSPOOL.@]
3078 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3080 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3081 HKEY hkeyPrinters, hkey;
3084 SetLastError(ERROR_INVALID_HANDLE);
3087 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3088 RegDeleteTreeW(hkeyPrinters, lpNameW);
3089 RegCloseKey(hkeyPrinters);
3091 WriteProfileStringW(devicesW, lpNameW, NULL);
3092 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3093 RegDeleteValueW(hkey, lpNameW);
3099 /*****************************************************************************
3100 * SetPrinterA [WINSPOOL.@]
3102 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3105 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3109 /*****************************************************************************
3110 * SetJobA [WINSPOOL.@]
3112 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3113 LPBYTE pJob, DWORD Command)
3117 UNICODE_STRING usBuffer;
3119 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3121 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3122 are all ignored by SetJob, so we don't bother copying them */
3130 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3131 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3133 JobW = (LPBYTE)info1W;
3134 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3135 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3136 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3137 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3138 info1W->Status = info1A->Status;
3139 info1W->Priority = info1A->Priority;
3140 info1W->Position = info1A->Position;
3141 info1W->PagesPrinted = info1A->PagesPrinted;
3146 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3147 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3149 JobW = (LPBYTE)info2W;
3150 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3151 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3152 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3153 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3154 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3155 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3156 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3157 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3158 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3159 info2W->Status = info2A->Status;
3160 info2W->Priority = info2A->Priority;
3161 info2W->Position = info2A->Position;
3162 info2W->StartTime = info2A->StartTime;
3163 info2W->UntilTime = info2A->UntilTime;
3164 info2W->PagesPrinted = info2A->PagesPrinted;
3168 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3169 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3172 SetLastError(ERROR_INVALID_LEVEL);
3176 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3182 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3183 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3184 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3185 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3186 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3191 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3192 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3193 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3194 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3195 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3196 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3197 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3198 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3199 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3203 HeapFree(GetProcessHeap(), 0, JobW);
3208 /*****************************************************************************
3209 * SetJobW [WINSPOOL.@]
3211 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3212 LPBYTE pJob, DWORD Command)
3217 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3218 FIXME("Ignoring everything other than document title\n");
3220 EnterCriticalSection(&printer_handles_cs);
3221 job = get_job(hPrinter, JobId);
3231 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3232 HeapFree(GetProcessHeap(), 0, job->document_title);
3233 job->document_title = strdupW(info1->pDocument);
3238 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3239 HeapFree(GetProcessHeap(), 0, job->document_title);
3240 job->document_title = strdupW(info2->pDocument);
3246 SetLastError(ERROR_INVALID_LEVEL);
3251 LeaveCriticalSection(&printer_handles_cs);
3255 /*****************************************************************************
3256 * EndDocPrinter [WINSPOOL.@]
3258 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3260 opened_printer_t *printer;
3262 TRACE("(%p)\n", hPrinter);
3264 EnterCriticalSection(&printer_handles_cs);
3266 printer = get_opened_printer(hPrinter);
3269 SetLastError(ERROR_INVALID_HANDLE);
3275 SetLastError(ERROR_SPL_NO_STARTDOC);
3279 CloseHandle(printer->doc->hf);
3280 ScheduleJob(hPrinter, printer->doc->job_id);
3281 HeapFree(GetProcessHeap(), 0, printer->doc);
3282 printer->doc = NULL;
3285 LeaveCriticalSection(&printer_handles_cs);
3289 /*****************************************************************************
3290 * EndPagePrinter [WINSPOOL.@]
3292 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3294 FIXME("(%p): stub\n", hPrinter);
3298 /*****************************************************************************
3299 * StartDocPrinterA [WINSPOOL.@]
3301 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3303 UNICODE_STRING usBuffer;
3305 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3308 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3309 or one (DOC_INFO_3) extra DWORDs */
3313 doc2W.JobId = doc2->JobId;
3316 doc2W.dwMode = doc2->dwMode;
3319 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3320 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3321 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3325 SetLastError(ERROR_INVALID_LEVEL);
3329 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3331 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3332 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3333 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3338 /*****************************************************************************
3339 * StartDocPrinterW [WINSPOOL.@]
3341 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3343 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3344 opened_printer_t *printer;
3345 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3346 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3347 JOB_INFO_1W job_info;
3348 DWORD needed, ret = 0;
3352 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3353 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3354 debugstr_w(doc->pDatatype));
3356 if(Level < 1 || Level > 3)
3358 SetLastError(ERROR_INVALID_LEVEL);
3362 EnterCriticalSection(&printer_handles_cs);
3363 printer = get_opened_printer(hPrinter);
3366 SetLastError(ERROR_INVALID_HANDLE);
3372 SetLastError(ERROR_INVALID_PRINTER_STATE);
3376 /* Even if we're printing to a file we still add a print job, we'll
3377 just ignore the spool file name */
3379 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3381 ERR("AddJob failed gle %u\n", GetLastError());
3385 if(doc->pOutputFile)
3386 filename = doc->pOutputFile;
3388 filename = addjob->Path;
3390 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3391 if(hf == INVALID_HANDLE_VALUE)
3394 memset(&job_info, 0, sizeof(job_info));
3395 job_info.pDocument = doc->pDocName;
3396 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3398 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3399 printer->doc->hf = hf;
3400 ret = printer->doc->job_id = addjob->JobId;
3402 LeaveCriticalSection(&printer_handles_cs);
3407 /*****************************************************************************
3408 * StartPagePrinter [WINSPOOL.@]
3410 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3412 FIXME("(%p): stub\n", hPrinter);
3416 /*****************************************************************************
3417 * GetFormA [WINSPOOL.@]
3419 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3420 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3422 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3423 Level,pForm,cbBuf,pcbNeeded);
3427 /*****************************************************************************
3428 * GetFormW [WINSPOOL.@]
3430 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3431 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3433 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3434 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3438 /*****************************************************************************
3439 * SetFormA [WINSPOOL.@]
3441 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3444 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3448 /*****************************************************************************
3449 * SetFormW [WINSPOOL.@]
3451 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3454 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3458 /*****************************************************************************
3459 * ReadPrinter [WINSPOOL.@]
3461 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3462 LPDWORD pNoBytesRead)
3464 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3468 /*****************************************************************************
3469 * ResetPrinterA [WINSPOOL.@]
3471 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3473 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3477 /*****************************************************************************
3478 * ResetPrinterW [WINSPOOL.@]
3480 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3482 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3486 /*****************************************************************************
3487 * WINSPOOL_GetDWORDFromReg
3489 * Return DWORD associated with ValueName from hkey.
3491 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3493 DWORD sz = sizeof(DWORD), type, value = 0;
3496 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3498 if(ret != ERROR_SUCCESS) {
3499 WARN("Got ret = %d on name %s\n", ret, ValueName);
3502 if(type != REG_DWORD) {
3503 ERR("Got type %d\n", type);
3510 /*****************************************************************************
3511 * get_filename_from_reg [internal]
3513 * Get ValueName from hkey storing result in out
3514 * when the Value in the registry has only a filename, use driverdir as prefix
3515 * outlen is space left in out
3516 * String is stored either as unicode or ascii
3520 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3521 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3523 WCHAR filename[MAX_PATH];
3527 LPWSTR buffer = filename;
3531 size = sizeof(filename);
3533 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3534 if (ret == ERROR_MORE_DATA) {
3535 TRACE("need dynamic buffer: %u\n", size);
3536 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3538 /* No Memory is bad */
3542 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3545 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3546 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3552 /* do we have a full path ? */
3553 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3554 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3557 /* we must build the full Path */
3559 if ((out) && (outlen > dirlen)) {
3561 lstrcpyW((LPWSTR)out, driverdir);
3565 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3574 /* write the filename */
3576 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3577 if ((out) && (outlen >= size)) {
3578 lstrcpyW((LPWSTR)out, ptr);
3587 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3588 if ((out) && (outlen >= size)) {
3589 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3597 ptr += lstrlenW(ptr)+1;
3598 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3601 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3603 /* write the multisz-termination */
3604 if (type == REG_MULTI_SZ) {
3605 size = (unicode) ? sizeof(WCHAR) : 1;
3608 if (out && (outlen >= size)) {
3609 memset (out, 0, size);
3615 /*****************************************************************************
3616 * WINSPOOL_GetStringFromReg
3618 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3619 * String is stored either as unicode or ascii.
3620 * Bit of a hack here to get the ValueName if we want ascii.
3622 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3623 DWORD buflen, DWORD *needed,
3626 DWORD sz = buflen, type;
3630 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3632 LPSTR ValueNameA = strdupWtoA(ValueName);
3633 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3634 HeapFree(GetProcessHeap(),0,ValueNameA);
3636 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3637 WARN("Got ret = %d\n", ret);
3641 /* add space for terminating '\0' */
3642 sz += unicode ? sizeof(WCHAR) : 1;
3646 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3651 /*****************************************************************************
3652 * WINSPOOL_GetDefaultDevMode
3654 * Get a default DevMode values for wineps.
3658 static void WINSPOOL_GetDefaultDevMode(
3660 DWORD buflen, DWORD *needed,
3664 static const char szwps[] = "wineps.drv";
3666 /* fill default DEVMODE - should be read from ppd... */
3667 ZeroMemory( &dm, sizeof(dm) );
3668 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3669 dm.dmSpecVersion = DM_SPECVERSION;
3670 dm.dmDriverVersion = 1;
3671 dm.dmSize = sizeof(DEVMODEA);
3672 dm.dmDriverExtra = 0;
3674 DM_ORIENTATION | DM_PAPERSIZE |
3675 DM_PAPERLENGTH | DM_PAPERWIDTH |
3678 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3679 DM_YRESOLUTION | DM_TTOPTION;
3681 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3682 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3683 dm.u1.s1.dmPaperLength = 2970;
3684 dm.u1.s1.dmPaperWidth = 2100;
3688 dm.dmDefaultSource = DMBIN_AUTO;
3689 dm.dmPrintQuality = DMRES_MEDIUM;
3692 dm.dmYResolution = 300; /* 300dpi */
3693 dm.dmTTOption = DMTT_BITMAP;
3696 /* dm.dmLogPixels */
3697 /* dm.dmBitsPerPel */
3698 /* dm.dmPelsWidth */
3699 /* dm.dmPelsHeight */
3700 /* dm.dmDisplayFlags */
3701 /* dm.dmDisplayFrequency */
3702 /* dm.dmICMMethod */
3703 /* dm.dmICMIntent */
3704 /* dm.dmMediaType */
3705 /* dm.dmDitherType */
3706 /* dm.dmReserved1 */
3707 /* dm.dmReserved2 */
3708 /* dm.dmPanningWidth */
3709 /* dm.dmPanningHeight */
3712 if(buflen >= sizeof(DEVMODEW)) {
3713 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3714 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3715 HeapFree(GetProcessHeap(),0,pdmW);
3717 *needed = sizeof(DEVMODEW);
3721 if(buflen >= sizeof(DEVMODEA)) {
3722 memcpy(ptr, &dm, sizeof(DEVMODEA));
3724 *needed = sizeof(DEVMODEA);
3728 /*****************************************************************************
3729 * WINSPOOL_GetDevModeFromReg
3731 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3732 * DevMode is stored either as unicode or ascii.
3734 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3736 DWORD buflen, DWORD *needed,
3739 DWORD sz = buflen, type;
3742 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3743 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3744 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3745 if (sz < sizeof(DEVMODEA))
3747 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3750 /* ensures that dmSize is not erratically bogus if registry is invalid */
3751 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3752 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3754 sz += (CCHDEVICENAME + CCHFORMNAME);
3756 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3757 memcpy(ptr, dmW, sz);
3758 HeapFree(GetProcessHeap(),0,dmW);
3765 /*********************************************************************
3766 * WINSPOOL_GetPrinter_1
3768 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3769 * The strings are either stored as unicode or ascii.
3771 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3772 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3775 DWORD size, left = cbBuf;
3776 BOOL space = (cbBuf > 0);
3781 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3783 if(space && size <= left) {
3784 pi1->pName = (LPWSTR)ptr;
3792 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3793 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3795 if(space && size <= left) {
3796 pi1->pDescription = (LPWSTR)ptr;
3804 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3806 if(space && size <= left) {
3807 pi1->pComment = (LPWSTR)ptr;
3815 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3817 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3818 memset(pi1, 0, sizeof(*pi1));
3822 /*********************************************************************
3823 * WINSPOOL_GetPrinter_2
3825 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3826 * The strings are either stored as unicode or ascii.
3828 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3829 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3832 DWORD size, left = cbBuf;
3833 BOOL space = (cbBuf > 0);
3838 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3840 if(space && size <= left) {
3841 pi2->pPrinterName = (LPWSTR)ptr;
3848 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3850 if(space && size <= left) {
3851 pi2->pShareName = (LPWSTR)ptr;
3858 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3860 if(space && size <= left) {
3861 pi2->pPortName = (LPWSTR)ptr;
3868 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3870 if(space && size <= left) {
3871 pi2->pDriverName = (LPWSTR)ptr;
3878 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3880 if(space && size <= left) {
3881 pi2->pComment = (LPWSTR)ptr;
3888 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3890 if(space && size <= left) {
3891 pi2->pLocation = (LPWSTR)ptr;
3898 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3900 if(space && size <= left) {
3901 pi2->pDevMode = (LPDEVMODEW)ptr;
3910 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3911 if(space && size <= left) {
3912 pi2->pDevMode = (LPDEVMODEW)ptr;
3919 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3921 if(space && size <= left) {
3922 pi2->pSepFile = (LPWSTR)ptr;
3929 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3931 if(space && size <= left) {
3932 pi2->pPrintProcessor = (LPWSTR)ptr;
3939 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3941 if(space && size <= left) {
3942 pi2->pDatatype = (LPWSTR)ptr;
3949 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3951 if(space && size <= left) {
3952 pi2->pParameters = (LPWSTR)ptr;
3960 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3961 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3962 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3963 "Default Priority");
3964 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3965 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3968 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3969 memset(pi2, 0, sizeof(*pi2));
3974 /*********************************************************************
3975 * WINSPOOL_GetPrinter_4
3977 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3979 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3980 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3983 DWORD size, left = cbBuf;
3984 BOOL space = (cbBuf > 0);
3989 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3991 if(space && size <= left) {
3992 pi4->pPrinterName = (LPWSTR)ptr;
4000 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4003 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4004 memset(pi4, 0, sizeof(*pi4));
4009 /*********************************************************************
4010 * WINSPOOL_GetPrinter_5
4012 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4014 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4015 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4018 DWORD size, left = cbBuf;
4019 BOOL space = (cbBuf > 0);
4024 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4026 if(space && size <= left) {
4027 pi5->pPrinterName = (LPWSTR)ptr;
4034 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4036 if(space && size <= left) {
4037 pi5->pPortName = (LPWSTR)ptr;
4045 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4046 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4048 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4052 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4053 memset(pi5, 0, sizeof(*pi5));
4058 /*****************************************************************************
4059 * WINSPOOL_GetPrinter
4061 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4062 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4063 * just a collection of pointers to strings.
4065 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4066 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4069 DWORD size, needed = 0;
4071 HKEY hkeyPrinter, hkeyPrinters;
4074 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4076 if (!(name = get_opened_printer_name(hPrinter))) {
4077 SetLastError(ERROR_INVALID_HANDLE);
4081 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4083 ERR("Can't create Printers key\n");
4086 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4088 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4089 RegCloseKey(hkeyPrinters);
4090 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4097 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4099 size = sizeof(PRINTER_INFO_2W);
4101 ptr = pPrinter + size;
4103 memset(pPrinter, 0, size);
4108 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4116 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4118 size = sizeof(PRINTER_INFO_4W);
4120 ptr = pPrinter + size;
4122 memset(pPrinter, 0, size);
4127 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4136 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4138 size = sizeof(PRINTER_INFO_5W);
4140 ptr = pPrinter + size;
4142 memset(pPrinter, 0, size);
4148 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4155 FIXME("Unimplemented level %d\n", Level);
4156 SetLastError(ERROR_INVALID_LEVEL);
4157 RegCloseKey(hkeyPrinters);
4158 RegCloseKey(hkeyPrinter);
4162 RegCloseKey(hkeyPrinter);
4163 RegCloseKey(hkeyPrinters);
4165 TRACE("returning %d needed = %d\n", ret, needed);
4166 if(pcbNeeded) *pcbNeeded = needed;
4168 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4172 /*****************************************************************************
4173 * GetPrinterW [WINSPOOL.@]
4175 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4176 DWORD cbBuf, LPDWORD pcbNeeded)
4178 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4182 /*****************************************************************************
4183 * GetPrinterA [WINSPOOL.@]
4185 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4186 DWORD cbBuf, LPDWORD pcbNeeded)
4188 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4192 /*****************************************************************************
4193 * WINSPOOL_EnumPrinters
4195 * Implementation of EnumPrintersA|W
4197 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4198 DWORD dwLevel, LPBYTE lpbPrinters,
4199 DWORD cbBuf, LPDWORD lpdwNeeded,
4200 LPDWORD lpdwReturned, BOOL unicode)
4203 HKEY hkeyPrinters, hkeyPrinter;
4204 WCHAR PrinterName[255];
4205 DWORD needed = 0, number = 0;
4206 DWORD used, i, left;
4210 memset(lpbPrinters, 0, cbBuf);
4216 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4217 if(dwType == PRINTER_ENUM_DEFAULT)
4220 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4221 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4222 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4224 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4232 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4233 FIXME("dwType = %08x\n", dwType);
4234 SetLastError(ERROR_INVALID_FLAGS);
4238 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4240 ERR("Can't create Printers key\n");
4244 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4245 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4246 RegCloseKey(hkeyPrinters);
4247 ERR("Can't query Printers key\n");
4250 TRACE("Found %d printers\n", number);
4254 used = number * sizeof(PRINTER_INFO_1W);
4257 used = number * sizeof(PRINTER_INFO_2W);
4260 used = number * sizeof(PRINTER_INFO_4W);
4263 used = number * sizeof(PRINTER_INFO_5W);
4267 SetLastError(ERROR_INVALID_LEVEL);
4268 RegCloseKey(hkeyPrinters);
4271 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4273 for(i = 0; i < number; i++) {
4274 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4276 ERR("Can't enum key number %d\n", i);
4277 RegCloseKey(hkeyPrinters);
4280 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4281 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4283 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4284 RegCloseKey(hkeyPrinters);
4289 buf = lpbPrinters + used;
4290 left = cbBuf - used;
4298 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4299 left, &needed, unicode);
4301 if(pi) pi += sizeof(PRINTER_INFO_1W);
4304 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4305 left, &needed, unicode);
4307 if(pi) pi += sizeof(PRINTER_INFO_2W);
4310 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4311 left, &needed, unicode);
4313 if(pi) pi += sizeof(PRINTER_INFO_4W);
4316 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4317 left, &needed, unicode);
4319 if(pi) pi += sizeof(PRINTER_INFO_5W);
4322 ERR("Shouldn't be here!\n");
4323 RegCloseKey(hkeyPrinter);
4324 RegCloseKey(hkeyPrinters);
4327 RegCloseKey(hkeyPrinter);
4329 RegCloseKey(hkeyPrinters);
4336 memset(lpbPrinters, 0, cbBuf);
4337 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4341 *lpdwReturned = number;
4342 SetLastError(ERROR_SUCCESS);
4347 /******************************************************************
4348 * EnumPrintersW [WINSPOOL.@]
4350 * Enumerates the available printers, print servers and print
4351 * providers, depending on the specified flags, name and level.
4355 * If level is set to 1:
4356 * Returns an array of PRINTER_INFO_1 data structures in the
4357 * lpbPrinters buffer.
4359 * If level is set to 2:
4360 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4361 * Returns an array of PRINTER_INFO_2 data structures in the
4362 * lpbPrinters buffer. Note that according to MSDN also an
4363 * OpenPrinter should be performed on every remote printer.
4365 * If level is set to 4 (officially WinNT only):
4366 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4367 * Fast: Only the registry is queried to retrieve printer names,
4368 * no connection to the driver is made.
4369 * Returns an array of PRINTER_INFO_4 data structures in the
4370 * lpbPrinters buffer.
4372 * If level is set to 5 (officially WinNT4/Win9x only):
4373 * Fast: Only the registry is queried to retrieve printer names,
4374 * no connection to the driver is made.
4375 * Returns an array of PRINTER_INFO_5 data structures in the
4376 * lpbPrinters buffer.
4378 * If level set to 3 or 6+:
4379 * returns zero (failure!)
4381 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4385 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4386 * - Only levels 2, 4 and 5 are implemented at the moment.
4387 * - 16-bit printer drivers are not enumerated.
4388 * - Returned amount of bytes used/needed does not match the real Windoze
4389 * implementation (as in this implementation, all strings are part
4390 * of the buffer, whereas Win32 keeps them somewhere else)
4391 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4394 * - In a regular Wine installation, no registry settings for printers
4395 * exist, which makes this function return an empty list.
4397 BOOL WINAPI EnumPrintersW(
4398 DWORD dwType, /* [in] Types of print objects to enumerate */
4399 LPWSTR lpszName, /* [in] name of objects to enumerate */
4400 DWORD dwLevel, /* [in] type of printer info structure */
4401 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4402 DWORD cbBuf, /* [in] max size of buffer in bytes */
4403 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4404 LPDWORD lpdwReturned /* [out] number of entries returned */
4407 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4408 lpdwNeeded, lpdwReturned, TRUE);
4411 /******************************************************************
4412 * EnumPrintersA [WINSPOOL.@]
4415 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4416 DWORD dwLevel, LPBYTE lpbPrinters,
4417 DWORD cbBuf, LPDWORD lpdwNeeded,
4418 LPDWORD lpdwReturned)
4420 BOOL ret, unicode = FALSE;
4421 UNICODE_STRING lpszNameW;
4424 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4425 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4426 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4427 lpdwNeeded, lpdwReturned, unicode);
4428 RtlFreeUnicodeString(&lpszNameW);
4432 /*****************************************************************************
4433 * WINSPOOL_GetDriverInfoFromReg [internal]
4435 * Enters the information from the registry into the DRIVER_INFO struct
4438 * zero if the printer driver does not exist in the registry
4439 * (only if Level > 1) otherwise nonzero
4441 static BOOL WINSPOOL_GetDriverInfoFromReg(
4444 const printenv_t * env,
4446 LPBYTE ptr, /* DRIVER_INFO */
4447 LPBYTE pDriverStrings, /* strings buffer */
4448 DWORD cbBuf, /* size of string buffer */
4449 LPDWORD pcbNeeded, /* space needed for str. */
4450 BOOL unicode) /* type of strings */
4454 WCHAR driverdir[MAX_PATH];
4456 LPBYTE strPtr = pDriverStrings;
4457 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4459 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4460 debugstr_w(DriverName), env,
4461 Level, di, pDriverStrings, cbBuf, unicode);
4463 if (di) ZeroMemory(di, di_sizeof[Level]);
4466 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4467 if (*pcbNeeded <= cbBuf)
4468 strcpyW((LPWSTR)strPtr, DriverName);
4472 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4473 if (*pcbNeeded <= cbBuf)
4474 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4477 /* pName for level 1 has a different offset! */
4479 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4483 /* .cVersion and .pName for level > 1 */
4485 di->cVersion = env->driverversion;
4486 di->pName = (LPWSTR) strPtr;
4487 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4490 /* Reserve Space for the largest subdir and a Backslash*/
4491 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4492 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4493 /* Should never Fail */
4496 lstrcatW(driverdir, env->versionsubdir);
4497 lstrcatW(driverdir, backslashW);
4499 /* dirlen must not include the terminating zero */
4500 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4501 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4503 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4504 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4505 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4511 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4513 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4516 if (*pcbNeeded <= cbBuf) {
4518 lstrcpyW((LPWSTR)strPtr, env->envname);
4522 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4524 if (di) di->pEnvironment = (LPWSTR)strPtr;
4525 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4528 /* .pDriverPath is the Graphics rendering engine.
4529 The full Path is required to avoid a crash in some apps */
4530 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4532 if (*pcbNeeded <= cbBuf)
4533 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4535 if (di) di->pDriverPath = (LPWSTR)strPtr;
4536 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4539 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4540 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4542 if (*pcbNeeded <= cbBuf)
4543 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4545 if (di) di->pDataFile = (LPWSTR)strPtr;
4546 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4549 /* .pConfigFile is the Driver user Interface */
4550 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4552 if (*pcbNeeded <= cbBuf)
4553 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4555 if (di) di->pConfigFile = (LPWSTR)strPtr;
4556 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4560 RegCloseKey(hkeyDriver);
4561 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4566 RegCloseKey(hkeyDriver);
4567 FIXME("level 5: incomplete\n");
4572 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4574 if (*pcbNeeded <= cbBuf)
4575 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4577 if (di) di->pHelpFile = (LPWSTR)strPtr;
4578 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4581 /* .pDependentFiles */
4582 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4584 if (*pcbNeeded <= cbBuf)
4585 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4587 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4588 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4591 /* .pMonitorName is the optional Language Monitor */
4592 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4594 if (*pcbNeeded <= cbBuf)
4595 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4597 if (di) di->pMonitorName = (LPWSTR)strPtr;
4598 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4601 /* .pDefaultDataType */
4602 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4604 if(*pcbNeeded <= cbBuf)
4605 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4607 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4608 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4612 RegCloseKey(hkeyDriver);
4613 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4617 /* .pszzPreviousNames */
4618 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4620 if(*pcbNeeded <= cbBuf)
4621 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4623 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4624 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4628 RegCloseKey(hkeyDriver);
4629 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4633 /* support is missing, but not important enough for a FIXME */
4634 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4637 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4639 if(*pcbNeeded <= cbBuf)
4640 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4642 if (di) di->pszMfgName = (LPWSTR)strPtr;
4643 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4647 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4649 if(*pcbNeeded <= cbBuf)
4650 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4652 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4653 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4656 /* .pszHardwareID */
4657 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4659 if(*pcbNeeded <= cbBuf)
4660 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4662 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4663 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4667 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4669 if(*pcbNeeded <= cbBuf)
4670 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4672 if (di) di->pszProvider = (LPWSTR)strPtr;
4673 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4677 RegCloseKey(hkeyDriver);
4681 /* support is missing, but not important enough for a FIXME */
4682 TRACE("level 8: incomplete\n");
4684 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4685 RegCloseKey(hkeyDriver);
4689 /*****************************************************************************
4690 * WINSPOOL_GetPrinterDriver
4692 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4693 DWORD Level, LPBYTE pDriverInfo,
4694 DWORD cbBuf, LPDWORD pcbNeeded,
4698 WCHAR DriverName[100];
4699 DWORD ret, type, size, needed = 0;
4701 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4702 const printenv_t * env;
4704 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4705 Level,pDriverInfo,cbBuf, pcbNeeded);
4708 if (!(name = get_opened_printer_name(hPrinter))) {
4709 SetLastError(ERROR_INVALID_HANDLE);
4713 if (Level < 1 || Level == 7 || Level > 8) {
4714 SetLastError(ERROR_INVALID_LEVEL);
4718 env = validate_envW(pEnvironment);
4719 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4721 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4723 ERR("Can't create Printers key\n");
4726 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4728 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4729 RegCloseKey(hkeyPrinters);
4730 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4733 size = sizeof(DriverName);
4735 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4736 (LPBYTE)DriverName, &size);
4737 RegCloseKey(hkeyPrinter);
4738 RegCloseKey(hkeyPrinters);
4739 if(ret != ERROR_SUCCESS) {
4740 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4744 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4746 ERR("Can't create Drivers key\n");
4750 size = di_sizeof[Level];
4751 if ((size <= cbBuf) && pDriverInfo)
4752 ptr = pDriverInfo + size;
4754 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4755 env, Level, pDriverInfo, ptr,
4756 (cbBuf < size) ? 0 : cbBuf - size,
4757 &needed, unicode)) {
4758 RegCloseKey(hkeyDrivers);
4762 RegCloseKey(hkeyDrivers);
4764 if(pcbNeeded) *pcbNeeded = size + needed;
4765 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4766 if(cbBuf >= needed) return TRUE;
4767 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4771 /*****************************************************************************
4772 * GetPrinterDriverA [WINSPOOL.@]
4774 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4775 DWORD Level, LPBYTE pDriverInfo,
4776 DWORD cbBuf, LPDWORD pcbNeeded)
4779 UNICODE_STRING pEnvW;
4782 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4783 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4784 cbBuf, pcbNeeded, FALSE);
4785 RtlFreeUnicodeString(&pEnvW);
4788 /*****************************************************************************
4789 * GetPrinterDriverW [WINSPOOL.@]
4791 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4792 DWORD Level, LPBYTE pDriverInfo,
4793 DWORD cbBuf, LPDWORD pcbNeeded)
4795 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4796 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4799 /*****************************************************************************
4800 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4802 * Return the PATH for the Printer-Drivers (UNICODE)
4805 * pName [I] Servername (NT only) or NULL (local Computer)
4806 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4807 * Level [I] Structure-Level (must be 1)
4808 * pDriverDirectory [O] PTR to Buffer that receives the Result
4809 * cbBuf [I] Size of Buffer at pDriverDirectory
4810 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4811 * required for pDriverDirectory
4814 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4815 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4816 * if cbBuf is too small
4818 * Native Values returned in pDriverDirectory on Success:
4819 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4820 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4821 *| win9x(Windows 4.0): "%winsysdir%"
4823 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4826 *- Only NULL or "" is supported for pName
4829 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4830 DWORD Level, LPBYTE pDriverDirectory,
4831 DWORD cbBuf, LPDWORD pcbNeeded)
4834 const printenv_t * env;
4836 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4837 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4838 if(pName != NULL && pName[0]) {
4839 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4840 SetLastError(ERROR_INVALID_PARAMETER);
4844 env = validate_envW(pEnvironment);
4845 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4848 WARN("(Level: %d) is ignored in win9x\n", Level);
4849 SetLastError(ERROR_INVALID_LEVEL);
4853 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4854 needed = GetSystemDirectoryW(NULL, 0);
4855 /* add the Size for the Subdirectories */
4856 needed += lstrlenW(spooldriversW);
4857 needed += lstrlenW(env->subdir);
4858 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4861 *pcbNeeded = needed;
4862 TRACE("required: 0x%x/%d\n", needed, needed);
4863 if(needed > cbBuf) {
4864 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4867 if(pcbNeeded == NULL) {
4868 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4869 SetLastError(RPC_X_NULL_REF_POINTER);
4872 if(pDriverDirectory == NULL) {
4873 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4874 SetLastError(ERROR_INVALID_USER_BUFFER);
4878 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4879 /* add the Subdirectories */
4880 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4881 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4882 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4887 /*****************************************************************************
4888 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4890 * Return the PATH for the Printer-Drivers (ANSI)
4892 * See GetPrinterDriverDirectoryW.
4895 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4898 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4899 DWORD Level, LPBYTE pDriverDirectory,
4900 DWORD cbBuf, LPDWORD pcbNeeded)
4902 UNICODE_STRING nameW, environmentW;
4905 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4906 WCHAR *driverDirectoryW = NULL;
4908 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4909 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4911 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4913 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4914 else nameW.Buffer = NULL;
4915 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4916 else environmentW.Buffer = NULL;
4918 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4919 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4922 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4923 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4925 *pcbNeeded = needed;
4926 ret = (needed <= cbBuf) ? TRUE : FALSE;
4928 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4930 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4932 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4933 RtlFreeUnicodeString(&environmentW);
4934 RtlFreeUnicodeString(&nameW);
4939 /*****************************************************************************
4940 * AddPrinterDriverA [WINSPOOL.@]
4942 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4945 HKEY hkeyDrivers, hkeyName;
4946 static CHAR empty[] = "",
4949 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4951 if(level != 2 && level != 3) {
4952 SetLastError(ERROR_INVALID_LEVEL);
4955 if ((pName) && (pName[0])) {
4956 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4957 SetLastError(ERROR_INVALID_PARAMETER);
4961 WARN("pDriverInfo == NULL\n");
4962 SetLastError(ERROR_INVALID_PARAMETER);
4967 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4969 memset(&di3, 0, sizeof(di3));
4970 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4973 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4975 SetLastError(ERROR_INVALID_PARAMETER);
4979 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4980 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4981 if(!di3.pHelpFile) di3.pHelpFile = empty;
4982 if(!di3.pMonitorName) di3.pMonitorName = empty;
4984 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4987 ERR("Can't create Drivers key\n");
4991 if(level == 2) { /* apparently can't overwrite with level2 */
4992 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4993 RegCloseKey(hkeyName);
4994 RegCloseKey(hkeyDrivers);
4995 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4996 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
5000 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
5001 RegCloseKey(hkeyDrivers);
5002 ERR("Can't create Name key\n");
5005 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
5006 lstrlenA(di3.pConfigFile) + 1);
5007 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
5008 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
5009 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
5011 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
5012 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
5013 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
5014 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
5015 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
5016 RegCloseKey(hkeyName);
5017 RegCloseKey(hkeyDrivers);
5022 /*****************************************************************************
5023 * AddPrinterDriverW [WINSPOOL.@]
5025 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
5028 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
5033 /*****************************************************************************
5034 * AddPrintProcessorA [WINSPOOL.@]
5036 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5037 LPSTR pPrintProcessorName)
5039 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5040 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5044 /*****************************************************************************
5045 * AddPrintProcessorW [WINSPOOL.@]
5047 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5048 LPWSTR pPrintProcessorName)
5050 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5051 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5055 /*****************************************************************************
5056 * AddPrintProvidorA [WINSPOOL.@]
5058 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5060 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5064 /*****************************************************************************
5065 * AddPrintProvidorW [WINSPOOL.@]
5067 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5069 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5073 /*****************************************************************************
5074 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5076 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5077 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5079 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5080 pDevModeOutput, pDevModeInput);
5084 /*****************************************************************************
5085 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5087 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5088 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5090 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5091 pDevModeOutput, pDevModeInput);
5095 /*****************************************************************************
5096 * PrinterProperties [WINSPOOL.@]
5098 * Displays a dialog to set the properties of the printer.
5101 * nonzero on success or zero on failure
5104 * implemented as stub only
5106 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5107 HANDLE hPrinter /* [in] handle to printer object */
5109 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5110 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5114 /*****************************************************************************
5115 * EnumJobsA [WINSPOOL.@]
5118 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5119 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5122 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5123 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5125 if(pcbNeeded) *pcbNeeded = 0;
5126 if(pcReturned) *pcReturned = 0;
5131 /*****************************************************************************
5132 * EnumJobsW [WINSPOOL.@]
5135 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5136 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5139 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5140 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5142 if(pcbNeeded) *pcbNeeded = 0;
5143 if(pcReturned) *pcReturned = 0;
5147 /*****************************************************************************
5148 * WINSPOOL_EnumPrinterDrivers [internal]
5150 * Delivers information about all printer drivers installed on the
5151 * localhost or a given server
5154 * nonzero on success or zero on failure. If the buffer for the returned
5155 * information is too small the function will return an error
5158 * - only implemented for localhost, foreign hosts will return an error
5160 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5161 DWORD Level, LPBYTE pDriverInfo,
5162 DWORD cbBuf, LPDWORD pcbNeeded,
5163 LPDWORD pcReturned, BOOL unicode)
5166 DWORD i, needed, number = 0, size = 0;
5167 WCHAR DriverNameW[255];
5169 const printenv_t * env;
5171 TRACE("%s,%s,%d,%p,%d,%d\n",
5172 debugstr_w(pName), debugstr_w(pEnvironment),
5173 Level, pDriverInfo, cbBuf, unicode);
5175 /* check for local drivers */
5176 if((pName) && (pName[0])) {
5177 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5178 SetLastError(ERROR_ACCESS_DENIED);
5182 env = validate_envW(pEnvironment);
5183 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5185 /* check input parameter */
5186 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5187 SetLastError(ERROR_INVALID_LEVEL);
5191 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5192 SetLastError(RPC_X_NULL_REF_POINTER);
5196 /* initialize return values */
5198 memset( pDriverInfo, 0, cbBuf);
5202 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5204 ERR("Can't open Drivers key\n");
5208 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5209 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5210 RegCloseKey(hkeyDrivers);
5211 ERR("Can't query Drivers key\n");
5214 TRACE("Found %d Drivers\n", number);
5216 /* get size of single struct
5217 * unicode and ascii structure have the same size
5219 size = di_sizeof[Level];
5221 /* calculate required buffer size */
5222 *pcbNeeded = size * number;
5224 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5226 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5227 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
5229 ERR("Can't enum key number %d\n", i);
5230 RegCloseKey(hkeyDrivers);
5233 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5235 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5236 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5237 &needed, unicode)) {
5238 RegCloseKey(hkeyDrivers);
5241 (*pcbNeeded) += needed;
5244 RegCloseKey(hkeyDrivers);
5246 if(cbBuf < *pcbNeeded){
5247 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5251 *pcReturned = number;
5255 /*****************************************************************************
5256 * EnumPrinterDriversW [WINSPOOL.@]
5258 * see function EnumPrinterDrivers for RETURNS, BUGS
5260 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5261 LPBYTE pDriverInfo, DWORD cbBuf,
5262 LPDWORD pcbNeeded, LPDWORD pcReturned)
5264 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5265 cbBuf, pcbNeeded, pcReturned, TRUE);
5268 /*****************************************************************************
5269 * EnumPrinterDriversA [WINSPOOL.@]
5271 * see function EnumPrinterDrivers for RETURNS, BUGS
5273 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5274 LPBYTE pDriverInfo, DWORD cbBuf,
5275 LPDWORD pcbNeeded, LPDWORD pcReturned)
5277 UNICODE_STRING pNameW, pEnvironmentW;
5278 PWSTR pwstrNameW, pwstrEnvironmentW;
5280 pwstrNameW = asciitounicode(&pNameW, pName);
5281 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5283 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5284 Level, pDriverInfo, cbBuf, pcbNeeded,
5286 RtlFreeUnicodeString(&pNameW);
5287 RtlFreeUnicodeString(&pEnvironmentW);
5292 /******************************************************************************
5293 * EnumPortsA (WINSPOOL.@)
5298 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5299 LPDWORD pcbNeeded, LPDWORD pcReturned)
5302 LPBYTE bufferW = NULL;
5303 LPWSTR nameW = NULL;
5305 DWORD numentries = 0;
5308 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5309 cbBuf, pcbNeeded, pcReturned);
5311 /* convert servername to unicode */
5313 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5314 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5315 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5317 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5318 needed = cbBuf * sizeof(WCHAR);
5319 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5320 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5322 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5323 if (pcbNeeded) needed = *pcbNeeded;
5324 /* HeapReAlloc return NULL, when bufferW was NULL */
5325 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5326 HeapAlloc(GetProcessHeap(), 0, needed);
5328 /* Try again with the large Buffer */
5329 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5331 needed = pcbNeeded ? *pcbNeeded : 0;
5332 numentries = pcReturned ? *pcReturned : 0;
5335 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5336 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5339 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5340 DWORD entrysize = 0;
5343 LPPORT_INFO_2W pi2w;
5344 LPPORT_INFO_2A pi2a;
5347 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5349 /* First pass: calculate the size for all Entries */
5350 pi2w = (LPPORT_INFO_2W) bufferW;
5351 pi2a = (LPPORT_INFO_2A) pPorts;
5353 while (index < numentries) {
5355 needed += entrysize; /* PORT_INFO_?A */
5356 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5358 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5359 NULL, 0, NULL, NULL);
5361 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5362 NULL, 0, NULL, NULL);
5363 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5364 NULL, 0, NULL, NULL);
5366 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5367 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5368 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5371 /* check for errors and quit on failure */
5372 if (cbBuf < needed) {
5373 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5377 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5378 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5379 cbBuf -= len ; /* free Bytes in the user-Buffer */
5380 pi2w = (LPPORT_INFO_2W) bufferW;
5381 pi2a = (LPPORT_INFO_2A) pPorts;
5383 /* Second Pass: Fill the User Buffer (if we have one) */
5384 while ((index < numentries) && pPorts) {
5386 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5387 pi2a->pPortName = ptr;
5388 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5389 ptr, cbBuf , NULL, NULL);
5393 pi2a->pMonitorName = ptr;
5394 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5395 ptr, cbBuf, NULL, NULL);
5399 pi2a->pDescription = ptr;
5400 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5401 ptr, cbBuf, NULL, NULL);
5405 pi2a->fPortType = pi2w->fPortType;
5406 pi2a->Reserved = 0; /* documented: "must be zero" */
5409 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5410 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5411 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5416 if (pcbNeeded) *pcbNeeded = needed;
5417 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5419 HeapFree(GetProcessHeap(), 0, nameW);
5420 HeapFree(GetProcessHeap(), 0, bufferW);
5422 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5423 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5429 /******************************************************************************
5430 * EnumPortsW (WINSPOOL.@)
5432 * Enumerate available Ports
5435 * name [I] Servername or NULL (local Computer)
5436 * level [I] Structure-Level (1 or 2)
5437 * buffer [O] PTR to Buffer that receives the Result
5438 * bufsize [I] Size of Buffer at buffer
5439 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5440 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5444 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5448 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5451 DWORD numentries = 0;
5454 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5455 cbBuf, pcbNeeded, pcReturned);
5457 if (pName && (pName[0])) {
5458 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5459 SetLastError(ERROR_ACCESS_DENIED);
5463 /* Level is not checked in win9x */
5464 if (!Level || (Level > 2)) {
5465 WARN("level (%d) is ignored in win9x\n", Level);
5466 SetLastError(ERROR_INVALID_LEVEL);
5470 SetLastError(RPC_X_NULL_REF_POINTER);
5474 EnterCriticalSection(&monitor_handles_cs);
5477 /* Scan all local Ports */
5479 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5481 /* we calculated the needed buffersize. now do the error-checks */
5482 if (cbBuf < needed) {
5483 monitor_unloadall();
5484 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5485 goto emP_cleanup_cs;
5487 else if (!pPorts || !pcReturned) {
5488 monitor_unloadall();
5489 SetLastError(RPC_X_NULL_REF_POINTER);
5490 goto emP_cleanup_cs;
5493 /* Fill the Buffer */
5494 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5496 monitor_unloadall();
5499 LeaveCriticalSection(&monitor_handles_cs);
5502 if (pcbNeeded) *pcbNeeded = needed;
5503 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5505 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5506 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5511 /******************************************************************************
5512 * GetDefaultPrinterW (WINSPOOL.@)
5515 * This function must read the value from data 'device' of key
5516 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5518 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5522 WCHAR *buffer, *ptr;
5526 SetLastError(ERROR_INVALID_PARAMETER);
5530 /* make the buffer big enough for the stuff from the profile/registry,
5531 * the content must fit into the local buffer to compute the correct
5532 * size even if the extern buffer is too small or not given.
5533 * (20 for ,driver,port) */
5535 len = max(100, (insize + 20));
5536 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5538 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5540 SetLastError (ERROR_FILE_NOT_FOUND);
5544 TRACE("%s\n", debugstr_w(buffer));
5546 if ((ptr = strchrW(buffer, ',')) == NULL)
5548 SetLastError(ERROR_INVALID_NAME);
5554 *namesize = strlenW(buffer) + 1;
5555 if(!name || (*namesize > insize))
5557 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5561 strcpyW(name, buffer);
5564 HeapFree( GetProcessHeap(), 0, buffer);
5569 /******************************************************************************
5570 * GetDefaultPrinterA (WINSPOOL.@)
5572 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5576 WCHAR *bufferW = NULL;
5580 SetLastError(ERROR_INVALID_PARAMETER);
5584 if(name && *namesize) {
5586 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5589 if(!GetDefaultPrinterW( bufferW, namesize)) {
5594 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5598 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5601 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5604 HeapFree( GetProcessHeap(), 0, bufferW);
5609 /******************************************************************************
5610 * SetDefaultPrinterW (WINSPOOL.204)
5612 * Set the Name of the Default Printer
5615 * pszPrinter [I] Name of the Printer or NULL
5622 * When the Parameter is NULL or points to an Empty String and
5623 * a Default Printer was already present, then this Function changes nothing.
5624 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5625 * the First enumerated local Printer is used.
5628 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5631 TRACE("(%s)\n", debugstr_w(pszPrinter));
5633 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5637 /******************************************************************************
5638 * SetDefaultPrinterA (WINSPOOL.202)
5640 * See SetDefaultPrinterW.
5643 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5646 TRACE("(%s)\n", debugstr_a(pszPrinter));
5648 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5653 /******************************************************************************
5654 * SetPrinterDataExA (WINSPOOL.@)
5656 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5657 LPCSTR pValueName, DWORD Type,
5658 LPBYTE pData, DWORD cbData)
5660 HKEY hkeyPrinter, hkeySubkey;
5663 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5664 debugstr_a(pValueName), Type, pData, cbData);
5666 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5670 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5672 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5673 RegCloseKey(hkeyPrinter);
5676 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5677 RegCloseKey(hkeySubkey);
5678 RegCloseKey(hkeyPrinter);
5682 /******************************************************************************
5683 * SetPrinterDataExW (WINSPOOL.@)
5685 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5686 LPCWSTR pValueName, DWORD Type,
5687 LPBYTE pData, DWORD cbData)
5689 HKEY hkeyPrinter, hkeySubkey;
5692 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5693 debugstr_w(pValueName), Type, pData, cbData);
5695 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5699 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5701 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5702 RegCloseKey(hkeyPrinter);
5705 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5706 RegCloseKey(hkeySubkey);
5707 RegCloseKey(hkeyPrinter);
5711 /******************************************************************************
5712 * SetPrinterDataA (WINSPOOL.@)
5714 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5715 LPBYTE pData, DWORD cbData)
5717 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5721 /******************************************************************************
5722 * SetPrinterDataW (WINSPOOL.@)
5724 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5725 LPBYTE pData, DWORD cbData)
5727 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5731 /******************************************************************************
5732 * GetPrinterDataExA (WINSPOOL.@)
5734 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5735 LPCSTR pValueName, LPDWORD pType,
5736 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5738 HKEY hkeyPrinter, hkeySubkey;
5741 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5742 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5745 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5749 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5751 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5752 RegCloseKey(hkeyPrinter);
5756 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5757 RegCloseKey(hkeySubkey);
5758 RegCloseKey(hkeyPrinter);
5762 /******************************************************************************
5763 * GetPrinterDataExW (WINSPOOL.@)
5765 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5766 LPCWSTR pValueName, LPDWORD pType,
5767 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5769 HKEY hkeyPrinter, hkeySubkey;
5772 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5773 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5776 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5780 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5782 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5783 RegCloseKey(hkeyPrinter);
5787 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5788 RegCloseKey(hkeySubkey);
5789 RegCloseKey(hkeyPrinter);
5793 /******************************************************************************
5794 * GetPrinterDataA (WINSPOOL.@)
5796 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5797 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5799 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5800 pData, nSize, pcbNeeded);
5803 /******************************************************************************
5804 * GetPrinterDataW (WINSPOOL.@)
5806 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5807 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5809 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5810 pData, nSize, pcbNeeded);
5813 /*******************************************************************************
5814 * EnumPrinterDataExW [WINSPOOL.@]
5816 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5817 LPBYTE pEnumValues, DWORD cbEnumValues,
5818 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5820 HKEY hkPrinter, hkSubKey;
5821 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5822 cbValueNameLen, cbMaxValueLen, cbValueLen,
5827 PPRINTER_ENUM_VALUESW ppev;
5829 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5831 if (pKeyName == NULL || *pKeyName == 0)
5832 return ERROR_INVALID_PARAMETER;
5834 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5835 if (ret != ERROR_SUCCESS)
5837 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5842 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5843 if (ret != ERROR_SUCCESS)
5845 r = RegCloseKey (hkPrinter);
5846 if (r != ERROR_SUCCESS)
5847 WARN ("RegCloseKey returned %i\n", r);
5848 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5849 debugstr_w (pKeyName), ret);
5853 ret = RegCloseKey (hkPrinter);
5854 if (ret != ERROR_SUCCESS)
5856 ERR ("RegCloseKey returned %i\n", ret);
5857 r = RegCloseKey (hkSubKey);
5858 if (r != ERROR_SUCCESS)
5859 WARN ("RegCloseKey returned %i\n", r);
5863 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5864 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5865 if (ret != ERROR_SUCCESS)
5867 r = RegCloseKey (hkSubKey);
5868 if (r != ERROR_SUCCESS)
5869 WARN ("RegCloseKey returned %i\n", r);
5870 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5874 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5875 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5877 if (cValues == 0) /* empty key */
5879 r = RegCloseKey (hkSubKey);
5880 if (r != ERROR_SUCCESS)
5881 WARN ("RegCloseKey returned %i\n", r);
5882 *pcbEnumValues = *pnEnumValues = 0;
5883 return ERROR_SUCCESS;
5886 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5888 hHeap = GetProcessHeap ();
5891 ERR ("GetProcessHeap failed\n");
5892 r = RegCloseKey (hkSubKey);
5893 if (r != ERROR_SUCCESS)
5894 WARN ("RegCloseKey returned %i\n", r);
5895 return ERROR_OUTOFMEMORY;
5898 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5899 if (lpValueName == NULL)
5901 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5902 r = RegCloseKey (hkSubKey);
5903 if (r != ERROR_SUCCESS)
5904 WARN ("RegCloseKey returned %i\n", r);
5905 return ERROR_OUTOFMEMORY;
5908 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5909 if (lpValue == NULL)
5911 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5912 if (HeapFree (hHeap, 0, lpValueName) == 0)
5913 WARN ("HeapFree failed with code %i\n", GetLastError ());
5914 r = RegCloseKey (hkSubKey);
5915 if (r != ERROR_SUCCESS)
5916 WARN ("RegCloseKey returned %i\n", r);
5917 return ERROR_OUTOFMEMORY;
5920 TRACE ("pass 1: calculating buffer required for all names and values\n");
5922 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5924 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5926 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5928 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5929 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5930 NULL, NULL, lpValue, &cbValueLen);
5931 if (ret != ERROR_SUCCESS)
5933 if (HeapFree (hHeap, 0, lpValue) == 0)
5934 WARN ("HeapFree failed with code %i\n", GetLastError ());
5935 if (HeapFree (hHeap, 0, lpValueName) == 0)
5936 WARN ("HeapFree failed with code %i\n", GetLastError ());
5937 r = RegCloseKey (hkSubKey);
5938 if (r != ERROR_SUCCESS)
5939 WARN ("RegCloseKey returned %i\n", r);
5940 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5944 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5945 debugstr_w (lpValueName), dwIndex,
5946 cbValueNameLen + 1, cbValueLen);
5948 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5949 cbBufSize += cbValueLen;
5952 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5954 *pcbEnumValues = cbBufSize;
5955 *pnEnumValues = cValues;
5957 if (cbEnumValues < cbBufSize) /* buffer too small */
5959 if (HeapFree (hHeap, 0, lpValue) == 0)
5960 WARN ("HeapFree failed with code %i\n", GetLastError ());
5961 if (HeapFree (hHeap, 0, lpValueName) == 0)
5962 WARN ("HeapFree failed with code %i\n", GetLastError ());
5963 r = RegCloseKey (hkSubKey);
5964 if (r != ERROR_SUCCESS)
5965 WARN ("RegCloseKey returned %i\n", r);
5966 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5967 return ERROR_MORE_DATA;
5970 TRACE ("pass 2: copying all names and values to buffer\n");
5972 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5973 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5975 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5977 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5978 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5979 NULL, &dwType, lpValue, &cbValueLen);
5980 if (ret != ERROR_SUCCESS)
5982 if (HeapFree (hHeap, 0, lpValue) == 0)
5983 WARN ("HeapFree failed with code %i\n", GetLastError ());
5984 if (HeapFree (hHeap, 0, lpValueName) == 0)
5985 WARN ("HeapFree failed with code %i\n", GetLastError ());
5986 r = RegCloseKey (hkSubKey);
5987 if (r != ERROR_SUCCESS)
5988 WARN ("RegCloseKey returned %i\n", r);
5989 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5993 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5994 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5995 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5996 pEnumValues += cbValueNameLen;
5998 /* return # of *bytes* (including trailing \0), not # of chars */
5999 ppev[dwIndex].cbValueName = cbValueNameLen;
6001 ppev[dwIndex].dwType = dwType;
6003 memcpy (pEnumValues, lpValue, cbValueLen);
6004 ppev[dwIndex].pData = pEnumValues;
6005 pEnumValues += cbValueLen;
6007 ppev[dwIndex].cbData = cbValueLen;
6009 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6010 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6013 if (HeapFree (hHeap, 0, lpValue) == 0)
6015 ret = GetLastError ();
6016 ERR ("HeapFree failed with code %i\n", ret);
6017 if (HeapFree (hHeap, 0, lpValueName) == 0)
6018 WARN ("HeapFree failed with code %i\n", GetLastError ());
6019 r = RegCloseKey (hkSubKey);
6020 if (r != ERROR_SUCCESS)
6021 WARN ("RegCloseKey returned %i\n", r);
6025 if (HeapFree (hHeap, 0, lpValueName) == 0)
6027 ret = GetLastError ();
6028 ERR ("HeapFree failed with code %i\n", ret);
6029 r = RegCloseKey (hkSubKey);
6030 if (r != ERROR_SUCCESS)
6031 WARN ("RegCloseKey returned %i\n", r);
6035 ret = RegCloseKey (hkSubKey);
6036 if (ret != ERROR_SUCCESS)
6038 ERR ("RegCloseKey returned %i\n", ret);
6042 return ERROR_SUCCESS;
6045 /*******************************************************************************
6046 * EnumPrinterDataExA [WINSPOOL.@]
6048 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6049 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6050 * what Windows 2000 SP1 does.
6053 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6054 LPBYTE pEnumValues, DWORD cbEnumValues,
6055 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6059 DWORD ret, dwIndex, dwBufSize;
6063 TRACE ("%p %s\n", hPrinter, pKeyName);
6065 if (pKeyName == NULL || *pKeyName == 0)
6066 return ERROR_INVALID_PARAMETER;
6068 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6071 ret = GetLastError ();
6072 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6076 hHeap = GetProcessHeap ();
6079 ERR ("GetProcessHeap failed\n");
6080 return ERROR_OUTOFMEMORY;
6083 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6084 if (pKeyNameW == NULL)
6086 ERR ("Failed to allocate %i bytes from process heap\n",
6087 (LONG)(len * sizeof (WCHAR)));
6088 return ERROR_OUTOFMEMORY;
6091 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6093 ret = GetLastError ();
6094 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6095 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6096 WARN ("HeapFree failed with code %i\n", GetLastError ());
6100 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6101 pcbEnumValues, pnEnumValues);
6102 if (ret != ERROR_SUCCESS)
6104 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6105 WARN ("HeapFree failed with code %i\n", GetLastError ());
6106 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6110 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6112 ret = GetLastError ();
6113 ERR ("HeapFree failed with code %i\n", ret);
6117 if (*pnEnumValues == 0) /* empty key */
6118 return ERROR_SUCCESS;
6121 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6123 PPRINTER_ENUM_VALUESW ppev =
6124 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6126 if (dwBufSize < ppev->cbValueName)
6127 dwBufSize = ppev->cbValueName;
6129 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6130 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6131 dwBufSize = ppev->cbData;
6134 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6136 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6137 if (pBuffer == NULL)
6139 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6140 return ERROR_OUTOFMEMORY;
6143 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6145 PPRINTER_ENUM_VALUESW ppev =
6146 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6148 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6149 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6153 ret = GetLastError ();
6154 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6155 if (HeapFree (hHeap, 0, pBuffer) == 0)
6156 WARN ("HeapFree failed with code %i\n", GetLastError ());
6160 memcpy (ppev->pValueName, pBuffer, len);
6162 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6164 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6165 ppev->dwType != REG_MULTI_SZ)
6168 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6169 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6172 ret = GetLastError ();
6173 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6174 if (HeapFree (hHeap, 0, pBuffer) == 0)
6175 WARN ("HeapFree failed with code %i\n", GetLastError ());
6179 memcpy (ppev->pData, pBuffer, len);
6181 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6182 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6185 if (HeapFree (hHeap, 0, pBuffer) == 0)
6187 ret = GetLastError ();
6188 ERR ("HeapFree failed with code %i\n", ret);
6192 return ERROR_SUCCESS;
6195 /******************************************************************************
6196 * AbortPrinter (WINSPOOL.@)
6198 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6200 FIXME("(%p), stub!\n", hPrinter);
6204 /******************************************************************************
6205 * AddPortA (WINSPOOL.@)
6210 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6212 LPWSTR nameW = NULL;
6213 LPWSTR monitorW = NULL;
6217 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6220 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6221 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6222 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6226 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6227 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6228 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6230 res = AddPortW(nameW, hWnd, monitorW);
6231 HeapFree(GetProcessHeap(), 0, nameW);
6232 HeapFree(GetProcessHeap(), 0, monitorW);
6236 /******************************************************************************
6237 * AddPortW (WINSPOOL.@)
6239 * Add a Port for a specific Monitor
6242 * pName [I] Servername or NULL (local Computer)
6243 * hWnd [I] Handle to parent Window for the Dialog-Box
6244 * pMonitorName [I] Name of the Monitor that manage the Port
6251 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6257 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6259 if (pName && pName[0]) {
6260 SetLastError(ERROR_INVALID_PARAMETER);
6264 if (!pMonitorName) {
6265 SetLastError(RPC_X_NULL_REF_POINTER);
6269 /* an empty Monitorname is Invalid */
6270 if (!pMonitorName[0]) {
6271 SetLastError(ERROR_NOT_SUPPORTED);
6275 pm = monitor_load(pMonitorName, NULL);
6276 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6277 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6278 TRACE("got %d with %u\n", res, GetLastError());
6283 pui = monitor_loadui(pm);
6284 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6285 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6286 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6287 TRACE("got %d with %u\n", res, GetLastError());
6292 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6293 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6295 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6296 SetLastError(ERROR_NOT_SUPPORTED);
6299 monitor_unload(pui);
6302 TRACE("returning %d with %u\n", res, GetLastError());
6306 /******************************************************************************
6307 * AddPortExA (WINSPOOL.@)
6312 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6315 PORT_INFO_2A * pi2A;
6316 LPWSTR nameW = NULL;
6317 LPWSTR monitorW = NULL;
6321 pi2A = (PORT_INFO_2A *) pBuffer;
6323 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6324 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6326 if ((level < 1) || (level > 2)) {
6327 SetLastError(ERROR_INVALID_LEVEL);
6332 SetLastError(ERROR_INVALID_PARAMETER);
6337 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6338 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6339 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6343 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6344 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6345 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6348 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6350 if (pi2A->pPortName) {
6351 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6352 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6353 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6357 if (pi2A->pMonitorName) {
6358 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6359 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6360 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6363 if (pi2A->pDescription) {
6364 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6365 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6366 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6368 pi2W.fPortType = pi2A->fPortType;
6369 pi2W.Reserved = pi2A->Reserved;
6372 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6374 HeapFree(GetProcessHeap(), 0, nameW);
6375 HeapFree(GetProcessHeap(), 0, monitorW);
6376 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6377 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6378 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6383 /******************************************************************************
6384 * AddPortExW (WINSPOOL.@)
6386 * Add a Port for a specific Monitor, without presenting a user interface
6389 * pName [I] Servername or NULL (local Computer)
6390 * level [I] Structure-Level (1 or 2) for pBuffer
6391 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6392 * pMonitorName [I] Name of the Monitor that manage the Port
6399 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6405 pi2 = (PORT_INFO_2W *) pBuffer;
6407 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6408 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6409 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6410 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6413 if ((level < 1) || (level > 2)) {
6414 SetLastError(ERROR_INVALID_LEVEL);
6418 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6419 SetLastError(ERROR_INVALID_PARAMETER);
6423 /* load the Monitor */
6424 pm = monitor_load(pMonitorName, NULL);
6426 SetLastError(ERROR_INVALID_PARAMETER);
6430 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6431 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6432 TRACE("got %u with %u\n", res, GetLastError());
6436 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6442 /******************************************************************************
6443 * AddPrinterConnectionA (WINSPOOL.@)
6445 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6447 FIXME("%s\n", debugstr_a(pName));
6451 /******************************************************************************
6452 * AddPrinterConnectionW (WINSPOOL.@)
6454 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6456 FIXME("%s\n", debugstr_w(pName));
6460 /******************************************************************************
6461 * AddPrinterDriverExW (WINSPOOL.@)
6463 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6466 * pName [I] Servername or NULL (local Computer)
6467 * level [I] Level for the supplied DRIVER_INFO_*W struct
6468 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6469 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6476 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6478 const printenv_t *env;
6488 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6490 if (level < 2 || level == 5 || level == 7 || level > 8) {
6491 SetLastError(ERROR_INVALID_LEVEL);
6496 SetLastError(ERROR_INVALID_PARAMETER);
6500 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
6501 FIXME("Flags 0x%x ignored (Fallback to APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
6504 ptr = get_servername_from_name(pName);
6505 HeapFree(GetProcessHeap(), 0, ptr);
6507 FIXME("not suported for server: %s\n", debugstr_w(pName));
6508 SetLastError(ERROR_ACCESS_DENIED);
6512 /* we need to set all entries in the Registry, independent from the Level of
6513 DRIVER_INFO, that the caller supplied */
6515 ZeroMemory(&di, sizeof(di));
6516 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
6517 memcpy(&di, pDriverInfo, di_sizeof[level]);
6520 /* dump the most used infos */
6521 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
6522 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
6523 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
6524 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
6525 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
6526 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
6527 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
6528 /* dump only the first of the additional Files */
6529 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
6532 /* check environment */
6533 env = validate_envW(di.pEnvironment);
6534 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
6536 /* fill the copy-data / get the driverdir */
6537 len = sizeof(apd.src) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
6538 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1,
6539 (LPBYTE) apd.src, len, &len)) {
6540 /* Should never Fail */
6543 memcpy(apd.dst, apd.src, len);
6544 lstrcatW(apd.src, backslashW);
6545 apd.srclen = lstrlenW(apd.src);
6546 lstrcatW(apd.dst, env->versionsubdir);
6547 lstrcatW(apd.dst, backslashW);
6548 apd.dstlen = lstrlenW(apd.dst);
6549 apd.copyflags = dwFileCopyFlags;
6550 CreateDirectoryW(apd.src, NULL);
6551 CreateDirectoryW(apd.dst, NULL);
6553 /* Fill the Registry for the Driver */
6554 hroot = WINSPOOL_OpenDriverReg(env->envname, TRUE);
6556 ERR("Can't create Drivers key\n");
6560 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
6561 KEY_WRITE | KEY_QUERY_VALUE, NULL,
6562 &hdrv, &disposition)) != ERROR_SUCCESS) {
6564 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
6571 if (disposition == REG_OPENED_EXISTING_KEY) {
6572 TRACE("driver %s already installed\n", debugstr_w(di.pName));
6574 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
6578 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
6579 RegSetValueExW(hdrv, VersionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
6582 RegSetValueExW(hdrv, DriverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
6583 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
6584 apd_copyfile(di.pDriverPath, &apd);
6586 RegSetValueExW(hdrv, Data_FileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
6587 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
6588 apd_copyfile(di.pDataFile, &apd);
6590 RegSetValueExW(hdrv, Configuration_FileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
6591 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
6592 apd_copyfile(di.pConfigFile, &apd);
6594 /* settings for level 3 */
6595 RegSetValueExW(hdrv, Help_FileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
6596 di.pHelpFile ? (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR) : 0);
6597 apd_copyfile(di.pHelpFile, &apd);
6600 ptr = di.pDependentFiles;
6601 RegSetValueExW(hdrv, Dependent_FilesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
6602 di.pDependentFiles ? multi_sz_lenW(di.pDependentFiles) : 0);
6603 while ((ptr != NULL) && (ptr[0])) {
6604 if (apd_copyfile(ptr, &apd)) {
6605 ptr += lstrlenW(ptr) + 1;
6609 WARN("Failed to copy %s\n", debugstr_w(ptr));
6614 /* The language-Monitor was already copied to "%SystemRoot%\system32" */
6615 RegSetValueExW(hdrv, MonitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
6616 di.pMonitorName ? (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR) : 0);
6618 RegSetValueExW(hdrv, DatatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
6619 di.pDefaultDataType ? (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR) : 0);
6621 /* settings for level 4 */
6622 RegSetValueExW(hdrv, Previous_NamesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
6623 di.pszzPreviousNames ? multi_sz_lenW(di.pszzPreviousNames) : 0);
6625 if (level > 5) FIXME("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
6629 FIXME("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
6632 TRACE("=> TRUE with %u\n", GetLastError());
6637 /******************************************************************************
6638 * AddPrinterDriverExA (WINSPOOL.@)
6640 * See AddPrinterDriverExW.
6643 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6645 DRIVER_INFO_8A *diA;
6647 LPWSTR nameW = NULL;
6652 FIXME("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6653 diA = (DRIVER_INFO_8A *) pDriverInfo;
6654 ZeroMemory(&diW, sizeof(diW));
6656 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6657 SetLastError(ERROR_INVALID_LEVEL);
6662 SetLastError(ERROR_INVALID_PARAMETER);
6666 /* convert servername to unicode */
6668 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6669 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6670 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6674 diW.cVersion = diA->cVersion;
6676 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6677 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6678 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6680 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6681 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6682 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6684 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6685 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6686 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6688 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6689 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6690 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6692 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6693 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6694 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6697 lenA = multi_sz_lenA(diA->pDependentFiles);
6698 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6699 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6700 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6702 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6703 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6704 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6708 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6709 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6710 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6712 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6713 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6714 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6715 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6719 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6720 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6721 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6723 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6724 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6725 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6727 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6728 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6729 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6731 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6732 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6733 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6737 FIXME("level %u is incomplete\n", Level);
6740 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6741 TRACE("got %u with %u\n", res, GetLastError());
6742 HeapFree(GetProcessHeap(), 0, nameW);
6743 HeapFree(GetProcessHeap(), 0, diW.pName);
6744 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6745 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6746 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6747 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6748 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6749 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6750 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6751 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6752 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6753 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6754 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6755 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6757 TRACE("=> %u with %u\n", res, GetLastError());
6761 /******************************************************************************
6762 * ConfigurePortA (WINSPOOL.@)
6764 * See ConfigurePortW.
6767 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6769 LPWSTR nameW = NULL;
6770 LPWSTR portW = NULL;
6774 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6776 /* convert servername to unicode */
6778 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6779 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6780 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6783 /* convert portname to unicode */
6785 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6786 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6787 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6790 res = ConfigurePortW(nameW, hWnd, portW);
6791 HeapFree(GetProcessHeap(), 0, nameW);
6792 HeapFree(GetProcessHeap(), 0, portW);
6796 /******************************************************************************
6797 * ConfigurePortW (WINSPOOL.@)
6799 * Display the Configuration-Dialog for a specific Port
6802 * pName [I] Servername or NULL (local Computer)
6803 * hWnd [I] Handle to parent Window for the Dialog-Box
6804 * pPortName [I] Name of the Port, that should be configured
6811 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6817 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6819 if (pName && pName[0]) {
6820 SetLastError(ERROR_INVALID_PARAMETER);
6825 SetLastError(RPC_X_NULL_REF_POINTER);
6829 /* an empty Portname is Invalid, but can popup a Dialog */
6830 if (!pPortName[0]) {
6831 SetLastError(ERROR_NOT_SUPPORTED);
6835 pm = monitor_load_by_port(pPortName);
6836 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6837 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6838 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6839 TRACE("got %d with %u\n", res, GetLastError());
6843 pui = monitor_loadui(pm);
6844 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6845 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6846 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6847 TRACE("got %d with %u\n", res, GetLastError());
6851 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6852 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6854 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6855 SetLastError(ERROR_NOT_SUPPORTED);
6858 monitor_unload(pui);
6862 TRACE("returning %d with %u\n", res, GetLastError());
6866 /******************************************************************************
6867 * ConnectToPrinterDlg (WINSPOOL.@)
6869 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6871 FIXME("%p %x\n", hWnd, Flags);
6875 /******************************************************************************
6876 * DeletePrinterConnectionA (WINSPOOL.@)
6878 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6880 FIXME("%s\n", debugstr_a(pName));
6884 /******************************************************************************
6885 * DeletePrinterConnectionW (WINSPOOL.@)
6887 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6889 FIXME("%s\n", debugstr_w(pName));
6893 /******************************************************************************
6894 * DeletePrinterDriverExW (WINSPOOL.@)
6896 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6897 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6902 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6903 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6905 if(pName && pName[0])
6907 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6908 SetLastError(ERROR_INVALID_PARAMETER);
6914 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6915 SetLastError(ERROR_INVALID_PARAMETER);
6919 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6923 ERR("Can't open drivers key\n");
6927 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6930 RegCloseKey(hkey_drivers);
6935 /******************************************************************************
6936 * DeletePrinterDriverExA (WINSPOOL.@)
6938 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6939 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6941 UNICODE_STRING NameW, EnvW, DriverW;
6944 asciitounicode(&NameW, pName);
6945 asciitounicode(&EnvW, pEnvironment);
6946 asciitounicode(&DriverW, pDriverName);
6948 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6950 RtlFreeUnicodeString(&DriverW);
6951 RtlFreeUnicodeString(&EnvW);
6952 RtlFreeUnicodeString(&NameW);
6957 /******************************************************************************
6958 * DeletePrinterDataExW (WINSPOOL.@)
6960 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6963 FIXME("%p %s %s\n", hPrinter,
6964 debugstr_w(pKeyName), debugstr_w(pValueName));
6965 return ERROR_INVALID_PARAMETER;
6968 /******************************************************************************
6969 * DeletePrinterDataExA (WINSPOOL.@)
6971 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6974 FIXME("%p %s %s\n", hPrinter,
6975 debugstr_a(pKeyName), debugstr_a(pValueName));
6976 return ERROR_INVALID_PARAMETER;
6979 /******************************************************************************
6980 * DeletePrintProcessorA (WINSPOOL.@)
6982 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6984 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6985 debugstr_a(pPrintProcessorName));
6989 /******************************************************************************
6990 * DeletePrintProcessorW (WINSPOOL.@)
6992 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6994 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6995 debugstr_w(pPrintProcessorName));
6999 /******************************************************************************
7000 * DeletePrintProvidorA (WINSPOOL.@)
7002 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7004 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7005 debugstr_a(pPrintProviderName));
7009 /******************************************************************************
7010 * DeletePrintProvidorW (WINSPOOL.@)
7012 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7014 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7015 debugstr_w(pPrintProviderName));
7019 /******************************************************************************
7020 * EnumFormsA (WINSPOOL.@)
7022 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7023 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7025 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7026 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7030 /******************************************************************************
7031 * EnumFormsW (WINSPOOL.@)
7033 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7034 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7036 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7037 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7041 /*****************************************************************************
7042 * EnumMonitorsA [WINSPOOL.@]
7044 * See EnumMonitorsW.
7047 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7048 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7051 LPBYTE bufferW = NULL;
7052 LPWSTR nameW = NULL;
7054 DWORD numentries = 0;
7057 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7058 cbBuf, pcbNeeded, pcReturned);
7060 /* convert servername to unicode */
7062 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7063 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7064 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7066 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7067 needed = cbBuf * sizeof(WCHAR);
7068 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7069 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7071 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7072 if (pcbNeeded) needed = *pcbNeeded;
7073 /* HeapReAlloc return NULL, when bufferW was NULL */
7074 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7075 HeapAlloc(GetProcessHeap(), 0, needed);
7077 /* Try again with the large Buffer */
7078 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7080 numentries = pcReturned ? *pcReturned : 0;
7083 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7084 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7087 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7088 DWORD entrysize = 0;
7091 LPMONITOR_INFO_2W mi2w;
7092 LPMONITOR_INFO_2A mi2a;
7094 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7095 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7097 /* First pass: calculate the size for all Entries */
7098 mi2w = (LPMONITOR_INFO_2W) bufferW;
7099 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7101 while (index < numentries) {
7103 needed += entrysize; /* MONITOR_INFO_?A */
7104 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7106 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7107 NULL, 0, NULL, NULL);
7109 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7110 NULL, 0, NULL, NULL);
7111 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7112 NULL, 0, NULL, NULL);
7114 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7115 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7116 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7119 /* check for errors and quit on failure */
7120 if (cbBuf < needed) {
7121 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7125 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7126 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7127 cbBuf -= len ; /* free Bytes in the user-Buffer */
7128 mi2w = (LPMONITOR_INFO_2W) bufferW;
7129 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7131 /* Second Pass: Fill the User Buffer (if we have one) */
7132 while ((index < numentries) && pMonitors) {
7134 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7136 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7137 ptr, cbBuf , NULL, NULL);
7141 mi2a->pEnvironment = ptr;
7142 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7143 ptr, cbBuf, NULL, NULL);
7147 mi2a->pDLLName = ptr;
7148 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7149 ptr, cbBuf, NULL, NULL);
7153 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7154 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7155 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7159 if (pcbNeeded) *pcbNeeded = needed;
7160 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7162 HeapFree(GetProcessHeap(), 0, nameW);
7163 HeapFree(GetProcessHeap(), 0, bufferW);
7165 TRACE("returning %d with %d (%d byte for %d entries)\n",
7166 (res), GetLastError(), needed, numentries);
7172 /*****************************************************************************
7173 * EnumMonitorsW [WINSPOOL.@]
7175 * Enumerate available Port-Monitors
7178 * pName [I] Servername or NULL (local Computer)
7179 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7180 * pMonitors [O] PTR to Buffer that receives the Result
7181 * cbBuf [I] Size of Buffer at pMonitors
7182 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7183 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7187 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7190 * Windows reads the Registry once and cache the Results.
7192 *| Language-Monitors are also installed in the same Registry-Location but
7193 *| they are filtered in Windows (not returned by EnumMonitors).
7194 *| We do no filtering to simplify our Code.
7197 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7198 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7201 DWORD numentries = 0;
7204 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7205 cbBuf, pcbNeeded, pcReturned);
7207 if (pName && (lstrlenW(pName))) {
7208 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7209 SetLastError(ERROR_ACCESS_DENIED);
7213 /* Level is not checked in win9x */
7214 if (!Level || (Level > 2)) {
7215 WARN("level (%d) is ignored in win9x\n", Level);
7216 SetLastError(ERROR_INVALID_LEVEL);
7220 SetLastError(RPC_X_NULL_REF_POINTER);
7224 /* Scan all Monitor-Keys */
7226 needed = get_local_monitors(Level, NULL, 0, &numentries);
7228 /* we calculated the needed buffersize. now do the error-checks */
7229 if (cbBuf < needed) {
7230 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7233 else if (!pMonitors || !pcReturned) {
7234 SetLastError(RPC_X_NULL_REF_POINTER);
7238 /* fill the Buffer with the Monitor-Keys */
7239 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7243 if (pcbNeeded) *pcbNeeded = needed;
7244 if (pcReturned) *pcReturned = numentries;
7246 TRACE("returning %d with %d (%d byte for %d entries)\n",
7247 res, GetLastError(), needed, numentries);
7252 /******************************************************************************
7253 * XcvDataW (WINSPOOL.@)
7255 * Execute commands in the Printmonitor DLL
7258 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7259 * pszDataName [i] Name of the command to execute
7260 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7261 * cbInputData [i] Size in Bytes of Buffer at pInputData
7262 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7263 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7264 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7265 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7272 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7273 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7275 * Minimal List of commands, that a Printmonitor DLL should support:
7277 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7278 *| "AddPort" : Add a Port
7279 *| "DeletePort": Delete a Port
7281 * Many Printmonitors support additional commands. Examples for localspl.dll:
7282 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7283 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7286 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7287 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7288 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7290 opened_printer_t *printer;
7292 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7293 pInputData, cbInputData, pOutputData,
7294 cbOutputData, pcbOutputNeeded, pdwStatus);
7296 printer = get_opened_printer(hXcv);
7297 if (!printer || (!printer->hXcv)) {
7298 SetLastError(ERROR_INVALID_HANDLE);
7302 if (!pcbOutputNeeded) {
7303 SetLastError(ERROR_INVALID_PARAMETER);
7307 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7308 SetLastError(RPC_X_NULL_REF_POINTER);
7312 *pcbOutputNeeded = 0;
7314 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7315 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7320 /*****************************************************************************
7321 * EnumPrinterDataA [WINSPOOL.@]
7324 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7325 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7326 DWORD cbData, LPDWORD pcbData )
7328 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7329 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7330 return ERROR_NO_MORE_ITEMS;
7333 /*****************************************************************************
7334 * EnumPrinterDataW [WINSPOOL.@]
7337 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7338 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7339 DWORD cbData, LPDWORD pcbData )
7341 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7342 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7343 return ERROR_NO_MORE_ITEMS;
7346 /*****************************************************************************
7347 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7350 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7351 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7352 LPDWORD pcbNeeded, LPDWORD pcReturned)
7354 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7355 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7356 pcbNeeded, pcReturned);
7360 /*****************************************************************************
7361 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7364 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7365 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7366 LPDWORD pcbNeeded, LPDWORD pcReturned)
7368 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7369 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7370 pcbNeeded, pcReturned);
7374 /*****************************************************************************
7375 * EnumPrintProcessorsA [WINSPOOL.@]
7378 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7379 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7381 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7382 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7386 /*****************************************************************************
7387 * EnumPrintProcessorsW [WINSPOOL.@]
7390 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7391 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7393 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7394 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7395 cbBuf, pcbNeeded, pcbReturned);
7399 /*****************************************************************************
7400 * ExtDeviceMode [WINSPOOL.@]
7403 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7404 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7407 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7408 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7409 debugstr_a(pProfile), fMode);
7413 /*****************************************************************************
7414 * FindClosePrinterChangeNotification [WINSPOOL.@]
7417 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7419 FIXME("Stub: %p\n", hChange);
7423 /*****************************************************************************
7424 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7427 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7428 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7430 FIXME("Stub: %p %x %x %p\n",
7431 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7432 return INVALID_HANDLE_VALUE;
7435 /*****************************************************************************
7436 * FindNextPrinterChangeNotification [WINSPOOL.@]
7439 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7440 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7442 FIXME("Stub: %p %p %p %p\n",
7443 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7447 /*****************************************************************************
7448 * FreePrinterNotifyInfo [WINSPOOL.@]
7451 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7453 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7457 /*****************************************************************************
7460 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7461 * ansi depending on the unicode parameter.
7463 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7473 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7476 memcpy(ptr, str, *size);
7483 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7486 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7493 /*****************************************************************************
7496 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7497 LPDWORD pcbNeeded, BOOL unicode)
7499 DWORD size, left = cbBuf;
7500 BOOL space = (cbBuf > 0);
7507 ji1->JobId = job->job_id;
7510 string_to_buf(job->document_title, ptr, left, &size, unicode);
7511 if(space && size <= left)
7513 ji1->pDocument = (LPWSTR)ptr;
7524 /*****************************************************************************
7527 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7528 LPDWORD pcbNeeded, BOOL unicode)
7530 DWORD size, left = cbBuf;
7531 BOOL space = (cbBuf > 0);
7538 ji2->JobId = job->job_id;
7541 string_to_buf(job->document_title, ptr, left, &size, unicode);
7542 if(space && size <= left)
7544 ji2->pDocument = (LPWSTR)ptr;
7555 /*****************************************************************************
7558 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7559 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7562 DWORD needed = 0, size;
7566 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7568 EnterCriticalSection(&printer_handles_cs);
7569 job = get_job(hPrinter, JobId);
7576 size = sizeof(JOB_INFO_1W);
7581 memset(pJob, 0, size);
7585 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7590 size = sizeof(JOB_INFO_2W);
7595 memset(pJob, 0, size);
7599 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7604 size = sizeof(JOB_INFO_3);
7608 memset(pJob, 0, size);
7617 SetLastError(ERROR_INVALID_LEVEL);
7621 *pcbNeeded = needed;
7623 LeaveCriticalSection(&printer_handles_cs);
7627 /*****************************************************************************
7628 * GetJobA [WINSPOOL.@]
7631 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7632 DWORD cbBuf, LPDWORD pcbNeeded)
7634 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7637 /*****************************************************************************
7638 * GetJobW [WINSPOOL.@]
7641 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7642 DWORD cbBuf, LPDWORD pcbNeeded)
7644 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7647 /*****************************************************************************
7650 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7652 char *unixname, *queue, *cmd;
7653 char fmt[] = "lpr -P%s %s";
7656 if(!(unixname = wine_get_unix_file_name(filename)))
7659 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7660 queue = HeapAlloc(GetProcessHeap(), 0, len);
7661 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7663 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7664 sprintf(cmd, fmt, queue, unixname);
7666 TRACE("printing with: %s\n", cmd);
7669 HeapFree(GetProcessHeap(), 0, cmd);
7670 HeapFree(GetProcessHeap(), 0, queue);
7671 HeapFree(GetProcessHeap(), 0, unixname);
7675 /*****************************************************************************
7678 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7680 #ifdef SONAME_LIBCUPS
7683 char *unixname, *queue, *doc_titleA;
7687 if(!(unixname = wine_get_unix_file_name(filename)))
7690 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7691 queue = HeapAlloc(GetProcessHeap(), 0, len);
7692 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7694 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7695 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7696 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7698 TRACE("printing via cups\n");
7699 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7700 HeapFree(GetProcessHeap(), 0, doc_titleA);
7701 HeapFree(GetProcessHeap(), 0, queue);
7702 HeapFree(GetProcessHeap(), 0, unixname);
7708 return schedule_lpr(printer_name, filename);
7712 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7719 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7723 if(HIWORD(wparam) == BN_CLICKED)
7725 if(LOWORD(wparam) == IDOK)
7728 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7731 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7732 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7734 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7736 WCHAR caption[200], message[200];
7739 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7740 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7741 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7742 if(mb_ret == IDCANCEL)
7744 HeapFree(GetProcessHeap(), 0, filename);
7748 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7749 if(hf == INVALID_HANDLE_VALUE)
7751 WCHAR caption[200], message[200];
7753 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7754 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7755 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7756 HeapFree(GetProcessHeap(), 0, filename);
7760 DeleteFileW(filename);
7761 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7763 EndDialog(hwnd, IDOK);
7766 if(LOWORD(wparam) == IDCANCEL)
7768 EndDialog(hwnd, IDCANCEL);
7777 /*****************************************************************************
7780 static BOOL get_filename(LPWSTR *filename)
7782 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7783 file_dlg_proc, (LPARAM)filename) == IDOK;
7786 /*****************************************************************************
7789 static BOOL schedule_file(LPCWSTR filename)
7791 LPWSTR output = NULL;
7793 if(get_filename(&output))
7795 TRACE("copy to %s\n", debugstr_w(output));
7796 CopyFileW(filename, output, FALSE);
7797 HeapFree(GetProcessHeap(), 0, output);
7803 /*****************************************************************************
7806 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7809 char *unixname, *cmdA;
7811 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7815 if(!(unixname = wine_get_unix_file_name(filename)))
7818 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7819 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7820 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7822 TRACE("printing with: %s\n", cmdA);
7824 if((file_fd = open(unixname, O_RDONLY)) == -1)
7829 ERR("pipe() failed!\n");
7839 /* reset signals that we previously set to SIG_IGN */
7840 signal(SIGPIPE, SIG_DFL);
7841 signal(SIGCHLD, SIG_DFL);
7843 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7847 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7848 write(fds[1], buf, no_read);
7853 if(file_fd != -1) close(file_fd);
7854 if(fds[0] != -1) close(fds[0]);
7855 if(fds[1] != -1) close(fds[1]);
7857 HeapFree(GetProcessHeap(), 0, cmdA);
7858 HeapFree(GetProcessHeap(), 0, unixname);
7865 /*****************************************************************************
7868 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7870 int in_fd, out_fd, no_read;
7873 char *unixname, *outputA;
7876 if(!(unixname = wine_get_unix_file_name(filename)))
7879 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7880 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7881 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7883 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7884 in_fd = open(unixname, O_RDONLY);
7885 if(out_fd == -1 || in_fd == -1)
7888 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7889 write(out_fd, buf, no_read);
7893 if(in_fd != -1) close(in_fd);
7894 if(out_fd != -1) close(out_fd);
7895 HeapFree(GetProcessHeap(), 0, outputA);
7896 HeapFree(GetProcessHeap(), 0, unixname);
7900 /*****************************************************************************
7901 * ScheduleJob [WINSPOOL.@]
7904 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7906 opened_printer_t *printer;
7908 struct list *cursor, *cursor2;
7910 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7911 EnterCriticalSection(&printer_handles_cs);
7912 printer = get_opened_printer(hPrinter);
7916 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7918 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7921 if(job->job_id != dwJobID) continue;
7923 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7924 if(hf != INVALID_HANDLE_VALUE)
7926 PRINTER_INFO_5W *pi5;
7930 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7931 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7933 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7934 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7935 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7936 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7937 debugstr_w(pi5->pPortName));
7941 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7942 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7944 DWORD type, count = sizeof(output);
7945 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7948 if(output[0] == '|')
7950 schedule_pipe(output + 1, job->filename);
7954 schedule_unixfile(output, job->filename);
7956 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7958 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7960 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7962 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7964 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7966 schedule_file(job->filename);
7970 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7972 HeapFree(GetProcessHeap(), 0, pi5);
7974 DeleteFileW(job->filename);
7976 list_remove(cursor);
7977 HeapFree(GetProcessHeap(), 0, job->document_title);
7978 HeapFree(GetProcessHeap(), 0, job->filename);
7979 HeapFree(GetProcessHeap(), 0, job);
7984 LeaveCriticalSection(&printer_handles_cs);
7988 /*****************************************************************************
7989 * StartDocDlgA [WINSPOOL.@]
7991 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7993 UNICODE_STRING usBuffer;
7996 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7999 docW.cbSize = sizeof(docW);
8000 if (doc->lpszDocName)
8002 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8003 if (!(docW.lpszDocName = docnameW)) return NULL;
8005 if (doc->lpszOutput)
8007 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8008 if (!(docW.lpszOutput = outputW)) return NULL;
8010 if (doc->lpszDatatype)
8012 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8013 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8015 docW.fwType = doc->fwType;
8017 retW = StartDocDlgW(hPrinter, &docW);
8021 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8022 ret = HeapAlloc(GetProcessHeap(), 0, len);
8023 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8024 HeapFree(GetProcessHeap(), 0, retW);
8027 HeapFree(GetProcessHeap(), 0, datatypeW);
8028 HeapFree(GetProcessHeap(), 0, outputW);
8029 HeapFree(GetProcessHeap(), 0, docnameW);
8034 /*****************************************************************************
8035 * StartDocDlgW [WINSPOOL.@]
8037 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8038 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8039 * port is "FILE:". Also returns the full path if passed a relative path.
8041 * The caller should free the returned string from the process heap.
8043 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8048 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8050 PRINTER_INFO_5W *pi5;
8051 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8052 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8054 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8055 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8056 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8058 HeapFree(GetProcessHeap(), 0, pi5);
8061 HeapFree(GetProcessHeap(), 0, pi5);
8064 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8068 if (get_filename(&name))
8070 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8072 HeapFree(GetProcessHeap(), 0, name);
8075 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8076 GetFullPathNameW(name, len, ret, NULL);
8077 HeapFree(GetProcessHeap(), 0, name);
8082 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8085 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8086 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8088 attr = GetFileAttributesW(ret);
8089 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8091 HeapFree(GetProcessHeap(), 0, ret);