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(cupsGetPrinters) *pcupsGetPrinters = NULL;
148 typeof(cupsGetDefault) *pcupsGetDefault = NULL;
149 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
151 int i,nrofdests,hadprinter = FALSE;
152 PRINTER_INFO_2A pinfo2a;
154 void *cupshandle = NULL;
157 UNICODE_STRING lpszNameW;
159 HKEY hkeyPrinters, hkeyPrinter;
161 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
166 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
167 if (!p##x) return FALSE;
169 DYNCUPS(cupsGetDefault);
171 DYNCUPS(cupsGetPrinters);
174 def = pcupsGetDefault();
176 if (def && !strcmp(def,"none")) /* CUPS has "none" for no default printer */
179 nrofdests = pcupsGetPrinters(&printers);
180 for (i=0;i<nrofdests;i++) {
181 /* First check that the printer doesn't exist already */
182 pwstrNameW = asciitounicode(&lpszNameW, printers[i]);
183 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) ==
185 if (RegOpenKeyW(hkeyPrinters, pwstrNameW, &hkeyPrinter) ==
187 /* We know this printer already */
188 RegCloseKey(hkeyPrinter);
189 RegCloseKey(hkeyPrinters);
190 RtlFreeUnicodeString(&lpszNameW);
191 TRACE("Printer %s already known. Skipping detection\n", printers[i]);
194 RegCloseKey(hkeyPrinters);
196 RtlFreeUnicodeString(&lpszNameW);
198 /* OK, we haven't seen this one yet. Request PPD for it */
199 ppd = pcupsGetPPD(printers[i]);
201 WARN("No ppd file for %s.\n",printers[i]);
202 /* If this was going to be the default printer,
203 * forget it and use another one.
205 if (def && !strcmp(def,printers[i]))
213 if (def && !strcmp(def,printers[i]))
214 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
216 /* The default printer has no PPD file, just use the first one
220 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
223 memset(&pinfo2a,0,sizeof(pinfo2a));
224 pinfo2a.pPrinterName = printers[i];
225 pinfo2a.pDatatype = "RAW";
226 pinfo2a.pPrintProcessor = "WinPrint";
227 pinfo2a.pDriverName = "PS Driver";
228 pinfo2a.pComment = "WINEPS Printer using CUPS";
229 pinfo2a.pLocation = "<physical location of printer>";
230 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
231 sprintf(port,"LPR:%s",printers[i]);
232 pinfo2a.pPortName = port;
233 pinfo2a.pParameters = "<parameters?>";
234 pinfo2a.pShareName = "<share name?>";
235 pinfo2a.pSepFile = "<sep file?>";
237 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
238 sprintf(devline,"WINEPS,%s",port);
239 WriteProfileStringA("devices",printers[i],devline);
240 HeapFree(GetProcessHeap(),0,devline);
242 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
243 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
244 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
246 HeapFree(GetProcessHeap(),0,port);
248 wine_dlclose(cupshandle, NULL, 0);
254 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
255 PRINTER_INFO_2A pinfo2a;
256 char *s,*name,*prettyname,*devname;
260 while (isspace(*pent)) pent++;
261 s = strchr(pent,':');
262 if (!s) return FALSE;
268 /* Determine whether this is a postscript printer. */
270 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
271 if (strstr(name,"ps") ||
272 strstr(name,"pd") || /* postscript double page */
273 strstr(name,"postscript") ||
274 strstr(name,"PostScript")
276 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
279 /* 2. Check if this is a remote printer. These usually are postscript
282 if (strstr(pent,":rm")) {
284 TRACE("%s is remote, assuming postscript.\n",name);
286 /* 3. Check if we have an input filter program. If we have one, it
287 * most likely is one capable of converting postscript.
288 * (Could probably check for occurrence of 'gs' or 'ghostscript'
289 * in the if file itself.)
291 if (strstr(pent,":if=/")) {
293 TRACE("%s has inputfilter program, assuming postscript.\n",name);
296 /* If it is not a postscript printer, we cannot use it. */
301 /* Get longest name, usually the one at the right for later display. */
302 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
303 s=strchr(name,'|');if (s) *s='\0';
305 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
306 * if it is too long, we use it as comment below. */
307 devname = prettyname;
308 if (strlen(devname)>=CCHDEVICENAME-1)
310 if (strlen(devname)>=CCHDEVICENAME-1)
313 if (isfirst) /* set first entry as default */
314 WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
316 memset(&pinfo2a,0,sizeof(pinfo2a));
317 pinfo2a.pPrinterName = devname;
318 pinfo2a.pDatatype = "RAW";
319 pinfo2a.pPrintProcessor = "WinPrint";
320 pinfo2a.pDriverName = "PS Driver";
321 pinfo2a.pComment = "WINEPS Printer using LPR";
322 pinfo2a.pLocation = prettyname;
323 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
324 sprintf(port,"LPR:%s",name);
325 pinfo2a.pPortName = port;
326 pinfo2a.pParameters = "<parameters?>";
327 pinfo2a.pShareName = "<share name?>";
328 pinfo2a.pSepFile = "<sep file?>";
330 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
331 sprintf(devline,"WINEPS,%s",port);
332 WriteProfileStringA("devices",devname,devline);
333 HeapFree(GetProcessHeap(),0,devline);
335 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
336 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
337 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
339 HeapFree(GetProcessHeap(),0,port);
344 PRINTCAP_LoadPrinters(void) {
345 BOOL hadprinter = FALSE, isfirst = TRUE;
349 f = fopen("/etc/printcap","r");
353 while (fgets(buf,sizeof(buf),f)) {
357 s=strchr(buf,'\n'); if (s) *s='\0';
358 if ((buf[0]=='#') || (buf[0]=='\0'))
362 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
365 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
369 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
370 pent[strlen(pent)-1] = '\0';
373 } while (fgets(buf,sizeof(buf),f));
375 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
377 if (pent) HeapFree(GetProcessHeap(),0,pent);
385 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
387 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
388 lstrlenW(value) * sizeof(WCHAR));
392 WINSPOOL_LoadSystemPrinters() {
395 di3a.cVersion = 0x400;
396 di3a.pName = "PS Driver";
397 di3a.pEnvironment = NULL; /* NULL means auto */
398 di3a.pDriverPath = "wineps16";
399 di3a.pDataFile = "<datafile?>";
400 di3a.pConfigFile = "wineps16";
401 di3a.pHelpFile = "<helpfile?>";
402 di3a.pDependentFiles = "<dependend files?>";
403 di3a.pMonitorName = "<monitor name?>";
404 di3a.pDefaultDataType = "RAW";
406 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
407 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
410 #ifdef HAVE_CUPS_CUPS_H
411 /* If we have any CUPS based printers, skip looking for printcap printers */
412 if (CUPS_LoadPrinters())
416 /* Check for [ppd] section in config file before parsing /etc/printcap */
418 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
419 &hkPPD) == ERROR_SUCCESS)
422 PRINTCAP_LoadPrinters();
427 /******************************************************************
428 * WINSPOOL_GetOpenedPrinterEntry
429 * Get the first place empty in the opened printer table
431 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
435 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
437 if (i >= nb_printers)
439 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
440 (nb_printers + 16) * sizeof(*new_array) );
441 if (!new_array) return 0;
442 printer_array = new_array;
446 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
448 strcpyW( printer_array[i], name );
449 return (HANDLE)(i + 1);
454 /******************************************************************
455 * WINSPOOL_GetOpenedPrinter
456 * Get the pointer to the opened printer referred by the handle
458 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
460 int idx = (int)printerHandle;
461 if ((idx <= 0) || (idx > nb_printers))
463 SetLastError(ERROR_INVALID_HANDLE);
466 return printer_array[idx - 1];
469 /******************************************************************
470 * WINSPOOL_GetOpenedPrinterRegKey
473 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
475 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
479 if(!name) return ERROR_INVALID_HANDLE;
481 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
485 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
487 ERR("Can't find opened printer %s in registry\n",
489 RegCloseKey(hkeyPrinters);
490 return ERROR_INVALID_PRINTER_NAME; /* ? */
492 RegCloseKey(hkeyPrinters);
493 return ERROR_SUCCESS;
496 /***********************************************************
499 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
502 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
505 Formname = (dmA->dmSize > off_formname);
506 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
507 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
510 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
511 dmA->dmSize - CCHDEVICENAME);
513 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
514 off_formname - CCHDEVICENAME);
515 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
517 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
518 (off_formname + CCHFORMNAME));
521 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
526 /***********************************************************
528 * Creates a unicode copy of supplied devmode on heap
530 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
535 ptrdiff_t off_formname;
538 if(!dmA) return NULL;
540 off_formname = (char *)dmA->dmFormName - (char *)dmA;
541 Formname = (dmA->dmSize > off_formname);
542 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
543 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
544 return DEVMODEcpyAtoW(dmW, dmA);
547 /***********************************************************
549 * Creates an ascii copy of supplied devmode on heap
551 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
556 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
558 if(!dmW) return NULL;
559 Formname = (dmW->dmSize > off_formname);
560 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
561 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
562 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
563 CCHDEVICENAME, NULL, NULL);
565 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
566 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
568 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
569 off_formname - CCHDEVICENAME * sizeof(WCHAR));
570 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
571 CCHFORMNAME, NULL, NULL);
572 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
573 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
576 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
581 /***********************************************************
583 * Creates a unicode copy of PRINTER_INFO_2A on heap
585 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
587 LPPRINTER_INFO_2W piW;
588 UNICODE_STRING usBuffer;
590 if(!piA) return NULL;
591 piW = HeapAlloc(heap, 0, sizeof(*piW));
592 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
594 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
595 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
596 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
597 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
598 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
599 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
600 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
601 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
602 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
603 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
604 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
605 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
609 /***********************************************************
610 * FREE_PRINTER_INFO_2W
611 * Free PRINTER_INFO_2W and all strings
613 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
617 HeapFree(heap,0,piW->pServerName);
618 HeapFree(heap,0,piW->pPrinterName);
619 HeapFree(heap,0,piW->pShareName);
620 HeapFree(heap,0,piW->pPortName);
621 HeapFree(heap,0,piW->pDriverName);
622 HeapFree(heap,0,piW->pComment);
623 HeapFree(heap,0,piW->pLocation);
624 HeapFree(heap,0,piW->pDevMode);
625 HeapFree(heap,0,piW->pSepFile);
626 HeapFree(heap,0,piW->pPrintProcessor);
627 HeapFree(heap,0,piW->pDatatype);
628 HeapFree(heap,0,piW->pParameters);
629 HeapFree(heap,0,piW);
633 /******************************************************************
634 * DeviceCapabilities [WINSPOOL.@]
635 * DeviceCapabilitiesA [WINSPOOL.@]
638 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
639 LPSTR pOutput, LPDEVMODEA lpdm)
643 if (!GDI_CallDeviceCapabilities16)
645 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
647 if (!GDI_CallDeviceCapabilities16) return -1;
649 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
651 /* If DC_PAPERSIZE map POINT16s to POINTs */
652 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
653 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
654 POINT *pt = (POINT *)pOutput;
656 memcpy(tmp, pOutput, ret * sizeof(POINT16));
657 for(i = 0; i < ret; i++, pt++)
662 HeapFree( GetProcessHeap(), 0, tmp );
668 /*****************************************************************************
669 * DeviceCapabilitiesW [WINSPOOL.@]
671 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
674 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
675 WORD fwCapability, LPWSTR pOutput,
676 const DEVMODEW *pDevMode)
678 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
679 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
680 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
683 if(pOutput && (fwCapability == DC_BINNAMES ||
684 fwCapability == DC_FILEDEPENDENCIES ||
685 fwCapability == DC_PAPERNAMES)) {
686 /* These need A -> W translation */
689 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
693 switch(fwCapability) {
698 case DC_FILEDEPENDENCIES:
702 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
703 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
705 for(i = 0; i < ret; i++)
706 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
707 pOutput + (i * size), size);
708 HeapFree(GetProcessHeap(), 0, pOutputA);
710 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
711 (LPSTR)pOutput, dmA);
713 HeapFree(GetProcessHeap(),0,pPortA);
714 HeapFree(GetProcessHeap(),0,pDeviceA);
715 HeapFree(GetProcessHeap(),0,dmA);
719 /******************************************************************
720 * DocumentPropertiesA [WINSPOOL.@]
723 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
724 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
725 LPDEVMODEA pDevModeInput,DWORD fMode )
727 LPSTR lpName = pDeviceName;
730 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
731 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
735 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
737 ERR("no name from hPrinter?\n");
740 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
743 if (!GDI_CallExtDeviceMode16)
745 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
747 if (!GDI_CallExtDeviceMode16) {
748 ERR("No CallExtDeviceMode16?\n");
752 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
753 pDevModeInput, NULL, fMode);
756 HeapFree(GetProcessHeap(),0,lpName);
761 /*****************************************************************************
762 * DocumentPropertiesW (WINSPOOL.@)
764 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
766 LPDEVMODEW pDevModeOutput,
767 LPDEVMODEW pDevModeInput, DWORD fMode)
770 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
771 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
772 LPDEVMODEA pDevModeOutputA = NULL;
775 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
776 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
779 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
780 if(ret < 0) return ret;
781 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
783 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
784 pDevModeInputA, fMode);
786 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
787 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
789 if(fMode == 0 && ret > 0)
790 ret += (CCHDEVICENAME + CCHFORMNAME);
791 HeapFree(GetProcessHeap(),0,pDevModeInputA);
792 HeapFree(GetProcessHeap(),0,pDeviceNameA);
796 /******************************************************************
797 * OpenPrinterA [WINSPOOL.@]
800 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
801 LPPRINTER_DEFAULTSA pDefault)
803 UNICODE_STRING lpPrinterNameW;
804 UNICODE_STRING usBuffer;
805 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
806 PWSTR pwstrPrinterNameW;
809 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
812 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
813 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
815 DefaultW.DesiredAccess = pDefault->DesiredAccess;
816 pDefaultW = &DefaultW;
818 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
820 RtlFreeUnicodeString(&usBuffer);
821 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
823 RtlFreeUnicodeString(&lpPrinterNameW);
827 /******************************************************************
828 * OpenPrinterW [WINSPOOL.@]
831 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
832 LPPRINTER_DEFAULTSW pDefault)
834 HKEY hkeyPrinters, hkeyPrinter;
836 if (!lpPrinterName) {
837 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
838 SetLastError(ERROR_INVALID_PARAMETER);
842 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
845 /* Check Printer exists */
846 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
848 ERR("Can't create Printers key\n");
849 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
853 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
854 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
856 TRACE("Can't find printer %s in registry\n",
857 debugstr_w(lpPrinterName));
858 RegCloseKey(hkeyPrinters);
859 SetLastError(ERROR_INVALID_PRINTER_NAME);
862 RegCloseKey(hkeyPrinter);
863 RegCloseKey(hkeyPrinters);
865 if(!phPrinter) /* This seems to be what win95 does anyway */
868 /* Get the unique handle of the printer*/
869 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
871 if (pDefault != NULL)
872 FIXME("Not handling pDefault\n");
877 /******************************************************************
878 * AddMonitorA [WINSPOOL.@]
881 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
883 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
884 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
888 /******************************************************************
889 * DeletePrinterDriverA [WINSPOOL.@]
893 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
895 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
896 debugstr_a(pDriverName));
897 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
902 /******************************************************************
903 * DeleteMonitorA [WINSPOOL.@]
907 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
909 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
910 debugstr_a(pMonitorName));
911 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
916 /******************************************************************
917 * DeletePortA [WINSPOOL.@]
921 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
923 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
924 debugstr_a(pPortName));
925 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
929 /******************************************************************************
930 * SetPrinterW [WINSPOOL.@]
940 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
944 /******************************************************************************
945 * WritePrinter [WINSPOOL.@]
955 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
959 /*****************************************************************************
960 * AddFormA [WINSPOOL.@]
962 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
964 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
968 /*****************************************************************************
969 * AddFormW [WINSPOOL.@]
971 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
973 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
977 /*****************************************************************************
978 * AddJobA [WINSPOOL.@]
980 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
981 DWORD cbBuf, LPDWORD pcbNeeded)
983 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
988 /*****************************************************************************
989 * AddJobW [WINSPOOL.@]
991 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
994 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
999 /*****************************************************************************
1000 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1002 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR environ,
1003 DWORD level, LPBYTE Info,
1004 DWORD cbBuf, LPDWORD needed)
1006 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", server, environ, level, Info,
1011 /*****************************************************************************
1012 * WINSPOOL_OpenDriverReg [internal]
1014 * opens the registry for the printer drivers depending on the given input
1015 * variable pEnvironment
1018 * the opened hkey on success
1021 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1023 LPSTR lpKey, p = NULL;
1026 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1029 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1033 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1035 if(!GetVersionExA( &ver))
1038 switch (ver.dwPlatformId) {
1039 case VER_PLATFORM_WIN32s:
1040 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1043 case VER_PLATFORM_WIN32_NT:
1044 p = "Windows NT x86";
1050 TRACE("set environment to %s\n", p);
1053 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1054 strlen(p) + strlen(Drivers));
1055 sprintf( lpKey, Drivers, p);
1057 TRACE("%s\n", lpKey);
1059 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1063 if(pEnvironment && unicode)
1064 HeapFree( GetProcessHeap(), 0, p);
1065 HeapFree( GetProcessHeap(), 0, lpKey);
1070 /*****************************************************************************
1071 * AddPrinterW [WINSPOOL.@]
1073 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1075 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1079 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1082 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1085 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1086 SetLastError(ERROR_INVALID_PARAMETER);
1090 ERR("Level = %ld, unsupported!\n", Level);
1091 SetLastError(ERROR_INVALID_LEVEL);
1094 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1095 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1096 debugstr_w(pi->pPrinterName)
1098 SetLastError(ERROR_INVALID_LEVEL);
1102 SetLastError(ERROR_INVALID_PARAMETER);
1105 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1107 ERR("Can't create Printers key\n");
1110 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1111 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1112 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1113 RegCloseKey(hkeyPrinter);
1114 RegCloseKey(hkeyPrinters);
1117 RegCloseKey(hkeyPrinter);
1119 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1121 ERR("Can't create Drivers key\n");
1122 RegCloseKey(hkeyPrinters);
1125 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1127 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1128 RegCloseKey(hkeyPrinters);
1129 RegCloseKey(hkeyDrivers);
1130 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1133 RegCloseKey(hkeyDriver);
1134 RegCloseKey(hkeyDrivers);
1136 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1137 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1138 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1139 RegCloseKey(hkeyPrinters);
1143 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1145 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1146 SetLastError(ERROR_INVALID_PRINTER_NAME);
1147 RegCloseKey(hkeyPrinters);
1150 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1151 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1152 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1154 /* See if we can load the driver. We may need the devmode structure anyway
1157 * Note that DocumentPropertiesW will briefly try to open the printer we
1158 * just create to find a DEVMODEA struct (it will use the WINEPS default
1159 * one in case it is not there, so we are ok).
1161 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1163 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1164 size = sizeof(DEVMODEW);
1169 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1171 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1172 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1173 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1176 /* set devmode to printer name */
1177 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1180 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1181 and we support these drivers. NT writes DEVMODEW so somehow
1182 we'll need to distinguish between these when we support NT
1184 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1185 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1186 dmA->dmSize + dmA->dmDriverExtra);
1187 HeapFree(GetProcessHeap(), 0, dmA);
1189 HeapFree(GetProcessHeap(), 0, dmW);
1190 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1191 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1192 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1193 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1195 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1196 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1197 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1198 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1199 (LPBYTE)&pi->Priority, sizeof(DWORD));
1200 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1201 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1202 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1203 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1204 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1205 (LPBYTE)&pi->Status, sizeof(DWORD));
1206 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1207 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1209 RegCloseKey(hkeyPrinter);
1210 RegCloseKey(hkeyPrinters);
1211 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1212 ERR("OpenPrinter failing\n");
1218 /*****************************************************************************
1219 * AddPrinterA [WINSPOOL.@]
1221 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1223 UNICODE_STRING pNameW;
1225 PRINTER_INFO_2W *piW;
1226 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1229 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1231 ERR("Level = %ld, unsupported!\n", Level);
1232 SetLastError(ERROR_INVALID_LEVEL);
1235 pwstrNameW = asciitounicode(&pNameW,pName);
1236 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1238 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1240 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1241 RtlFreeUnicodeString(&pNameW);
1246 /*****************************************************************************
1247 * ClosePrinter [WINSPOOL.@]
1249 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1251 int i = (int)hPrinter;
1253 TRACE("Handle %p\n", hPrinter);
1255 if ((i <= 0) || (i > nb_printers)) return FALSE;
1256 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1257 printer_array[i - 1] = NULL;
1261 /*****************************************************************************
1262 * DeleteFormA [WINSPOOL.@]
1264 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1266 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1270 /*****************************************************************************
1271 * DeleteFormW [WINSPOOL.@]
1273 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1275 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1279 /*****************************************************************************
1280 * DeletePrinter [WINSPOOL.@]
1282 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1284 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1287 if(!lpNameW) return FALSE;
1288 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1290 ERR("Can't open Printers key\n");
1294 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1295 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1296 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1297 RegCloseKey(hkeyPrinters);
1301 ClosePrinter(hPrinter);
1305 /*****************************************************************************
1306 * SetPrinterA [WINSPOOL.@]
1308 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1311 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1315 /*****************************************************************************
1316 * SetJobA [WINSPOOL.@]
1318 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1319 LPBYTE pJob, DWORD Command)
1321 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1326 /*****************************************************************************
1327 * SetJobW [WINSPOOL.@]
1329 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1330 LPBYTE pJob, DWORD Command)
1332 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1337 /*****************************************************************************
1338 * EndDocPrinter [WINSPOOL.@]
1340 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1342 FIXME("(hPrinter=%p): stub\n", hPrinter);
1346 /*****************************************************************************
1347 * EndPagePrinter [WINSPOOL.@]
1349 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1351 FIXME("(hPrinter=%p): stub\n", hPrinter);
1355 /*****************************************************************************
1356 * StartDocPrinterA [WINSPOOL.@]
1358 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1360 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1364 /*****************************************************************************
1365 * StartDocPrinterW [WINSPOOL.@]
1367 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1369 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1373 /*****************************************************************************
1374 * StartPagePrinter [WINSPOOL.@]
1376 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1378 FIXME("(hPrinter=%p): stub\n", hPrinter);
1382 /*****************************************************************************
1383 * GetFormA [WINSPOOL.@]
1385 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1386 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1388 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1389 Level,pForm,cbBuf,pcbNeeded);
1393 /*****************************************************************************
1394 * GetFormW [WINSPOOL.@]
1396 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1397 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1399 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1400 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1404 /*****************************************************************************
1405 * SetFormA [WINSPOOL.@]
1407 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1410 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1414 /*****************************************************************************
1415 * SetFormW [WINSPOOL.@]
1417 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1420 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1424 /*****************************************************************************
1425 * ReadPrinter [WINSPOOL.@]
1427 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1428 LPDWORD pNoBytesRead)
1430 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1434 /*****************************************************************************
1435 * ResetPrinterA [WINSPOOL.@]
1437 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1439 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1443 /*****************************************************************************
1444 * ResetPrinterW [WINSPOOL.@]
1446 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1448 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1452 /*****************************************************************************
1453 * WINSPOOL_GetDWORDFromReg
1455 * Return DWORD associated with ValueName from hkey.
1457 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1459 DWORD sz = sizeof(DWORD), type, value = 0;
1462 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1464 if(ret != ERROR_SUCCESS) {
1465 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1468 if(type != REG_DWORD) {
1469 ERR("Got type %ld\n", type);
1475 /*****************************************************************************
1476 * WINSPOOL_GetStringFromReg
1478 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1479 * String is stored either as unicode or ascii.
1480 * Bit of a hack here to get the ValueName if we want ascii.
1482 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1483 DWORD buflen, DWORD *needed,
1486 DWORD sz = buflen, type;
1490 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1492 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1493 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1494 HeapFree(GetProcessHeap(),0,ValueNameA);
1496 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1497 WARN("Got ret = %ld\n", ret);
1505 /*****************************************************************************
1506 * WINSPOOL_GetDefaultDevMode
1508 * Get a default DevMode values for wineps.
1512 static void WINSPOOL_GetDefaultDevMode(
1514 DWORD buflen, DWORD *needed,
1519 /* fill default DEVMODE - should be read from ppd... */
1520 ZeroMemory( &dm, sizeof(dm) );
1521 strcpy(dm.dmDeviceName,"wineps");
1522 dm.dmSpecVersion = DM_SPECVERSION;
1523 dm.dmDriverVersion = 1;
1524 dm.dmSize = sizeof(DEVMODEA);
1525 dm.dmDriverExtra = 0;
1527 DM_ORIENTATION | DM_PAPERSIZE |
1528 DM_PAPERLENGTH | DM_PAPERWIDTH |
1531 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1532 DM_YRESOLUTION | DM_TTOPTION;
1534 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1535 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1536 dm.u1.s1.dmPaperLength = 2970;
1537 dm.u1.s1.dmPaperWidth = 2100;
1541 dm.dmDefaultSource = DMBIN_AUTO;
1542 dm.dmPrintQuality = DMRES_MEDIUM;
1545 dm.dmYResolution = 300; /* 300dpi */
1546 dm.dmTTOption = DMTT_BITMAP;
1549 /* dm.dmLogPixels */
1550 /* dm.dmBitsPerPel */
1551 /* dm.dmPelsWidth */
1552 /* dm.dmPelsHeight */
1553 /* dm.dmDisplayFlags */
1554 /* dm.dmDisplayFrequency */
1555 /* dm.dmICMMethod */
1556 /* dm.dmICMIntent */
1557 /* dm.dmMediaType */
1558 /* dm.dmDitherType */
1559 /* dm.dmReserved1 */
1560 /* dm.dmReserved2 */
1561 /* dm.dmPanningWidth */
1562 /* dm.dmPanningHeight */
1565 if(buflen >= sizeof(DEVMODEW)) {
1566 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1567 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1568 HeapFree(GetProcessHeap(),0,pdmW);
1570 *needed = sizeof(DEVMODEW);
1574 if(buflen >= sizeof(DEVMODEA)) {
1575 memcpy(ptr, &dm, sizeof(DEVMODEA));
1577 *needed = sizeof(DEVMODEA);
1581 /*****************************************************************************
1582 * WINSPOOL_GetDevModeFromReg
1584 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1585 * DevMode is stored either as unicode or ascii.
1587 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1589 DWORD buflen, DWORD *needed,
1592 DWORD sz = buflen, type;
1595 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1596 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1597 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1598 if (sz < sizeof(DEVMODEA))
1600 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1603 /* ensures that dmSize is not erratically bogus if registry is invalid */
1604 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1605 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1607 sz += (CCHDEVICENAME + CCHFORMNAME);
1609 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1610 memcpy(ptr, dmW, sz);
1611 HeapFree(GetProcessHeap(),0,dmW);
1618 /*********************************************************************
1619 * WINSPOOL_GetPrinter_2
1621 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1622 * The strings are either stored as unicode or ascii.
1624 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1625 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1628 DWORD size, left = cbBuf;
1629 BOOL space = (cbBuf > 0);
1634 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1636 if(space && size <= left) {
1637 pi2->pPrinterName = (LPWSTR)ptr;
1644 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1646 if(space && size <= left) {
1647 pi2->pShareName = (LPWSTR)ptr;
1654 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1656 if(space && size <= left) {
1657 pi2->pPortName = (LPWSTR)ptr;
1664 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1666 if(space && size <= left) {
1667 pi2->pDriverName = (LPWSTR)ptr;
1674 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1676 if(space && size <= left) {
1677 pi2->pComment = (LPWSTR)ptr;
1684 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1686 if(space && size <= left) {
1687 pi2->pLocation = (LPWSTR)ptr;
1694 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1696 if(space && size <= left) {
1697 pi2->pDevMode = (LPDEVMODEW)ptr;
1706 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1707 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
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 dwType |= PRINTER_ENUM_LOCAL;
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);