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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "wine/port.h"
33 #ifdef HAVE_CUPS_CUPS_H
34 # include <cups/cups.h>
35 # ifndef SONAME_LIBCUPS
36 # define SONAME_LIBCUPS "libcups.so"
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "wine/library.h"
50 #include "wine/windef16.h"
51 #include "wine/unicode.h"
52 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
58 static LPWSTR *printer_array;
59 static int nb_printers;
61 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
62 WORD fwCapability, LPSTR lpszOutput,
64 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
65 LPSTR lpszDevice, LPSTR lpszPort,
66 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
69 static char Printers[] =
70 "System\\CurrentControlSet\\control\\Print\\Printers\\";
71 static char Drivers[] =
72 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
74 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
76 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
77 'i','o','n',' ','F','i','l','e',0};
78 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
79 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
80 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
82 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
84 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
85 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
86 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
87 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
88 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
89 static WCHAR NameW[] = {'N','a','m','e',0};
90 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
91 static WCHAR PortW[] = {'P','o','r','t',0};
92 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
94 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
96 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
97 'v','e','r','D','a','t','a',0};
98 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
100 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
101 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
103 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
104 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
105 DWORD Level, LPBYTE pDriverInfo,
106 DWORD cbBuf, LPDWORD pcbNeeded,
109 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
110 if passed a NULL string. This returns NULLs to the result.
112 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
116 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
117 return usBufferPtr->Buffer;
119 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
124 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
127 /* If forcing, or no profile string entry for device yet, set the entry
129 * The always change entry if not WINEPS yet is discussable.
132 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
134 !strstr(qbuf,"WINEPS")
136 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
138 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
139 WriteProfileStringA("windows","device",buf);
140 HeapFree(GetProcessHeap(),0,buf);
144 #ifdef HAVE_CUPS_CUPS_H
146 CUPS_LoadPrinters(void) {
147 typeof(cupsGetDests) *pcupsGetDests = NULL;
148 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
150 BOOL hadprinter = FALSE;
152 PRINTER_INFO_2A pinfo2a;
153 void *cupshandle = NULL;
156 UNICODE_STRING lpszNameW;
158 HKEY hkeyPrinters, hkeyPrinter;
160 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
163 TRACE("loaded %s\n", SONAME_LIBCUPS);
166 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
167 if (!p##x) return FALSE;
170 DYNCUPS(cupsGetDests);
174 nrofdests = pcupsGetDests(&dests);
175 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
176 for (i=0;i<nrofdests;i++) {
177 /* First check that the printer doesn't exist already */
178 pwstrNameW = asciitounicode(&lpszNameW, dests[i].name);
179 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) ==
181 if (RegOpenKeyW(hkeyPrinters, pwstrNameW, &hkeyPrinter) ==
183 /* We know this printer already */
184 RegCloseKey(hkeyPrinter);
185 RegCloseKey(hkeyPrinters);
186 RtlFreeUnicodeString(&lpszNameW);
188 if(dests[i].is_default)
189 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
190 TRACE("Printer %s already known. Skipping detection\n", dests[i].name);
193 RegCloseKey(hkeyPrinters);
195 RtlFreeUnicodeString(&lpszNameW);
197 /* OK, we haven't seen this one yet. Request PPD for it */
198 ppd = pcupsGetPPD(dests[i].name);
200 WARN("No ppd file for %s.\n",dests[i].name);
201 /* If this was going to be the default printer,
202 * forget it and use another one.
208 memset(&pinfo2a,0,sizeof(pinfo2a));
209 pinfo2a.pPrinterName = dests[i].name;
210 pinfo2a.pDatatype = "RAW";
211 pinfo2a.pPrintProcessor = "WinPrint";
212 pinfo2a.pDriverName = "PS Driver";
213 pinfo2a.pComment = "WINEPS Printer using CUPS";
214 pinfo2a.pLocation = "<physical location of printer>";
215 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
216 sprintf(port,"LPR:%s",dests[i].name);
217 pinfo2a.pPortName = port;
218 pinfo2a.pParameters = "<parameters?>";
219 pinfo2a.pShareName = "<share name?>";
220 pinfo2a.pSepFile = "<sep file?>";
222 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
223 sprintf(devline,"WINEPS,%s",port);
224 WriteProfileStringA("devices",dests[i].name,devline);
225 HeapFree(GetProcessHeap(),0,devline);
227 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
228 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
229 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
231 HeapFree(GetProcessHeap(),0,port);
234 if (dests[i].is_default)
235 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
237 wine_dlclose(cupshandle, NULL, 0);
243 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
244 PRINTER_INFO_2A pinfo2a;
245 char *s,*name,*prettyname,*devname;
249 while (isspace(*pent)) pent++;
250 s = strchr(pent,':');
251 if (!s) return FALSE;
257 /* Determine whether this is a postscript printer. */
259 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
260 if (strstr(name,"ps") ||
261 strstr(name,"pd") || /* postscript double page */
262 strstr(name,"postscript") ||
263 strstr(name,"PostScript")
265 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
268 /* 2. Check if this is a remote printer. These usually are postscript
271 if (strstr(pent,":rm")) {
273 TRACE("%s is remote, assuming postscript.\n",name);
275 /* 3. Check if we have an input filter program. If we have one, it
276 * most likely is one capable of converting postscript.
277 * (Could probably check for occurrence of 'gs' or 'ghostscript'
278 * in the if file itself.)
280 if (strstr(pent,":if=/")) {
282 TRACE("%s has inputfilter program, assuming postscript.\n",name);
285 /* If it is not a postscript printer, we cannot use it. */
290 /* Get longest name, usually the one at the right for later display. */
291 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
292 s=strchr(name,'|');if (s) *s='\0';
294 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
295 * if it is too long, we use it as comment below. */
296 devname = prettyname;
297 if (strlen(devname)>=CCHDEVICENAME-1)
299 if (strlen(devname)>=CCHDEVICENAME-1)
302 if (isfirst) /* set first entry as default */
303 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
305 memset(&pinfo2a,0,sizeof(pinfo2a));
306 pinfo2a.pPrinterName = devname;
307 pinfo2a.pDatatype = "RAW";
308 pinfo2a.pPrintProcessor = "WinPrint";
309 pinfo2a.pDriverName = "PS Driver";
310 pinfo2a.pComment = "WINEPS Printer using LPR";
311 pinfo2a.pLocation = prettyname;
312 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
313 sprintf(port,"LPR:%s",name);
314 pinfo2a.pPortName = port;
315 pinfo2a.pParameters = "<parameters?>";
316 pinfo2a.pShareName = "<share name?>";
317 pinfo2a.pSepFile = "<sep file?>";
319 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
320 sprintf(devline,"WINEPS,%s",port);
321 WriteProfileStringA("devices",devname,devline);
322 HeapFree(GetProcessHeap(),0,devline);
324 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
325 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
326 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
328 HeapFree(GetProcessHeap(),0,port);
333 PRINTCAP_LoadPrinters(void) {
334 BOOL hadprinter = FALSE, isfirst = TRUE;
338 f = fopen("/etc/printcap","r");
342 while (fgets(buf,sizeof(buf),f)) {
346 s=strchr(buf,'\n'); if (s) *s='\0';
347 if ((buf[0]=='#') || (buf[0]=='\0'))
351 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
354 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
358 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
359 pent[strlen(pent)-1] = '\0';
362 } while (fgets(buf,sizeof(buf),f));
364 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
366 if (pent) HeapFree(GetProcessHeap(),0,pent);
374 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
377 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
378 lstrlenW(value) * sizeof(WCHAR));
380 return ERROR_FILE_NOT_FOUND;
384 WINSPOOL_LoadSystemPrinters() {
387 di3a.cVersion = 0x400;
388 di3a.pName = "PS Driver";
389 di3a.pEnvironment = NULL; /* NULL means auto */
390 di3a.pDriverPath = "wineps16";
391 di3a.pDataFile = "<datafile?>";
392 di3a.pConfigFile = "wineps16";
393 di3a.pHelpFile = "<helpfile?>";
394 di3a.pDependentFiles = "<dependend files?>";
395 di3a.pMonitorName = "<monitor name?>";
396 di3a.pDefaultDataType = "RAW";
398 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
399 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
402 #ifdef HAVE_CUPS_CUPS_H
403 /* If we have any CUPS based printers, skip looking for printcap printers */
404 if (CUPS_LoadPrinters())
408 /* Check for [ppd] section in config file before parsing /etc/printcap */
410 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
411 &hkPPD) == ERROR_SUCCESS)
414 PRINTCAP_LoadPrinters();
419 /******************************************************************
420 * WINSPOOL_GetOpenedPrinterEntry
421 * Get the first place empty in the opened printer table
423 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
427 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
429 if (i >= nb_printers)
431 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
432 (nb_printers + 16) * sizeof(*new_array) );
433 if (!new_array) return 0;
434 printer_array = new_array;
438 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
440 strcpyW( printer_array[i], name );
441 return (HANDLE)(i + 1);
446 /******************************************************************
447 * WINSPOOL_GetOpenedPrinter
448 * Get the pointer to the opened printer referred by the handle
450 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
452 int idx = (int)printerHandle;
453 if ((idx <= 0) || (idx > nb_printers))
455 SetLastError(ERROR_INVALID_HANDLE);
458 return printer_array[idx - 1];
461 /******************************************************************
462 * WINSPOOL_GetOpenedPrinterRegKey
465 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
467 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
471 if(!name) return ERROR_INVALID_HANDLE;
473 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
477 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
479 ERR("Can't find opened printer %s in registry\n",
481 RegCloseKey(hkeyPrinters);
482 return ERROR_INVALID_PRINTER_NAME; /* ? */
484 RegCloseKey(hkeyPrinters);
485 return ERROR_SUCCESS;
488 /***********************************************************
491 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
494 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
497 Formname = (dmA->dmSize > off_formname);
498 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
499 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
502 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
503 dmA->dmSize - CCHDEVICENAME);
505 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
506 off_formname - CCHDEVICENAME);
507 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
509 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
510 (off_formname + CCHFORMNAME));
513 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
518 /***********************************************************
520 * Creates a unicode copy of supplied devmode on heap
522 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
527 ptrdiff_t off_formname;
530 if(!dmA) return NULL;
532 off_formname = (char *)dmA->dmFormName - (char *)dmA;
533 Formname = (dmA->dmSize > off_formname);
534 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
535 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
536 return DEVMODEcpyAtoW(dmW, dmA);
539 /***********************************************************
541 * Creates an ascii copy of supplied devmode on heap
543 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
548 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
550 if(!dmW) return NULL;
551 Formname = (dmW->dmSize > off_formname);
552 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
553 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
554 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
555 CCHDEVICENAME, NULL, NULL);
557 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
558 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
560 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
561 off_formname - CCHDEVICENAME * sizeof(WCHAR));
562 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
563 CCHFORMNAME, NULL, NULL);
564 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
565 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
568 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
573 /***********************************************************
575 * Creates a unicode copy of PRINTER_INFO_2A on heap
577 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
579 LPPRINTER_INFO_2W piW;
580 UNICODE_STRING usBuffer;
582 if(!piA) return NULL;
583 piW = HeapAlloc(heap, 0, sizeof(*piW));
584 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
586 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
587 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
588 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
589 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
590 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
591 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
592 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
593 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
594 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
595 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
596 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
597 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
601 /***********************************************************
602 * FREE_PRINTER_INFO_2W
603 * Free PRINTER_INFO_2W and all strings
605 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
609 HeapFree(heap,0,piW->pServerName);
610 HeapFree(heap,0,piW->pPrinterName);
611 HeapFree(heap,0,piW->pShareName);
612 HeapFree(heap,0,piW->pPortName);
613 HeapFree(heap,0,piW->pDriverName);
614 HeapFree(heap,0,piW->pComment);
615 HeapFree(heap,0,piW->pLocation);
616 HeapFree(heap,0,piW->pDevMode);
617 HeapFree(heap,0,piW->pSepFile);
618 HeapFree(heap,0,piW->pPrintProcessor);
619 HeapFree(heap,0,piW->pDatatype);
620 HeapFree(heap,0,piW->pParameters);
621 HeapFree(heap,0,piW);
625 /******************************************************************
626 * DeviceCapabilities [WINSPOOL.@]
627 * DeviceCapabilitiesA [WINSPOOL.@]
630 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
631 LPSTR pOutput, LPDEVMODEA lpdm)
635 if (!GDI_CallDeviceCapabilities16)
637 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
639 if (!GDI_CallDeviceCapabilities16) return -1;
641 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
643 /* If DC_PAPERSIZE map POINT16s to POINTs */
644 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
645 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
646 POINT *pt = (POINT *)pOutput;
648 memcpy(tmp, pOutput, ret * sizeof(POINT16));
649 for(i = 0; i < ret; i++, pt++)
654 HeapFree( GetProcessHeap(), 0, tmp );
660 /*****************************************************************************
661 * DeviceCapabilitiesW [WINSPOOL.@]
663 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
666 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
667 WORD fwCapability, LPWSTR pOutput,
668 const DEVMODEW *pDevMode)
670 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
671 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
672 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
675 if(pOutput && (fwCapability == DC_BINNAMES ||
676 fwCapability == DC_FILEDEPENDENCIES ||
677 fwCapability == DC_PAPERNAMES)) {
678 /* These need A -> W translation */
681 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
685 switch(fwCapability) {
690 case DC_FILEDEPENDENCIES:
694 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
695 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
697 for(i = 0; i < ret; i++)
698 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
699 pOutput + (i * size), size);
700 HeapFree(GetProcessHeap(), 0, pOutputA);
702 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
703 (LPSTR)pOutput, dmA);
705 HeapFree(GetProcessHeap(),0,pPortA);
706 HeapFree(GetProcessHeap(),0,pDeviceA);
707 HeapFree(GetProcessHeap(),0,dmA);
711 /******************************************************************
712 * DocumentPropertiesA [WINSPOOL.@]
715 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
716 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
717 LPDEVMODEA pDevModeInput,DWORD fMode )
719 LPSTR lpName = pDeviceName;
722 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
723 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
727 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
729 ERR("no name from hPrinter?\n");
732 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
735 if (!GDI_CallExtDeviceMode16)
737 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
739 if (!GDI_CallExtDeviceMode16) {
740 ERR("No CallExtDeviceMode16?\n");
744 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
745 pDevModeInput, NULL, fMode);
748 HeapFree(GetProcessHeap(),0,lpName);
753 /*****************************************************************************
754 * DocumentPropertiesW (WINSPOOL.@)
756 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
758 LPDEVMODEW pDevModeOutput,
759 LPDEVMODEW pDevModeInput, DWORD fMode)
762 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
763 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
764 LPDEVMODEA pDevModeOutputA = NULL;
767 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
768 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
771 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
772 if(ret < 0) return ret;
773 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
775 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
776 pDevModeInputA, fMode);
778 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
779 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
781 if(fMode == 0 && ret > 0)
782 ret += (CCHDEVICENAME + CCHFORMNAME);
783 HeapFree(GetProcessHeap(),0,pDevModeInputA);
784 HeapFree(GetProcessHeap(),0,pDeviceNameA);
788 /******************************************************************
789 * OpenPrinterA [WINSPOOL.@]
792 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
793 LPPRINTER_DEFAULTSA pDefault)
795 UNICODE_STRING lpPrinterNameW;
796 UNICODE_STRING usBuffer;
797 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
798 PWSTR pwstrPrinterNameW;
801 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
804 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
805 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
807 DefaultW.DesiredAccess = pDefault->DesiredAccess;
808 pDefaultW = &DefaultW;
810 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
812 RtlFreeUnicodeString(&usBuffer);
813 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
815 RtlFreeUnicodeString(&lpPrinterNameW);
819 /******************************************************************
820 * OpenPrinterW [WINSPOOL.@]
823 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
824 LPPRINTER_DEFAULTSW pDefault)
826 HKEY hkeyPrinters, hkeyPrinter;
828 if (!lpPrinterName) {
829 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
830 SetLastError(ERROR_INVALID_PARAMETER);
834 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
837 /* Check Printer exists */
838 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
840 ERR("Can't create Printers key\n");
841 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
845 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
846 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
848 TRACE("Can't find printer %s in registry\n",
849 debugstr_w(lpPrinterName));
850 RegCloseKey(hkeyPrinters);
851 SetLastError(ERROR_INVALID_PRINTER_NAME);
854 RegCloseKey(hkeyPrinter);
855 RegCloseKey(hkeyPrinters);
857 if(!phPrinter) /* This seems to be what win95 does anyway */
860 /* Get the unique handle of the printer*/
861 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
863 if (pDefault != NULL)
864 FIXME("Not handling pDefault\n");
869 /******************************************************************
870 * AddMonitorA [WINSPOOL.@]
873 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
875 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
876 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
880 /******************************************************************
881 * DeletePrinterDriverA [WINSPOOL.@]
885 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
887 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
888 debugstr_a(pDriverName));
889 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
894 /******************************************************************
895 * DeleteMonitorA [WINSPOOL.@]
899 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
901 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
902 debugstr_a(pMonitorName));
903 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
908 /******************************************************************
909 * DeletePortA [WINSPOOL.@]
913 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
915 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
916 debugstr_a(pPortName));
917 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
921 /******************************************************************************
922 * SetPrinterW [WINSPOOL.@]
932 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
936 /******************************************************************************
937 * WritePrinter [WINSPOOL.@]
947 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
951 /*****************************************************************************
952 * AddFormA [WINSPOOL.@]
954 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
956 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
960 /*****************************************************************************
961 * AddFormW [WINSPOOL.@]
963 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
965 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
969 /*****************************************************************************
970 * AddJobA [WINSPOOL.@]
972 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
973 DWORD cbBuf, LPDWORD pcbNeeded)
975 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
980 /*****************************************************************************
981 * AddJobW [WINSPOOL.@]
983 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
986 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
991 /*****************************************************************************
992 * GetPrintProcessorDirectoryA [WINSPOOL.@]
994 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR environ,
995 DWORD level, LPBYTE Info,
996 DWORD cbBuf, LPDWORD needed)
998 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", server, environ, level, Info,
1003 /*****************************************************************************
1004 * WINSPOOL_OpenDriverReg [internal]
1006 * opens the registry for the printer drivers depending on the given input
1007 * variable pEnvironment
1010 * the opened hkey on success
1013 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1015 LPSTR lpKey, p = NULL;
1018 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1021 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1025 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1027 if(!GetVersionExA( &ver))
1030 switch (ver.dwPlatformId) {
1031 case VER_PLATFORM_WIN32s:
1032 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1035 case VER_PLATFORM_WIN32_NT:
1036 p = "Windows NT x86";
1042 TRACE("set environment to %s\n", p);
1045 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1046 strlen(p) + strlen(Drivers));
1047 sprintf( lpKey, Drivers, p);
1049 TRACE("%s\n", lpKey);
1051 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1055 if(pEnvironment && unicode)
1056 HeapFree( GetProcessHeap(), 0, p);
1057 HeapFree( GetProcessHeap(), 0, lpKey);
1062 /*****************************************************************************
1063 * AddPrinterW [WINSPOOL.@]
1065 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1067 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1071 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1074 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1077 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1078 SetLastError(ERROR_INVALID_PARAMETER);
1082 ERR("Level = %ld, unsupported!\n", Level);
1083 SetLastError(ERROR_INVALID_LEVEL);
1086 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1087 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1088 debugstr_w(pi->pPrinterName)
1090 SetLastError(ERROR_INVALID_LEVEL);
1094 SetLastError(ERROR_INVALID_PARAMETER);
1097 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1099 ERR("Can't create Printers key\n");
1102 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1103 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1104 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1105 RegCloseKey(hkeyPrinter);
1106 RegCloseKey(hkeyPrinters);
1109 RegCloseKey(hkeyPrinter);
1111 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1113 ERR("Can't create Drivers key\n");
1114 RegCloseKey(hkeyPrinters);
1117 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1119 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1120 RegCloseKey(hkeyPrinters);
1121 RegCloseKey(hkeyDrivers);
1122 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1125 RegCloseKey(hkeyDriver);
1126 RegCloseKey(hkeyDrivers);
1128 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1129 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1130 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1131 RegCloseKey(hkeyPrinters);
1135 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1137 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1138 SetLastError(ERROR_INVALID_PRINTER_NAME);
1139 RegCloseKey(hkeyPrinters);
1142 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1143 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1144 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1146 /* See if we can load the driver. We may need the devmode structure anyway
1149 * Note that DocumentPropertiesW will briefly try to open the printer we
1150 * just create to find a DEVMODEA struct (it will use the WINEPS default
1151 * one in case it is not there, so we are ok).
1153 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1156 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1157 size = sizeof(DEVMODEW);
1163 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1164 ZeroMemory(dmW,size);
1166 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1168 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1169 HeapFree(GetProcessHeap(),0,dmW);
1174 /* set devmode to printer name */
1175 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1179 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1180 and we support these drivers. NT writes DEVMODEW so somehow
1181 we'll need to distinguish between these when we support NT
1185 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1186 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1187 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1188 HeapFree(GetProcessHeap(), 0, dmA);
1190 HeapFree(GetProcessHeap(), 0, dmW);
1192 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1193 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1194 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1195 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1197 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1198 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1199 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1200 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1201 (LPBYTE)&pi->Priority, sizeof(DWORD));
1202 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1203 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1204 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1205 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1206 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1207 (LPBYTE)&pi->Status, sizeof(DWORD));
1208 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1209 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1211 RegCloseKey(hkeyPrinter);
1212 RegCloseKey(hkeyPrinters);
1213 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1214 ERR("OpenPrinter failing\n");
1220 /*****************************************************************************
1221 * AddPrinterA [WINSPOOL.@]
1223 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1225 UNICODE_STRING pNameW;
1227 PRINTER_INFO_2W *piW;
1228 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1231 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1233 ERR("Level = %ld, unsupported!\n", Level);
1234 SetLastError(ERROR_INVALID_LEVEL);
1237 pwstrNameW = asciitounicode(&pNameW,pName);
1238 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1240 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1242 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1243 RtlFreeUnicodeString(&pNameW);
1248 /*****************************************************************************
1249 * ClosePrinter [WINSPOOL.@]
1251 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1253 int i = (int)hPrinter;
1255 TRACE("Handle %p\n", hPrinter);
1257 if ((i <= 0) || (i > nb_printers)) return FALSE;
1258 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1259 printer_array[i - 1] = NULL;
1263 /*****************************************************************************
1264 * DeleteFormA [WINSPOOL.@]
1266 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1268 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1272 /*****************************************************************************
1273 * DeleteFormW [WINSPOOL.@]
1275 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1277 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1281 /*****************************************************************************
1282 * DeletePrinter [WINSPOOL.@]
1284 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1286 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1289 if(!lpNameW) return FALSE;
1290 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1292 ERR("Can't open Printers key\n");
1296 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1297 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1298 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1299 RegCloseKey(hkeyPrinters);
1303 ClosePrinter(hPrinter);
1307 /*****************************************************************************
1308 * SetPrinterA [WINSPOOL.@]
1310 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1313 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1317 /*****************************************************************************
1318 * SetJobA [WINSPOOL.@]
1320 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1321 LPBYTE pJob, DWORD Command)
1323 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1328 /*****************************************************************************
1329 * SetJobW [WINSPOOL.@]
1331 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1332 LPBYTE pJob, DWORD Command)
1334 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1339 /*****************************************************************************
1340 * EndDocPrinter [WINSPOOL.@]
1342 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1344 FIXME("(hPrinter=%p): stub\n", hPrinter);
1348 /*****************************************************************************
1349 * EndPagePrinter [WINSPOOL.@]
1351 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1353 FIXME("(hPrinter=%p): stub\n", hPrinter);
1357 /*****************************************************************************
1358 * StartDocPrinterA [WINSPOOL.@]
1360 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1362 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1366 /*****************************************************************************
1367 * StartDocPrinterW [WINSPOOL.@]
1369 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1371 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1375 /*****************************************************************************
1376 * StartPagePrinter [WINSPOOL.@]
1378 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1380 FIXME("(hPrinter=%p): stub\n", hPrinter);
1384 /*****************************************************************************
1385 * GetFormA [WINSPOOL.@]
1387 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1388 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1390 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1391 Level,pForm,cbBuf,pcbNeeded);
1395 /*****************************************************************************
1396 * GetFormW [WINSPOOL.@]
1398 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1399 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1401 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1402 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1406 /*****************************************************************************
1407 * SetFormA [WINSPOOL.@]
1409 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1412 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1416 /*****************************************************************************
1417 * SetFormW [WINSPOOL.@]
1419 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1422 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1426 /*****************************************************************************
1427 * ReadPrinter [WINSPOOL.@]
1429 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1430 LPDWORD pNoBytesRead)
1432 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1436 /*****************************************************************************
1437 * ResetPrinterA [WINSPOOL.@]
1439 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1441 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1445 /*****************************************************************************
1446 * ResetPrinterW [WINSPOOL.@]
1448 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1450 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1454 /*****************************************************************************
1455 * WINSPOOL_GetDWORDFromReg
1457 * Return DWORD associated with ValueName from hkey.
1459 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1461 DWORD sz = sizeof(DWORD), type, value = 0;
1464 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1466 if(ret != ERROR_SUCCESS) {
1467 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1470 if(type != REG_DWORD) {
1471 ERR("Got type %ld\n", type);
1477 /*****************************************************************************
1478 * WINSPOOL_GetStringFromReg
1480 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1481 * String is stored either as unicode or ascii.
1482 * Bit of a hack here to get the ValueName if we want ascii.
1484 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1485 DWORD buflen, DWORD *needed,
1488 DWORD sz = buflen, type;
1492 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1494 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1495 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1496 HeapFree(GetProcessHeap(),0,ValueNameA);
1498 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1499 WARN("Got ret = %ld\n", ret);
1507 /*****************************************************************************
1508 * WINSPOOL_GetDefaultDevMode
1510 * Get a default DevMode values for wineps.
1514 static void WINSPOOL_GetDefaultDevMode(
1516 DWORD buflen, DWORD *needed,
1521 /* fill default DEVMODE - should be read from ppd... */
1522 ZeroMemory( &dm, sizeof(dm) );
1523 strcpy(dm.dmDeviceName,"wineps");
1524 dm.dmSpecVersion = DM_SPECVERSION;
1525 dm.dmDriverVersion = 1;
1526 dm.dmSize = sizeof(DEVMODEA);
1527 dm.dmDriverExtra = 0;
1529 DM_ORIENTATION | DM_PAPERSIZE |
1530 DM_PAPERLENGTH | DM_PAPERWIDTH |
1533 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1534 DM_YRESOLUTION | DM_TTOPTION;
1536 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1537 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1538 dm.u1.s1.dmPaperLength = 2970;
1539 dm.u1.s1.dmPaperWidth = 2100;
1543 dm.dmDefaultSource = DMBIN_AUTO;
1544 dm.dmPrintQuality = DMRES_MEDIUM;
1547 dm.dmYResolution = 300; /* 300dpi */
1548 dm.dmTTOption = DMTT_BITMAP;
1551 /* dm.dmLogPixels */
1552 /* dm.dmBitsPerPel */
1553 /* dm.dmPelsWidth */
1554 /* dm.dmPelsHeight */
1555 /* dm.dmDisplayFlags */
1556 /* dm.dmDisplayFrequency */
1557 /* dm.dmICMMethod */
1558 /* dm.dmICMIntent */
1559 /* dm.dmMediaType */
1560 /* dm.dmDitherType */
1561 /* dm.dmReserved1 */
1562 /* dm.dmReserved2 */
1563 /* dm.dmPanningWidth */
1564 /* dm.dmPanningHeight */
1567 if(buflen >= sizeof(DEVMODEW)) {
1568 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1569 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1570 HeapFree(GetProcessHeap(),0,pdmW);
1572 *needed = sizeof(DEVMODEW);
1576 if(buflen >= sizeof(DEVMODEA)) {
1577 memcpy(ptr, &dm, sizeof(DEVMODEA));
1579 *needed = sizeof(DEVMODEA);
1583 /*****************************************************************************
1584 * WINSPOOL_GetDevModeFromReg
1586 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1587 * DevMode is stored either as unicode or ascii.
1589 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1591 DWORD buflen, DWORD *needed,
1594 DWORD sz = buflen, type;
1597 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1598 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1599 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1600 if (sz < sizeof(DEVMODEA))
1602 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1605 /* ensures that dmSize is not erratically bogus if registry is invalid */
1606 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1607 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1609 sz += (CCHDEVICENAME + CCHFORMNAME);
1611 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1612 memcpy(ptr, dmW, sz);
1613 HeapFree(GetProcessHeap(),0,dmW);
1620 /*********************************************************************
1621 * WINSPOOL_GetPrinter_2
1623 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1624 * The strings are either stored as unicode or ascii.
1626 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1627 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1630 DWORD size, left = cbBuf;
1631 BOOL space = (cbBuf > 0);
1636 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1638 if(space && size <= left) {
1639 pi2->pPrinterName = (LPWSTR)ptr;
1646 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1648 if(space && size <= left) {
1649 pi2->pShareName = (LPWSTR)ptr;
1656 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1658 if(space && size <= left) {
1659 pi2->pPortName = (LPWSTR)ptr;
1666 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1668 if(space && size <= left) {
1669 pi2->pDriverName = (LPWSTR)ptr;
1676 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1678 if(space && size <= left) {
1679 pi2->pComment = (LPWSTR)ptr;
1686 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1688 if(space && size <= left) {
1689 pi2->pLocation = (LPWSTR)ptr;
1696 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1698 if(space && size <= left) {
1699 pi2->pDevMode = (LPDEVMODEW)ptr;
1708 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1709 if(space && size <= left) {
1710 pi2->pDevMode = (LPDEVMODEW)ptr;
1717 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1719 if(space && size <= left) {
1720 pi2->pSepFile = (LPWSTR)ptr;
1727 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1729 if(space && size <= left) {
1730 pi2->pPrintProcessor = (LPWSTR)ptr;
1737 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1739 if(space && size <= left) {
1740 pi2->pDatatype = (LPWSTR)ptr;
1747 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1749 if(space && size <= left) {
1750 pi2->pParameters = (LPWSTR)ptr;
1758 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1759 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1760 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1761 "Default Priority");
1762 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1763 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1766 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1767 memset(pi2, 0, sizeof(*pi2));
1772 /*********************************************************************
1773 * WINSPOOL_GetPrinter_4
1775 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1777 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1778 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1781 DWORD size, left = cbBuf;
1782 BOOL space = (cbBuf > 0);
1787 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1789 if(space && size <= left) {
1790 pi4->pPrinterName = (LPWSTR)ptr;
1798 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1801 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1802 memset(pi4, 0, sizeof(*pi4));
1807 /*********************************************************************
1808 * WINSPOOL_GetPrinter_5
1810 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1812 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1813 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1816 DWORD size, left = cbBuf;
1817 BOOL space = (cbBuf > 0);
1822 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1824 if(space && size <= left) {
1825 pi5->pPrinterName = (LPWSTR)ptr;
1832 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1834 if(space && size <= left) {
1835 pi5->pPortName = (LPWSTR)ptr;
1843 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1844 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1846 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1850 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1851 memset(pi5, 0, sizeof(*pi5));
1856 /*****************************************************************************
1857 * WINSPOOL_GetPrinter
1859 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1860 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1861 * just a collection of pointers to strings.
1863 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1864 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1867 DWORD size, needed = 0;
1869 HKEY hkeyPrinter, hkeyPrinters;
1872 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1874 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1876 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1878 ERR("Can't create Printers key\n");
1881 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1883 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1884 RegCloseKey(hkeyPrinters);
1885 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1892 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1894 size = sizeof(PRINTER_INFO_2W);
1896 ptr = pPrinter + size;
1898 memset(pPrinter, 0, size);
1903 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1911 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1913 size = sizeof(PRINTER_INFO_4W);
1915 ptr = pPrinter + size;
1917 memset(pPrinter, 0, size);
1922 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1931 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1933 size = sizeof(PRINTER_INFO_5W);
1935 ptr = pPrinter + size;
1937 memset(pPrinter, 0, size);
1943 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1950 FIXME("Unimplemented level %ld\n", Level);
1951 SetLastError(ERROR_INVALID_LEVEL);
1952 RegCloseKey(hkeyPrinters);
1953 RegCloseKey(hkeyPrinter);
1957 RegCloseKey(hkeyPrinter);
1958 RegCloseKey(hkeyPrinters);
1960 TRACE("returning %d needed = %ld\n", ret, needed);
1961 if(pcbNeeded) *pcbNeeded = needed;
1963 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1967 /*****************************************************************************
1968 * GetPrinterW [WINSPOOL.@]
1970 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1971 DWORD cbBuf, LPDWORD pcbNeeded)
1973 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1977 /*****************************************************************************
1978 * GetPrinterA [WINSPOOL.@]
1980 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1981 DWORD cbBuf, LPDWORD pcbNeeded)
1983 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1987 /*****************************************************************************
1988 * WINSPOOL_EnumPrinters
1990 * Implementation of EnumPrintersA|W
1992 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1993 DWORD dwLevel, LPBYTE lpbPrinters,
1994 DWORD cbBuf, LPDWORD lpdwNeeded,
1995 LPDWORD lpdwReturned, BOOL unicode)
1998 HKEY hkeyPrinters, hkeyPrinter;
1999 WCHAR PrinterName[255];
2000 DWORD needed = 0, number = 0;
2001 DWORD used, i, left;
2005 memset(lpbPrinters, 0, cbBuf);
2011 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2012 if(dwType == PRINTER_ENUM_DEFAULT)
2015 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2016 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
2017 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
2018 if(!dwType) return TRUE;
2021 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2022 FIXME("dwType = %08lx\n", dwType);
2023 SetLastError(ERROR_INVALID_FLAGS);
2027 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2029 ERR("Can't create Printers key\n");
2033 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2034 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2035 RegCloseKey(hkeyPrinters);
2036 ERR("Can't query Printers key\n");
2039 TRACE("Found %ld printers\n", number);
2043 RegCloseKey(hkeyPrinters);
2045 *lpdwReturned = number;
2049 used = number * sizeof(PRINTER_INFO_2W);
2052 used = number * sizeof(PRINTER_INFO_4W);
2055 used = number * sizeof(PRINTER_INFO_5W);
2059 SetLastError(ERROR_INVALID_LEVEL);
2060 RegCloseKey(hkeyPrinters);
2063 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2065 for(i = 0; i < number; i++) {
2066 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2068 ERR("Can't enum key number %ld\n", i);
2069 RegCloseKey(hkeyPrinters);
2072 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2073 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2075 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2076 RegCloseKey(hkeyPrinters);
2081 buf = lpbPrinters + used;
2082 left = cbBuf - used;
2090 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2091 left, &needed, unicode);
2093 if(pi) pi += sizeof(PRINTER_INFO_2W);
2096 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2097 left, &needed, unicode);
2099 if(pi) pi += sizeof(PRINTER_INFO_4W);
2102 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2103 left, &needed, unicode);
2105 if(pi) pi += sizeof(PRINTER_INFO_5W);
2108 ERR("Shouldn't be here!\n");
2109 RegCloseKey(hkeyPrinter);
2110 RegCloseKey(hkeyPrinters);
2113 RegCloseKey(hkeyPrinter);
2115 RegCloseKey(hkeyPrinters);
2122 memset(lpbPrinters, 0, cbBuf);
2123 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2127 *lpdwReturned = number;
2128 SetLastError(ERROR_SUCCESS);
2133 /******************************************************************
2134 * EnumPrintersW [WINSPOOL.@]
2136 * Enumerates the available printers, print servers and print
2137 * providers, depending on the specified flags, name and level.
2141 * If level is set to 1:
2142 * Not implemented yet!
2143 * Returns TRUE with an empty list.
2145 * If level is set to 2:
2146 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2147 * Returns an array of PRINTER_INFO_2 data structures in the
2148 * lpbPrinters buffer. Note that according to MSDN also an
2149 * OpenPrinter should be performed on every remote printer.
2151 * If level is set to 4 (officially WinNT only):
2152 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2153 * Fast: Only the registry is queried to retrieve printer names,
2154 * no connection to the driver is made.
2155 * Returns an array of PRINTER_INFO_4 data structures in the
2156 * lpbPrinters buffer.
2158 * If level is set to 5 (officially WinNT4/Win9x only):
2159 * Fast: Only the registry is queried to retrieve printer names,
2160 * no connection to the driver is made.
2161 * Returns an array of PRINTER_INFO_5 data structures in the
2162 * lpbPrinters buffer.
2164 * If level set to 3 or 6+:
2165 * returns zero (failure!)
2167 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2171 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2172 * - Only levels 2, 4 and 5 are implemented at the moment.
2173 * - 16-bit printer drivers are not enumerated.
2174 * - Returned amount of bytes used/needed does not match the real Windoze
2175 * implementation (as in this implementation, all strings are part
2176 * of the buffer, whereas Win32 keeps them somewhere else)
2177 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2180 * - In a regular Wine installation, no registry settings for printers
2181 * exist, which makes this function return an empty list.
2183 BOOL WINAPI EnumPrintersW(
2184 DWORD dwType, /* [in] Types of print objects to enumerate */
2185 LPWSTR lpszName, /* [in] name of objects to enumerate */
2186 DWORD dwLevel, /* [in] type of printer info structure */
2187 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2188 DWORD cbBuf, /* [in] max size of buffer in bytes */
2189 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2190 LPDWORD lpdwReturned /* [out] number of entries returned */
2193 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2194 lpdwNeeded, lpdwReturned, TRUE);
2197 /******************************************************************
2198 * EnumPrintersA [WINSPOOL.@]
2201 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2202 DWORD dwLevel, LPBYTE lpbPrinters,
2203 DWORD cbBuf, LPDWORD lpdwNeeded,
2204 LPDWORD lpdwReturned)
2207 UNICODE_STRING lpszNameW;
2210 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2211 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2212 lpdwNeeded, lpdwReturned, FALSE);
2213 RtlFreeUnicodeString(&lpszNameW);
2217 /*****************************************************************************
2218 * WINSPOOL_GetDriverInfoFromReg [internal]
2220 * Enters the information from the registry into the DRIVER_INFO struct
2223 * zero if the printer driver does not exist in the registry
2224 * (only if Level > 1) otherwise nonzero
2226 static BOOL WINSPOOL_GetDriverInfoFromReg(
2229 LPWSTR pEnvironment,
2231 LPBYTE ptr, /* DRIVER_INFO */
2232 LPBYTE pDriverStrings, /* strings buffer */
2233 DWORD cbBuf, /* size of string buffer */
2234 LPDWORD pcbNeeded, /* space needed for str. */
2235 BOOL unicode) /* type of strings */
2236 { DWORD dw, size, tmp, type;
2238 LPBYTE strPtr = pDriverStrings;
2240 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2241 debugstr_w(DriverName), debugstr_w(pEnvironment),
2242 Level, ptr, pDriverStrings, cbBuf, unicode);
2245 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2246 if (*pcbNeeded <= cbBuf)
2247 strcpyW((LPWSTR)strPtr, DriverName);
2249 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2251 if(*pcbNeeded <= cbBuf)
2252 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2257 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2261 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2262 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2265 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2266 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2267 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2272 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2274 WARN("Can't get Version\n");
2276 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2279 pEnvironment = DefaultEnvironmentW;
2281 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2283 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2286 if(*pcbNeeded <= cbBuf) {
2288 strcpyW((LPWSTR)strPtr, pEnvironment);
2290 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2293 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2294 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2297 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2300 if(*pcbNeeded <= cbBuf)
2301 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2304 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2305 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2308 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2311 if(*pcbNeeded <= cbBuf)
2312 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2315 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2316 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2319 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2320 0, &size, unicode)) {
2322 if(*pcbNeeded <= cbBuf)
2323 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2324 size, &tmp, unicode);
2326 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2327 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2331 RegCloseKey(hkeyDriver);
2332 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2336 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2339 if(*pcbNeeded <= cbBuf)
2340 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2341 size, &tmp, unicode);
2343 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2344 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2347 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2350 if(*pcbNeeded <= cbBuf)
2351 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2352 size, &tmp, unicode);
2354 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2355 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2358 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2361 if(*pcbNeeded <= cbBuf)
2362 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2363 size, &tmp, unicode);
2365 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2366 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2369 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2372 if(*pcbNeeded <= cbBuf)
2373 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2374 size, &tmp, unicode);
2376 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2377 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2380 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2381 RegCloseKey(hkeyDriver);
2385 /*****************************************************************************
2386 * WINSPOOL_GetPrinterDriver
2388 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2389 DWORD Level, LPBYTE pDriverInfo,
2390 DWORD cbBuf, LPDWORD pcbNeeded,
2394 WCHAR DriverName[100];
2395 DWORD ret, type, size, needed = 0;
2397 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2399 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2400 Level,pDriverInfo,cbBuf, pcbNeeded);
2402 ZeroMemory(pDriverInfo, cbBuf);
2404 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2406 if(Level < 1 || Level > 3) {
2407 SetLastError(ERROR_INVALID_LEVEL);
2410 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2412 ERR("Can't create Printers key\n");
2415 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2417 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2418 RegCloseKey(hkeyPrinters);
2419 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2422 size = sizeof(DriverName);
2424 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2425 (LPBYTE)DriverName, &size);
2426 RegCloseKey(hkeyPrinter);
2427 RegCloseKey(hkeyPrinters);
2428 if(ret != ERROR_SUCCESS) {
2429 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2433 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2435 ERR("Can't create Drivers key\n");
2441 size = sizeof(DRIVER_INFO_1W);
2444 size = sizeof(DRIVER_INFO_2W);
2447 size = sizeof(DRIVER_INFO_3W);
2450 ERR("Invalid level\n");
2455 ptr = pDriverInfo + size;
2457 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2458 pEnvironment, Level, pDriverInfo,
2459 (cbBuf < size) ? NULL : ptr,
2460 (cbBuf < size) ? 0 : cbBuf - size,
2461 &needed, unicode)) {
2462 RegCloseKey(hkeyDrivers);
2466 RegCloseKey(hkeyDrivers);
2468 if(pcbNeeded) *pcbNeeded = size + needed;
2469 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2470 if(cbBuf >= needed) return TRUE;
2471 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2475 /*****************************************************************************
2476 * GetPrinterDriverA [WINSPOOL.@]
2478 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2479 DWORD Level, LPBYTE pDriverInfo,
2480 DWORD cbBuf, LPDWORD pcbNeeded)
2483 UNICODE_STRING pEnvW;
2486 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2487 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2488 cbBuf, pcbNeeded, FALSE);
2489 RtlFreeUnicodeString(&pEnvW);
2492 /*****************************************************************************
2493 * GetPrinterDriverW [WINSPOOL.@]
2495 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2496 DWORD Level, LPBYTE pDriverInfo,
2497 DWORD cbBuf, LPDWORD pcbNeeded)
2499 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2500 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2503 /*****************************************************************************
2504 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2506 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2507 DWORD Level, LPBYTE pDriverDirectory,
2508 DWORD cbBuf, LPDWORD pcbNeeded)
2512 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2513 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2515 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2516 SetLastError(ERROR_INVALID_PARAMETER);
2519 if(pEnvironment != NULL) {
2520 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2521 SetLastError(ERROR_INVALID_ENVIRONMENT);
2524 if(Level != 1) /* win95 ignores this so we just carry on */
2525 WARN("Level = %ld - assuming 1\n", Level);
2527 /* FIXME should read from registry */
2528 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2529 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2533 needed*=sizeof(WCHAR);
2536 *pcbNeeded = needed;
2537 TRACE("required <%08lx>\n", *pcbNeeded);
2538 if(needed > cbBuf) {
2539 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2546 /*****************************************************************************
2547 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2549 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2550 DWORD Level, LPBYTE pDriverDirectory,
2551 DWORD cbBuf, LPDWORD pcbNeeded)
2553 UNICODE_STRING nameW, environmentW;
2556 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2557 WCHAR *driverDirectoryW = NULL;
2559 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2561 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2562 else nameW.Buffer = NULL;
2563 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2564 else environmentW.Buffer = NULL;
2566 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2567 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2570 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2571 pDriverDirectory, cbBuf, NULL, NULL);
2573 *pcbNeeded = needed;
2574 ret = (needed <= cbBuf) ? TRUE : FALSE;
2576 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2578 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2580 if(driverDirectoryW)
2581 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2582 RtlFreeUnicodeString(&environmentW);
2583 RtlFreeUnicodeString(&nameW);
2588 /*****************************************************************************
2589 * AddPrinterDriverA [WINSPOOL.@]
2591 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2594 HKEY hkeyDrivers, hkeyName;
2596 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2598 if(level != 2 && level != 3) {
2599 SetLastError(ERROR_INVALID_LEVEL);
2603 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2604 SetLastError(ERROR_INVALID_PARAMETER);
2608 WARN("pDriverInfo == NULL\n");
2609 SetLastError(ERROR_INVALID_PARAMETER);
2614 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2616 memset(&di3, 0, sizeof(di3));
2617 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2620 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2622 SetLastError(ERROR_INVALID_PARAMETER);
2625 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2626 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2627 if(!di3.pHelpFile) di3.pHelpFile = "";
2628 if(!di3.pMonitorName) di3.pMonitorName = "";
2630 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2633 ERR("Can't create Drivers key\n");
2637 if(level == 2) { /* apparently can't overwrite with level2 */
2638 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2639 RegCloseKey(hkeyName);
2640 RegCloseKey(hkeyDrivers);
2641 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2642 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2646 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2647 RegCloseKey(hkeyDrivers);
2648 ERR("Can't create Name key\n");
2651 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2653 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2654 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2655 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2657 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2658 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2659 di3.pDependentFiles, 0);
2660 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2661 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2662 RegCloseKey(hkeyName);
2663 RegCloseKey(hkeyDrivers);
2667 /*****************************************************************************
2668 * AddPrinterDriverW [WINSPOOL.@]
2670 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2673 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2679 /*****************************************************************************
2680 * PrinterProperties [WINSPOOL.@]
2682 * Displays a dialog to set the properties of the printer.
2685 * nonzero on success or zero on failure
2688 * implemented as stub only
2690 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2691 HANDLE hPrinter /* [in] handle to printer object */
2693 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2694 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2698 /*****************************************************************************
2699 * EnumJobsA [WINSPOOL.@]
2702 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2703 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2706 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2707 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2709 if(pcbNeeded) *pcbNeeded = 0;
2710 if(pcReturned) *pcReturned = 0;
2715 /*****************************************************************************
2716 * EnumJobsW [WINSPOOL.@]
2719 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2720 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2723 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2724 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2726 if(pcbNeeded) *pcbNeeded = 0;
2727 if(pcReturned) *pcReturned = 0;
2731 /*****************************************************************************
2732 * WINSPOOL_EnumPrinterDrivers [internal]
2734 * Delivers information about all printer drivers installed on the
2735 * localhost or a given server
2738 * nonzero on success or zero on failure. If the buffer for the returned
2739 * information is too small the function will return an error
2742 * - only implemented for localhost, foreign hosts will return an error
2744 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2745 DWORD Level, LPBYTE pDriverInfo,
2746 DWORD cbBuf, LPDWORD pcbNeeded,
2747 LPDWORD pcReturned, BOOL unicode)
2750 DWORD i, needed, number = 0, size = 0;
2751 WCHAR DriverNameW[255];
2754 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2755 debugstr_w(pName), debugstr_w(pEnvironment),
2756 Level, pDriverInfo, cbBuf, unicode);
2758 /* check for local drivers */
2760 ERR("remote drivers unsupported! Current remote host is %s\n",
2765 /* check input parameter */
2766 if((Level < 1) || (Level > 3)) {
2767 ERR("unsupported level %ld \n", Level);
2771 /* initialize return values */
2773 memset( pDriverInfo, 0, cbBuf);
2777 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2779 ERR("Can't open Drivers key\n");
2783 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2784 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2785 RegCloseKey(hkeyDrivers);
2786 ERR("Can't query Drivers key\n");
2789 TRACE("Found %ld Drivers\n", number);
2791 /* get size of single struct
2792 * unicode and ascii structure have the same size
2796 size = sizeof(DRIVER_INFO_1A);
2799 size = sizeof(DRIVER_INFO_2A);
2802 size = sizeof(DRIVER_INFO_3A);
2806 /* calculate required buffer size */
2807 *pcbNeeded = size * number;
2809 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2811 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2812 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2814 ERR("Can't enum key number %ld\n", i);
2815 RegCloseKey(hkeyDrivers);
2818 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2819 pEnvironment, Level, ptr,
2820 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2821 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2822 &needed, unicode)) {
2823 RegCloseKey(hkeyDrivers);
2826 (*pcbNeeded) += needed;
2829 RegCloseKey(hkeyDrivers);
2831 if(cbBuf < *pcbNeeded){
2832 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2839 /*****************************************************************************
2840 * EnumPrinterDriversW [WINSPOOL.@]
2842 * see function EnumPrinterDrivers for RETURNS, BUGS
2844 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2845 LPBYTE pDriverInfo, DWORD cbBuf,
2846 LPDWORD pcbNeeded, LPDWORD pcReturned)
2848 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2849 cbBuf, pcbNeeded, pcReturned, TRUE);
2852 /*****************************************************************************
2853 * EnumPrinterDriversA [WINSPOOL.@]
2855 * see function EnumPrinterDrivers for RETURNS, BUGS
2857 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2858 LPBYTE pDriverInfo, DWORD cbBuf,
2859 LPDWORD pcbNeeded, LPDWORD pcReturned)
2861 UNICODE_STRING pNameW, pEnvironmentW;
2862 PWSTR pwstrNameW, pwstrEnvironmentW;
2864 pwstrNameW = asciitounicode(&pNameW, pName);
2865 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
2867 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
2868 Level, pDriverInfo, cbBuf, pcbNeeded,
2870 RtlFreeUnicodeString(&pNameW);
2871 RtlFreeUnicodeString(&pEnvironmentW);
2876 static CHAR PortMonitor[] = "Wine Port Monitor";
2877 static CHAR PortDescription[] = "Wine Port";
2879 /******************************************************************************
2880 * EnumPortsA (WINSPOOL.@)
2882 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
2883 LPDWORD bufneeded,LPDWORD bufreturned)
2886 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
2887 const LPCSTR szSerialPortKey = "Software\\Wine\\Wine\\Config\\serialports";
2888 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
2889 HKEY hkey_serial, hkey_printer;
2891 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
2892 name,level,buffer,bufsize,bufneeded,bufreturned);
2897 info_size = sizeof (PORT_INFO_1A);
2900 info_size = sizeof (PORT_INFO_2A);
2903 SetLastError(ERROR_INVALID_LEVEL);
2907 /* see how many exist */
2913 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szSerialPortKey, &hkey_serial);
2914 if (r == ERROR_SUCCESS)
2916 RegQueryInfoKeyA ( hkey_serial, NULL, NULL, NULL, NULL, NULL, NULL,
2917 &serial_count, NULL, NULL, NULL, NULL);
2920 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
2921 if ( r == ERROR_SUCCESS )
2923 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
2924 &printer_count, NULL, NULL, NULL, NULL);
2926 count = serial_count + printer_count;
2928 /* then fill in the structure info structure once
2929 we know the offset to the first string */
2931 memset( buffer, 0, bufsize );
2933 ofs = info_size*count;
2934 for ( i=0; i<count; i++)
2936 DWORD vallen = sizeof(portname) - 1;
2938 /* get the serial port values, then the printer values */
2939 if ( i < serial_count )
2940 r = RegEnumValueA( hkey_serial, i,
2941 portname, &vallen, NULL, NULL, NULL, 0 );
2943 r = RegEnumValueA( hkey_printer, i-serial_count,
2944 portname, &vallen, NULL, NULL, NULL, 0 );
2949 /* add a colon if necessary, and make it upper case */
2950 CharUpperBuffA(portname,vallen);
2951 if (strcasecmp(portname,"nul")!=0)
2952 if (vallen && (portname[vallen-1] != ':') )
2953 lstrcatA(portname,":");
2955 /* add the port info structure if we can fit it */
2956 if ( info_size*(n+1) < bufsize )
2960 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
2961 info->pName = (LPSTR) &buffer[ofs];
2963 else if ( level == 2)
2965 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
2966 info->pPortName = (LPSTR) &buffer[ofs];
2967 /* FIXME: fill in more stuff here */
2968 info->pMonitorName = PortMonitor;
2969 info->pDescription = PortDescription;
2970 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
2973 /* add the name of the port if we can fit it */
2974 if ( ofs < bufsize )
2975 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
2978 ofs += lstrlenA(portname)+1;
2982 RegCloseKey(hkey_serial);
2983 RegCloseKey(hkey_printer);
2989 *bufreturned = count;
2994 /******************************************************************************
2995 * GetDefaultPrinterA (WINSPOOL.@)
2997 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2999 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3005 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3009 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
3011 SetLastError (ERROR_FILE_NOT_FOUND);
3015 if ((ptr = strchr (name, ',')) == NULL)
3017 SetLastError (ERROR_FILE_NOT_FOUND);
3022 *namesize = strlen (name) + 1;
3027 /******************************************************************************
3028 * GetDefaultPrinterW (WINSPOOL.@)
3030 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3037 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3041 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
3042 ret = GetDefaultPrinterA (buf, namesize);
3045 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
3048 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3051 else *namesize = len;
3054 HeapFree (GetProcessHeap (), 0, buf);
3059 /******************************************************************************
3060 * SetPrinterDataExA (WINSPOOL.@)
3062 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
3063 LPSTR pValueName, DWORD Type,
3064 LPBYTE pData, DWORD cbData)
3066 HKEY hkeyPrinter, hkeySubkey;
3069 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3070 debugstr_a(pValueName), Type, pData, cbData);
3072 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3076 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3078 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3079 RegCloseKey(hkeyPrinter);
3082 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3083 RegCloseKey(hkeySubkey);
3084 RegCloseKey(hkeyPrinter);
3088 /******************************************************************************
3089 * SetPrinterDataExW (WINSPOOL.@)
3091 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
3092 LPWSTR pValueName, DWORD Type,
3093 LPBYTE pData, DWORD cbData)
3095 HKEY hkeyPrinter, hkeySubkey;
3098 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3099 debugstr_w(pValueName), Type, pData, cbData);
3101 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3105 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3107 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3108 RegCloseKey(hkeyPrinter);
3111 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3112 RegCloseKey(hkeySubkey);
3113 RegCloseKey(hkeyPrinter);
3117 /******************************************************************************
3118 * SetPrinterDataA (WINSPOOL.@)
3120 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3121 LPBYTE pData, DWORD cbData)
3123 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3127 /******************************************************************************
3128 * SetPrinterDataW (WINSPOOL.@)
3130 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3131 LPBYTE pData, DWORD cbData)
3133 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3137 /******************************************************************************
3138 * GetPrinterDataExA (WINSPOOL.@)
3140 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
3141 LPSTR pValueName, LPDWORD pType,
3142 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3144 HKEY hkeyPrinter, hkeySubkey;
3147 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3148 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3151 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3155 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3157 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3158 RegCloseKey(hkeyPrinter);
3162 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3163 RegCloseKey(hkeySubkey);
3164 RegCloseKey(hkeyPrinter);
3168 /******************************************************************************
3169 * GetPrinterDataExW (WINSPOOL.@)
3171 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
3172 LPWSTR pValueName, LPDWORD pType,
3173 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3175 HKEY hkeyPrinter, hkeySubkey;
3178 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3179 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3182 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3186 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3188 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3189 RegCloseKey(hkeyPrinter);
3193 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3194 RegCloseKey(hkeySubkey);
3195 RegCloseKey(hkeyPrinter);
3199 /******************************************************************************
3200 * GetPrinterDataA (WINSPOOL.@)
3202 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3203 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3205 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3206 pData, nSize, pcbNeeded);
3209 /******************************************************************************
3210 * GetPrinterDataW (WINSPOOL.@)
3212 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3213 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3215 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3216 pData, nSize, pcbNeeded);
3219 /*******************************************************************************
3220 * EnumPrinterDataExW [WINSPOOL.@]
3222 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3223 LPBYTE pEnumValues, DWORD cbEnumValues,
3224 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3226 HKEY hkPrinter, hkSubKey;
3227 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3228 cbValueNameLen, cbMaxValueLen, cbValueLen,
3233 PPRINTER_ENUM_VALUESW ppev;
3235 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3237 if (pKeyName == NULL || *pKeyName == 0)
3238 return ERROR_INVALID_PARAMETER;
3240 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3241 if (ret != ERROR_SUCCESS)
3243 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3248 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3249 if (ret != ERROR_SUCCESS)
3251 r = RegCloseKey (hkPrinter);
3252 if (r != ERROR_SUCCESS)
3253 WARN ("RegCloseKey returned %li\n", r);
3254 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3255 debugstr_w (pKeyName), ret);
3259 ret = RegCloseKey (hkPrinter);
3260 if (ret != ERROR_SUCCESS)
3262 ERR ("RegCloseKey returned %li\n", ret);
3263 r = RegCloseKey (hkSubKey);
3264 if (r != ERROR_SUCCESS)
3265 WARN ("RegCloseKey returned %li\n", r);
3269 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3270 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3271 if (ret != ERROR_SUCCESS)
3273 r = RegCloseKey (hkSubKey);
3274 if (r != ERROR_SUCCESS)
3275 WARN ("RegCloseKey returned %li\n", r);
3276 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3280 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3281 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3283 if (cValues == 0) /* empty key */
3285 r = RegCloseKey (hkSubKey);
3286 if (r != ERROR_SUCCESS)
3287 WARN ("RegCloseKey returned %li\n", r);
3288 *pcbEnumValues = *pnEnumValues = 0;
3289 return ERROR_SUCCESS;
3292 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3294 hHeap = GetProcessHeap ();
3297 ERR ("GetProcessHeap failed\n");
3298 r = RegCloseKey (hkSubKey);
3299 if (r != ERROR_SUCCESS)
3300 WARN ("RegCloseKey returned %li\n", r);
3301 return ERROR_OUTOFMEMORY;
3304 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3305 if (lpValueName == NULL)
3307 ERR ("Failed to allocate %li bytes from process heap\n",
3308 cbMaxValueNameLen * sizeof (WCHAR));
3309 r = RegCloseKey (hkSubKey);
3310 if (r != ERROR_SUCCESS)
3311 WARN ("RegCloseKey returned %li\n", r);
3312 return ERROR_OUTOFMEMORY;
3315 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3316 if (lpValue == NULL)
3318 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3319 if (HeapFree (hHeap, 0, lpValueName) == 0)
3320 WARN ("HeapFree failed with code %li\n", GetLastError ());
3321 r = RegCloseKey (hkSubKey);
3322 if (r != ERROR_SUCCESS)
3323 WARN ("RegCloseKey returned %li\n", r);
3324 return ERROR_OUTOFMEMORY;
3327 TRACE ("pass 1: calculating buffer required for all names and values\n");
3329 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3331 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3333 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3335 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3336 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3337 NULL, NULL, lpValue, &cbValueLen);
3338 if (ret != ERROR_SUCCESS)
3340 if (HeapFree (hHeap, 0, lpValue) == 0)
3341 WARN ("HeapFree failed with code %li\n", GetLastError ());
3342 if (HeapFree (hHeap, 0, lpValueName) == 0)
3343 WARN ("HeapFree failed with code %li\n", GetLastError ());
3344 r = RegCloseKey (hkSubKey);
3345 if (r != ERROR_SUCCESS)
3346 WARN ("RegCloseKey returned %li\n", r);
3347 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3351 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3352 debugstr_w (lpValueName), dwIndex,
3353 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3355 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3356 cbBufSize += cbValueLen;
3359 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3361 *pcbEnumValues = cbBufSize;
3362 *pnEnumValues = cValues;
3364 if (cbEnumValues < cbBufSize) /* buffer too small */
3366 if (HeapFree (hHeap, 0, lpValue) == 0)
3367 WARN ("HeapFree failed with code %li\n", GetLastError ());
3368 if (HeapFree (hHeap, 0, lpValueName) == 0)
3369 WARN ("HeapFree failed with code %li\n", GetLastError ());
3370 r = RegCloseKey (hkSubKey);
3371 if (r != ERROR_SUCCESS)
3372 WARN ("RegCloseKey returned %li\n", r);
3373 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3374 return ERROR_MORE_DATA;
3377 TRACE ("pass 2: copying all names and values to buffer\n");
3379 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3380 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3382 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3384 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3385 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3386 NULL, &dwType, lpValue, &cbValueLen);
3387 if (ret != ERROR_SUCCESS)
3389 if (HeapFree (hHeap, 0, lpValue) == 0)
3390 WARN ("HeapFree failed with code %li\n", GetLastError ());
3391 if (HeapFree (hHeap, 0, lpValueName) == 0)
3392 WARN ("HeapFree failed with code %li\n", GetLastError ());
3393 r = RegCloseKey (hkSubKey);
3394 if (r != ERROR_SUCCESS)
3395 WARN ("RegCloseKey returned %li\n", r);
3396 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3400 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3401 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3402 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3403 pEnumValues += cbValueNameLen;
3405 /* return # of *bytes* (including trailing \0), not # of chars */
3406 ppev[dwIndex].cbValueName = cbValueNameLen;
3408 ppev[dwIndex].dwType = dwType;
3410 memcpy (pEnumValues, lpValue, cbValueLen);
3411 ppev[dwIndex].pData = pEnumValues;
3412 pEnumValues += cbValueLen;
3414 ppev[dwIndex].cbData = cbValueLen;
3416 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3417 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3420 if (HeapFree (hHeap, 0, lpValue) == 0)
3422 ret = GetLastError ();
3423 ERR ("HeapFree failed with code %li\n", ret);
3424 if (HeapFree (hHeap, 0, lpValueName) == 0)
3425 WARN ("HeapFree failed with code %li\n", GetLastError ());
3426 r = RegCloseKey (hkSubKey);
3427 if (r != ERROR_SUCCESS)
3428 WARN ("RegCloseKey returned %li\n", r);
3432 if (HeapFree (hHeap, 0, lpValueName) == 0)
3434 ret = GetLastError ();
3435 ERR ("HeapFree failed with code %li\n", ret);
3436 r = RegCloseKey (hkSubKey);
3437 if (r != ERROR_SUCCESS)
3438 WARN ("RegCloseKey returned %li\n", r);
3442 ret = RegCloseKey (hkSubKey);
3443 if (ret != ERROR_SUCCESS)
3445 ERR ("RegCloseKey returned %li\n", ret);
3449 return ERROR_SUCCESS;
3452 /*******************************************************************************
3453 * EnumPrinterDataExA [WINSPOOL.@]
3455 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3456 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3457 * what Windows 2000 SP1 does.
3460 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3461 LPBYTE pEnumValues, DWORD cbEnumValues,
3462 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3466 DWORD ret, dwIndex, dwBufSize;
3470 TRACE ("%p %s\n", hPrinter, pKeyName);
3472 if (pKeyName == NULL || *pKeyName == 0)
3473 return ERROR_INVALID_PARAMETER;
3475 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3478 ret = GetLastError ();
3479 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3483 hHeap = GetProcessHeap ();
3486 ERR ("GetProcessHeap failed\n");
3487 return ERROR_OUTOFMEMORY;
3490 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3491 if (pKeyNameW == NULL)
3493 ERR ("Failed to allocate %li bytes from process heap\n",
3494 (LONG) len * sizeof (WCHAR));
3495 return ERROR_OUTOFMEMORY;
3498 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3500 ret = GetLastError ();
3501 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3502 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3503 WARN ("HeapFree failed with code %li\n", GetLastError ());
3507 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3508 pcbEnumValues, pnEnumValues);
3509 if (ret != ERROR_SUCCESS)
3511 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3512 WARN ("HeapFree failed with code %li\n", GetLastError ());
3513 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3517 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3519 ret = GetLastError ();
3520 ERR ("HeapFree failed with code %li\n", ret);
3524 if (*pnEnumValues == 0) /* empty key */
3525 return ERROR_SUCCESS;
3528 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3530 PPRINTER_ENUM_VALUESW ppev =
3531 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3533 if (dwBufSize < ppev->cbValueName)
3534 dwBufSize = ppev->cbValueName;
3536 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3537 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3538 dwBufSize = ppev->cbData;
3541 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3543 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3544 if (pBuffer == NULL)
3546 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3547 return ERROR_OUTOFMEMORY;
3550 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3552 PPRINTER_ENUM_VALUESW ppev =
3553 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3555 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3556 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3560 ret = GetLastError ();
3561 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3562 if (HeapFree (hHeap, 0, pBuffer) == 0)
3563 WARN ("HeapFree failed with code %li\n", GetLastError ());
3567 memcpy (ppev->pValueName, pBuffer, len);
3569 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3571 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3572 ppev->dwType != REG_MULTI_SZ)
3575 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3576 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3579 ret = GetLastError ();
3580 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3581 if (HeapFree (hHeap, 0, pBuffer) == 0)
3582 WARN ("HeapFree failed with code %li\n", GetLastError ());
3586 memcpy (ppev->pData, pBuffer, len);
3588 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3589 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3592 if (HeapFree (hHeap, 0, pBuffer) == 0)
3594 ret = GetLastError ();
3595 ERR ("HeapFree failed with code %li\n", ret);
3599 return ERROR_SUCCESS;
3602 /******************************************************************************
3603 * AddPortA (WINSPOOL.@)
3605 BOOL WINAPI AddPortA(LPSTR pName ,HWND hWnd, LPSTR pMonitorName)
3607 FIXME("(%s, %p, %s\n), stub!\n",pName,hWnd,pMonitorName);