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"
49 #include "wine/windef16.h"
50 #include "wine/unicode.h"
51 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
57 static LPWSTR *printer_array;
58 static int nb_printers;
60 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
61 WORD fwCapability, LPSTR lpszOutput,
63 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
64 LPSTR lpszDevice, LPSTR lpszPort,
65 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
68 static char Printers[] =
69 "System\\CurrentControlSet\\control\\Print\\Printers\\";
70 static char Drivers[] =
71 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
73 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
75 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
76 'i','o','n',' ','F','i','l','e',0};
77 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
78 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
79 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
81 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
83 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
84 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
85 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
86 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
87 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
88 static WCHAR NameW[] = {'N','a','m','e',0};
89 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
90 static WCHAR PortW[] = {'P','o','r','t',0};
91 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
93 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
95 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
96 'v','e','r','D','a','t','a',0};
97 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
99 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
100 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
102 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
103 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
104 DWORD Level, LPBYTE pDriverInfo,
105 DWORD cbBuf, LPDWORD pcbNeeded,
108 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
109 if passed a NULL string. This returns NULLs to the result.
111 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
115 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
116 return usBufferPtr->Buffer;
118 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
123 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
126 /* If forcing, or no profile string entry for device yet, set the entry
128 * The always change entry if not WINEPS yet is discussable.
131 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
133 !strstr(qbuf,"WINEPS")
135 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
137 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
138 WriteProfileStringA("windows","device",buf);
139 HeapFree(GetProcessHeap(),0,buf);
143 #ifdef HAVE_CUPS_CUPS_H
145 CUPS_LoadPrinters(void) {
146 typeof(cupsGetPrinters) *pcupsGetPrinters = NULL;
147 typeof(cupsGetDefault) *pcupsGetDefault = NULL;
148 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
150 int i,nrofdests,hadprinter = FALSE;
151 PRINTER_INFO_2A pinfo2a;
153 void *cupshandle = NULL;
156 UNICODE_STRING lpszNameW;
158 HKEY hkeyPrinters, hkeyPrinter;
160 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
165 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
166 if (!p##x) return FALSE;
168 DYNCUPS(cupsGetDefault);
170 DYNCUPS(cupsGetPrinters);
173 def = pcupsGetDefault();
175 if (def && !strcmp(def,"none")) /* CUPS has "none" for no default printer */
178 nrofdests = pcupsGetPrinters(&printers);
179 for (i=0;i<nrofdests;i++) {
180 /* First check that the printer doesn't exist already */
181 pwstrNameW = asciitounicode(&lpszNameW, printers[i]);
182 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) ==
184 if (RegOpenKeyW(hkeyPrinters, pwstrNameW, &hkeyPrinter) ==
186 /* We know this printer already */
187 RegCloseKey(hkeyPrinter);
188 RegCloseKey(hkeyPrinters);
189 RtlFreeUnicodeString(&lpszNameW);
190 TRACE("Printer %s already known. Skipping detection\n", printers[i]);
193 RegCloseKey(hkeyPrinters);
195 RtlFreeUnicodeString(&lpszNameW);
197 /* OK, we haven't seen this one yet. Request PPD for it */
198 ppd = pcupsGetPPD(printers[i]);
200 WARN("No ppd file for %s.\n",printers[i]);
201 /* If this was going to be the default printer,
202 * forget it and use another one.
204 if (def && !strcmp(def,printers[i]))
212 if (def && !strcmp(def,printers[i]))
213 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
215 /* The default printer has no PPD file, just use the first one
219 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
222 memset(&pinfo2a,0,sizeof(pinfo2a));
223 pinfo2a.pPrinterName = printers[i];
224 pinfo2a.pDatatype = "RAW";
225 pinfo2a.pPrintProcessor = "WinPrint";
226 pinfo2a.pDriverName = "PS Driver";
227 pinfo2a.pComment = "WINEPS Printer using CUPS";
228 pinfo2a.pLocation = "<physical location of printer>";
229 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
230 sprintf(port,"LPR:%s",printers[i]);
231 pinfo2a.pPortName = port;
232 pinfo2a.pParameters = "<parameters?>";
233 pinfo2a.pShareName = "<share name?>";
234 pinfo2a.pSepFile = "<sep file?>";
236 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
237 sprintf(devline,"WINEPS,%s",port);
238 WriteProfileStringA("devices",printers[i],devline);
239 HeapFree(GetProcessHeap(),0,devline);
241 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
242 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
243 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
245 HeapFree(GetProcessHeap(),0,port);
247 wine_dlclose(cupshandle, NULL, 0);
253 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
254 PRINTER_INFO_2A pinfo2a;
255 char *s,*name,*prettyname,*devname;
259 while (isspace(*pent)) pent++;
260 s = strchr(pent,':');
261 if (!s) return FALSE;
267 /* Determine whether this is a postscript printer. */
269 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
270 if (strstr(name,"ps") ||
271 strstr(name,"pd") || /* postscript double page */
272 strstr(name,"postscript") ||
273 strstr(name,"PostScript")
275 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
278 /* 2. Check if this is a remote printer. These usually are postscript
281 if (strstr(pent,":rm")) {
283 TRACE("%s is remote, assuming postscript.\n",name);
285 /* 3. Check if we have an input filter program. If we have one, it
286 * most likely is one capable of converting postscript.
287 * (Could probably check for occurrence of 'gs' or 'ghostscript'
288 * in the if file itself.)
290 if (strstr(pent,":if=/")) {
292 TRACE("%s has inputfilter program, assuming postscript.\n",name);
295 /* If it is not a postscript printer, we cannot use it. */
300 /* Get longest name, usually the one at the right for later display. */
301 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
302 s=strchr(name,'|');if (s) *s='\0';
304 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
305 * if it is too long, we use it as comment below. */
306 devname = prettyname;
307 if (strlen(devname)>=CCHDEVICENAME-1)
309 if (strlen(devname)>=CCHDEVICENAME-1)
312 if (isfirst) /* set first entry as default */
313 WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
315 memset(&pinfo2a,0,sizeof(pinfo2a));
316 pinfo2a.pPrinterName = devname;
317 pinfo2a.pDatatype = "RAW";
318 pinfo2a.pPrintProcessor = "WinPrint";
319 pinfo2a.pDriverName = "PS Driver";
320 pinfo2a.pComment = "WINEPS Printer using LPR";
321 pinfo2a.pLocation = prettyname;
322 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
323 sprintf(port,"LPR:%s",name);
324 pinfo2a.pPortName = port;
325 pinfo2a.pParameters = "<parameters?>";
326 pinfo2a.pShareName = "<share name?>";
327 pinfo2a.pSepFile = "<sep file?>";
329 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
330 sprintf(devline,"WINEPS,%s",port);
331 WriteProfileStringA("devices",devname,devline);
332 HeapFree(GetProcessHeap(),0,devline);
334 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
335 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
336 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
338 HeapFree(GetProcessHeap(),0,port);
343 PRINTCAP_LoadPrinters(void) {
344 BOOL hadprinter = FALSE, isfirst = TRUE;
348 f = fopen("/etc/printcap","r");
352 while (fgets(buf,sizeof(buf),f)) {
356 s=strchr(buf,'\n'); if (s) *s='\0';
357 if ((buf[0]=='#') || (buf[0]=='\0'))
361 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
364 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
368 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
369 pent[strlen(pent)-1] = '\0';
372 } while (fgets(buf,sizeof(buf),f));
374 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
376 if (pent) HeapFree(GetProcessHeap(),0,pent);
384 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
386 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
387 lstrlenW(value) * sizeof(WCHAR));
391 WINSPOOL_LoadSystemPrinters() {
394 di3a.cVersion = 0x400;
395 di3a.pName = "PS Driver";
396 di3a.pEnvironment = NULL; /* NULL means auto */
397 di3a.pDriverPath = "wineps16";
398 di3a.pDataFile = "<datafile?>";
399 di3a.pConfigFile = "wineps16";
400 di3a.pHelpFile = "<helpfile?>";
401 di3a.pDependentFiles = "<dependend files?>";
402 di3a.pMonitorName = "<monitor name?>";
403 di3a.pDefaultDataType = "RAW";
405 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
406 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
409 #ifdef HAVE_CUPS_CUPS_H
410 /* If we have any CUPS based printers, skip looking for printcap printers */
411 if (CUPS_LoadPrinters())
415 /* Check for [ppd] section in config file before parsing /etc/printcap */
417 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
418 &hkPPD) == ERROR_SUCCESS)
421 PRINTCAP_LoadPrinters();
426 /******************************************************************
427 * WINSPOOL_GetOpenedPrinterEntry
428 * Get the first place empty in the opened printer table
430 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
434 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
436 if (i >= nb_printers)
438 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
439 (nb_printers + 16) * sizeof(*new_array) );
440 if (!new_array) return 0;
441 printer_array = new_array;
445 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
447 strcpyW( printer_array[i], name );
448 return (HANDLE)(i + 1);
453 /******************************************************************
454 * WINSPOOL_GetOpenedPrinter
455 * Get the pointer to the opened printer referred by the handle
457 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
459 int idx = (int)printerHandle;
460 if ((idx <= 0) || (idx > nb_printers))
462 SetLastError(ERROR_INVALID_HANDLE);
465 return printer_array[idx - 1];
468 /******************************************************************
469 * WINSPOOL_GetOpenedPrinterRegKey
472 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
474 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
478 if(!name) return ERROR_INVALID_HANDLE;
480 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
484 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
486 ERR("Can't find opened printer %s in registry\n",
488 RegCloseKey(hkeyPrinters);
489 return ERROR_INVALID_PRINTER_NAME; /* ? */
491 RegCloseKey(hkeyPrinters);
492 return ERROR_SUCCESS;
495 /***********************************************************
498 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
501 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
504 Formname = (dmA->dmSize > off_formname);
505 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
506 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
509 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
510 dmA->dmSize - CCHDEVICENAME);
512 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
513 off_formname - CCHDEVICENAME);
514 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
516 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
517 (off_formname + CCHFORMNAME));
520 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
525 /***********************************************************
527 * Creates a unicode copy of supplied devmode on heap
529 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
534 ptrdiff_t off_formname;
537 if(!dmA) return NULL;
539 off_formname = (char *)dmA->dmFormName - (char *)dmA;
540 Formname = (dmA->dmSize > off_formname);
541 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
542 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
543 return DEVMODEcpyAtoW(dmW, dmA);
546 /***********************************************************
548 * Creates an ascii copy of supplied devmode on heap
550 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
555 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
557 if(!dmW) return NULL;
558 Formname = (dmW->dmSize > off_formname);
559 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
560 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
561 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
562 CCHDEVICENAME, NULL, NULL);
564 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
565 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
567 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
568 off_formname - CCHDEVICENAME * sizeof(WCHAR));
569 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
570 CCHFORMNAME, NULL, NULL);
571 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
572 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
575 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
580 /***********************************************************
582 * Creates a unicode copy of PRINTER_INFO_2A on heap
584 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
586 LPPRINTER_INFO_2W piW;
587 UNICODE_STRING usBuffer;
589 if(!piA) return NULL;
590 piW = HeapAlloc(heap, 0, sizeof(*piW));
591 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
593 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
594 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
595 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
596 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
597 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
598 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
599 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
600 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
601 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
602 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
603 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
604 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
608 /***********************************************************
609 * FREE_PRINTER_INFO_2W
610 * Free PRINTER_INFO_2W and all strings
612 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
616 HeapFree(heap,0,piW->pServerName);
617 HeapFree(heap,0,piW->pPrinterName);
618 HeapFree(heap,0,piW->pShareName);
619 HeapFree(heap,0,piW->pPortName);
620 HeapFree(heap,0,piW->pDriverName);
621 HeapFree(heap,0,piW->pComment);
622 HeapFree(heap,0,piW->pLocation);
623 HeapFree(heap,0,piW->pDevMode);
624 HeapFree(heap,0,piW->pSepFile);
625 HeapFree(heap,0,piW->pPrintProcessor);
626 HeapFree(heap,0,piW->pDatatype);
627 HeapFree(heap,0,piW->pParameters);
628 HeapFree(heap,0,piW);
632 /******************************************************************
633 * DeviceCapabilities [WINSPOOL.@]
634 * DeviceCapabilitiesA [WINSPOOL.@]
637 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
638 LPSTR pOutput, LPDEVMODEA lpdm)
642 if (!GDI_CallDeviceCapabilities16)
644 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
646 if (!GDI_CallDeviceCapabilities16) return -1;
648 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
650 /* If DC_PAPERSIZE map POINT16s to POINTs */
651 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
652 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
653 POINT *pt = (POINT *)pOutput;
655 memcpy(tmp, pOutput, ret * sizeof(POINT16));
656 for(i = 0; i < ret; i++, pt++)
661 HeapFree( GetProcessHeap(), 0, tmp );
667 /*****************************************************************************
668 * DeviceCapabilitiesW [WINSPOOL.@]
670 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
673 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
674 WORD fwCapability, LPWSTR pOutput,
675 const DEVMODEW *pDevMode)
677 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
678 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
679 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
682 if(pOutput && (fwCapability == DC_BINNAMES ||
683 fwCapability == DC_FILEDEPENDENCIES ||
684 fwCapability == DC_PAPERNAMES)) {
685 /* These need A -> W translation */
688 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
692 switch(fwCapability) {
697 case DC_FILEDEPENDENCIES:
701 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
702 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
704 for(i = 0; i < ret; i++)
705 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
706 pOutput + (i * size), size);
707 HeapFree(GetProcessHeap(), 0, pOutputA);
709 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
710 (LPSTR)pOutput, dmA);
712 HeapFree(GetProcessHeap(),0,pPortA);
713 HeapFree(GetProcessHeap(),0,pDeviceA);
714 HeapFree(GetProcessHeap(),0,dmA);
718 /******************************************************************
719 * DocumentPropertiesA [WINSPOOL.@]
722 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
723 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
724 LPDEVMODEA pDevModeInput,DWORD fMode )
726 LPSTR lpName = pDeviceName;
729 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
730 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
734 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
736 ERR("no name from hPrinter?\n");
739 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
742 if (!GDI_CallExtDeviceMode16)
744 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
746 if (!GDI_CallExtDeviceMode16) {
747 ERR("No CallExtDeviceMode16?\n");
751 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
752 pDevModeInput, NULL, fMode);
755 HeapFree(GetProcessHeap(),0,lpName);
760 /*****************************************************************************
761 * DocumentPropertiesW (WINSPOOL.@)
763 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
765 LPDEVMODEW pDevModeOutput,
766 LPDEVMODEW pDevModeInput, DWORD fMode)
769 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
770 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
771 LPDEVMODEA pDevModeOutputA = NULL;
774 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
775 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
778 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
779 if(ret < 0) return ret;
780 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
782 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
783 pDevModeInputA, fMode);
785 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
786 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
788 if(fMode == 0 && ret > 0)
789 ret += (CCHDEVICENAME + CCHFORMNAME);
790 HeapFree(GetProcessHeap(),0,pDevModeInputA);
791 HeapFree(GetProcessHeap(),0,pDeviceNameA);
795 /******************************************************************
796 * OpenPrinterA [WINSPOOL.@]
799 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
800 LPPRINTER_DEFAULTSA pDefault)
802 UNICODE_STRING lpPrinterNameW;
803 UNICODE_STRING usBuffer;
804 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
805 PWSTR pwstrPrinterNameW;
808 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
811 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
812 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
814 DefaultW.DesiredAccess = pDefault->DesiredAccess;
815 pDefaultW = &DefaultW;
817 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
819 RtlFreeUnicodeString(&usBuffer);
820 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
822 RtlFreeUnicodeString(&lpPrinterNameW);
826 /******************************************************************
827 * OpenPrinterW [WINSPOOL.@]
830 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
831 LPPRINTER_DEFAULTSW pDefault)
833 HKEY hkeyPrinters, hkeyPrinter;
835 if (!lpPrinterName) {
836 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
837 SetLastError(ERROR_INVALID_PARAMETER);
841 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
844 /* Check Printer exists */
845 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
847 ERR("Can't create Printers key\n");
848 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
852 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
853 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
855 TRACE("Can't find printer %s in registry\n",
856 debugstr_w(lpPrinterName));
857 RegCloseKey(hkeyPrinters);
858 SetLastError(ERROR_INVALID_PRINTER_NAME);
861 RegCloseKey(hkeyPrinter);
862 RegCloseKey(hkeyPrinters);
864 if(!phPrinter) /* This seems to be what win95 does anyway */
867 /* Get the unique handle of the printer*/
868 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
870 if (pDefault != NULL)
871 FIXME("Not handling pDefault\n");
876 /******************************************************************
877 * AddMonitorA [WINSPOOL.@]
880 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
882 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
883 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
887 /******************************************************************
888 * DeletePrinterDriverA [WINSPOOL.@]
892 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
894 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
895 debugstr_a(pDriverName));
896 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
901 /******************************************************************
902 * DeleteMonitorA [WINSPOOL.@]
906 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
908 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
909 debugstr_a(pMonitorName));
910 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
915 /******************************************************************
916 * DeletePortA [WINSPOOL.@]
920 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
922 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
923 debugstr_a(pPortName));
924 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
928 /******************************************************************************
929 * SetPrinterW [WINSPOOL.@]
939 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
943 /******************************************************************************
944 * WritePrinter [WINSPOOL.@]
954 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
958 /*****************************************************************************
959 * AddFormA [WINSPOOL.@]
961 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
963 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
967 /*****************************************************************************
968 * AddFormW [WINSPOOL.@]
970 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
972 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
976 /*****************************************************************************
977 * AddJobA [WINSPOOL.@]
979 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
980 DWORD cbBuf, LPDWORD pcbNeeded)
982 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
987 /*****************************************************************************
988 * AddJobW [WINSPOOL.@]
990 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
993 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
998 /*****************************************************************************
999 * WINSPOOL_OpenDriverReg [internal]
1001 * opens the registry for the printer drivers depending on the given input
1002 * variable pEnvironment
1005 * the opened hkey on success
1008 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1010 LPSTR lpKey, p = NULL;
1013 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1016 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1020 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1022 if(!GetVersionExA( &ver))
1025 switch (ver.dwPlatformId) {
1026 case VER_PLATFORM_WIN32s:
1027 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1030 case VER_PLATFORM_WIN32_NT:
1031 p = "Windows NT x86";
1037 TRACE("set environment to %s\n", p);
1040 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1041 strlen(p) + strlen(Drivers));
1042 sprintf( lpKey, Drivers, p);
1044 TRACE("%s\n", lpKey);
1046 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1050 if(pEnvironment && unicode)
1051 HeapFree( GetProcessHeap(), 0, p);
1052 HeapFree( GetProcessHeap(), 0, lpKey);
1057 /*****************************************************************************
1058 * AddPrinterW [WINSPOOL.@]
1060 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1062 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1066 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1069 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1072 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1073 SetLastError(ERROR_INVALID_PARAMETER);
1077 ERR("Level = %ld, unsupported!\n", Level);
1078 SetLastError(ERROR_INVALID_LEVEL);
1081 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1082 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1083 debugstr_w(pi->pPrinterName)
1085 SetLastError(ERROR_INVALID_LEVEL);
1089 SetLastError(ERROR_INVALID_PARAMETER);
1092 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1094 ERR("Can't create Printers key\n");
1097 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1098 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1099 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1100 RegCloseKey(hkeyPrinter);
1101 RegCloseKey(hkeyPrinters);
1104 RegCloseKey(hkeyPrinter);
1106 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1108 ERR("Can't create Drivers key\n");
1109 RegCloseKey(hkeyPrinters);
1112 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1114 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1115 RegCloseKey(hkeyPrinters);
1116 RegCloseKey(hkeyDrivers);
1117 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1120 RegCloseKey(hkeyDriver);
1121 RegCloseKey(hkeyDrivers);
1123 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1124 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1125 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1126 RegCloseKey(hkeyPrinters);
1130 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1132 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1133 SetLastError(ERROR_INVALID_PRINTER_NAME);
1134 RegCloseKey(hkeyPrinters);
1137 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1138 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1139 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1141 /* See if we can load the driver. We may need the devmode structure anyway
1144 * Note that DocumentPropertiesW will briefly try to open the printer we
1145 * just create to find a DEVMODEA struct (it will use the WINEPS default
1146 * one in case it is not there, so we are ok).
1148 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1150 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1151 size = sizeof(DEVMODEW);
1156 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1158 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1159 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1160 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1163 /* set devmode to printer name */
1164 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1167 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1168 and we support these drivers. NT writes DEVMODEW so somehow
1169 we'll need to distinguish between these when we support NT
1171 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1172 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1173 dmA->dmSize + dmA->dmDriverExtra);
1174 HeapFree(GetProcessHeap(), 0, dmA);
1176 HeapFree(GetProcessHeap(), 0, dmW);
1177 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1178 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1179 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1180 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1182 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1183 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1184 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1185 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1186 (LPBYTE)&pi->Priority, sizeof(DWORD));
1187 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1188 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1189 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1190 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1191 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1192 (LPBYTE)&pi->Status, sizeof(DWORD));
1193 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1194 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1196 RegCloseKey(hkeyPrinter);
1197 RegCloseKey(hkeyPrinters);
1198 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1199 ERR("OpenPrinter failing\n");
1205 /*****************************************************************************
1206 * AddPrinterA [WINSPOOL.@]
1208 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1210 UNICODE_STRING pNameW;
1212 PRINTER_INFO_2W *piW;
1213 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1216 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1218 ERR("Level = %ld, unsupported!\n", Level);
1219 SetLastError(ERROR_INVALID_LEVEL);
1222 pwstrNameW = asciitounicode(&pNameW,pName);
1223 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1225 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1227 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1228 RtlFreeUnicodeString(&pNameW);
1233 /*****************************************************************************
1234 * ClosePrinter [WINSPOOL.@]
1236 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1238 int i = (int)hPrinter;
1240 TRACE("Handle %p\n", hPrinter);
1242 if ((i <= 0) || (i > nb_printers)) return FALSE;
1243 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1244 printer_array[i - 1] = NULL;
1248 /*****************************************************************************
1249 * DeleteFormA [WINSPOOL.@]
1251 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1253 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1257 /*****************************************************************************
1258 * DeleteFormW [WINSPOOL.@]
1260 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1262 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1266 /*****************************************************************************
1267 * DeletePrinter [WINSPOOL.@]
1269 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1271 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1274 if(!lpNameW) return FALSE;
1275 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1277 ERR("Can't open Printers key\n");
1281 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1282 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1283 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1284 RegCloseKey(hkeyPrinters);
1288 ClosePrinter(hPrinter);
1292 /*****************************************************************************
1293 * SetPrinterA [WINSPOOL.@]
1295 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1298 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1302 /*****************************************************************************
1303 * SetJobA [WINSPOOL.@]
1305 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1306 LPBYTE pJob, DWORD Command)
1308 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1313 /*****************************************************************************
1314 * SetJobW [WINSPOOL.@]
1316 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1317 LPBYTE pJob, DWORD Command)
1319 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1324 /*****************************************************************************
1325 * EndDocPrinter [WINSPOOL.@]
1327 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1329 FIXME("(hPrinter=%p): stub\n", hPrinter);
1333 /*****************************************************************************
1334 * EndPagePrinter [WINSPOOL.@]
1336 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1338 FIXME("(hPrinter=%p): stub\n", hPrinter);
1342 /*****************************************************************************
1343 * StartDocPrinterA [WINSPOOL.@]
1345 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1347 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1351 /*****************************************************************************
1352 * StartDocPrinterW [WINSPOOL.@]
1354 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1356 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1360 /*****************************************************************************
1361 * StartPagePrinter [WINSPOOL.@]
1363 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1365 FIXME("(hPrinter=%p): stub\n", hPrinter);
1369 /*****************************************************************************
1370 * GetFormA [WINSPOOL.@]
1372 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1373 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1375 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1376 Level,pForm,cbBuf,pcbNeeded);
1380 /*****************************************************************************
1381 * GetFormW [WINSPOOL.@]
1383 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1384 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1386 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1387 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1391 /*****************************************************************************
1392 * SetFormA [WINSPOOL.@]
1394 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1397 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1401 /*****************************************************************************
1402 * SetFormW [WINSPOOL.@]
1404 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1407 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1411 /*****************************************************************************
1412 * ReadPrinter [WINSPOOL.@]
1414 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1415 LPDWORD pNoBytesRead)
1417 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1421 /*****************************************************************************
1422 * ResetPrinterA [WINSPOOL.@]
1424 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1426 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1430 /*****************************************************************************
1431 * ResetPrinterW [WINSPOOL.@]
1433 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1435 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1439 /*****************************************************************************
1440 * WINSPOOL_GetDWORDFromReg
1442 * Return DWORD associated with ValueName from hkey.
1444 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1446 DWORD sz = sizeof(DWORD), type, value = 0;
1449 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1451 if(ret != ERROR_SUCCESS) {
1452 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1455 if(type != REG_DWORD) {
1456 ERR("Got type %ld\n", type);
1462 /*****************************************************************************
1463 * WINSPOOL_GetStringFromReg
1465 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1466 * String is stored either as unicode or ascii.
1467 * Bit of a hack here to get the ValueName if we want ascii.
1469 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1470 DWORD buflen, DWORD *needed,
1473 DWORD sz = buflen, type;
1477 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1479 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1480 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1481 HeapFree(GetProcessHeap(),0,ValueNameA);
1483 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1484 WARN("Got ret = %ld\n", ret);
1492 /*****************************************************************************
1493 * WINSPOOL_GetDefaultDevMode
1495 * Get a default DevMode values for wineps.
1499 static void WINSPOOL_GetDefaultDevMode(
1501 DWORD buflen, DWORD *needed,
1506 /* fill default DEVMODE - should be read from ppd... */
1507 ZeroMemory( &dm, sizeof(dm) );
1508 strcpy(dm.dmDeviceName,"wineps");
1509 dm.dmSpecVersion = DM_SPECVERSION;
1510 dm.dmDriverVersion = 1;
1511 dm.dmSize = sizeof(DEVMODEA);
1512 dm.dmDriverExtra = 0;
1514 DM_ORIENTATION | DM_PAPERSIZE |
1515 DM_PAPERLENGTH | DM_PAPERWIDTH |
1518 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1519 DM_YRESOLUTION | DM_TTOPTION;
1521 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1522 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1523 dm.u1.s1.dmPaperLength = 2970;
1524 dm.u1.s1.dmPaperWidth = 2100;
1528 dm.dmDefaultSource = DMBIN_AUTO;
1529 dm.dmPrintQuality = DMRES_MEDIUM;
1532 dm.dmYResolution = 300; /* 300dpi */
1533 dm.dmTTOption = DMTT_BITMAP;
1536 /* dm.dmLogPixels */
1537 /* dm.dmBitsPerPel */
1538 /* dm.dmPelsWidth */
1539 /* dm.dmPelsHeight */
1540 /* dm.dmDisplayFlags */
1541 /* dm.dmDisplayFrequency */
1542 /* dm.dmICMMethod */
1543 /* dm.dmICMIntent */
1544 /* dm.dmMediaType */
1545 /* dm.dmDitherType */
1546 /* dm.dmReserved1 */
1547 /* dm.dmReserved2 */
1548 /* dm.dmPanningWidth */
1549 /* dm.dmPanningHeight */
1552 if(buflen >= sizeof(DEVMODEW)) {
1553 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1554 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1555 HeapFree(GetProcessHeap(),0,pdmW);
1557 *needed = sizeof(DEVMODEW);
1561 if(buflen >= sizeof(DEVMODEA)) {
1562 memcpy(ptr, &dm, sizeof(DEVMODEA));
1564 *needed = sizeof(DEVMODEA);
1568 /*****************************************************************************
1569 * WINSPOOL_GetDevModeFromReg
1571 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1572 * DevMode is stored either as unicode or ascii.
1574 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1576 DWORD buflen, DWORD *needed,
1579 DWORD sz = buflen, type;
1582 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1583 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1584 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1585 if (sz < sizeof(DEVMODEA))
1587 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1590 /* ensures that dmSize is not erratically bogus if registry is invalid */
1591 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1592 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1594 sz += (CCHDEVICENAME + CCHFORMNAME);
1596 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1597 memcpy(ptr, dmW, sz);
1598 HeapFree(GetProcessHeap(),0,dmW);
1605 /*********************************************************************
1606 * WINSPOOL_GetPrinter_2
1608 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1609 * The strings are either stored as unicode or ascii.
1611 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1612 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1615 DWORD size, left = cbBuf;
1616 BOOL space = (cbBuf > 0);
1621 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1623 if(space && size <= left) {
1624 pi2->pPrinterName = (LPWSTR)ptr;
1631 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1633 if(space && size <= left) {
1634 pi2->pShareName = (LPWSTR)ptr;
1641 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1643 if(space && size <= left) {
1644 pi2->pPortName = (LPWSTR)ptr;
1651 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1653 if(space && size <= left) {
1654 pi2->pDriverName = (LPWSTR)ptr;
1661 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1663 if(space && size <= left) {
1664 pi2->pComment = (LPWSTR)ptr;
1671 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1673 if(space && size <= left) {
1674 pi2->pLocation = (LPWSTR)ptr;
1681 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1683 if(space && size <= left) {
1684 pi2->pDevMode = (LPDEVMODEW)ptr;
1693 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1694 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
1695 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1696 if(space && size <= left) {
1697 pi2->pDevMode = (LPDEVMODEW)ptr;
1704 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1706 if(space && size <= left) {
1707 pi2->pSepFile = (LPWSTR)ptr;
1714 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1716 if(space && size <= left) {
1717 pi2->pPrintProcessor = (LPWSTR)ptr;
1724 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1726 if(space && size <= left) {
1727 pi2->pDatatype = (LPWSTR)ptr;
1734 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1736 if(space && size <= left) {
1737 pi2->pParameters = (LPWSTR)ptr;
1745 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1746 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1747 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1748 "Default Priority");
1749 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1750 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1753 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1754 memset(pi2, 0, sizeof(*pi2));
1759 /*********************************************************************
1760 * WINSPOOL_GetPrinter_4
1762 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1764 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1765 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1768 DWORD size, left = cbBuf;
1769 BOOL space = (cbBuf > 0);
1774 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1776 if(space && size <= left) {
1777 pi4->pPrinterName = (LPWSTR)ptr;
1785 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1788 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1789 memset(pi4, 0, sizeof(*pi4));
1794 /*********************************************************************
1795 * WINSPOOL_GetPrinter_5
1797 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1799 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1800 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1803 DWORD size, left = cbBuf;
1804 BOOL space = (cbBuf > 0);
1809 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1811 if(space && size <= left) {
1812 pi5->pPrinterName = (LPWSTR)ptr;
1819 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1821 if(space && size <= left) {
1822 pi5->pPortName = (LPWSTR)ptr;
1830 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1831 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1833 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1837 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1838 memset(pi5, 0, sizeof(*pi5));
1843 /*****************************************************************************
1844 * WINSPOOL_GetPrinter
1846 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1847 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1848 * just a collection of pointers to strings.
1850 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1851 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1854 DWORD size, needed = 0;
1856 HKEY hkeyPrinter, hkeyPrinters;
1859 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1861 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1863 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1865 ERR("Can't create Printers key\n");
1868 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1870 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1871 RegCloseKey(hkeyPrinters);
1872 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1879 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1881 size = sizeof(PRINTER_INFO_2W);
1883 ptr = pPrinter + size;
1885 memset(pPrinter, 0, size);
1890 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1898 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1900 size = sizeof(PRINTER_INFO_4W);
1902 ptr = pPrinter + size;
1904 memset(pPrinter, 0, size);
1909 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1918 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1920 size = sizeof(PRINTER_INFO_5W);
1922 ptr = pPrinter + size;
1924 memset(pPrinter, 0, size);
1930 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1937 FIXME("Unimplemented level %ld\n", Level);
1938 SetLastError(ERROR_INVALID_LEVEL);
1939 RegCloseKey(hkeyPrinters);
1940 RegCloseKey(hkeyPrinter);
1944 RegCloseKey(hkeyPrinter);
1945 RegCloseKey(hkeyPrinters);
1947 TRACE("returning %d needed = %ld\n", ret, needed);
1948 if(pcbNeeded) *pcbNeeded = needed;
1950 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1954 /*****************************************************************************
1955 * GetPrinterW [WINSPOOL.@]
1957 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1958 DWORD cbBuf, LPDWORD pcbNeeded)
1960 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1964 /*****************************************************************************
1965 * GetPrinterA [WINSPOOL.@]
1967 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1968 DWORD cbBuf, LPDWORD pcbNeeded)
1970 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1974 /*****************************************************************************
1975 * WINSPOOL_EnumPrinters
1977 * Implementation of EnumPrintersA|W
1979 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1980 DWORD dwLevel, LPBYTE lpbPrinters,
1981 DWORD cbBuf, LPDWORD lpdwNeeded,
1982 LPDWORD lpdwReturned, BOOL unicode)
1985 HKEY hkeyPrinters, hkeyPrinter;
1986 WCHAR PrinterName[255];
1987 DWORD needed = 0, number = 0;
1988 DWORD used, i, left;
1992 memset(lpbPrinters, 0, cbBuf);
1998 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1999 if(dwType == PRINTER_ENUM_DEFAULT)
2002 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2003 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
2004 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
2005 dwType |= PRINTER_ENUM_LOCAL;
2008 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2009 FIXME("dwType = %08lx\n", dwType);
2010 SetLastError(ERROR_INVALID_FLAGS);
2014 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2016 ERR("Can't create Printers key\n");
2020 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2021 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2022 RegCloseKey(hkeyPrinters);
2023 ERR("Can't query Printers key\n");
2026 TRACE("Found %ld printers\n", number);
2030 RegCloseKey(hkeyPrinters);
2032 *lpdwReturned = number;
2036 used = number * sizeof(PRINTER_INFO_2W);
2039 used = number * sizeof(PRINTER_INFO_4W);
2042 used = number * sizeof(PRINTER_INFO_5W);
2046 SetLastError(ERROR_INVALID_LEVEL);
2047 RegCloseKey(hkeyPrinters);
2050 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2052 for(i = 0; i < number; i++) {
2053 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2055 ERR("Can't enum key number %ld\n", i);
2056 RegCloseKey(hkeyPrinters);
2059 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2060 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2062 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2063 RegCloseKey(hkeyPrinters);
2068 buf = lpbPrinters + used;
2069 left = cbBuf - used;
2077 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2078 left, &needed, unicode);
2080 if(pi) pi += sizeof(PRINTER_INFO_2W);
2083 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2084 left, &needed, unicode);
2086 if(pi) pi += sizeof(PRINTER_INFO_4W);
2089 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2090 left, &needed, unicode);
2092 if(pi) pi += sizeof(PRINTER_INFO_5W);
2095 ERR("Shouldn't be here!\n");
2096 RegCloseKey(hkeyPrinter);
2097 RegCloseKey(hkeyPrinters);
2100 RegCloseKey(hkeyPrinter);
2102 RegCloseKey(hkeyPrinters);
2109 memset(lpbPrinters, 0, cbBuf);
2110 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2114 *lpdwReturned = number;
2115 SetLastError(ERROR_SUCCESS);
2120 /******************************************************************
2121 * EnumPrintersW [WINSPOOL.@]
2123 * Enumerates the available printers, print servers and print
2124 * providers, depending on the specified flags, name and level.
2128 * If level is set to 1:
2129 * Not implemented yet!
2130 * Returns TRUE with an empty list.
2132 * If level is set to 2:
2133 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2134 * Returns an array of PRINTER_INFO_2 data structures in the
2135 * lpbPrinters buffer. Note that according to MSDN also an
2136 * OpenPrinter should be performed on every remote printer.
2138 * If level is set to 4 (officially WinNT only):
2139 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2140 * Fast: Only the registry is queried to retrieve printer names,
2141 * no connection to the driver is made.
2142 * Returns an array of PRINTER_INFO_4 data structures in the
2143 * lpbPrinters buffer.
2145 * If level is set to 5 (officially WinNT4/Win9x only):
2146 * Fast: Only the registry is queried to retrieve printer names,
2147 * no connection to the driver is made.
2148 * Returns an array of PRINTER_INFO_5 data structures in the
2149 * lpbPrinters buffer.
2151 * If level set to 3 or 6+:
2152 * returns zero (failure!)
2154 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2158 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2159 * - Only levels 2, 4 and 5 are implemented at the moment.
2160 * - 16-bit printer drivers are not enumerated.
2161 * - Returned amount of bytes used/needed does not match the real Windoze
2162 * implementation (as in this implementation, all strings are part
2163 * of the buffer, whereas Win32 keeps them somewhere else)
2164 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2167 * - In a regular Wine installation, no registry settings for printers
2168 * exist, which makes this function return an empty list.
2170 BOOL WINAPI EnumPrintersW(
2171 DWORD dwType, /* [in] Types of print objects to enumerate */
2172 LPWSTR lpszName, /* [in] name of objects to enumerate */
2173 DWORD dwLevel, /* [in] type of printer info structure */
2174 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2175 DWORD cbBuf, /* [in] max size of buffer in bytes */
2176 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2177 LPDWORD lpdwReturned /* [out] number of entries returned */
2180 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2181 lpdwNeeded, lpdwReturned, TRUE);
2184 /******************************************************************
2185 * EnumPrintersA [WINSPOOL.@]
2188 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2189 DWORD dwLevel, LPBYTE lpbPrinters,
2190 DWORD cbBuf, LPDWORD lpdwNeeded,
2191 LPDWORD lpdwReturned)
2194 UNICODE_STRING lpszNameW;
2197 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2198 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2199 lpdwNeeded, lpdwReturned, FALSE);
2200 RtlFreeUnicodeString(&lpszNameW);
2204 /*****************************************************************************
2205 * WINSPOOL_GetDriverInfoFromReg [internal]
2207 * Enters the information from the registry into the DRIVER_INFO struct
2210 * zero if the printer driver does not exist in the registry
2211 * (only if Level > 1) otherwise nonzero
2213 static BOOL WINSPOOL_GetDriverInfoFromReg(
2216 LPWSTR pEnvironment,
2218 LPBYTE ptr, /* DRIVER_INFO */
2219 LPBYTE pDriverStrings, /* strings buffer */
2220 DWORD cbBuf, /* size of string buffer */
2221 LPDWORD pcbNeeded, /* space needed for str. */
2222 BOOL unicode) /* type of strings */
2223 { DWORD dw, size, tmp, type;
2225 LPBYTE strPtr = pDriverStrings;
2227 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2228 debugstr_w(DriverName), debugstr_w(pEnvironment),
2229 Level, ptr, pDriverStrings, cbBuf, unicode);
2232 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2233 if (*pcbNeeded <= cbBuf)
2234 strcpyW((LPWSTR)strPtr, DriverName);
2236 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2238 if(*pcbNeeded <= cbBuf)
2239 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2244 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2248 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2249 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2252 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2253 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2254 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2259 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2261 WARN("Can't get Version\n");
2263 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2266 pEnvironment = DefaultEnvironmentW;
2268 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2270 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2273 if(*pcbNeeded <= cbBuf) {
2275 strcpyW((LPWSTR)strPtr, pEnvironment);
2277 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2280 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2281 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2284 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2287 if(*pcbNeeded <= cbBuf)
2288 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2291 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2292 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2295 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2298 if(*pcbNeeded <= cbBuf)
2299 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2302 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2303 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2306 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2307 0, &size, unicode)) {
2309 if(*pcbNeeded <= cbBuf)
2310 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2311 size, &tmp, unicode);
2313 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2314 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2318 RegCloseKey(hkeyDriver);
2319 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2323 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2326 if(*pcbNeeded <= cbBuf)
2327 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2328 size, &tmp, unicode);
2330 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2331 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2334 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2337 if(*pcbNeeded <= cbBuf)
2338 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2339 size, &tmp, unicode);
2341 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2342 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2345 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2348 if(*pcbNeeded <= cbBuf)
2349 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2350 size, &tmp, unicode);
2352 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2353 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2356 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2359 if(*pcbNeeded <= cbBuf)
2360 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2361 size, &tmp, unicode);
2363 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2364 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2367 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2368 RegCloseKey(hkeyDriver);
2372 /*****************************************************************************
2373 * WINSPOOL_GetPrinterDriver
2375 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2376 DWORD Level, LPBYTE pDriverInfo,
2377 DWORD cbBuf, LPDWORD pcbNeeded,
2381 WCHAR DriverName[100];
2382 DWORD ret, type, size, needed = 0;
2384 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2386 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2387 Level,pDriverInfo,cbBuf, pcbNeeded);
2389 ZeroMemory(pDriverInfo, cbBuf);
2391 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2393 if(Level < 1 || Level > 3) {
2394 SetLastError(ERROR_INVALID_LEVEL);
2397 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2399 ERR("Can't create Printers key\n");
2402 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2404 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2405 RegCloseKey(hkeyPrinters);
2406 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2409 size = sizeof(DriverName);
2411 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2412 (LPBYTE)DriverName, &size);
2413 RegCloseKey(hkeyPrinter);
2414 RegCloseKey(hkeyPrinters);
2415 if(ret != ERROR_SUCCESS) {
2416 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2420 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2422 ERR("Can't create Drivers key\n");
2428 size = sizeof(DRIVER_INFO_1W);
2431 size = sizeof(DRIVER_INFO_2W);
2434 size = sizeof(DRIVER_INFO_3W);
2437 ERR("Invalid level\n");
2442 ptr = pDriverInfo + size;
2444 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2445 pEnvironment, Level, pDriverInfo,
2446 (cbBuf < size) ? NULL : ptr,
2447 (cbBuf < size) ? 0 : cbBuf - size,
2448 &needed, unicode)) {
2449 RegCloseKey(hkeyDrivers);
2453 RegCloseKey(hkeyDrivers);
2455 if(pcbNeeded) *pcbNeeded = size + needed;
2456 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2457 if(cbBuf >= needed) return TRUE;
2458 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2462 /*****************************************************************************
2463 * GetPrinterDriverA [WINSPOOL.@]
2465 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2466 DWORD Level, LPBYTE pDriverInfo,
2467 DWORD cbBuf, LPDWORD pcbNeeded)
2470 UNICODE_STRING pEnvW;
2473 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2474 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2475 cbBuf, pcbNeeded, FALSE);
2476 RtlFreeUnicodeString(&pEnvW);
2479 /*****************************************************************************
2480 * GetPrinterDriverW [WINSPOOL.@]
2482 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2483 DWORD Level, LPBYTE pDriverInfo,
2484 DWORD cbBuf, LPDWORD pcbNeeded)
2486 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2487 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2490 /*****************************************************************************
2491 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2493 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2494 DWORD Level, LPBYTE pDriverDirectory,
2495 DWORD cbBuf, LPDWORD pcbNeeded)
2499 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2500 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2502 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2503 SetLastError(ERROR_INVALID_PARAMETER);
2506 if(pEnvironment != NULL) {
2507 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2508 SetLastError(ERROR_INVALID_ENVIRONMENT);
2511 if(Level != 1) /* win95 ignores this so we just carry on */
2512 WARN("Level = %ld - assuming 1\n", Level);
2514 /* FIXME should read from registry */
2515 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2516 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2520 needed*=sizeof(WCHAR);
2523 *pcbNeeded = needed;
2524 TRACE("required <%08lx>\n", *pcbNeeded);
2525 if(needed > cbBuf) {
2526 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2533 /*****************************************************************************
2534 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2536 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2537 DWORD Level, LPBYTE pDriverDirectory,
2538 DWORD cbBuf, LPDWORD pcbNeeded)
2540 UNICODE_STRING nameW, environmentW;
2543 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2544 WCHAR *driverDirectoryW = NULL;
2546 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2548 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2549 else nameW.Buffer = NULL;
2550 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2551 else environmentW.Buffer = NULL;
2553 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2554 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2557 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2558 pDriverDirectory, cbBuf, NULL, NULL);
2560 *pcbNeeded = needed;
2561 ret = (needed <= cbBuf) ? TRUE : FALSE;
2563 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2565 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2567 if(driverDirectoryW)
2568 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2569 RtlFreeUnicodeString(&environmentW);
2570 RtlFreeUnicodeString(&nameW);
2575 /*****************************************************************************
2576 * AddPrinterDriverA [WINSPOOL.@]
2578 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2581 HKEY hkeyDrivers, hkeyName;
2583 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2585 if(level != 2 && level != 3) {
2586 SetLastError(ERROR_INVALID_LEVEL);
2590 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2591 SetLastError(ERROR_INVALID_PARAMETER);
2595 WARN("pDriverInfo == NULL\n");
2596 SetLastError(ERROR_INVALID_PARAMETER);
2601 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2603 memset(&di3, 0, sizeof(di3));
2604 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2607 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2609 SetLastError(ERROR_INVALID_PARAMETER);
2612 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2613 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2614 if(!di3.pHelpFile) di3.pHelpFile = "";
2615 if(!di3.pMonitorName) di3.pMonitorName = "";
2617 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2620 ERR("Can't create Drivers key\n");
2624 if(level == 2) { /* apparently can't overwrite with level2 */
2625 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2626 RegCloseKey(hkeyName);
2627 RegCloseKey(hkeyDrivers);
2628 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2629 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2633 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2634 RegCloseKey(hkeyDrivers);
2635 ERR("Can't create Name key\n");
2638 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2640 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2641 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2642 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2644 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2645 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2646 di3.pDependentFiles, 0);
2647 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2648 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2649 RegCloseKey(hkeyName);
2650 RegCloseKey(hkeyDrivers);
2654 /*****************************************************************************
2655 * AddPrinterDriverW [WINSPOOL.@]
2657 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2660 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2666 /*****************************************************************************
2667 * PrinterProperties [WINSPOOL.@]
2669 * Displays a dialog to set the properties of the printer.
2672 * nonzero on success or zero on failure
2675 * implemented as stub only
2677 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2678 HANDLE hPrinter /* [in] handle to printer object */
2680 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2681 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2685 /*****************************************************************************
2686 * EnumJobsA [WINSPOOL.@]
2689 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2690 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2693 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2694 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2696 if(pcbNeeded) *pcbNeeded = 0;
2697 if(pcReturned) *pcReturned = 0;
2702 /*****************************************************************************
2703 * EnumJobsW [WINSPOOL.@]
2706 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2707 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2710 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2711 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2713 if(pcbNeeded) *pcbNeeded = 0;
2714 if(pcReturned) *pcReturned = 0;
2718 /*****************************************************************************
2719 * WINSPOOL_EnumPrinterDrivers [internal]
2721 * Delivers information about all printer drivers installed on the
2722 * localhost or a given server
2725 * nonzero on success or zero on failure. If the buffer for the returned
2726 * information is too small the function will return an error
2729 * - only implemented for localhost, foreign hosts will return an error
2731 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2732 DWORD Level, LPBYTE pDriverInfo,
2733 DWORD cbBuf, LPDWORD pcbNeeded,
2734 LPDWORD pcReturned, BOOL unicode)
2737 DWORD i, needed, number = 0, size = 0;
2738 WCHAR DriverNameW[255];
2741 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2742 debugstr_w(pName), debugstr_w(pEnvironment),
2743 Level, pDriverInfo, cbBuf, unicode);
2745 /* check for local drivers */
2747 ERR("remote drivers unsupported! Current remote host is %s\n",
2752 /* check input parameter */
2753 if((Level < 1) || (Level > 3)) {
2754 ERR("unsupported level %ld \n", Level);
2758 /* initialize return values */
2760 memset( pDriverInfo, 0, cbBuf);
2764 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2766 ERR("Can't open Drivers key\n");
2770 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2771 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2772 RegCloseKey(hkeyDrivers);
2773 ERR("Can't query Drivers key\n");
2776 TRACE("Found %ld Drivers\n", number);
2778 /* get size of single struct
2779 * unicode and ascii structure have the same size
2783 size = sizeof(DRIVER_INFO_1A);
2786 size = sizeof(DRIVER_INFO_2A);
2789 size = sizeof(DRIVER_INFO_3A);
2793 /* calculate required buffer size */
2794 *pcbNeeded = size * number;
2796 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2798 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2799 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2801 ERR("Can't enum key number %ld\n", i);
2802 RegCloseKey(hkeyDrivers);
2805 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2806 pEnvironment, Level, ptr,
2807 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2808 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2809 &needed, unicode)) {
2810 RegCloseKey(hkeyDrivers);
2813 (*pcbNeeded) += needed;
2816 RegCloseKey(hkeyDrivers);
2818 if(cbBuf < *pcbNeeded){
2819 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2826 /*****************************************************************************
2827 * EnumPrinterDriversW [WINSPOOL.@]
2829 * see function EnumPrinterDrivers for RETURNS, BUGS
2831 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2832 LPBYTE pDriverInfo, DWORD cbBuf,
2833 LPDWORD pcbNeeded, LPDWORD pcReturned)
2835 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2836 cbBuf, pcbNeeded, pcReturned, TRUE);
2839 /*****************************************************************************
2840 * EnumPrinterDriversA [WINSPOOL.@]
2842 * see function EnumPrinterDrivers for RETURNS, BUGS
2844 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2845 LPBYTE pDriverInfo, DWORD cbBuf,
2846 LPDWORD pcbNeeded, LPDWORD pcReturned)
2848 UNICODE_STRING pNameW, pEnvironmentW;
2849 PWSTR pwstrNameW, pwstrEnvironmentW;
2851 pwstrNameW = asciitounicode(&pNameW, pName);
2852 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
2854 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
2855 Level, pDriverInfo, cbBuf, pcbNeeded,
2857 RtlFreeUnicodeString(&pNameW);
2858 RtlFreeUnicodeString(&pEnvironmentW);
2864 /******************************************************************************
2865 * EnumPortsA (WINSPOOL.@)
2867 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2868 LPDWORD bufneeded,LPDWORD bufreturned)
2870 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2874 /******************************************************************************
2875 * GetDefaultPrinterA (WINSPOOL.@)
2877 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2879 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
2885 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2889 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
2891 SetLastError (ERROR_FILE_NOT_FOUND);
2895 if ((ptr = strchr (name, ',')) == NULL)
2897 SetLastError (ERROR_FILE_NOT_FOUND);
2902 *namesize = strlen (name) + 1;
2907 /******************************************************************************
2908 * GetDefaultPrinterW (WINSPOOL.@)
2910 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
2917 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2921 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
2922 ret = GetDefaultPrinterA (buf, namesize);
2925 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
2928 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2931 else *namesize = len;
2934 HeapFree (GetProcessHeap (), 0, buf);
2939 /******************************************************************************
2940 * SetPrinterDataExA (WINSPOOL.@)
2942 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2943 LPSTR pValueName, DWORD Type,
2944 LPBYTE pData, DWORD cbData)
2946 HKEY hkeyPrinter, hkeySubkey;
2949 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2950 debugstr_a(pValueName), Type, pData, cbData);
2952 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2956 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2958 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2959 RegCloseKey(hkeyPrinter);
2962 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2963 RegCloseKey(hkeySubkey);
2964 RegCloseKey(hkeyPrinter);
2968 /******************************************************************************
2969 * SetPrinterDataExW (WINSPOOL.@)
2971 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2972 LPWSTR pValueName, DWORD Type,
2973 LPBYTE pData, DWORD cbData)
2975 HKEY hkeyPrinter, hkeySubkey;
2978 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2979 debugstr_w(pValueName), Type, pData, cbData);
2981 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2985 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2987 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2988 RegCloseKey(hkeyPrinter);
2991 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2992 RegCloseKey(hkeySubkey);
2993 RegCloseKey(hkeyPrinter);
2997 /******************************************************************************
2998 * SetPrinterDataA (WINSPOOL.@)
3000 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3001 LPBYTE pData, DWORD cbData)
3003 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3007 /******************************************************************************
3008 * SetPrinterDataW (WINSPOOL.@)
3010 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3011 LPBYTE pData, DWORD cbData)
3013 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3017 /******************************************************************************
3018 * GetPrinterDataExA (WINSPOOL.@)
3020 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
3021 LPSTR pValueName, LPDWORD pType,
3022 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3024 HKEY hkeyPrinter, hkeySubkey;
3027 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3028 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3031 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3035 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3037 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3038 RegCloseKey(hkeyPrinter);
3042 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3043 RegCloseKey(hkeySubkey);
3044 RegCloseKey(hkeyPrinter);
3048 /******************************************************************************
3049 * GetPrinterDataExW (WINSPOOL.@)
3051 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
3052 LPWSTR pValueName, LPDWORD pType,
3053 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3055 HKEY hkeyPrinter, hkeySubkey;
3058 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3059 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3062 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3066 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3068 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3069 RegCloseKey(hkeyPrinter);
3073 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3074 RegCloseKey(hkeySubkey);
3075 RegCloseKey(hkeyPrinter);
3079 /******************************************************************************
3080 * GetPrinterDataA (WINSPOOL.@)
3082 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3083 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3085 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3086 pData, nSize, pcbNeeded);
3089 /******************************************************************************
3090 * GetPrinterDataW (WINSPOOL.@)
3092 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3093 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3095 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3096 pData, nSize, pcbNeeded);
3099 /*******************************************************************************
3100 * EnumPrinterDataExW [WINSPOOL.@]
3102 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3103 LPBYTE pEnumValues, DWORD cbEnumValues,
3104 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3106 HKEY hkPrinter, hkSubKey;
3107 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3108 cbValueNameLen, cbMaxValueLen, cbValueLen,
3113 PPRINTER_ENUM_VALUESW ppev;
3115 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3117 if (pKeyName == NULL || *pKeyName == 0)
3118 return ERROR_INVALID_PARAMETER;
3120 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3121 if (ret != ERROR_SUCCESS)
3123 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3128 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3129 if (ret != ERROR_SUCCESS)
3131 r = RegCloseKey (hkPrinter);
3132 if (r != ERROR_SUCCESS)
3133 WARN ("RegCloseKey returned %li\n", r);
3134 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3135 debugstr_w (pKeyName), ret);
3139 ret = RegCloseKey (hkPrinter);
3140 if (ret != ERROR_SUCCESS)
3142 ERR ("RegCloseKey returned %li\n", ret);
3143 r = RegCloseKey (hkSubKey);
3144 if (r != ERROR_SUCCESS)
3145 WARN ("RegCloseKey returned %li\n", r);
3149 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3150 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3151 if (ret != ERROR_SUCCESS)
3153 r = RegCloseKey (hkSubKey);
3154 if (r != ERROR_SUCCESS)
3155 WARN ("RegCloseKey returned %li\n", r);
3156 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3160 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3161 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3163 if (cValues == 0) /* empty key */
3165 r = RegCloseKey (hkSubKey);
3166 if (r != ERROR_SUCCESS)
3167 WARN ("RegCloseKey returned %li\n", r);
3168 *pcbEnumValues = *pnEnumValues = 0;
3169 return ERROR_SUCCESS;
3172 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3174 hHeap = GetProcessHeap ();
3177 ERR ("GetProcessHeap failed\n");
3178 r = RegCloseKey (hkSubKey);
3179 if (r != ERROR_SUCCESS)
3180 WARN ("RegCloseKey returned %li\n", r);
3181 return ERROR_OUTOFMEMORY;
3184 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3185 if (lpValueName == NULL)
3187 ERR ("Failed to allocate %li bytes from process heap\n",
3188 cbMaxValueNameLen * sizeof (WCHAR));
3189 r = RegCloseKey (hkSubKey);
3190 if (r != ERROR_SUCCESS)
3191 WARN ("RegCloseKey returned %li\n", r);
3192 return ERROR_OUTOFMEMORY;
3195 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3196 if (lpValue == NULL)
3198 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3199 if (HeapFree (hHeap, 0, lpValueName) == 0)
3200 WARN ("HeapFree failed with code %li\n", GetLastError ());
3201 r = RegCloseKey (hkSubKey);
3202 if (r != ERROR_SUCCESS)
3203 WARN ("RegCloseKey returned %li\n", r);
3204 return ERROR_OUTOFMEMORY;
3207 TRACE ("pass 1: calculating buffer required for all names and values\n");
3209 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3211 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3213 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3215 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3216 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3217 NULL, NULL, lpValue, &cbValueLen);
3218 if (ret != ERROR_SUCCESS)
3220 if (HeapFree (hHeap, 0, lpValue) == 0)
3221 WARN ("HeapFree failed with code %li\n", GetLastError ());
3222 if (HeapFree (hHeap, 0, lpValueName) == 0)
3223 WARN ("HeapFree failed with code %li\n", GetLastError ());
3224 r = RegCloseKey (hkSubKey);
3225 if (r != ERROR_SUCCESS)
3226 WARN ("RegCloseKey returned %li\n", r);
3227 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3231 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3232 debugstr_w (lpValueName), dwIndex,
3233 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3235 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3236 cbBufSize += cbValueLen;
3239 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3241 *pcbEnumValues = cbBufSize;
3242 *pnEnumValues = cValues;
3244 if (cbEnumValues < cbBufSize) /* buffer too small */
3246 if (HeapFree (hHeap, 0, lpValue) == 0)
3247 WARN ("HeapFree failed with code %li\n", GetLastError ());
3248 if (HeapFree (hHeap, 0, lpValueName) == 0)
3249 WARN ("HeapFree failed with code %li\n", GetLastError ());
3250 r = RegCloseKey (hkSubKey);
3251 if (r != ERROR_SUCCESS)
3252 WARN ("RegCloseKey returned %li\n", r);
3253 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3254 return ERROR_MORE_DATA;
3257 TRACE ("pass 2: copying all names and values to buffer\n");
3259 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3260 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3262 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3264 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3265 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3266 NULL, &dwType, lpValue, &cbValueLen);
3267 if (ret != ERROR_SUCCESS)
3269 if (HeapFree (hHeap, 0, lpValue) == 0)
3270 WARN ("HeapFree failed with code %li\n", GetLastError ());
3271 if (HeapFree (hHeap, 0, lpValueName) == 0)
3272 WARN ("HeapFree failed with code %li\n", GetLastError ());
3273 r = RegCloseKey (hkSubKey);
3274 if (r != ERROR_SUCCESS)
3275 WARN ("RegCloseKey returned %li\n", r);
3276 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3280 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3281 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3282 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3283 pEnumValues += cbValueNameLen;
3285 /* return # of *bytes* (including trailing \0), not # of chars */
3286 ppev[dwIndex].cbValueName = cbValueNameLen;
3288 ppev[dwIndex].dwType = dwType;
3290 memcpy (pEnumValues, lpValue, cbValueLen);
3291 ppev[dwIndex].pData = pEnumValues;
3292 pEnumValues += cbValueLen;
3294 ppev[dwIndex].cbData = cbValueLen;
3296 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3297 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3300 if (HeapFree (hHeap, 0, lpValue) == 0)
3302 ret = GetLastError ();
3303 ERR ("HeapFree failed with code %li\n", ret);
3304 if (HeapFree (hHeap, 0, lpValueName) == 0)
3305 WARN ("HeapFree failed with code %li\n", GetLastError ());
3306 r = RegCloseKey (hkSubKey);
3307 if (r != ERROR_SUCCESS)
3308 WARN ("RegCloseKey returned %li\n", r);
3312 if (HeapFree (hHeap, 0, lpValueName) == 0)
3314 ret = GetLastError ();
3315 ERR ("HeapFree failed with code %li\n", ret);
3316 r = RegCloseKey (hkSubKey);
3317 if (r != ERROR_SUCCESS)
3318 WARN ("RegCloseKey returned %li\n", r);
3322 ret = RegCloseKey (hkSubKey);
3323 if (ret != ERROR_SUCCESS)
3325 ERR ("RegCloseKey returned %li\n", ret);
3329 return ERROR_SUCCESS;
3332 /*******************************************************************************
3333 * EnumPrinterDataExA [WINSPOOL.@]
3335 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3336 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3337 * what Windows 2000 SP1 does.
3340 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3341 LPBYTE pEnumValues, DWORD cbEnumValues,
3342 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3346 DWORD ret, dwIndex, dwBufSize;
3350 TRACE ("%p %s\n", hPrinter, pKeyName);
3352 if (pKeyName == NULL || *pKeyName == 0)
3353 return ERROR_INVALID_PARAMETER;
3355 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3358 ret = GetLastError ();
3359 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3363 hHeap = GetProcessHeap ();
3366 ERR ("GetProcessHeap failed\n");
3367 return ERROR_OUTOFMEMORY;
3370 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3371 if (pKeyNameW == NULL)
3373 ERR ("Failed to allocate %li bytes from process heap\n",
3374 (LONG) len * sizeof (WCHAR));
3375 return ERROR_OUTOFMEMORY;
3378 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3380 ret = GetLastError ();
3381 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3382 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3383 WARN ("HeapFree failed with code %li\n", GetLastError ());
3387 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3388 pcbEnumValues, pnEnumValues);
3389 if (ret != ERROR_SUCCESS)
3391 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3392 WARN ("HeapFree failed with code %li\n", GetLastError ());
3393 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3397 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3399 ret = GetLastError ();
3400 ERR ("HeapFree failed with code %li\n", ret);
3404 if (*pnEnumValues == 0) /* empty key */
3405 return ERROR_SUCCESS;
3408 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3410 PPRINTER_ENUM_VALUESW ppev =
3411 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3413 if (dwBufSize < ppev->cbValueName)
3414 dwBufSize = ppev->cbValueName;
3416 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3417 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3418 dwBufSize = ppev->cbData;
3421 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3423 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3424 if (pBuffer == NULL)
3426 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3427 return ERROR_OUTOFMEMORY;
3430 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3432 PPRINTER_ENUM_VALUESW ppev =
3433 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3435 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3436 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3440 ret = GetLastError ();
3441 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3442 if (HeapFree (hHeap, 0, pBuffer) == 0)
3443 WARN ("HeapFree failed with code %li\n", GetLastError ());
3447 memcpy (ppev->pValueName, pBuffer, len);
3449 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3451 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3452 ppev->dwType != REG_MULTI_SZ)
3455 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3456 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3459 ret = GetLastError ();
3460 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3461 if (HeapFree (hHeap, 0, pBuffer) == 0)
3462 WARN ("HeapFree failed with code %li\n", GetLastError ());
3466 memcpy (ppev->pData, pBuffer, len);
3468 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3469 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3472 if (HeapFree (hHeap, 0, pBuffer) == 0)
3474 ret = GetLastError ();
3475 ERR ("HeapFree failed with code %li\n", ret);
3479 return ERROR_SUCCESS;