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
19 # include <cups/cups.h>
25 #include "wine/windef16.h"
26 #include "wine/unicode.h"
27 #include "debugtools.h"
31 DEFAULT_DEBUG_CHANNEL(winspool);
33 static LPWSTR *printer_array;
34 static int nb_printers;
36 static DWORD WINAPI (*GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
37 WORD fwCapability, LPSTR lpszOutput,
39 static INT WINAPI (*GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
40 LPSTR lpszDevice, LPSTR lpszPort,
41 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
44 static char Printers[] =
45 "System\\CurrentControlSet\\control\\Print\\Printers\\";
46 static char Drivers[] =
47 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
49 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
51 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
52 'i','o','n',' ','F','i','l','e',0};
53 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
54 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
55 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
57 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
59 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
60 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
61 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
62 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
63 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
64 static WCHAR NameW[] = {'N','a','m','e',0};
65 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
66 static WCHAR PortW[] = {'P','o','r','t',0};
67 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
69 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
71 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
72 'v','e','r','D','a','t','a',0};
73 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
75 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
76 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
78 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
79 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
80 DWORD Level, LPBYTE pDriverInfo,
81 DWORD cbBuf, LPDWORD pcbNeeded,
84 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
87 /* If forcing, or no profile string entry for device yet, set the entry
89 * The always change entry if not WINEPS yet is discussable.
92 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
94 !strstr(qbuf,"WINEPS")
96 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
98 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
99 WriteProfileStringA("windows","device",buf);
100 HeapFree(GetProcessHeap(),0,buf);
106 CUPS_LoadPrinters(void) {
108 int i,nrofdests,hadprinter = FALSE;
109 PRINTER_INFO_2A pinfo2a;
110 const char* def = cupsGetDefault();
112 nrofdests = cupsGetPrinters(&printers);
114 for (i=0;i<nrofdests;i++) {
115 const char *ppd = cupsGetPPD(printers[i]);
119 WARN("No ppd file for %s.\n",printers[i]);
126 if (!strcmp(def,printers[i]))
127 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
128 memset(&pinfo2a,0,sizeof(pinfo2a));
129 pinfo2a.pPrinterName = printers[i];
130 pinfo2a.pDatatype = "RAW";
131 pinfo2a.pPrintProcessor = "WinPrint";
132 pinfo2a.pDriverName = "PS Driver";
133 pinfo2a.pComment = "WINEPS Printer using CUPS";
134 pinfo2a.pLocation = "<physical location of printer>";
135 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
136 sprintf(port,"LPR:%s",printers[i]);
137 pinfo2a.pPortName = port;
138 pinfo2a.pParameters = "<parameters?>";
139 pinfo2a.pShareName = "<share name?>";
140 pinfo2a.pSepFile = "<sep file?>";
142 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
143 sprintf(devline,"WINEPS,%s",port);
144 WriteProfileStringA("devices",printers[i],devline);
145 HeapFree(GetProcessHeap(),0,devline);
147 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
148 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
149 ERR("%s not added by AddPrinterA (%ld)\n",printers[i],GetLastError());
151 HeapFree(GetProcessHeap(),0,port);
158 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
159 PRINTER_INFO_2A pinfo2a;
160 char *s,*name,*prettyname,*devname;
164 s = strchr(pent,':');
165 if (!s) return FALSE;
171 /* Determine whether this is a postscript printer. */
173 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
174 if (strstr(name,"ps") ||
175 strstr(name,"pd") || /* postscript double page */
176 strstr(name,"postscript") ||
177 strstr(name,"PostScript")
179 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
182 /* 2. Check if this is a remote printer. These usually are postscript
185 if (strstr(pent,":rm")) {
187 TRACE("%s is remote, assuming postscript.\n",name);
189 /* 3. Check if we have an input filter program. If we have one, it
190 * most likely is one capable of converting postscript.
191 * (Could probably check for occurence of 'gs' or 'ghostscript'
192 * in the if file itself.)
194 if (strstr(pent,":if=/")) {
196 TRACE("%s has inputfilter program, assuming postscript.\n",name);
199 /* If it is not a postscript printer, we cannot use it. */
204 /* Get longest name, usually the one at the right for later display. */
205 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
206 s=strchr(name,'|');if (s) *s='\0';
208 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
209 * if it is too long, we use it as comment below. */
210 devname = prettyname;
211 if (strlen(devname)>=CCHDEVICENAME-1)
213 if (strlen(devname)>=CCHDEVICENAME-1)
216 if (isfirst) /* set first entry as default */
217 WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
219 memset(&pinfo2a,0,sizeof(pinfo2a));
220 pinfo2a.pPrinterName = devname;
221 pinfo2a.pDatatype = "RAW";
222 pinfo2a.pPrintProcessor = "WinPrint";
223 pinfo2a.pDriverName = "PS Driver";
224 pinfo2a.pComment = "WINEPS Printer using LPR";
225 pinfo2a.pLocation = prettyname;
226 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
227 sprintf(port,"LPR:%s",name);
228 pinfo2a.pPortName = port;
229 pinfo2a.pParameters = "<parameters?>";
230 pinfo2a.pShareName = "<share name?>";
231 pinfo2a.pSepFile = "<sep file?>";
233 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
234 sprintf(devline,"WINEPS,%s",port);
235 WriteProfileStringA("devices",devname,devline);
236 HeapFree(GetProcessHeap(),0,devline);
238 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
239 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
240 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
242 HeapFree(GetProcessHeap(),0,port);
247 PRINTCAP_LoadPrinters(void) {
248 BOOL hadprinter = FALSE, isfirst = TRUE;
252 f = fopen("/etc/printcap","r");
256 while (fgets(buf,sizeof(buf),f)) {
260 s=strchr(buf,'\n'); if (s) *s='\0';
261 if ((buf[0]=='#') || (buf[0]=='\0'))
265 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
268 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
272 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
273 pent[strlen(pent)-1] = '\0';
276 } while (fgets(buf,sizeof(buf),f));
278 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
280 if (pent) HeapFree(GetProcessHeap(),0,pent);
289 WINSPOOL_LoadSystemPrinters() {
292 di3a.cVersion = 0x400;
293 di3a.pName = "PS Driver";
294 di3a.pEnvironment = NULL; /* NULL means auto */
295 di3a.pDriverPath = "wineps.drv";
296 di3a.pDataFile = "<datafile?>";
297 di3a.pConfigFile = "wineps.drv";
298 di3a.pHelpFile = "<helpfile?>";
299 di3a.pDependentFiles = "<dependend files?>";
300 di3a.pMonitorName = "<monitor name?>";
301 di3a.pDefaultDataType = "RAW";
303 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
304 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
308 /* If we have any CUPS based printers, skip looking for printcap printers */
309 if (CUPS_LoadPrinters())
313 /* Check for [ppd] section in config file before parsing /etc/printcap */
315 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
316 &hkPPD) == ERROR_SUCCESS)
319 PRINTCAP_LoadPrinters();
324 /******************************************************************
325 * WINSPOOL_GetOpenedPrinterEntry
326 * Get the first place empty in the opened printer table
328 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
332 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
334 if (i >= nb_printers)
336 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
337 (nb_printers + 16) * sizeof(*new_array) );
338 if (!new_array) return 0;
339 printer_array = new_array;
343 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
345 strcpyW( printer_array[i], name );
346 return (HANDLE)(i + 1);
351 /******************************************************************
352 * WINSPOOL_GetOpenedPrinter
353 * Get the pointer to the opened printer referred by the handle
355 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
357 int idx = (int)printerHandle;
358 if ((idx <= 0) || (idx > nb_printers))
360 SetLastError(ERROR_INVALID_HANDLE);
363 return printer_array[idx - 1];
366 /******************************************************************
367 * WINSPOOL_GetOpenedPrinterRegKey
370 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
372 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
376 if(!name) return ERROR_INVALID_HANDLE;
378 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
382 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
384 ERR("Can't find opened printer %s in registry\n",
386 RegCloseKey(hkeyPrinters);
387 return ERROR_INVALID_PRINTER_NAME; /* ? */
389 RegCloseKey(hkeyPrinters);
390 return ERROR_SUCCESS;
393 /***********************************************************
396 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
399 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
402 Formname = (dmA->dmSize > off_formname);
403 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
404 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
407 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
408 dmA->dmSize - CCHDEVICENAME);
410 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
411 off_formname - CCHDEVICENAME);
412 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
414 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
415 (off_formname + CCHFORMNAME));
418 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
423 /***********************************************************
425 * Creates a unicode copy of supplied devmode on heap
427 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
432 ptrdiff_t off_formname;
435 if(!dmA) return NULL;
437 off_formname = (char *)dmA->dmFormName - (char *)dmA;
438 Formname = (dmA->dmSize > off_formname);
439 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
440 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
441 return DEVMODEcpyAtoW(dmW, dmA);
444 /***********************************************************
446 * Creates an ascii copy of supplied devmode on heap
448 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
453 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
455 if(!dmW) return NULL;
456 Formname = (dmW->dmSize > off_formname);
457 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
458 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
459 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
460 CCHDEVICENAME, NULL, NULL);
462 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
463 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
465 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
466 off_formname - CCHDEVICENAME * sizeof(WCHAR));
467 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
468 CCHFORMNAME, NULL, NULL);
469 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
470 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
473 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
478 /***********************************************************
480 * Creates a unicode copy of PRINTER_INFO_2A on heap
482 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
484 LPPRINTER_INFO_2W piW;
485 if(!piA) return NULL;
486 piW = HeapAlloc(heap, 0, sizeof(*piW));
487 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
488 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
489 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
490 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
491 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
492 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
493 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
494 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
495 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
496 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
497 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
498 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
499 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
503 /***********************************************************
504 * FREE_PRINTER_INFO_2W
505 * Free PRINTER_INFO_2W and all strings
507 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
511 HeapFree(heap,0,piW->pServerName);
512 HeapFree(heap,0,piW->pPrinterName);
513 HeapFree(heap,0,piW->pShareName);
514 HeapFree(heap,0,piW->pPortName);
515 HeapFree(heap,0,piW->pDriverName);
516 HeapFree(heap,0,piW->pComment);
517 HeapFree(heap,0,piW->pLocation);
518 HeapFree(heap,0,piW->pDevMode);
519 HeapFree(heap,0,piW->pSepFile);
520 HeapFree(heap,0,piW->pPrintProcessor);
521 HeapFree(heap,0,piW->pDatatype);
522 HeapFree(heap,0,piW->pParameters);
523 HeapFree(heap,0,piW);
527 /******************************************************************
528 * DeviceCapabilities [WINSPOOL.@]
529 * DeviceCapabilitiesA [WINSPOOL.@]
532 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
533 LPSTR pOutput, LPDEVMODEA lpdm)
537 if (!GDI_CallDeviceCapabilities16)
539 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
541 if (!GDI_CallDeviceCapabilities16) return -1;
543 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
545 /* If DC_PAPERSIZE map POINT16s to POINTs */
546 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
547 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
548 POINT *pt = (POINT *)pOutput;
550 memcpy(tmp, pOutput, ret * sizeof(POINT16));
551 for(i = 0; i < ret; i++, pt++)
556 HeapFree( GetProcessHeap(), 0, tmp );
562 /*****************************************************************************
563 * DeviceCapabilitiesW [WINSPOOL.@]
565 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
568 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
569 WORD fwCapability, LPWSTR pOutput,
570 const DEVMODEW *pDevMode)
572 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
573 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
574 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
577 if(pOutput && (fwCapability == DC_BINNAMES ||
578 fwCapability == DC_FILEDEPENDENCIES ||
579 fwCapability == DC_PAPERNAMES)) {
580 /* These need A -> W translation */
583 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
587 switch(fwCapability) {
592 case DC_FILEDEPENDENCIES:
596 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
597 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
599 for(i = 0; i < ret; i++)
600 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
601 pOutput + (i * size), size);
602 HeapFree(GetProcessHeap(), 0, pOutputA);
604 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
605 (LPSTR)pOutput, dmA);
607 HeapFree(GetProcessHeap(),0,pPortA);
608 HeapFree(GetProcessHeap(),0,pDeviceA);
609 HeapFree(GetProcessHeap(),0,dmA);
613 /******************************************************************
614 * DocumentPropertiesA [WINSPOOL.@]
617 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
618 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
619 LPDEVMODEA pDevModeInput,DWORD fMode )
621 LPSTR lpName = pDeviceName;
624 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
625 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
629 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
631 ERR("no name from hPrinter?\n");
634 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
637 if (!GDI_CallExtDeviceMode16)
639 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
641 if (!GDI_CallExtDeviceMode16) {
642 ERR("No CallExtDeviceMode16?\n");
646 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
647 pDevModeInput, NULL, fMode);
650 HeapFree(GetProcessHeap(),0,lpName);
655 /*****************************************************************************
656 * DocumentPropertiesW (WINSPOOL.@)
658 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
660 LPDEVMODEW pDevModeOutput,
661 LPDEVMODEW pDevModeInput, DWORD fMode)
664 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
665 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
666 LPDEVMODEA pDevModeOutputA = NULL;
669 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
670 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
673 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
674 if(ret < 0) return ret;
675 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
677 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
678 pDevModeInputA, fMode);
680 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
681 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
683 if(fMode == 0 && ret > 0)
684 ret += (CCHDEVICENAME + CCHFORMNAME);
685 HeapFree(GetProcessHeap(),0,pDevModeInputA);
686 HeapFree(GetProcessHeap(),0,pDeviceNameA);
690 /******************************************************************
691 * OpenPrinterA [WINSPOOL.@]
694 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
695 LPPRINTER_DEFAULTSA pDefault)
697 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
698 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
702 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
703 pDefault->pDatatype);
704 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
706 DefaultW.DesiredAccess = pDefault->DesiredAccess;
707 pDefaultW = &DefaultW;
709 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
711 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
712 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
714 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
718 /******************************************************************
719 * OpenPrinterW [WINSPOOL.@]
722 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
723 LPPRINTER_DEFAULTSW pDefault)
725 HKEY hkeyPrinters, hkeyPrinter;
727 if (!lpPrinterName) {
728 WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
729 SetLastError(ERROR_INVALID_PARAMETER);
733 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
736 /* Check Printer exists */
737 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
739 ERR("Can't create Printers key\n");
740 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
744 if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
746 ERR("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
747 RegCloseKey(hkeyPrinters);
748 SetLastError(ERROR_INVALID_PARAMETER);
751 RegCloseKey(hkeyPrinter);
752 RegCloseKey(hkeyPrinters);
754 if(!phPrinter) /* This seems to be what win95 does anyway */
757 /* Get the unique handle of the printer*/
758 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
760 if (pDefault != NULL)
761 FIXME("Not handling pDefault\n");
766 /******************************************************************
767 * AddMonitorA [WINSPOOL.@]
770 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
772 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
773 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
777 /******************************************************************
778 * DeletePrinterDriverA [WINSPOOL.@]
782 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
784 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
785 debugstr_a(pDriverName));
786 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
791 /******************************************************************
792 * DeleteMonitorA [WINSPOOL.@]
796 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
798 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
799 debugstr_a(pMonitorName));
800 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
805 /******************************************************************
806 * DeletePortA [WINSPOOL.@]
810 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
812 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
813 debugstr_a(pPortName));
814 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
818 /******************************************************************************
819 * SetPrinterW [WINSPOOL.@]
829 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
833 /******************************************************************************
834 * WritePrinter [WINSPOOL.@]
844 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
848 /*****************************************************************************
849 * AddFormA [WINSPOOL.@]
851 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
853 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
857 /*****************************************************************************
858 * AddFormW [WINSPOOL.@]
860 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
862 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
866 /*****************************************************************************
867 * AddJobA [WINSPOOL.@]
869 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
870 DWORD cbBuf, LPDWORD pcbNeeded)
872 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
877 /*****************************************************************************
878 * AddJobW [WINSPOOL.@]
880 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
883 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
888 /*****************************************************************************
889 * WINSPOOL_OpenDriverReg [internal]
891 * opens the registry for the printer drivers depending on the given input
892 * variable pEnvironment
895 * the opened hkey on success
898 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
900 LPSTR lpKey, p = NULL;
903 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
906 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
910 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
912 if(!GetVersionExA( &ver))
915 switch (ver.dwPlatformId) {
916 case VER_PLATFORM_WIN32s:
918 case VER_PLATFORM_WIN32_NT:
919 p = "Windows NT x86";
925 TRACE("set environment to %s\n", p);
928 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
929 strlen(p) + strlen(Drivers));
930 sprintf( lpKey, Drivers, p);
932 TRACE("%s\n", lpKey);
934 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
938 if(pEnvironment && unicode)
939 HeapFree( GetProcessHeap(), 0, p);
940 HeapFree( GetProcessHeap(), 0, lpKey);
945 /*****************************************************************************
946 * AddPrinterW [WINSPOOL.@]
948 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
950 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
954 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
957 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
960 ERR("pName = %s - unsupported\n", debugstr_w(pName));
961 SetLastError(ERROR_INVALID_PARAMETER);
965 ERR("Level = %ld, unsupported!\n", Level);
966 SetLastError(ERROR_INVALID_LEVEL);
969 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
970 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
971 debugstr_w(pi->pPrinterName)
973 SetLastError(ERROR_INVALID_LEVEL);
977 SetLastError(ERROR_INVALID_PARAMETER);
980 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
982 ERR("Can't create Printers key\n");
985 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
986 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
987 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
988 RegCloseKey(hkeyPrinter);
989 RegCloseKey(hkeyPrinters);
992 RegCloseKey(hkeyPrinter);
994 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
996 ERR("Can't create Drivers key\n");
997 RegCloseKey(hkeyPrinters);
1000 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1002 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1003 RegCloseKey(hkeyPrinters);
1004 RegCloseKey(hkeyDrivers);
1005 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1008 RegCloseKey(hkeyDriver);
1009 RegCloseKey(hkeyDrivers);
1011 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1012 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1013 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1014 RegCloseKey(hkeyPrinters);
1018 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1020 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1021 SetLastError(ERROR_INVALID_PRINTER_NAME);
1022 RegCloseKey(hkeyPrinters);
1025 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1026 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1027 RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
1030 /* See if we can load the driver. We may need the devmode structure anyway
1033 * Note that DocumentPropertiesW will briefly try to open the printer we
1034 * just create to find a DEVMODEA struct (it will use the WINEPS default
1035 * one in case it is not there, so we are ok).
1037 size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
1039 FIXME("DocumentProperties fails\n");
1040 size = sizeof(DEVMODEW);
1045 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1047 if (0>DocumentPropertiesW(0,-1,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1048 ERR("DocumentPropertiesW failed!\n");
1049 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1052 /* set devmode to printer name */
1053 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1056 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1057 and we support these drivers. NT writes DEVMODEW so somehow
1058 we'll need to distinguish between these when we support NT
1060 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1061 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1062 dmA->dmSize + dmA->dmDriverExtra);
1063 HeapFree(GetProcessHeap(), 0, dmA);
1065 HeapFree(GetProcessHeap(), 0, dmW);
1066 RegSetValueExW(hkeyPrinter, DescriptionW, 0, REG_SZ, (LPBYTE)pi->pComment,
1068 RegSetValueExW(hkeyPrinter, LocationW, 0, REG_SZ, (LPBYTE)pi->pLocation,
1070 RegSetValueExW(hkeyPrinter, NameW, 0, REG_SZ, (LPBYTE)pi->pPrinterName, 0);
1071 RegSetValueExW(hkeyPrinter, ParametersW, 0, REG_SZ,
1072 (LPBYTE)pi->pParameters, 0);
1073 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)pi->pPortName, 0);
1074 RegSetValueExW(hkeyPrinter, Print_ProcessorW, 0, REG_SZ,
1075 (LPBYTE)pi->pPrintProcessor, 0);
1076 RegSetValueExW(hkeyPrinter, Printer_DriverW, 0, REG_SZ,
1077 (LPBYTE)pi->pDriverName, 0);
1078 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1079 (LPBYTE)&pi->Priority, sizeof(DWORD));
1080 RegSetValueExW(hkeyPrinter, Separator_FileW, 0, REG_SZ,
1081 (LPBYTE)pi->pSepFile, 0);
1082 RegSetValueExW(hkeyPrinter, Share_NameW, 0, REG_SZ, (LPBYTE)pi->pShareName,
1084 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1085 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1086 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1087 (LPBYTE)&pi->Status, sizeof(DWORD));
1088 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1089 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1091 RegCloseKey(hkeyPrinter);
1092 RegCloseKey(hkeyPrinters);
1093 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1094 ERR("OpenPrinter failing\n");
1100 /*****************************************************************************
1101 * AddPrinterA [WINSPOOL.@]
1103 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1106 PRINTER_INFO_2W *piW;
1107 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1110 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1112 ERR("Level = %ld, unsupported!\n", Level);
1113 SetLastError(ERROR_INVALID_LEVEL);
1116 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
1117 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1119 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
1121 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1122 HeapFree(GetProcessHeap(),0,pNameW);
1127 /*****************************************************************************
1128 * ClosePrinter [WINSPOOL.@]
1130 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1132 int i = (int)hPrinter;
1134 TRACE("Handle %d\n", hPrinter);
1136 if ((i <= 0) || (i > nb_printers)) return FALSE;
1137 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1138 printer_array[i - 1] = NULL;
1142 /*****************************************************************************
1143 * DeleteFormA [WINSPOOL.@]
1145 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1147 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
1151 /*****************************************************************************
1152 * DeleteFormW [WINSPOOL.@]
1154 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1156 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
1160 /*****************************************************************************
1161 * DeletePrinter [WINSPOOL.@]
1163 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1165 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1168 if(!lpNameW) return FALSE;
1169 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1171 ERR("Can't open Printers key\n");
1175 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1176 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1177 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1178 RegCloseKey(hkeyPrinters);
1182 ClosePrinter(hPrinter);
1186 /*****************************************************************************
1187 * SetPrinterA [WINSPOOL.@]
1189 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1192 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1196 /*****************************************************************************
1197 * SetJobA [WINSPOOL.@]
1199 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1200 LPBYTE pJob, DWORD Command)
1202 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1207 /*****************************************************************************
1208 * SetJobW [WINSPOOL.@]
1210 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1211 LPBYTE pJob, DWORD Command)
1213 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1218 /*****************************************************************************
1219 * GetFormA [WINSPOOL.@]
1221 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1222 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1224 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1225 Level,pForm,cbBuf,pcbNeeded);
1229 /*****************************************************************************
1230 * GetFormW [WINSPOOL.@]
1232 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1233 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1235 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1236 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1240 /*****************************************************************************
1241 * SetFormA [WINSPOOL.@]
1243 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1246 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1250 /*****************************************************************************
1251 * SetFormW [WINSPOOL.@]
1253 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1256 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1260 /*****************************************************************************
1261 * ReadPrinter [WINSPOOL.@]
1263 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1264 LPDWORD pNoBytesRead)
1266 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1270 /*****************************************************************************
1271 * ResetPrinterA [WINSPOOL.@]
1273 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1275 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1279 /*****************************************************************************
1280 * ResetPrinterW [WINSPOOL.@]
1282 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1284 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1288 /*****************************************************************************
1289 * WINSPOOL_GetDWORDFromReg
1291 * Return DWORD associated with ValueName from hkey.
1293 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1295 DWORD sz = sizeof(DWORD), type, value = 0;
1298 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1300 if(ret != ERROR_SUCCESS) {
1301 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1304 if(type != REG_DWORD) {
1305 ERR("Got type %ld\n", type);
1311 /*****************************************************************************
1312 * WINSPOOL_GetStringFromReg
1314 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1315 * String is stored either as unicode or ascii.
1316 * Bit of a hack here to get the ValueName if we want ascii.
1318 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1319 DWORD buflen, DWORD *needed,
1322 DWORD sz = buflen, type;
1326 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1328 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1329 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1330 HeapFree(GetProcessHeap(),0,ValueNameA);
1332 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1333 WARN("Got ret = %ld\n", ret);
1341 /*****************************************************************************
1342 * WINSPOOL_GetDevModeFromReg
1344 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1345 * DevMode is stored either as unicode or ascii.
1347 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1349 DWORD buflen, DWORD *needed,
1352 DWORD sz = buflen, type;
1355 if (ptr) memset(ptr, 0, sizeof(DEVMODEA));
1356 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1357 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1358 if (sz < sizeof(DEVMODEA))
1360 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1363 /* ensures that dmSize is not erratically bogus if registry is invalid */
1364 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1365 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1367 sz += (CCHDEVICENAME + CCHFORMNAME);
1369 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1370 memcpy(ptr, dmW, sz);
1371 HeapFree(GetProcessHeap(),0,dmW);
1378 /*********************************************************************
1379 * WINSPOOL_GetPrinter_2
1381 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1382 * The strings are either stored as unicode or ascii.
1384 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1385 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1388 DWORD size, left = cbBuf;
1389 BOOL space = (cbBuf > 0);
1394 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1396 if(space && size <= left) {
1397 pi2->pPrinterName = (LPWSTR)ptr;
1404 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1406 if(space && size <= left) {
1407 pi2->pShareName = (LPWSTR)ptr;
1414 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1416 if(space && size <= left) {
1417 pi2->pPortName = (LPWSTR)ptr;
1424 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1426 if(space && size <= left) {
1427 pi2->pDriverName = (LPWSTR)ptr;
1434 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1436 if(space && size <= left) {
1437 pi2->pComment = (LPWSTR)ptr;
1444 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1446 if(space && size <= left) {
1447 pi2->pLocation = (LPWSTR)ptr;
1454 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1456 if(space && size <= left) {
1457 pi2->pDevMode = (LPDEVMODEW)ptr;
1464 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1466 if(space && size <= left) {
1467 pi2->pSepFile = (LPWSTR)ptr;
1474 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1476 if(space && size <= left) {
1477 pi2->pPrintProcessor = (LPWSTR)ptr;
1484 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1486 if(space && size <= left) {
1487 pi2->pDatatype = (LPWSTR)ptr;
1494 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1496 if(space && size <= left) {
1497 pi2->pParameters = (LPWSTR)ptr;
1505 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1506 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1507 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1508 "Default Priority");
1509 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1510 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1513 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1514 memset(pi2, 0, sizeof(*pi2));
1519 /*********************************************************************
1520 * WINSPOOL_GetPrinter_4
1522 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1524 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1525 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1528 DWORD size, left = cbBuf;
1529 BOOL space = (cbBuf > 0);
1534 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1536 if(space && size <= left) {
1537 pi4->pPrinterName = (LPWSTR)ptr;
1545 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1548 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1549 memset(pi4, 0, sizeof(*pi4));
1554 /*********************************************************************
1555 * WINSPOOL_GetPrinter_5
1557 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1559 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1560 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1563 DWORD size, left = cbBuf;
1564 BOOL space = (cbBuf > 0);
1569 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1571 if(space && size <= left) {
1572 pi5->pPrinterName = (LPWSTR)ptr;
1579 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1581 if(space && size <= left) {
1582 pi5->pPortName = (LPWSTR)ptr;
1590 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1591 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1593 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1597 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1598 memset(pi5, 0, sizeof(*pi5));
1603 /*****************************************************************************
1604 * WINSPOOL_GetPrinter
1606 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1607 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1608 * just a collection of pointers to strings.
1610 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1611 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1614 DWORD size, needed = 0;
1616 HKEY hkeyPrinter, hkeyPrinters;
1619 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1621 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1623 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1625 ERR("Can't create Printers key\n");
1628 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1630 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1631 RegCloseKey(hkeyPrinters);
1632 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1639 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1641 size = sizeof(PRINTER_INFO_2W);
1643 ptr = pPrinter + size;
1645 memset(pPrinter, 0, size);
1650 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1658 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1660 size = sizeof(PRINTER_INFO_4W);
1662 ptr = pPrinter + size;
1664 memset(pPrinter, 0, size);
1669 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1678 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1680 size = sizeof(PRINTER_INFO_5W);
1682 ptr = pPrinter + size;
1684 memset(pPrinter, 0, size);
1690 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1697 FIXME("Unimplemented level %ld\n", Level);
1698 SetLastError(ERROR_INVALID_LEVEL);
1699 RegCloseKey(hkeyPrinters);
1700 RegCloseKey(hkeyPrinter);
1704 RegCloseKey(hkeyPrinter);
1705 RegCloseKey(hkeyPrinters);
1707 TRACE("returing %d needed = %ld\n", ret, needed);
1708 if(pcbNeeded) *pcbNeeded = needed;
1710 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1714 /*****************************************************************************
1715 * GetPrinterW [WINSPOOL.@]
1717 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1718 DWORD cbBuf, LPDWORD pcbNeeded)
1720 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1724 /*****************************************************************************
1725 * GetPrinterA [WINSPOOL.@]
1727 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1728 DWORD cbBuf, LPDWORD pcbNeeded)
1730 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1734 /*****************************************************************************
1735 * WINSPOOL_EnumPrinters
1737 * Implementation of EnumPrintersA|W
1739 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1740 DWORD dwLevel, LPBYTE lpbPrinters,
1741 DWORD cbBuf, LPDWORD lpdwNeeded,
1742 LPDWORD lpdwReturned, BOOL unicode)
1745 HKEY hkeyPrinters, hkeyPrinter;
1746 WCHAR PrinterName[255];
1747 DWORD needed = 0, number = 0;
1748 DWORD used, i, left;
1752 memset(lpbPrinters, 0, cbBuf);
1758 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1759 if(dwType == PRINTER_ENUM_DEFAULT)
1762 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1763 FIXME("dwType = %08lx\n", dwType);
1764 SetLastError(ERROR_INVALID_FLAGS);
1768 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1770 ERR("Can't create Printers key\n");
1774 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1775 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1776 RegCloseKey(hkeyPrinters);
1777 ERR("Can't query Printers key\n");
1780 TRACE("Found %ld printers\n", number);
1784 RegCloseKey(hkeyPrinters);
1786 *lpdwReturned = number;
1790 used = number * sizeof(PRINTER_INFO_2W);
1793 used = number * sizeof(PRINTER_INFO_4W);
1796 used = number * sizeof(PRINTER_INFO_5W);
1800 SetLastError(ERROR_INVALID_LEVEL);
1801 RegCloseKey(hkeyPrinters);
1804 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1806 for(i = 0; i < number; i++) {
1807 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1809 ERR("Can't enum key number %ld\n", i);
1810 RegCloseKey(hkeyPrinters);
1813 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1814 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1816 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1817 RegCloseKey(hkeyPrinters);
1822 buf = lpbPrinters + used;
1823 left = cbBuf - used;
1831 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1832 left, &needed, unicode);
1834 if(pi) pi += sizeof(PRINTER_INFO_2W);
1837 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1838 left, &needed, unicode);
1840 if(pi) pi += sizeof(PRINTER_INFO_4W);
1843 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1844 left, &needed, unicode);
1846 if(pi) pi += sizeof(PRINTER_INFO_5W);
1849 ERR("Shouldn't be here!\n");
1850 RegCloseKey(hkeyPrinter);
1851 RegCloseKey(hkeyPrinters);
1854 RegCloseKey(hkeyPrinter);
1856 RegCloseKey(hkeyPrinters);
1863 memset(lpbPrinters, 0, cbBuf);
1864 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1868 *lpdwReturned = number;
1869 SetLastError(ERROR_SUCCESS);
1874 /******************************************************************
1875 * EnumPrintersW [WINSPOOL.@]
1877 * Enumerates the available printers, print servers and print
1878 * providers, depending on the specified flags, name and level.
1882 * If level is set to 1:
1883 * Not implemented yet!
1884 * Returns TRUE with an empty list.
1886 * If level is set to 2:
1887 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1888 * Returns an array of PRINTER_INFO_2 data structures in the
1889 * lpbPrinters buffer. Note that according to MSDN also an
1890 * OpenPrinter should be performed on every remote printer.
1892 * If level is set to 4 (officially WinNT only):
1893 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1894 * Fast: Only the registry is queried to retrieve printer names,
1895 * no connection to the driver is made.
1896 * Returns an array of PRINTER_INFO_4 data structures in the
1897 * lpbPrinters buffer.
1899 * If level is set to 5 (officially WinNT4/Win9x only):
1900 * Fast: Only the registry is queried to retrieve printer names,
1901 * no connection to the driver is made.
1902 * Returns an array of PRINTER_INFO_5 data structures in the
1903 * lpbPrinters buffer.
1905 * If level set to 3 or 6+:
1906 * returns zero (failure!)
1908 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
1912 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
1913 * - Only levels 2, 4 and 5 are implemented at the moment.
1914 * - 16-bit printer drivers are not enumerated.
1915 * - Returned amount of bytes used/needed does not match the real Windoze
1916 * implementation (as in this implementation, all strings are part
1917 * of the buffer, whereas Win32 keeps them somewhere else)
1918 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1921 * - In a regular Wine installation, no registry settings for printers
1922 * exist, which makes this function return an empty list.
1924 BOOL WINAPI EnumPrintersW(
1925 DWORD dwType, /* [in] Types of print objects to enumerate */
1926 LPWSTR lpszName, /* [in] name of objects to enumerate */
1927 DWORD dwLevel, /* [in] type of printer info structure */
1928 LPBYTE lpbPrinters, /* [out] buffer which receives info */
1929 DWORD cbBuf, /* [in] max size of buffer in bytes */
1930 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
1931 LPDWORD lpdwReturned /* [out] number of entries returned */
1934 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
1935 lpdwNeeded, lpdwReturned, TRUE);
1938 /******************************************************************
1939 * EnumPrintersA [WINSPOOL.@]
1942 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1943 DWORD dwLevel, LPBYTE lpbPrinters,
1944 DWORD cbBuf, LPDWORD lpdwNeeded,
1945 LPDWORD lpdwReturned)
1948 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1950 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
1951 lpdwNeeded, lpdwReturned, FALSE);
1952 HeapFree(GetProcessHeap(),0,lpszNameW);
1956 /*****************************************************************************
1957 * WINSPOOL_GetDriverInfoFromReg [internal]
1959 * Enters the information from the registry into the DRIVER_INFO struct
1962 * zero if the printer driver does not exist in the registry
1963 * (only if Level > 1) otherwise nonzero
1965 static BOOL WINSPOOL_GetDriverInfoFromReg(
1968 LPWSTR pEnvironment,
1970 LPBYTE ptr, /* DRIVER_INFO */
1971 LPBYTE pDriverStrings, /* strings buffer */
1972 DWORD cbBuf, /* size of string buffer */
1973 LPDWORD pcbNeeded, /* space needed for str. */
1974 BOOL unicode) /* type of strings */
1975 { DWORD dw, size, tmp, type;
1977 LPBYTE strPtr = pDriverStrings;
1979 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
1980 debugstr_w(DriverName), debugstr_w(pEnvironment),
1981 Level, ptr, pDriverStrings, cbBuf, unicode);
1984 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1985 if (*pcbNeeded <= cbBuf)
1986 strcpyW((LPWSTR)strPtr, DriverName);
1988 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1990 if(*pcbNeeded <= cbBuf)
1991 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
1996 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2000 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2001 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2004 if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2005 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
2006 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2011 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2013 WARN("Can't get Version\n");
2015 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2018 pEnvironment = DefaultEnvironmentW;
2020 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2022 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2025 if(*pcbNeeded <= cbBuf) {
2027 strcpyW((LPWSTR)strPtr, pEnvironment);
2029 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2032 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2033 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2036 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2039 if(*pcbNeeded <= cbBuf)
2040 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2043 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2044 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2047 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2050 if(*pcbNeeded <= cbBuf)
2051 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2054 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2055 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2058 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2059 0, &size, unicode)) {
2061 if(*pcbNeeded <= cbBuf)
2062 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2063 size, &tmp, unicode);
2065 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2066 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2070 RegCloseKey(hkeyDriver);
2071 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2075 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2078 if(*pcbNeeded <= cbBuf)
2079 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2080 size, &tmp, unicode);
2082 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2083 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2086 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2089 if(*pcbNeeded <= cbBuf)
2090 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2091 size, &tmp, unicode);
2093 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2094 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2097 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2100 if(*pcbNeeded <= cbBuf)
2101 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2102 size, &tmp, unicode);
2104 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2105 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2108 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2111 if(*pcbNeeded <= cbBuf)
2112 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2113 size, &tmp, unicode);
2115 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2116 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2119 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2120 RegCloseKey(hkeyDriver);
2124 /*****************************************************************************
2125 * WINSPOOL_GetPrinterDriver
2127 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2128 DWORD Level, LPBYTE pDriverInfo,
2129 DWORD cbBuf, LPDWORD pcbNeeded,
2133 WCHAR DriverName[100];
2134 DWORD ret, type, size, needed = 0;
2136 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2138 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2139 Level,pDriverInfo,cbBuf, pcbNeeded);
2141 ZeroMemory(pDriverInfo, cbBuf);
2143 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2145 if(Level < 1 || Level > 3) {
2146 SetLastError(ERROR_INVALID_LEVEL);
2149 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2151 ERR("Can't create Printers key\n");
2154 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2156 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2157 RegCloseKey(hkeyPrinters);
2158 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2161 size = sizeof(DriverName);
2162 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2163 (LPBYTE)DriverName, &size);
2164 RegCloseKey(hkeyPrinter);
2165 RegCloseKey(hkeyPrinters);
2166 if(ret != ERROR_SUCCESS) {
2167 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2171 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2173 ERR("Can't create Drivers key\n");
2179 size = sizeof(DRIVER_INFO_1W);
2182 size = sizeof(DRIVER_INFO_2W);
2185 size = sizeof(DRIVER_INFO_3W);
2188 ERR("Invalid level\n");
2193 ptr = pDriverInfo + size;
2195 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2196 pEnvironment, Level, pDriverInfo,
2197 (cbBuf < size) ? NULL : ptr,
2198 (cbBuf < size) ? 0 : cbBuf - size,
2199 &needed, unicode)) {
2200 RegCloseKey(hkeyDrivers);
2204 RegCloseKey(hkeyDrivers);
2206 if(pcbNeeded) *pcbNeeded = size + needed;
2207 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2208 if(cbBuf >= needed) return TRUE;
2209 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2213 /*****************************************************************************
2214 * GetPrinterDriverA [WINSPOOL.@]
2216 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2217 DWORD Level, LPBYTE pDriverInfo,
2218 DWORD cbBuf, LPDWORD pcbNeeded)
2221 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2222 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2223 cbBuf, pcbNeeded, FALSE);
2224 HeapFree(GetProcessHeap(),0,pEnvW);
2227 /*****************************************************************************
2228 * GetPrinterDriverW [WINSPOOL.@]
2230 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2231 DWORD Level, LPBYTE pDriverInfo,
2232 DWORD cbBuf, LPDWORD pcbNeeded)
2234 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2235 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2238 /*****************************************************************************
2239 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2241 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2242 DWORD Level, LPBYTE pDriverDirectory,
2243 DWORD cbBuf, LPDWORD pcbNeeded)
2247 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2248 pDriverDirectory, cbBuf, pcbNeeded);
2250 FIXME("pName = `%s' - unsupported\n", pName);
2251 SetLastError(ERROR_INVALID_PARAMETER);
2254 if(pEnvironment != NULL) {
2255 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2256 SetLastError(ERROR_INVALID_ENVIRONMENT);
2259 if(Level != 1) /* win95 ignores this so we just carry on */
2260 WARN("Level = %ld - assuming 1\n", Level);
2262 /* FIXME should read from registry */
2263 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2266 *pcbNeeded = needed;
2267 if(needed > cbBuf) {
2268 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2275 /*****************************************************************************
2276 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2278 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2279 DWORD Level, LPBYTE pDriverDirectory,
2280 DWORD cbBuf, LPDWORD pcbNeeded)
2282 LPSTR pNameA = NULL, pEnvironmentA = NULL;
2286 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2288 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2289 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2290 pDriverDirectory, cbBuf, pcbNeeded );
2292 HeapFree( GetProcessHeap(), 0, pNameA );
2294 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2299 /*****************************************************************************
2300 * AddPrinterDriverA [WINSPOOL.@]
2302 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2305 HKEY hkeyDrivers, hkeyName;
2307 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
2309 if(level != 2 && level != 3) {
2310 SetLastError(ERROR_INVALID_LEVEL);
2314 FIXME("pName= `%s' - unsupported\n", pName);
2315 SetLastError(ERROR_INVALID_PARAMETER);
2319 WARN("pDriverInfo == NULL\n");
2320 SetLastError(ERROR_INVALID_PARAMETER);
2325 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2327 memset(&di3, 0, sizeof(di3));
2328 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2331 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2333 SetLastError(ERROR_INVALID_PARAMETER);
2336 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2337 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2338 if(!di3.pHelpFile) di3.pHelpFile = "";
2339 if(!di3.pMonitorName) di3.pMonitorName = "";
2341 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2344 ERR("Can't create Drivers key\n");
2348 if(level == 2) { /* apparently can't overwrite with level2 */
2349 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2350 RegCloseKey(hkeyName);
2351 RegCloseKey(hkeyDrivers);
2352 WARN("Trying to create existing printer driver `%s'\n", di3.pName);
2353 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2357 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2358 RegCloseKey(hkeyDrivers);
2359 ERR("Can't create Name key\n");
2362 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2364 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2365 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2366 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2368 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2369 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2370 di3.pDependentFiles, 0);
2371 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2372 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2373 RegCloseKey(hkeyName);
2374 RegCloseKey(hkeyDrivers);
2378 /*****************************************************************************
2379 * AddPrinterDriverW [WINSPOOL.@]
2381 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2384 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2390 /*****************************************************************************
2391 * PrinterProperties [WINSPOOL.@]
2393 * Displays a dialog to set the properties of the printer.
2396 * nonzero on success or zero on failure
2399 * implemented as stub only
2401 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2402 HANDLE hPrinter /* [in] handle to printer object */
2404 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2405 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2409 /*****************************************************************************
2410 * EnumJobsA [WINSPOOL.@]
2413 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2414 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2418 if(pcbNeeded) *pcbNeeded = 0;
2419 if(pcReturned) *pcReturned = 0;
2424 /*****************************************************************************
2425 * EnumJobsW [WINSPOOL.@]
2428 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2429 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2433 if(pcbNeeded) *pcbNeeded = 0;
2434 if(pcReturned) *pcReturned = 0;
2438 /*****************************************************************************
2439 * WINSPOOL_EnumPrinterDrivers [internal]
2441 * Delivers information about all printer drivers installed on the
2442 * localhost or a given server
2445 * nonzero on success or zero on failure. If the buffer for the returned
2446 * information is too small the function will return an error
2449 * - only implemented for localhost, foreign hosts will return an error
2451 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2452 DWORD Level, LPBYTE pDriverInfo,
2453 DWORD cbBuf, LPDWORD pcbNeeded,
2454 LPDWORD pcReturned, BOOL unicode)
2457 DWORD i, needed, number = 0, size = 0;
2458 WCHAR DriverNameW[255];
2461 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2462 debugstr_w(pName), debugstr_w(pEnvironment),
2463 Level, pDriverInfo, cbBuf, unicode);
2465 /* check for local drivers */
2467 ERR("remote drivers unsupported! Current remote host is %s\n",
2472 /* check input parameter */
2473 if((Level < 1) || (Level > 3)) {
2474 ERR("unsupported level %ld \n", Level);
2478 /* initialize return values */
2480 memset( pDriverInfo, 0, cbBuf);
2484 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2486 ERR("Can't open Drivers key\n");
2490 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2491 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2492 RegCloseKey(hkeyDrivers);
2493 ERR("Can't query Drivers key\n");
2496 TRACE("Found %ld Drivers\n", number);
2498 /* get size of single struct
2499 * unicode and ascii structure have the same size
2503 size = sizeof(DRIVER_INFO_1A);
2506 size = sizeof(DRIVER_INFO_2A);
2509 size = sizeof(DRIVER_INFO_3A);
2513 /* calculate required buffer size */
2514 *pcbNeeded = size * number;
2516 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2518 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2519 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2521 ERR("Can't enum key number %ld\n", i);
2522 RegCloseKey(hkeyDrivers);
2525 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2526 pEnvironment, Level, ptr,
2527 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2528 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2529 &needed, unicode)) {
2530 RegCloseKey(hkeyDrivers);
2533 (*pcbNeeded) += needed;
2536 RegCloseKey(hkeyDrivers);
2538 if(cbBuf < *pcbNeeded){
2539 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2546 /*****************************************************************************
2547 * EnumPrinterDriversW [WINSPOOL.@]
2549 * see function EnumPrinterDrivers for RETURNS, BUGS
2551 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2552 LPBYTE pDriverInfo, DWORD cbBuf,
2553 LPDWORD pcbNeeded, LPDWORD pcReturned)
2555 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2556 cbBuf, pcbNeeded, pcReturned, TRUE);
2559 /*****************************************************************************
2560 * EnumPrinterDriversA [WINSPOOL.@]
2562 * see function EnumPrinterDrivers for RETURNS, BUGS
2564 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2565 LPBYTE pDriverInfo, DWORD cbBuf,
2566 LPDWORD pcbNeeded, LPDWORD pcReturned)
2568 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2571 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2573 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2575 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2576 cbBuf, pcbNeeded, pcReturned, FALSE);
2578 HeapFree(GetProcessHeap(), 0, pNameW);
2580 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2586 /******************************************************************************
2587 * EnumPortsA (WINSPOOL.@)
2589 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2590 LPDWORD bufneeded,LPDWORD bufreturned)
2592 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2596 /******************************************************************************
2597 * SetPrinterDataExA (WINSPOOL.@)
2599 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2600 LPSTR pValueName, DWORD Type,
2601 LPBYTE pData, DWORD cbData)
2603 HKEY hkeyPrinter, hkeySubkey;
2606 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2607 debugstr_a(pValueName), Type, pData, cbData);
2609 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2613 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2615 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2616 RegCloseKey(hkeyPrinter);
2619 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2620 RegCloseKey(hkeySubkey);
2621 RegCloseKey(hkeyPrinter);
2625 /******************************************************************************
2626 * SetPrinterDataExW (WINSPOOL.@)
2628 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2629 LPWSTR pValueName, DWORD Type,
2630 LPBYTE pData, DWORD cbData)
2632 HKEY hkeyPrinter, hkeySubkey;
2635 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2636 debugstr_w(pValueName), Type, pData, cbData);
2638 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2642 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2644 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2645 RegCloseKey(hkeyPrinter);
2648 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2649 RegCloseKey(hkeySubkey);
2650 RegCloseKey(hkeyPrinter);
2654 /******************************************************************************
2655 * SetPrinterDataA (WINSPOOL.@)
2657 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2658 LPBYTE pData, DWORD cbData)
2660 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2664 /******************************************************************************
2665 * SetPrinterDataW (WINSPOOL.@)
2667 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2668 LPBYTE pData, DWORD cbData)
2670 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2674 /******************************************************************************
2675 * GetPrinterDataExA (WINSPOOL.@)
2677 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2678 LPSTR pValueName, LPDWORD pType,
2679 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2681 HKEY hkeyPrinter, hkeySubkey;
2684 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2685 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2688 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2692 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2694 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2695 RegCloseKey(hkeyPrinter);
2699 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2700 RegCloseKey(hkeySubkey);
2701 RegCloseKey(hkeyPrinter);
2705 /******************************************************************************
2706 * GetPrinterDataExW (WINSPOOL.@)
2708 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2709 LPWSTR pValueName, LPDWORD pType,
2710 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2712 HKEY hkeyPrinter, hkeySubkey;
2715 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2716 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2719 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2723 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2725 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2726 RegCloseKey(hkeyPrinter);
2730 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2731 RegCloseKey(hkeySubkey);
2732 RegCloseKey(hkeyPrinter);
2736 /******************************************************************************
2737 * GetPrinterDataA (WINSPOOL.@)
2739 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
2740 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2742 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
2743 pData, nSize, pcbNeeded);
2746 /******************************************************************************
2747 * GetPrinterDataW (WINSPOOL.@)
2749 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
2750 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2752 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
2753 pData, nSize, pcbNeeded);
2756 /*******************************************************************************
2757 * EnumPrinterDataExW [WINSPOOL.@]
2759 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
2760 LPBYTE pEnumValues, DWORD cbEnumValues,
2761 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2763 HKEY hkPrinter, hkSubKey;
2764 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
2765 cbValueNameLen, cbMaxValueLen, cbValueLen,
2770 PPRINTER_ENUM_VALUESW ppev;
2772 TRACE ("%08x %s\n", hPrinter, debugstr_w (pKeyName));
2774 if (pKeyName == NULL || *pKeyName == 0)
2775 return ERROR_INVALID_PARAMETER;
2777 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
2778 if (ret != ERROR_SUCCESS)
2780 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%08x) returned %li\n",
2785 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
2786 if (ret != ERROR_SUCCESS)
2788 r = RegCloseKey (hkPrinter);
2789 if (r != ERROR_SUCCESS)
2790 WARN ("RegCloseKey returned %li\n", r);
2791 TRACE ("RegOpenKeyExW (%08x, %s) returned %li\n", hPrinter,
2792 debugstr_w (pKeyName), ret);
2796 ret = RegCloseKey (hkPrinter);
2797 if (ret != ERROR_SUCCESS)
2799 ERR ("RegCloseKey returned %li\n", ret);
2800 r = RegCloseKey (hkSubKey);
2801 if (r != ERROR_SUCCESS)
2802 WARN ("RegCloseKey returned %li\n", r);
2806 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
2807 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
2808 if (ret != ERROR_SUCCESS)
2810 r = RegCloseKey (hkSubKey);
2811 if (r != ERROR_SUCCESS)
2812 WARN ("RegCloseKey returned %li\n", r);
2813 TRACE ("RegQueryInfoKeyW (%08x) returned %li\n", hkSubKey, ret);
2817 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
2818 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
2820 if (cValues == 0) /* empty key */
2822 r = RegCloseKey (hkSubKey);
2823 if (r != ERROR_SUCCESS)
2824 WARN ("RegCloseKey returned %li\n", r);
2825 *pcbEnumValues = *pnEnumValues = 0;
2826 return ERROR_SUCCESS;
2829 ++cbMaxValueNameLen; /* allow for trailing '\0' */
2831 hHeap = GetProcessHeap ();
2832 if (hHeap == (HANDLE) NULL)
2834 ERR ("GetProcessHeap failed\n");
2835 r = RegCloseKey (hkSubKey);
2836 if (r != ERROR_SUCCESS)
2837 WARN ("RegCloseKey returned %li\n", r);
2838 return ERROR_OUTOFMEMORY;
2841 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
2842 if (lpValueName == NULL)
2844 ERR ("Failed to allocate %li bytes from process heap\n",
2845 cbMaxValueNameLen * sizeof (WCHAR));
2846 r = RegCloseKey (hkSubKey);
2847 if (r != ERROR_SUCCESS)
2848 WARN ("RegCloseKey returned %li\n", r);
2849 return ERROR_OUTOFMEMORY;
2852 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
2853 if (lpValue == NULL)
2855 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
2856 if (HeapFree (hHeap, 0, lpValueName) == 0)
2857 WARN ("HeapFree failed with code %li\n", GetLastError ());
2858 r = RegCloseKey (hkSubKey);
2859 if (r != ERROR_SUCCESS)
2860 WARN ("RegCloseKey returned %li\n", r);
2861 return ERROR_OUTOFMEMORY;
2864 TRACE ("pass 1: calculating buffer required for all names and values\n");
2866 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
2868 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
2870 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2872 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2873 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2874 NULL, NULL, lpValue, &cbValueLen);
2875 if (ret != ERROR_SUCCESS)
2877 if (HeapFree (hHeap, 0, lpValue) == 0)
2878 WARN ("HeapFree failed with code %li\n", GetLastError ());
2879 if (HeapFree (hHeap, 0, lpValueName) == 0)
2880 WARN ("HeapFree failed with code %li\n", GetLastError ());
2881 r = RegCloseKey (hkSubKey);
2882 if (r != ERROR_SUCCESS)
2883 WARN ("RegCloseKey returned %li\n", r);
2884 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2888 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
2889 debugstr_w (lpValueName), dwIndex,
2890 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
2892 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
2893 cbBufSize += cbValueLen;
2896 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
2898 *pcbEnumValues = cbBufSize;
2899 *pnEnumValues = cValues;
2901 if (cbEnumValues < cbBufSize) /* buffer too small */
2903 if (HeapFree (hHeap, 0, lpValue) == 0)
2904 WARN ("HeapFree failed with code %li\n", GetLastError ());
2905 if (HeapFree (hHeap, 0, lpValueName) == 0)
2906 WARN ("HeapFree failed with code %li\n", GetLastError ());
2907 r = RegCloseKey (hkSubKey);
2908 if (r != ERROR_SUCCESS)
2909 WARN ("RegCloseKey returned %li\n", r);
2910 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
2911 return ERROR_MORE_DATA;
2914 TRACE ("pass 2: copying all names and values to buffer\n");
2916 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
2917 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
2919 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2921 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2922 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2923 NULL, &dwType, lpValue, &cbValueLen);
2924 if (ret != ERROR_SUCCESS)
2926 if (HeapFree (hHeap, 0, lpValue) == 0)
2927 WARN ("HeapFree failed with code %li\n", GetLastError ());
2928 if (HeapFree (hHeap, 0, lpValueName) == 0)
2929 WARN ("HeapFree failed with code %li\n", GetLastError ());
2930 r = RegCloseKey (hkSubKey);
2931 if (r != ERROR_SUCCESS)
2932 WARN ("RegCloseKey returned %li\n", r);
2933 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2937 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
2938 memcpy (pEnumValues, lpValueName, cbValueNameLen);
2939 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
2940 pEnumValues += cbValueNameLen;
2942 /* return # of *bytes* (including trailing \0), not # of chars */
2943 ppev[dwIndex].cbValueName = cbValueNameLen;
2945 ppev[dwIndex].dwType = dwType;
2947 memcpy (pEnumValues, lpValue, cbValueLen);
2948 ppev[dwIndex].pData = pEnumValues;
2949 pEnumValues += cbValueLen;
2951 ppev[dwIndex].cbData = cbValueLen;
2953 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
2954 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
2957 if (HeapFree (hHeap, 0, lpValue) == 0)
2959 ret = GetLastError ();
2960 ERR ("HeapFree failed with code %li\n", ret);
2961 if (HeapFree (hHeap, 0, lpValueName) == 0)
2962 WARN ("HeapFree failed with code %li\n", GetLastError ());
2963 r = RegCloseKey (hkSubKey);
2964 if (r != ERROR_SUCCESS)
2965 WARN ("RegCloseKey returned %li\n", r);
2969 if (HeapFree (hHeap, 0, lpValueName) == 0)
2971 ret = GetLastError ();
2972 ERR ("HeapFree failed with code %li\n", ret);
2973 r = RegCloseKey (hkSubKey);
2974 if (r != ERROR_SUCCESS)
2975 WARN ("RegCloseKey returned %li\n", r);
2979 ret = RegCloseKey (hkSubKey);
2980 if (ret != ERROR_SUCCESS)
2982 ERR ("RegCloseKey returned %li\n", ret);
2986 return ERROR_SUCCESS;
2989 /*******************************************************************************
2990 * EnumPrinterDataExA [WINSPOOL.@]
2992 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
2993 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
2994 * what Windows 2000 SP1 does.
2997 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
2998 LPBYTE pEnumValues, DWORD cbEnumValues,
2999 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3003 DWORD ret, dwIndex, dwBufSize;
3007 TRACE ("%08x %s\n", hPrinter, pKeyName);
3009 if (pKeyName == NULL || *pKeyName == 0)
3010 return ERROR_INVALID_PARAMETER;
3012 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3015 ret = GetLastError ();
3016 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3020 hHeap = GetProcessHeap ();
3021 if (hHeap == (HANDLE) NULL)
3023 ERR ("GetProcessHeap failed\n");
3024 return ERROR_OUTOFMEMORY;
3027 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3028 if (pKeyNameW == NULL)
3030 ERR ("Failed to allocate %li bytes from process heap\n",
3031 (LONG) len * sizeof (WCHAR));
3032 return ERROR_OUTOFMEMORY;
3035 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3037 ret = GetLastError ();
3038 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3039 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3040 WARN ("HeapFree failed with code %li\n", GetLastError ());
3044 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3045 pcbEnumValues, pnEnumValues);
3046 if (ret != ERROR_SUCCESS)
3048 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3049 WARN ("HeapFree failed with code %li\n", GetLastError ());
3050 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3054 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3056 ret = GetLastError ();
3057 ERR ("HeapFree failed with code %li\n", ret);
3061 if (*pnEnumValues == 0) /* empty key */
3062 return ERROR_SUCCESS;
3065 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3067 PPRINTER_ENUM_VALUESW ppev =
3068 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3070 if (dwBufSize < ppev->cbValueName)
3071 dwBufSize = ppev->cbValueName;
3073 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3074 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3075 dwBufSize = ppev->cbData;
3078 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3080 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3081 if (pBuffer == NULL)
3083 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3084 return ERROR_OUTOFMEMORY;
3087 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3089 PPRINTER_ENUM_VALUESW ppev =
3090 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3092 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3093 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3097 ret = GetLastError ();
3098 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3099 if (HeapFree (hHeap, 0, pBuffer) == 0)
3100 WARN ("HeapFree failed with code %li\n", GetLastError ());
3104 memcpy (ppev->pValueName, pBuffer, len);
3106 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3108 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3109 ppev->dwType != REG_MULTI_SZ)
3112 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3113 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3116 ret = GetLastError ();
3117 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3118 if (HeapFree (hHeap, 0, pBuffer) == 0)
3119 WARN ("HeapFree failed with code %li\n", GetLastError ());
3123 memcpy (ppev->pData, pBuffer, len);
3125 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3126 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3129 if (HeapFree (hHeap, 0, pBuffer) == 0)
3131 ret = GetLastError ();
3132 ERR ("HeapFree failed with code %li\n", ret);
3136 return ERROR_SUCCESS;