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"
27 #include "wine/library.h"
34 #ifdef HAVE_CUPS_CUPS_H
35 # include <cups/cups.h>
37 # define CUPS_SONAME "libcups.so"
44 #include "wine/windef16.h"
45 #include "wine/unicode.h"
46 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
52 static LPWSTR *printer_array;
53 static int nb_printers;
55 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
56 WORD fwCapability, LPSTR lpszOutput,
58 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
59 LPSTR lpszDevice, LPSTR lpszPort,
60 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
63 static char Printers[] =
64 "System\\CurrentControlSet\\control\\Print\\Printers\\";
65 static char Drivers[] =
66 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
68 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
70 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
71 'i','o','n',' ','F','i','l','e',0};
72 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
73 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
74 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
76 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
78 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
79 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
80 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
81 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
82 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
83 static WCHAR NameW[] = {'N','a','m','e',0};
84 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
85 static WCHAR PortW[] = {'P','o','r','t',0};
86 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
88 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
90 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
91 'v','e','r','D','a','t','a',0};
92 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
94 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
95 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
97 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
98 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
99 DWORD Level, LPBYTE pDriverInfo,
100 DWORD cbBuf, LPDWORD pcbNeeded,
103 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
106 /* If forcing, or no profile string entry for device yet, set the entry
108 * The always change entry if not WINEPS yet is discussable.
111 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
113 !strstr(qbuf,"WINEPS")
115 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
117 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
118 WriteProfileStringA("windows","device",buf);
119 HeapFree(GetProcessHeap(),0,buf);
123 #ifdef HAVE_CUPS_CUPS_H
125 CUPS_LoadPrinters(void) {
126 typeof(cupsGetPrinters) *pcupsGetPrinters = NULL;
127 typeof(cupsGetDefault) *pcupsGetDefault = NULL;
128 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
130 int i,nrofdests,hadprinter = FALSE;
131 PRINTER_INFO_2A pinfo2a;
133 void *cupshandle = NULL;
135 cupshandle = wine_dlopen(CUPS_SONAME, RTLD_NOW, NULL, 0);
140 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
141 if (!p##x) return FALSE;
143 DYNCUPS(cupsGetDefault);
145 DYNCUPS(cupsGetPrinters);
148 def = pcupsGetDefault();
150 if (def && !strcmp(def,"none")) /* CUPS has "none" for no default printer */
153 nrofdests = pcupsGetPrinters(&printers);
154 for (i=0;i<nrofdests;i++) {
155 const char *ppd = pcupsGetPPD(printers[i]);
159 WARN("No ppd file for %s.\n",printers[i]);
160 /* If this was going to be the default printer,
161 * forget it and use another one.
163 if (def && !strcmp(def,printers[i]))
171 if (def && !strcmp(def,printers[i]))
172 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
174 /* The default printer has no PPD file, just use the first one
178 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
181 memset(&pinfo2a,0,sizeof(pinfo2a));
182 pinfo2a.pPrinterName = printers[i];
183 pinfo2a.pDatatype = "RAW";
184 pinfo2a.pPrintProcessor = "WinPrint";
185 pinfo2a.pDriverName = "PS Driver";
186 pinfo2a.pComment = "WINEPS Printer using CUPS";
187 pinfo2a.pLocation = "<physical location of printer>";
188 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
189 sprintf(port,"LPR:%s",printers[i]);
190 pinfo2a.pPortName = port;
191 pinfo2a.pParameters = "<parameters?>";
192 pinfo2a.pShareName = "<share name?>";
193 pinfo2a.pSepFile = "<sep file?>";
195 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
196 sprintf(devline,"WINEPS,%s",port);
197 WriteProfileStringA("devices",printers[i],devline);
198 HeapFree(GetProcessHeap(),0,devline);
200 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
201 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
202 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
204 HeapFree(GetProcessHeap(),0,port);
206 wine_dlclose(cupshandle, NULL, 0);
212 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
213 PRINTER_INFO_2A pinfo2a;
214 char *s,*name,*prettyname,*devname;
218 while (isspace(*pent)) pent++;
219 s = strchr(pent,':');
220 if (!s) return FALSE;
226 /* Determine whether this is a postscript printer. */
228 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
229 if (strstr(name,"ps") ||
230 strstr(name,"pd") || /* postscript double page */
231 strstr(name,"postscript") ||
232 strstr(name,"PostScript")
234 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
237 /* 2. Check if this is a remote printer. These usually are postscript
240 if (strstr(pent,":rm")) {
242 TRACE("%s is remote, assuming postscript.\n",name);
244 /* 3. Check if we have an input filter program. If we have one, it
245 * most likely is one capable of converting postscript.
246 * (Could probably check for occurrence of 'gs' or 'ghostscript'
247 * in the if file itself.)
249 if (strstr(pent,":if=/")) {
251 TRACE("%s has inputfilter program, assuming postscript.\n",name);
254 /* If it is not a postscript printer, we cannot use it. */
259 /* Get longest name, usually the one at the right for later display. */
260 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
261 s=strchr(name,'|');if (s) *s='\0';
263 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
264 * if it is too long, we use it as comment below. */
265 devname = prettyname;
266 if (strlen(devname)>=CCHDEVICENAME-1)
268 if (strlen(devname)>=CCHDEVICENAME-1)
271 if (isfirst) /* set first entry as default */
272 WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
274 memset(&pinfo2a,0,sizeof(pinfo2a));
275 pinfo2a.pPrinterName = devname;
276 pinfo2a.pDatatype = "RAW";
277 pinfo2a.pPrintProcessor = "WinPrint";
278 pinfo2a.pDriverName = "PS Driver";
279 pinfo2a.pComment = "WINEPS Printer using LPR";
280 pinfo2a.pLocation = prettyname;
281 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
282 sprintf(port,"LPR:%s",name);
283 pinfo2a.pPortName = port;
284 pinfo2a.pParameters = "<parameters?>";
285 pinfo2a.pShareName = "<share name?>";
286 pinfo2a.pSepFile = "<sep file?>";
288 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
289 sprintf(devline,"WINEPS,%s",port);
290 WriteProfileStringA("devices",devname,devline);
291 HeapFree(GetProcessHeap(),0,devline);
293 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
294 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
295 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
297 HeapFree(GetProcessHeap(),0,port);
302 PRINTCAP_LoadPrinters(void) {
303 BOOL hadprinter = FALSE, isfirst = TRUE;
307 f = fopen("/etc/printcap","r");
311 while (fgets(buf,sizeof(buf),f)) {
315 s=strchr(buf,'\n'); if (s) *s='\0';
316 if ((buf[0]=='#') || (buf[0]=='\0'))
320 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
323 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
327 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
328 pent[strlen(pent)-1] = '\0';
331 } while (fgets(buf,sizeof(buf),f));
333 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
335 if (pent) HeapFree(GetProcessHeap(),0,pent);
343 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
345 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
346 lstrlenW(value) * sizeof(WCHAR));
350 WINSPOOL_LoadSystemPrinters() {
353 di3a.cVersion = 0x400;
354 di3a.pName = "PS Driver";
355 di3a.pEnvironment = NULL; /* NULL means auto */
356 di3a.pDriverPath = "wineps.drv";
357 di3a.pDataFile = "<datafile?>";
358 di3a.pConfigFile = "wineps.drv";
359 di3a.pHelpFile = "<helpfile?>";
360 di3a.pDependentFiles = "<dependend files?>";
361 di3a.pMonitorName = "<monitor name?>";
362 di3a.pDefaultDataType = "RAW";
364 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
365 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
368 #ifdef HAVE_CUPS_CUPS_H
369 /* If we have any CUPS based printers, skip looking for printcap printers */
370 if (CUPS_LoadPrinters())
374 /* Check for [ppd] section in config file before parsing /etc/printcap */
376 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
377 &hkPPD) == ERROR_SUCCESS)
380 PRINTCAP_LoadPrinters();
385 /******************************************************************
386 * WINSPOOL_GetOpenedPrinterEntry
387 * Get the first place empty in the opened printer table
389 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
393 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
395 if (i >= nb_printers)
397 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
398 (nb_printers + 16) * sizeof(*new_array) );
399 if (!new_array) return 0;
400 printer_array = new_array;
404 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
406 strcpyW( printer_array[i], name );
407 return (HANDLE)(i + 1);
412 /******************************************************************
413 * WINSPOOL_GetOpenedPrinter
414 * Get the pointer to the opened printer referred by the handle
416 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
418 int idx = (int)printerHandle;
419 if ((idx <= 0) || (idx > nb_printers))
421 SetLastError(ERROR_INVALID_HANDLE);
424 return printer_array[idx - 1];
427 /******************************************************************
428 * WINSPOOL_GetOpenedPrinterRegKey
431 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
433 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
437 if(!name) return ERROR_INVALID_HANDLE;
439 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
443 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
445 ERR("Can't find opened printer %s in registry\n",
447 RegCloseKey(hkeyPrinters);
448 return ERROR_INVALID_PRINTER_NAME; /* ? */
450 RegCloseKey(hkeyPrinters);
451 return ERROR_SUCCESS;
454 /***********************************************************
457 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
460 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
463 Formname = (dmA->dmSize > off_formname);
464 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
465 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
468 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
469 dmA->dmSize - CCHDEVICENAME);
471 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
472 off_formname - CCHDEVICENAME);
473 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
475 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
476 (off_formname + CCHFORMNAME));
479 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
484 /***********************************************************
486 * Creates a unicode copy of supplied devmode on heap
488 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
493 ptrdiff_t off_formname;
496 if(!dmA) return NULL;
498 off_formname = (char *)dmA->dmFormName - (char *)dmA;
499 Formname = (dmA->dmSize > off_formname);
500 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
501 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
502 return DEVMODEcpyAtoW(dmW, dmA);
505 /***********************************************************
507 * Creates an ascii copy of supplied devmode on heap
509 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
514 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
516 if(!dmW) return NULL;
517 Formname = (dmW->dmSize > off_formname);
518 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
519 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
520 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
521 CCHDEVICENAME, NULL, NULL);
523 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
524 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
526 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
527 off_formname - CCHDEVICENAME * sizeof(WCHAR));
528 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
529 CCHFORMNAME, NULL, NULL);
530 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
531 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
534 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
539 /***********************************************************
541 * Creates a unicode copy of PRINTER_INFO_2A on heap
543 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
545 LPPRINTER_INFO_2W piW;
546 if(!piA) return NULL;
547 piW = HeapAlloc(heap, 0, sizeof(*piW));
548 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
549 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
550 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
551 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
552 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
553 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
554 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
555 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
556 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
557 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
558 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
559 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
560 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
564 /***********************************************************
565 * FREE_PRINTER_INFO_2W
566 * Free PRINTER_INFO_2W and all strings
568 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
572 HeapFree(heap,0,piW->pServerName);
573 HeapFree(heap,0,piW->pPrinterName);
574 HeapFree(heap,0,piW->pShareName);
575 HeapFree(heap,0,piW->pPortName);
576 HeapFree(heap,0,piW->pDriverName);
577 HeapFree(heap,0,piW->pComment);
578 HeapFree(heap,0,piW->pLocation);
579 HeapFree(heap,0,piW->pDevMode);
580 HeapFree(heap,0,piW->pSepFile);
581 HeapFree(heap,0,piW->pPrintProcessor);
582 HeapFree(heap,0,piW->pDatatype);
583 HeapFree(heap,0,piW->pParameters);
584 HeapFree(heap,0,piW);
588 /******************************************************************
589 * DeviceCapabilities [WINSPOOL.@]
590 * DeviceCapabilitiesA [WINSPOOL.@]
593 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
594 LPSTR pOutput, LPDEVMODEA lpdm)
598 if (!GDI_CallDeviceCapabilities16)
600 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
602 if (!GDI_CallDeviceCapabilities16) return -1;
604 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
606 /* If DC_PAPERSIZE map POINT16s to POINTs */
607 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
608 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
609 POINT *pt = (POINT *)pOutput;
611 memcpy(tmp, pOutput, ret * sizeof(POINT16));
612 for(i = 0; i < ret; i++, pt++)
617 HeapFree( GetProcessHeap(), 0, tmp );
623 /*****************************************************************************
624 * DeviceCapabilitiesW [WINSPOOL.@]
626 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
629 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
630 WORD fwCapability, LPWSTR pOutput,
631 const DEVMODEW *pDevMode)
633 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
634 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
635 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
638 if(pOutput && (fwCapability == DC_BINNAMES ||
639 fwCapability == DC_FILEDEPENDENCIES ||
640 fwCapability == DC_PAPERNAMES)) {
641 /* These need A -> W translation */
644 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
648 switch(fwCapability) {
653 case DC_FILEDEPENDENCIES:
657 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
658 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
660 for(i = 0; i < ret; i++)
661 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
662 pOutput + (i * size), size);
663 HeapFree(GetProcessHeap(), 0, pOutputA);
665 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
666 (LPSTR)pOutput, dmA);
668 HeapFree(GetProcessHeap(),0,pPortA);
669 HeapFree(GetProcessHeap(),0,pDeviceA);
670 HeapFree(GetProcessHeap(),0,dmA);
674 /******************************************************************
675 * DocumentPropertiesA [WINSPOOL.@]
678 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
679 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
680 LPDEVMODEA pDevModeInput,DWORD fMode )
682 LPSTR lpName = pDeviceName;
685 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
686 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
690 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
692 ERR("no name from hPrinter?\n");
695 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
698 if (!GDI_CallExtDeviceMode16)
700 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
702 if (!GDI_CallExtDeviceMode16) {
703 ERR("No CallExtDeviceMode16?\n");
707 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
708 pDevModeInput, NULL, fMode);
711 HeapFree(GetProcessHeap(),0,lpName);
716 /*****************************************************************************
717 * DocumentPropertiesW (WINSPOOL.@)
719 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
721 LPDEVMODEW pDevModeOutput,
722 LPDEVMODEW pDevModeInput, DWORD fMode)
725 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
726 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
727 LPDEVMODEA pDevModeOutputA = NULL;
730 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
731 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
734 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
735 if(ret < 0) return ret;
736 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
738 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
739 pDevModeInputA, fMode);
741 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
742 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
744 if(fMode == 0 && ret > 0)
745 ret += (CCHDEVICENAME + CCHFORMNAME);
746 HeapFree(GetProcessHeap(),0,pDevModeInputA);
747 HeapFree(GetProcessHeap(),0,pDeviceNameA);
751 /******************************************************************
752 * OpenPrinterA [WINSPOOL.@]
755 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
756 LPPRINTER_DEFAULTSA pDefault)
758 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
759 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
763 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
764 pDefault->pDatatype);
765 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
767 DefaultW.DesiredAccess = pDefault->DesiredAccess;
768 pDefaultW = &DefaultW;
770 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
772 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
773 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
775 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
779 /******************************************************************
780 * OpenPrinterW [WINSPOOL.@]
783 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
784 LPPRINTER_DEFAULTSW pDefault)
786 HKEY hkeyPrinters, hkeyPrinter;
788 if (!lpPrinterName) {
789 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
790 SetLastError(ERROR_INVALID_PARAMETER);
794 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
797 /* Check Printer exists */
798 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
800 ERR("Can't create Printers key\n");
801 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
805 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
806 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
808 TRACE("Can't find printer %s in registry\n",
809 debugstr_w(lpPrinterName));
810 RegCloseKey(hkeyPrinters);
811 SetLastError(ERROR_INVALID_PRINTER_NAME);
814 RegCloseKey(hkeyPrinter);
815 RegCloseKey(hkeyPrinters);
817 if(!phPrinter) /* This seems to be what win95 does anyway */
820 /* Get the unique handle of the printer*/
821 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
823 if (pDefault != NULL)
824 FIXME("Not handling pDefault\n");
829 /******************************************************************
830 * AddMonitorA [WINSPOOL.@]
833 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
835 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
836 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
840 /******************************************************************
841 * DeletePrinterDriverA [WINSPOOL.@]
845 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
847 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
848 debugstr_a(pDriverName));
849 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
854 /******************************************************************
855 * DeleteMonitorA [WINSPOOL.@]
859 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
861 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
862 debugstr_a(pMonitorName));
863 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
868 /******************************************************************
869 * DeletePortA [WINSPOOL.@]
873 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
875 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
876 debugstr_a(pPortName));
877 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
881 /******************************************************************************
882 * SetPrinterW [WINSPOOL.@]
892 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
896 /******************************************************************************
897 * WritePrinter [WINSPOOL.@]
907 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
911 /*****************************************************************************
912 * AddFormA [WINSPOOL.@]
914 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
916 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
920 /*****************************************************************************
921 * AddFormW [WINSPOOL.@]
923 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
925 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
929 /*****************************************************************************
930 * AddJobA [WINSPOOL.@]
932 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
933 DWORD cbBuf, LPDWORD pcbNeeded)
935 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
940 /*****************************************************************************
941 * AddJobW [WINSPOOL.@]
943 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
946 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
951 /*****************************************************************************
952 * WINSPOOL_OpenDriverReg [internal]
954 * opens the registry for the printer drivers depending on the given input
955 * variable pEnvironment
958 * the opened hkey on success
961 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
963 LPSTR lpKey, p = NULL;
966 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
969 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
973 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
975 if(!GetVersionExA( &ver))
978 switch (ver.dwPlatformId) {
979 case VER_PLATFORM_WIN32s:
980 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
983 case VER_PLATFORM_WIN32_NT:
984 p = "Windows NT x86";
990 TRACE("set environment to %s\n", p);
993 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
994 strlen(p) + strlen(Drivers));
995 sprintf( lpKey, Drivers, p);
997 TRACE("%s\n", lpKey);
999 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1003 if(pEnvironment && unicode)
1004 HeapFree( GetProcessHeap(), 0, p);
1005 HeapFree( GetProcessHeap(), 0, lpKey);
1010 /*****************************************************************************
1011 * AddPrinterW [WINSPOOL.@]
1013 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1015 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1019 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1022 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1025 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1026 SetLastError(ERROR_INVALID_PARAMETER);
1030 ERR("Level = %ld, unsupported!\n", Level);
1031 SetLastError(ERROR_INVALID_LEVEL);
1034 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1035 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1036 debugstr_w(pi->pPrinterName)
1038 SetLastError(ERROR_INVALID_LEVEL);
1042 SetLastError(ERROR_INVALID_PARAMETER);
1045 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1047 ERR("Can't create Printers key\n");
1050 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1051 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1052 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1053 RegCloseKey(hkeyPrinter);
1054 RegCloseKey(hkeyPrinters);
1057 RegCloseKey(hkeyPrinter);
1059 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1061 ERR("Can't create Drivers key\n");
1062 RegCloseKey(hkeyPrinters);
1065 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1067 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1068 RegCloseKey(hkeyPrinters);
1069 RegCloseKey(hkeyDrivers);
1070 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1073 RegCloseKey(hkeyDriver);
1074 RegCloseKey(hkeyDrivers);
1076 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1077 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1078 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1079 RegCloseKey(hkeyPrinters);
1083 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1085 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1086 SetLastError(ERROR_INVALID_PRINTER_NAME);
1087 RegCloseKey(hkeyPrinters);
1090 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1091 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1092 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1094 /* See if we can load the driver. We may need the devmode structure anyway
1097 * Note that DocumentPropertiesW will briefly try to open the printer we
1098 * just create to find a DEVMODEA struct (it will use the WINEPS default
1099 * one in case it is not there, so we are ok).
1101 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1103 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1104 size = sizeof(DEVMODEW);
1109 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1111 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1112 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1113 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1116 /* set devmode to printer name */
1117 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1120 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1121 and we support these drivers. NT writes DEVMODEW so somehow
1122 we'll need to distinguish between these when we support NT
1124 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1125 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1126 dmA->dmSize + dmA->dmDriverExtra);
1127 HeapFree(GetProcessHeap(), 0, dmA);
1129 HeapFree(GetProcessHeap(), 0, dmW);
1130 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1131 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1132 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1133 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1135 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1136 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1137 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1138 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1139 (LPBYTE)&pi->Priority, sizeof(DWORD));
1140 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1141 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1142 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1143 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1144 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1145 (LPBYTE)&pi->Status, sizeof(DWORD));
1146 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1147 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1149 RegCloseKey(hkeyPrinter);
1150 RegCloseKey(hkeyPrinters);
1151 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1152 ERR("OpenPrinter failing\n");
1158 /*****************************************************************************
1159 * AddPrinterA [WINSPOOL.@]
1161 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1164 PRINTER_INFO_2W *piW;
1165 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1168 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1170 ERR("Level = %ld, unsupported!\n", Level);
1171 SetLastError(ERROR_INVALID_LEVEL);
1174 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
1175 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1177 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
1179 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1180 HeapFree(GetProcessHeap(),0,pNameW);
1185 /*****************************************************************************
1186 * ClosePrinter [WINSPOOL.@]
1188 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1190 int i = (int)hPrinter;
1192 TRACE("Handle %p\n", hPrinter);
1194 if ((i <= 0) || (i > nb_printers)) return FALSE;
1195 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1196 printer_array[i - 1] = NULL;
1200 /*****************************************************************************
1201 * DeleteFormA [WINSPOOL.@]
1203 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1205 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1209 /*****************************************************************************
1210 * DeleteFormW [WINSPOOL.@]
1212 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1214 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1218 /*****************************************************************************
1219 * DeletePrinter [WINSPOOL.@]
1221 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1223 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1226 if(!lpNameW) return FALSE;
1227 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1229 ERR("Can't open Printers key\n");
1233 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1234 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1235 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1236 RegCloseKey(hkeyPrinters);
1240 ClosePrinter(hPrinter);
1244 /*****************************************************************************
1245 * SetPrinterA [WINSPOOL.@]
1247 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1250 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1254 /*****************************************************************************
1255 * SetJobA [WINSPOOL.@]
1257 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1258 LPBYTE pJob, DWORD Command)
1260 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1265 /*****************************************************************************
1266 * SetJobW [WINSPOOL.@]
1268 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1269 LPBYTE pJob, DWORD Command)
1271 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1276 /*****************************************************************************
1277 * GetFormA [WINSPOOL.@]
1279 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1280 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1282 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1283 Level,pForm,cbBuf,pcbNeeded);
1287 /*****************************************************************************
1288 * GetFormW [WINSPOOL.@]
1290 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1291 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1293 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1294 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1298 /*****************************************************************************
1299 * SetFormA [WINSPOOL.@]
1301 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1304 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1308 /*****************************************************************************
1309 * SetFormW [WINSPOOL.@]
1311 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1314 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1318 /*****************************************************************************
1319 * ReadPrinter [WINSPOOL.@]
1321 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1322 LPDWORD pNoBytesRead)
1324 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1328 /*****************************************************************************
1329 * ResetPrinterA [WINSPOOL.@]
1331 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1333 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1337 /*****************************************************************************
1338 * ResetPrinterW [WINSPOOL.@]
1340 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1342 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1346 /*****************************************************************************
1347 * WINSPOOL_GetDWORDFromReg
1349 * Return DWORD associated with ValueName from hkey.
1351 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1353 DWORD sz = sizeof(DWORD), type, value = 0;
1356 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1358 if(ret != ERROR_SUCCESS) {
1359 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1362 if(type != REG_DWORD) {
1363 ERR("Got type %ld\n", type);
1369 /*****************************************************************************
1370 * WINSPOOL_GetStringFromReg
1372 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1373 * String is stored either as unicode or ascii.
1374 * Bit of a hack here to get the ValueName if we want ascii.
1376 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1377 DWORD buflen, DWORD *needed,
1380 DWORD sz = buflen, type;
1384 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1386 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1387 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1388 HeapFree(GetProcessHeap(),0,ValueNameA);
1390 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1391 WARN("Got ret = %ld\n", ret);
1399 /*****************************************************************************
1400 * WINSPOOL_GetDefaultDevMode
1402 * Get a default DevMode values for wineps.
1406 static void WINSPOOL_GetDefaultDevMode(
1408 DWORD buflen, DWORD *needed,
1413 /* fill default DEVMODE - should be read from ppd... */
1414 ZeroMemory( &dm, sizeof(dm) );
1415 strcpy(dm.dmDeviceName,"wineps");
1416 dm.dmSpecVersion = DM_SPECVERSION;
1417 dm.dmDriverVersion = 1;
1418 dm.dmSize = sizeof(DEVMODEA);
1419 dm.dmDriverExtra = 0;
1421 DM_ORIENTATION | DM_PAPERSIZE |
1422 DM_PAPERLENGTH | DM_PAPERWIDTH |
1425 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1426 DM_YRESOLUTION | DM_TTOPTION;
1428 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1429 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1430 dm.u1.s1.dmPaperLength = 2970;
1431 dm.u1.s1.dmPaperWidth = 2100;
1435 dm.dmDefaultSource = DMBIN_AUTO;
1436 dm.dmPrintQuality = DMRES_MEDIUM;
1439 dm.dmYResolution = 300; /* 300dpi */
1440 dm.dmTTOption = DMTT_BITMAP;
1443 /* dm.dmLogPixels */
1444 /* dm.dmBitsPerPel */
1445 /* dm.dmPelsWidth */
1446 /* dm.dmPelsHeight */
1447 /* dm.dmDisplayFlags */
1448 /* dm.dmDisplayFrequency */
1449 /* dm.dmICMMethod */
1450 /* dm.dmICMIntent */
1451 /* dm.dmMediaType */
1452 /* dm.dmDitherType */
1453 /* dm.dmReserved1 */
1454 /* dm.dmReserved2 */
1455 /* dm.dmPanningWidth */
1456 /* dm.dmPanningHeight */
1459 if(buflen >= sizeof(DEVMODEW)) {
1460 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1461 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1462 HeapFree(GetProcessHeap(),0,pdmW);
1464 *needed = sizeof(DEVMODEW);
1468 if(buflen >= sizeof(DEVMODEA)) {
1469 memcpy(ptr, &dm, sizeof(DEVMODEA));
1471 *needed = sizeof(DEVMODEA);
1475 /*****************************************************************************
1476 * WINSPOOL_GetDevModeFromReg
1478 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1479 * DevMode is stored either as unicode or ascii.
1481 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1483 DWORD buflen, DWORD *needed,
1486 DWORD sz = buflen, type;
1489 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1490 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1491 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1492 if (sz < sizeof(DEVMODEA))
1494 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1497 /* ensures that dmSize is not erratically bogus if registry is invalid */
1498 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1499 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1501 sz += (CCHDEVICENAME + CCHFORMNAME);
1503 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1504 memcpy(ptr, dmW, sz);
1505 HeapFree(GetProcessHeap(),0,dmW);
1512 /*********************************************************************
1513 * WINSPOOL_GetPrinter_2
1515 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1516 * The strings are either stored as unicode or ascii.
1518 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1519 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1522 DWORD size, left = cbBuf;
1523 BOOL space = (cbBuf > 0);
1528 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1530 if(space && size <= left) {
1531 pi2->pPrinterName = (LPWSTR)ptr;
1538 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1540 if(space && size <= left) {
1541 pi2->pShareName = (LPWSTR)ptr;
1548 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1550 if(space && size <= left) {
1551 pi2->pPortName = (LPWSTR)ptr;
1558 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1560 if(space && size <= left) {
1561 pi2->pDriverName = (LPWSTR)ptr;
1568 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1570 if(space && size <= left) {
1571 pi2->pComment = (LPWSTR)ptr;
1578 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1580 if(space && size <= left) {
1581 pi2->pLocation = (LPWSTR)ptr;
1588 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1590 if(space && size <= left) {
1591 pi2->pDevMode = (LPDEVMODEW)ptr;
1600 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1601 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
1602 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1603 if(space && size <= left) {
1604 pi2->pDevMode = (LPDEVMODEW)ptr;
1611 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1613 if(space && size <= left) {
1614 pi2->pSepFile = (LPWSTR)ptr;
1621 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1623 if(space && size <= left) {
1624 pi2->pPrintProcessor = (LPWSTR)ptr;
1631 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1633 if(space && size <= left) {
1634 pi2->pDatatype = (LPWSTR)ptr;
1641 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1643 if(space && size <= left) {
1644 pi2->pParameters = (LPWSTR)ptr;
1652 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1653 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1654 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1655 "Default Priority");
1656 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1657 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1660 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1661 memset(pi2, 0, sizeof(*pi2));
1666 /*********************************************************************
1667 * WINSPOOL_GetPrinter_4
1669 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1671 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1672 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1675 DWORD size, left = cbBuf;
1676 BOOL space = (cbBuf > 0);
1681 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1683 if(space && size <= left) {
1684 pi4->pPrinterName = (LPWSTR)ptr;
1692 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1695 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1696 memset(pi4, 0, sizeof(*pi4));
1701 /*********************************************************************
1702 * WINSPOOL_GetPrinter_5
1704 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1706 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1707 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1710 DWORD size, left = cbBuf;
1711 BOOL space = (cbBuf > 0);
1716 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1718 if(space && size <= left) {
1719 pi5->pPrinterName = (LPWSTR)ptr;
1726 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1728 if(space && size <= left) {
1729 pi5->pPortName = (LPWSTR)ptr;
1737 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1738 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1740 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1744 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1745 memset(pi5, 0, sizeof(*pi5));
1750 /*****************************************************************************
1751 * WINSPOOL_GetPrinter
1753 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1754 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1755 * just a collection of pointers to strings.
1757 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1758 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1761 DWORD size, needed = 0;
1763 HKEY hkeyPrinter, hkeyPrinters;
1766 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1768 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1770 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1772 ERR("Can't create Printers key\n");
1775 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1777 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1778 RegCloseKey(hkeyPrinters);
1779 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1786 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1788 size = sizeof(PRINTER_INFO_2W);
1790 ptr = pPrinter + size;
1792 memset(pPrinter, 0, size);
1797 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1805 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1807 size = sizeof(PRINTER_INFO_4W);
1809 ptr = pPrinter + size;
1811 memset(pPrinter, 0, size);
1816 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1825 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1827 size = sizeof(PRINTER_INFO_5W);
1829 ptr = pPrinter + size;
1831 memset(pPrinter, 0, size);
1837 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1844 FIXME("Unimplemented level %ld\n", Level);
1845 SetLastError(ERROR_INVALID_LEVEL);
1846 RegCloseKey(hkeyPrinters);
1847 RegCloseKey(hkeyPrinter);
1851 RegCloseKey(hkeyPrinter);
1852 RegCloseKey(hkeyPrinters);
1854 TRACE("returning %d needed = %ld\n", ret, needed);
1855 if(pcbNeeded) *pcbNeeded = needed;
1857 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1861 /*****************************************************************************
1862 * GetPrinterW [WINSPOOL.@]
1864 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1865 DWORD cbBuf, LPDWORD pcbNeeded)
1867 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1871 /*****************************************************************************
1872 * GetPrinterA [WINSPOOL.@]
1874 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1875 DWORD cbBuf, LPDWORD pcbNeeded)
1877 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1881 /*****************************************************************************
1882 * WINSPOOL_EnumPrinters
1884 * Implementation of EnumPrintersA|W
1886 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1887 DWORD dwLevel, LPBYTE lpbPrinters,
1888 DWORD cbBuf, LPDWORD lpdwNeeded,
1889 LPDWORD lpdwReturned, BOOL unicode)
1892 HKEY hkeyPrinters, hkeyPrinter;
1893 WCHAR PrinterName[255];
1894 DWORD needed = 0, number = 0;
1895 DWORD used, i, left;
1899 memset(lpbPrinters, 0, cbBuf);
1905 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1906 if(dwType == PRINTER_ENUM_DEFAULT)
1909 if (dwType & PRINTER_ENUM_CONNECTIONS) {
1910 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
1911 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
1912 dwType |= PRINTER_ENUM_LOCAL;
1915 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1916 FIXME("dwType = %08lx\n", dwType);
1917 SetLastError(ERROR_INVALID_FLAGS);
1921 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1923 ERR("Can't create Printers key\n");
1927 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1928 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1929 RegCloseKey(hkeyPrinters);
1930 ERR("Can't query Printers key\n");
1933 TRACE("Found %ld printers\n", number);
1937 RegCloseKey(hkeyPrinters);
1939 *lpdwReturned = number;
1943 used = number * sizeof(PRINTER_INFO_2W);
1946 used = number * sizeof(PRINTER_INFO_4W);
1949 used = number * sizeof(PRINTER_INFO_5W);
1953 SetLastError(ERROR_INVALID_LEVEL);
1954 RegCloseKey(hkeyPrinters);
1957 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1959 for(i = 0; i < number; i++) {
1960 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1962 ERR("Can't enum key number %ld\n", i);
1963 RegCloseKey(hkeyPrinters);
1966 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1967 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1969 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1970 RegCloseKey(hkeyPrinters);
1975 buf = lpbPrinters + used;
1976 left = cbBuf - used;
1984 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1985 left, &needed, unicode);
1987 if(pi) pi += sizeof(PRINTER_INFO_2W);
1990 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1991 left, &needed, unicode);
1993 if(pi) pi += sizeof(PRINTER_INFO_4W);
1996 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1997 left, &needed, unicode);
1999 if(pi) pi += sizeof(PRINTER_INFO_5W);
2002 ERR("Shouldn't be here!\n");
2003 RegCloseKey(hkeyPrinter);
2004 RegCloseKey(hkeyPrinters);
2007 RegCloseKey(hkeyPrinter);
2009 RegCloseKey(hkeyPrinters);
2016 memset(lpbPrinters, 0, cbBuf);
2017 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2021 *lpdwReturned = number;
2022 SetLastError(ERROR_SUCCESS);
2027 /******************************************************************
2028 * EnumPrintersW [WINSPOOL.@]
2030 * Enumerates the available printers, print servers and print
2031 * providers, depending on the specified flags, name and level.
2035 * If level is set to 1:
2036 * Not implemented yet!
2037 * Returns TRUE with an empty list.
2039 * If level is set to 2:
2040 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2041 * Returns an array of PRINTER_INFO_2 data structures in the
2042 * lpbPrinters buffer. Note that according to MSDN also an
2043 * OpenPrinter should be performed on every remote printer.
2045 * If level is set to 4 (officially WinNT only):
2046 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2047 * Fast: Only the registry is queried to retrieve printer names,
2048 * no connection to the driver is made.
2049 * Returns an array of PRINTER_INFO_4 data structures in the
2050 * lpbPrinters buffer.
2052 * If level is set to 5 (officially WinNT4/Win9x only):
2053 * Fast: Only the registry is queried to retrieve printer names,
2054 * no connection to the driver is made.
2055 * Returns an array of PRINTER_INFO_5 data structures in the
2056 * lpbPrinters buffer.
2058 * If level set to 3 or 6+:
2059 * returns zero (failure!)
2061 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2065 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2066 * - Only levels 2, 4 and 5 are implemented at the moment.
2067 * - 16-bit printer drivers are not enumerated.
2068 * - Returned amount of bytes used/needed does not match the real Windoze
2069 * implementation (as in this implementation, all strings are part
2070 * of the buffer, whereas Win32 keeps them somewhere else)
2071 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2074 * - In a regular Wine installation, no registry settings for printers
2075 * exist, which makes this function return an empty list.
2077 BOOL WINAPI EnumPrintersW(
2078 DWORD dwType, /* [in] Types of print objects to enumerate */
2079 LPWSTR lpszName, /* [in] name of objects to enumerate */
2080 DWORD dwLevel, /* [in] type of printer info structure */
2081 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2082 DWORD cbBuf, /* [in] max size of buffer in bytes */
2083 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2084 LPDWORD lpdwReturned /* [out] number of entries returned */
2087 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2088 lpdwNeeded, lpdwReturned, TRUE);
2091 /******************************************************************
2092 * EnumPrintersA [WINSPOOL.@]
2095 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2096 DWORD dwLevel, LPBYTE lpbPrinters,
2097 DWORD cbBuf, LPDWORD lpdwNeeded,
2098 LPDWORD lpdwReturned)
2101 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
2103 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
2104 lpdwNeeded, lpdwReturned, FALSE);
2105 HeapFree(GetProcessHeap(),0,lpszNameW);
2109 /*****************************************************************************
2110 * WINSPOOL_GetDriverInfoFromReg [internal]
2112 * Enters the information from the registry into the DRIVER_INFO struct
2115 * zero if the printer driver does not exist in the registry
2116 * (only if Level > 1) otherwise nonzero
2118 static BOOL WINSPOOL_GetDriverInfoFromReg(
2121 LPWSTR pEnvironment,
2123 LPBYTE ptr, /* DRIVER_INFO */
2124 LPBYTE pDriverStrings, /* strings buffer */
2125 DWORD cbBuf, /* size of string buffer */
2126 LPDWORD pcbNeeded, /* space needed for str. */
2127 BOOL unicode) /* type of strings */
2128 { DWORD dw, size, tmp, type;
2130 LPBYTE strPtr = pDriverStrings;
2132 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2133 debugstr_w(DriverName), debugstr_w(pEnvironment),
2134 Level, ptr, pDriverStrings, cbBuf, unicode);
2137 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2138 if (*pcbNeeded <= cbBuf)
2139 strcpyW((LPWSTR)strPtr, DriverName);
2141 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2143 if(*pcbNeeded <= cbBuf)
2144 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2149 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2153 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2154 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2157 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2158 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2159 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2164 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2166 WARN("Can't get Version\n");
2168 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2171 pEnvironment = DefaultEnvironmentW;
2173 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2175 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2178 if(*pcbNeeded <= cbBuf) {
2180 strcpyW((LPWSTR)strPtr, pEnvironment);
2182 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2185 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2186 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2189 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2192 if(*pcbNeeded <= cbBuf)
2193 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2196 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2197 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2200 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2203 if(*pcbNeeded <= cbBuf)
2204 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2207 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2208 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2211 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2212 0, &size, unicode)) {
2214 if(*pcbNeeded <= cbBuf)
2215 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2216 size, &tmp, unicode);
2218 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2219 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2223 RegCloseKey(hkeyDriver);
2224 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2228 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2231 if(*pcbNeeded <= cbBuf)
2232 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2233 size, &tmp, unicode);
2235 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2236 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2239 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2242 if(*pcbNeeded <= cbBuf)
2243 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2244 size, &tmp, unicode);
2246 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2247 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2250 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2253 if(*pcbNeeded <= cbBuf)
2254 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2255 size, &tmp, unicode);
2257 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2258 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2261 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2264 if(*pcbNeeded <= cbBuf)
2265 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2266 size, &tmp, unicode);
2268 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2269 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2272 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2273 RegCloseKey(hkeyDriver);
2277 /*****************************************************************************
2278 * WINSPOOL_GetPrinterDriver
2280 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2281 DWORD Level, LPBYTE pDriverInfo,
2282 DWORD cbBuf, LPDWORD pcbNeeded,
2286 WCHAR DriverName[100];
2287 DWORD ret, type, size, needed = 0;
2289 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2291 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2292 Level,pDriverInfo,cbBuf, pcbNeeded);
2294 ZeroMemory(pDriverInfo, cbBuf);
2296 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2298 if(Level < 1 || Level > 3) {
2299 SetLastError(ERROR_INVALID_LEVEL);
2302 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2304 ERR("Can't create Printers key\n");
2307 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2309 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2310 RegCloseKey(hkeyPrinters);
2311 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2314 size = sizeof(DriverName);
2316 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2317 (LPBYTE)DriverName, &size);
2318 RegCloseKey(hkeyPrinter);
2319 RegCloseKey(hkeyPrinters);
2320 if(ret != ERROR_SUCCESS) {
2321 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2325 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2327 ERR("Can't create Drivers key\n");
2333 size = sizeof(DRIVER_INFO_1W);
2336 size = sizeof(DRIVER_INFO_2W);
2339 size = sizeof(DRIVER_INFO_3W);
2342 ERR("Invalid level\n");
2347 ptr = pDriverInfo + size;
2349 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2350 pEnvironment, Level, pDriverInfo,
2351 (cbBuf < size) ? NULL : ptr,
2352 (cbBuf < size) ? 0 : cbBuf - size,
2353 &needed, unicode)) {
2354 RegCloseKey(hkeyDrivers);
2358 RegCloseKey(hkeyDrivers);
2360 if(pcbNeeded) *pcbNeeded = size + needed;
2361 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2362 if(cbBuf >= needed) return TRUE;
2363 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2367 /*****************************************************************************
2368 * GetPrinterDriverA [WINSPOOL.@]
2370 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2371 DWORD Level, LPBYTE pDriverInfo,
2372 DWORD cbBuf, LPDWORD pcbNeeded)
2375 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2376 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2377 cbBuf, pcbNeeded, FALSE);
2378 HeapFree(GetProcessHeap(),0,pEnvW);
2381 /*****************************************************************************
2382 * GetPrinterDriverW [WINSPOOL.@]
2384 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2385 DWORD Level, LPBYTE pDriverInfo,
2386 DWORD cbBuf, LPDWORD pcbNeeded)
2388 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2389 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2392 /*****************************************************************************
2393 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2395 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2396 DWORD Level, LPBYTE pDriverDirectory,
2397 DWORD cbBuf, LPDWORD pcbNeeded)
2401 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2402 pDriverDirectory, cbBuf, pcbNeeded);
2404 FIXME("pName = `%s' - unsupported\n", pName);
2405 SetLastError(ERROR_INVALID_PARAMETER);
2408 if(pEnvironment != NULL) {
2409 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2410 SetLastError(ERROR_INVALID_ENVIRONMENT);
2413 if(Level != 1) /* win95 ignores this so we just carry on */
2414 WARN("Level = %ld - assuming 1\n", Level);
2416 /* FIXME should read from registry */
2417 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2420 *pcbNeeded = needed;
2421 if(needed > cbBuf) {
2422 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2429 /*****************************************************************************
2430 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2432 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2433 DWORD Level, LPBYTE pDriverDirectory,
2434 DWORD cbBuf, LPDWORD pcbNeeded)
2436 LPSTR pNameA = NULL, pEnvironmentA = NULL;
2440 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2442 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2443 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2444 pDriverDirectory, cbBuf, pcbNeeded );
2446 HeapFree( GetProcessHeap(), 0, pNameA );
2448 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2453 /*****************************************************************************
2454 * AddPrinterDriverA [WINSPOOL.@]
2456 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2459 HKEY hkeyDrivers, hkeyName;
2461 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2463 if(level != 2 && level != 3) {
2464 SetLastError(ERROR_INVALID_LEVEL);
2468 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2469 SetLastError(ERROR_INVALID_PARAMETER);
2473 WARN("pDriverInfo == NULL\n");
2474 SetLastError(ERROR_INVALID_PARAMETER);
2479 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2481 memset(&di3, 0, sizeof(di3));
2482 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2485 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2487 SetLastError(ERROR_INVALID_PARAMETER);
2490 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2491 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2492 if(!di3.pHelpFile) di3.pHelpFile = "";
2493 if(!di3.pMonitorName) di3.pMonitorName = "";
2495 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2498 ERR("Can't create Drivers key\n");
2502 if(level == 2) { /* apparently can't overwrite with level2 */
2503 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2504 RegCloseKey(hkeyName);
2505 RegCloseKey(hkeyDrivers);
2506 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2507 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2511 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2512 RegCloseKey(hkeyDrivers);
2513 ERR("Can't create Name key\n");
2516 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2518 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2519 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2520 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2522 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2523 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2524 di3.pDependentFiles, 0);
2525 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2526 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2527 RegCloseKey(hkeyName);
2528 RegCloseKey(hkeyDrivers);
2532 /*****************************************************************************
2533 * AddPrinterDriverW [WINSPOOL.@]
2535 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2538 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2544 /*****************************************************************************
2545 * PrinterProperties [WINSPOOL.@]
2547 * Displays a dialog to set the properties of the printer.
2550 * nonzero on success or zero on failure
2553 * implemented as stub only
2555 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2556 HANDLE hPrinter /* [in] handle to printer object */
2558 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2559 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2563 /*****************************************************************************
2564 * EnumJobsA [WINSPOOL.@]
2567 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2568 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2571 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2572 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2574 if(pcbNeeded) *pcbNeeded = 0;
2575 if(pcReturned) *pcReturned = 0;
2580 /*****************************************************************************
2581 * EnumJobsW [WINSPOOL.@]
2584 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2585 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2588 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2589 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2591 if(pcbNeeded) *pcbNeeded = 0;
2592 if(pcReturned) *pcReturned = 0;
2596 /*****************************************************************************
2597 * WINSPOOL_EnumPrinterDrivers [internal]
2599 * Delivers information about all printer drivers installed on the
2600 * localhost or a given server
2603 * nonzero on success or zero on failure. If the buffer for the returned
2604 * information is too small the function will return an error
2607 * - only implemented for localhost, foreign hosts will return an error
2609 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2610 DWORD Level, LPBYTE pDriverInfo,
2611 DWORD cbBuf, LPDWORD pcbNeeded,
2612 LPDWORD pcReturned, BOOL unicode)
2615 DWORD i, needed, number = 0, size = 0;
2616 WCHAR DriverNameW[255];
2619 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2620 debugstr_w(pName), debugstr_w(pEnvironment),
2621 Level, pDriverInfo, cbBuf, unicode);
2623 /* check for local drivers */
2625 ERR("remote drivers unsupported! Current remote host is %s\n",
2630 /* check input parameter */
2631 if((Level < 1) || (Level > 3)) {
2632 ERR("unsupported level %ld \n", Level);
2636 /* initialize return values */
2638 memset( pDriverInfo, 0, cbBuf);
2642 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2644 ERR("Can't open Drivers key\n");
2648 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2649 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2650 RegCloseKey(hkeyDrivers);
2651 ERR("Can't query Drivers key\n");
2654 TRACE("Found %ld Drivers\n", number);
2656 /* get size of single struct
2657 * unicode and ascii structure have the same size
2661 size = sizeof(DRIVER_INFO_1A);
2664 size = sizeof(DRIVER_INFO_2A);
2667 size = sizeof(DRIVER_INFO_3A);
2671 /* calculate required buffer size */
2672 *pcbNeeded = size * number;
2674 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2676 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2677 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2679 ERR("Can't enum key number %ld\n", i);
2680 RegCloseKey(hkeyDrivers);
2683 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2684 pEnvironment, Level, ptr,
2685 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2686 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2687 &needed, unicode)) {
2688 RegCloseKey(hkeyDrivers);
2691 (*pcbNeeded) += needed;
2694 RegCloseKey(hkeyDrivers);
2696 if(cbBuf < *pcbNeeded){
2697 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2704 /*****************************************************************************
2705 * EnumPrinterDriversW [WINSPOOL.@]
2707 * see function EnumPrinterDrivers for RETURNS, BUGS
2709 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2710 LPBYTE pDriverInfo, DWORD cbBuf,
2711 LPDWORD pcbNeeded, LPDWORD pcReturned)
2713 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2714 cbBuf, pcbNeeded, pcReturned, TRUE);
2717 /*****************************************************************************
2718 * EnumPrinterDriversA [WINSPOOL.@]
2720 * see function EnumPrinterDrivers for RETURNS, BUGS
2722 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2723 LPBYTE pDriverInfo, DWORD cbBuf,
2724 LPDWORD pcbNeeded, LPDWORD pcReturned)
2726 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2729 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2731 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2733 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2734 cbBuf, pcbNeeded, pcReturned, FALSE);
2736 HeapFree(GetProcessHeap(), 0, pNameW);
2738 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2744 /******************************************************************************
2745 * EnumPortsA (WINSPOOL.@)
2747 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2748 LPDWORD bufneeded,LPDWORD bufreturned)
2750 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2754 /******************************************************************************
2755 * GetDefaultPrinterA (WINSPOOL.@)
2757 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2759 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
2765 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2769 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
2771 SetLastError (ERROR_FILE_NOT_FOUND);
2775 if ((ptr = strchr (name, ',')) == NULL)
2777 SetLastError (ERROR_FILE_NOT_FOUND);
2782 *namesize = strlen (name) + 1;
2787 /******************************************************************************
2788 * GetDefaultPrinterW (WINSPOOL.@)
2790 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
2797 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2801 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
2802 ret = GetDefaultPrinterA (buf, namesize);
2805 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
2808 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2811 else *namesize = len;
2814 HeapFree (GetProcessHeap (), 0, buf);
2819 /******************************************************************************
2820 * SetPrinterDataExA (WINSPOOL.@)
2822 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2823 LPSTR pValueName, DWORD Type,
2824 LPBYTE pData, DWORD cbData)
2826 HKEY hkeyPrinter, hkeySubkey;
2829 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2830 debugstr_a(pValueName), Type, pData, cbData);
2832 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2836 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2838 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2839 RegCloseKey(hkeyPrinter);
2842 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2843 RegCloseKey(hkeySubkey);
2844 RegCloseKey(hkeyPrinter);
2848 /******************************************************************************
2849 * SetPrinterDataExW (WINSPOOL.@)
2851 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2852 LPWSTR pValueName, DWORD Type,
2853 LPBYTE pData, DWORD cbData)
2855 HKEY hkeyPrinter, hkeySubkey;
2858 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2859 debugstr_w(pValueName), Type, pData, cbData);
2861 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2865 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2867 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2868 RegCloseKey(hkeyPrinter);
2871 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2872 RegCloseKey(hkeySubkey);
2873 RegCloseKey(hkeyPrinter);
2877 /******************************************************************************
2878 * SetPrinterDataA (WINSPOOL.@)
2880 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2881 LPBYTE pData, DWORD cbData)
2883 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2887 /******************************************************************************
2888 * SetPrinterDataW (WINSPOOL.@)
2890 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2891 LPBYTE pData, DWORD cbData)
2893 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2897 /******************************************************************************
2898 * GetPrinterDataExA (WINSPOOL.@)
2900 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2901 LPSTR pValueName, LPDWORD pType,
2902 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2904 HKEY hkeyPrinter, hkeySubkey;
2907 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2908 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2911 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2915 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2917 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2918 RegCloseKey(hkeyPrinter);
2922 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2923 RegCloseKey(hkeySubkey);
2924 RegCloseKey(hkeyPrinter);
2928 /******************************************************************************
2929 * GetPrinterDataExW (WINSPOOL.@)
2931 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2932 LPWSTR pValueName, LPDWORD pType,
2933 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2935 HKEY hkeyPrinter, hkeySubkey;
2938 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2939 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2942 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2946 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2948 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2949 RegCloseKey(hkeyPrinter);
2953 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2954 RegCloseKey(hkeySubkey);
2955 RegCloseKey(hkeyPrinter);
2959 /******************************************************************************
2960 * GetPrinterDataA (WINSPOOL.@)
2962 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
2963 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2965 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
2966 pData, nSize, pcbNeeded);
2969 /******************************************************************************
2970 * GetPrinterDataW (WINSPOOL.@)
2972 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
2973 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2975 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
2976 pData, nSize, pcbNeeded);
2979 /*******************************************************************************
2980 * EnumPrinterDataExW [WINSPOOL.@]
2982 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
2983 LPBYTE pEnumValues, DWORD cbEnumValues,
2984 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2986 HKEY hkPrinter, hkSubKey;
2987 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
2988 cbValueNameLen, cbMaxValueLen, cbValueLen,
2993 PPRINTER_ENUM_VALUESW ppev;
2995 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
2997 if (pKeyName == NULL || *pKeyName == 0)
2998 return ERROR_INVALID_PARAMETER;
3000 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3001 if (ret != ERROR_SUCCESS)
3003 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3008 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3009 if (ret != ERROR_SUCCESS)
3011 r = RegCloseKey (hkPrinter);
3012 if (r != ERROR_SUCCESS)
3013 WARN ("RegCloseKey returned %li\n", r);
3014 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3015 debugstr_w (pKeyName), ret);
3019 ret = RegCloseKey (hkPrinter);
3020 if (ret != ERROR_SUCCESS)
3022 ERR ("RegCloseKey returned %li\n", ret);
3023 r = RegCloseKey (hkSubKey);
3024 if (r != ERROR_SUCCESS)
3025 WARN ("RegCloseKey returned %li\n", r);
3029 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3030 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3031 if (ret != ERROR_SUCCESS)
3033 r = RegCloseKey (hkSubKey);
3034 if (r != ERROR_SUCCESS)
3035 WARN ("RegCloseKey returned %li\n", r);
3036 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3040 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3041 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3043 if (cValues == 0) /* empty key */
3045 r = RegCloseKey (hkSubKey);
3046 if (r != ERROR_SUCCESS)
3047 WARN ("RegCloseKey returned %li\n", r);
3048 *pcbEnumValues = *pnEnumValues = 0;
3049 return ERROR_SUCCESS;
3052 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3054 hHeap = GetProcessHeap ();
3055 if (hHeap == (HANDLE) NULL)
3057 ERR ("GetProcessHeap failed\n");
3058 r = RegCloseKey (hkSubKey);
3059 if (r != ERROR_SUCCESS)
3060 WARN ("RegCloseKey returned %li\n", r);
3061 return ERROR_OUTOFMEMORY;
3064 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3065 if (lpValueName == NULL)
3067 ERR ("Failed to allocate %li bytes from process heap\n",
3068 cbMaxValueNameLen * sizeof (WCHAR));
3069 r = RegCloseKey (hkSubKey);
3070 if (r != ERROR_SUCCESS)
3071 WARN ("RegCloseKey returned %li\n", r);
3072 return ERROR_OUTOFMEMORY;
3075 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3076 if (lpValue == NULL)
3078 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3079 if (HeapFree (hHeap, 0, lpValueName) == 0)
3080 WARN ("HeapFree failed with code %li\n", GetLastError ());
3081 r = RegCloseKey (hkSubKey);
3082 if (r != ERROR_SUCCESS)
3083 WARN ("RegCloseKey returned %li\n", r);
3084 return ERROR_OUTOFMEMORY;
3087 TRACE ("pass 1: calculating buffer required for all names and values\n");
3089 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3091 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3093 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3095 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3096 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3097 NULL, NULL, lpValue, &cbValueLen);
3098 if (ret != ERROR_SUCCESS)
3100 if (HeapFree (hHeap, 0, lpValue) == 0)
3101 WARN ("HeapFree failed with code %li\n", GetLastError ());
3102 if (HeapFree (hHeap, 0, lpValueName) == 0)
3103 WARN ("HeapFree failed with code %li\n", GetLastError ());
3104 r = RegCloseKey (hkSubKey);
3105 if (r != ERROR_SUCCESS)
3106 WARN ("RegCloseKey returned %li\n", r);
3107 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3111 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3112 debugstr_w (lpValueName), dwIndex,
3113 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3115 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3116 cbBufSize += cbValueLen;
3119 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3121 *pcbEnumValues = cbBufSize;
3122 *pnEnumValues = cValues;
3124 if (cbEnumValues < cbBufSize) /* buffer too small */
3126 if (HeapFree (hHeap, 0, lpValue) == 0)
3127 WARN ("HeapFree failed with code %li\n", GetLastError ());
3128 if (HeapFree (hHeap, 0, lpValueName) == 0)
3129 WARN ("HeapFree failed with code %li\n", GetLastError ());
3130 r = RegCloseKey (hkSubKey);
3131 if (r != ERROR_SUCCESS)
3132 WARN ("RegCloseKey returned %li\n", r);
3133 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3134 return ERROR_MORE_DATA;
3137 TRACE ("pass 2: copying all names and values to buffer\n");
3139 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3140 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3142 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3144 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3145 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3146 NULL, &dwType, lpValue, &cbValueLen);
3147 if (ret != ERROR_SUCCESS)
3149 if (HeapFree (hHeap, 0, lpValue) == 0)
3150 WARN ("HeapFree failed with code %li\n", GetLastError ());
3151 if (HeapFree (hHeap, 0, lpValueName) == 0)
3152 WARN ("HeapFree failed with code %li\n", GetLastError ());
3153 r = RegCloseKey (hkSubKey);
3154 if (r != ERROR_SUCCESS)
3155 WARN ("RegCloseKey returned %li\n", r);
3156 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3160 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3161 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3162 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3163 pEnumValues += cbValueNameLen;
3165 /* return # of *bytes* (including trailing \0), not # of chars */
3166 ppev[dwIndex].cbValueName = cbValueNameLen;
3168 ppev[dwIndex].dwType = dwType;
3170 memcpy (pEnumValues, lpValue, cbValueLen);
3171 ppev[dwIndex].pData = pEnumValues;
3172 pEnumValues += cbValueLen;
3174 ppev[dwIndex].cbData = cbValueLen;
3176 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3177 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3180 if (HeapFree (hHeap, 0, lpValue) == 0)
3182 ret = GetLastError ();
3183 ERR ("HeapFree failed with code %li\n", ret);
3184 if (HeapFree (hHeap, 0, lpValueName) == 0)
3185 WARN ("HeapFree failed with code %li\n", GetLastError ());
3186 r = RegCloseKey (hkSubKey);
3187 if (r != ERROR_SUCCESS)
3188 WARN ("RegCloseKey returned %li\n", r);
3192 if (HeapFree (hHeap, 0, lpValueName) == 0)
3194 ret = GetLastError ();
3195 ERR ("HeapFree failed with code %li\n", ret);
3196 r = RegCloseKey (hkSubKey);
3197 if (r != ERROR_SUCCESS)
3198 WARN ("RegCloseKey returned %li\n", r);
3202 ret = RegCloseKey (hkSubKey);
3203 if (ret != ERROR_SUCCESS)
3205 ERR ("RegCloseKey returned %li\n", ret);
3209 return ERROR_SUCCESS;
3212 /*******************************************************************************
3213 * EnumPrinterDataExA [WINSPOOL.@]
3215 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3216 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3217 * what Windows 2000 SP1 does.
3220 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3221 LPBYTE pEnumValues, DWORD cbEnumValues,
3222 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3226 DWORD ret, dwIndex, dwBufSize;
3230 TRACE ("%p %s\n", hPrinter, pKeyName);
3232 if (pKeyName == NULL || *pKeyName == 0)
3233 return ERROR_INVALID_PARAMETER;
3235 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3238 ret = GetLastError ();
3239 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3243 hHeap = GetProcessHeap ();
3244 if (hHeap == (HANDLE) NULL)
3246 ERR ("GetProcessHeap failed\n");
3247 return ERROR_OUTOFMEMORY;
3250 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3251 if (pKeyNameW == NULL)
3253 ERR ("Failed to allocate %li bytes from process heap\n",
3254 (LONG) len * sizeof (WCHAR));
3255 return ERROR_OUTOFMEMORY;
3258 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3260 ret = GetLastError ();
3261 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3262 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3263 WARN ("HeapFree failed with code %li\n", GetLastError ());
3267 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3268 pcbEnumValues, pnEnumValues);
3269 if (ret != ERROR_SUCCESS)
3271 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3272 WARN ("HeapFree failed with code %li\n", GetLastError ());
3273 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3277 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3279 ret = GetLastError ();
3280 ERR ("HeapFree failed with code %li\n", ret);
3284 if (*pnEnumValues == 0) /* empty key */
3285 return ERROR_SUCCESS;
3288 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3290 PPRINTER_ENUM_VALUESW ppev =
3291 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3293 if (dwBufSize < ppev->cbValueName)
3294 dwBufSize = ppev->cbValueName;
3296 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3297 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3298 dwBufSize = ppev->cbData;
3301 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3303 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3304 if (pBuffer == NULL)
3306 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3307 return ERROR_OUTOFMEMORY;
3310 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3312 PPRINTER_ENUM_VALUESW ppev =
3313 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3315 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3316 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3320 ret = GetLastError ();
3321 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3322 if (HeapFree (hHeap, 0, pBuffer) == 0)
3323 WARN ("HeapFree failed with code %li\n", GetLastError ());
3327 memcpy (ppev->pValueName, pBuffer, len);
3329 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3331 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3332 ppev->dwType != REG_MULTI_SZ)
3335 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3336 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3339 ret = GetLastError ();
3340 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3341 if (HeapFree (hHeap, 0, pBuffer) == 0)
3342 WARN ("HeapFree failed with code %li\n", GetLastError ());
3346 memcpy (ppev->pData, pBuffer, len);
3348 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3349 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3352 if (HeapFree (hHeap, 0, pBuffer) == 0)
3354 ret = GetLastError ();
3355 ERR ("HeapFree failed with code %li\n", ret);
3359 return ERROR_SUCCESS;