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 * DeviceCapabilitiesA [WINSPOOL.150 & WINSPOOL.151]
531 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
532 LPSTR pOutput, LPDEVMODEA lpdm)
536 if (!GDI_CallDeviceCapabilities16)
538 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
540 if (!GDI_CallDeviceCapabilities16) return -1;
542 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
544 /* If DC_PAPERSIZE map POINT16s to POINTs */
545 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
546 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
547 POINT *pt = (POINT *)pOutput;
549 memcpy(tmp, pOutput, ret * sizeof(POINT16));
550 for(i = 0; i < ret; i++, pt++)
555 HeapFree( GetProcessHeap(), 0, tmp );
561 /*****************************************************************************
562 * DeviceCapabilitiesW [WINSPOOL.@]
564 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
567 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
568 WORD fwCapability, LPWSTR pOutput,
569 const DEVMODEW *pDevMode)
571 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
572 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
573 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
576 if(pOutput && (fwCapability == DC_BINNAMES ||
577 fwCapability == DC_FILEDEPENDENCIES ||
578 fwCapability == DC_PAPERNAMES)) {
579 /* These need A -> W translation */
582 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
586 switch(fwCapability) {
591 case DC_FILEDEPENDENCIES:
595 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
596 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
598 for(i = 0; i < ret; i++)
599 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
600 pOutput + (i * size), size);
601 HeapFree(GetProcessHeap(), 0, pOutputA);
603 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
604 (LPSTR)pOutput, dmA);
606 HeapFree(GetProcessHeap(),0,pPortA);
607 HeapFree(GetProcessHeap(),0,pDeviceA);
608 HeapFree(GetProcessHeap(),0,dmA);
612 /******************************************************************
613 * DocumentPropertiesA [WINSPOOL.@]
616 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
617 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
618 LPDEVMODEA pDevModeInput,DWORD fMode )
620 LPSTR lpName = pDeviceName;
623 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
624 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
628 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
630 ERR("no name from hPrinter?\n");
633 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
636 if (!GDI_CallExtDeviceMode16)
638 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
640 if (!GDI_CallExtDeviceMode16) {
641 ERR("No CallExtDeviceMode16?\n");
645 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
646 pDevModeInput, NULL, fMode);
649 HeapFree(GetProcessHeap(),0,lpName);
654 /*****************************************************************************
655 * DocumentPropertiesW (WINSPOOL.@)
657 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
659 LPDEVMODEW pDevModeOutput,
660 LPDEVMODEW pDevModeInput, DWORD fMode)
663 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
664 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
665 LPDEVMODEA pDevModeOutputA = NULL;
668 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
669 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
672 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
673 if(ret < 0) return ret;
674 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
676 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
677 pDevModeInputA, fMode);
679 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
680 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
682 if(fMode == 0 && ret > 0)
683 ret += (CCHDEVICENAME + CCHFORMNAME);
684 HeapFree(GetProcessHeap(),0,pDevModeInputA);
685 HeapFree(GetProcessHeap(),0,pDeviceNameA);
689 /******************************************************************
690 * OpenPrinterA [WINSPOOL.@]
693 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
694 LPPRINTER_DEFAULTSA pDefault)
696 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
697 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
701 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
702 pDefault->pDatatype);
703 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
705 DefaultW.DesiredAccess = pDefault->DesiredAccess;
706 pDefaultW = &DefaultW;
708 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
710 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
711 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
713 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
717 /******************************************************************
718 * OpenPrinterW [WINSPOOL.@]
721 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
722 LPPRINTER_DEFAULTSW pDefault)
724 HKEY hkeyPrinters, hkeyPrinter;
726 if (!lpPrinterName) {
727 WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
728 SetLastError(ERROR_INVALID_PARAMETER);
732 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
735 /* Check Printer exists */
736 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
738 ERR("Can't create Printers key\n");
739 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
743 if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
745 ERR("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
746 RegCloseKey(hkeyPrinters);
747 SetLastError(ERROR_INVALID_PARAMETER);
750 RegCloseKey(hkeyPrinter);
751 RegCloseKey(hkeyPrinters);
753 if(!phPrinter) /* This seems to be what win95 does anyway */
756 /* Get the unique handle of the printer*/
757 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
759 if (pDefault != NULL)
760 FIXME("Not handling pDefault\n");
765 /******************************************************************
766 * AddMonitorA [WINSPOOL.@]
769 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
771 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
772 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
776 /******************************************************************
777 * DeletePrinterDriverA [WINSPOOL.@]
781 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
783 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
784 debugstr_a(pDriverName));
785 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
790 /******************************************************************
791 * DeleteMonitorA [WINSPOOL.@]
795 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
797 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
798 debugstr_a(pMonitorName));
799 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
804 /******************************************************************
805 * DeletePortA [WINSPOOL.@]
809 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
811 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
812 debugstr_a(pPortName));
813 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
817 /******************************************************************************
818 * SetPrinterW [WINSPOOL.@]
828 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
832 /******************************************************************************
833 * WritePrinter [WINSPOOL.@]
843 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
847 /*****************************************************************************
848 * AddFormA [WINSPOOL.@]
850 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
852 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
856 /*****************************************************************************
857 * AddFormW [WINSPOOL.@]
859 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
861 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
865 /*****************************************************************************
866 * AddJobA [WINSPOOL.@]
868 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
869 DWORD cbBuf, LPDWORD pcbNeeded)
871 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
876 /*****************************************************************************
877 * AddJobW [WINSPOOL.@]
879 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
882 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
887 /*****************************************************************************
888 * WINSPOOL_OpenDriverReg [internal]
890 * opens the registry for the printer drivers depending on the given input
891 * variable pEnvironment
894 * the opened hkey on success
897 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
899 LPSTR lpKey, p = NULL;
902 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
905 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
909 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
911 if(!GetVersionExA( &ver))
914 switch (ver.dwPlatformId) {
915 case VER_PLATFORM_WIN32s:
917 case VER_PLATFORM_WIN32_NT:
918 p = "Windows NT x86";
924 TRACE("set environment to %s\n", p);
927 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
928 strlen(p) + strlen(Drivers));
929 sprintf( lpKey, Drivers, p);
931 TRACE("%s\n", lpKey);
933 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
937 if(pEnvironment && unicode)
938 HeapFree( GetProcessHeap(), 0, p);
939 HeapFree( GetProcessHeap(), 0, lpKey);
944 /*****************************************************************************
945 * AddPrinterW [WINSPOOL.@]
947 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
949 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
953 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
956 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
959 ERR("pName = %s - unsupported\n", debugstr_w(pName));
960 SetLastError(ERROR_INVALID_PARAMETER);
964 ERR("Level = %ld, unsupported!\n", Level);
965 SetLastError(ERROR_INVALID_LEVEL);
968 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
969 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
970 debugstr_w(pi->pPrinterName)
972 SetLastError(ERROR_INVALID_LEVEL);
976 SetLastError(ERROR_INVALID_PARAMETER);
979 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
981 ERR("Can't create Printers key\n");
984 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
985 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
986 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
987 RegCloseKey(hkeyPrinter);
988 RegCloseKey(hkeyPrinters);
991 RegCloseKey(hkeyPrinter);
993 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
995 ERR("Can't create Drivers key\n");
996 RegCloseKey(hkeyPrinters);
999 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1001 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1002 RegCloseKey(hkeyPrinters);
1003 RegCloseKey(hkeyDrivers);
1004 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1007 RegCloseKey(hkeyDriver);
1008 RegCloseKey(hkeyDrivers);
1010 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1011 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1012 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1013 RegCloseKey(hkeyPrinters);
1017 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1019 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1020 SetLastError(ERROR_INVALID_PRINTER_NAME);
1021 RegCloseKey(hkeyPrinters);
1024 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1025 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1026 RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
1029 /* See if we can load the driver. We may need the devmode structure anyway
1032 * Note that DocumentPropertiesW will briefly try to open the printer we
1033 * just create to find a DEVMODEA struct (it will use the WINEPS default
1034 * one in case it is not there, so we are ok).
1036 size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
1038 FIXME("DocumentProperties fails\n");
1039 size = sizeof(DEVMODEW);
1044 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1046 if (0>DocumentPropertiesW(0,-1,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1047 ERR("DocumentPropertiesW failed!\n");
1048 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1051 /* set devmode to printer name */
1052 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1055 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1056 and we support these drivers. NT writes DEVMODEW so somehow
1057 we'll need to distinguish between these when we support NT
1059 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1060 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1061 dmA->dmSize + dmA->dmDriverExtra);
1062 HeapFree(GetProcessHeap(), 0, dmA);
1064 HeapFree(GetProcessHeap(), 0, dmW);
1065 RegSetValueExW(hkeyPrinter, DescriptionW, 0, REG_SZ, (LPBYTE)pi->pComment,
1067 RegSetValueExW(hkeyPrinter, LocationW, 0, REG_SZ, (LPBYTE)pi->pLocation,
1069 RegSetValueExW(hkeyPrinter, NameW, 0, REG_SZ, (LPBYTE)pi->pPrinterName, 0);
1070 RegSetValueExW(hkeyPrinter, ParametersW, 0, REG_SZ,
1071 (LPBYTE)pi->pParameters, 0);
1072 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)pi->pPortName, 0);
1073 RegSetValueExW(hkeyPrinter, Print_ProcessorW, 0, REG_SZ,
1074 (LPBYTE)pi->pPrintProcessor, 0);
1075 RegSetValueExW(hkeyPrinter, Printer_DriverW, 0, REG_SZ,
1076 (LPBYTE)pi->pDriverName, 0);
1077 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1078 (LPBYTE)&pi->Priority, sizeof(DWORD));
1079 RegSetValueExW(hkeyPrinter, Separator_FileW, 0, REG_SZ,
1080 (LPBYTE)pi->pSepFile, 0);
1081 RegSetValueExW(hkeyPrinter, Share_NameW, 0, REG_SZ, (LPBYTE)pi->pShareName,
1083 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1084 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1085 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1086 (LPBYTE)&pi->Status, sizeof(DWORD));
1087 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1088 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1090 RegCloseKey(hkeyPrinter);
1091 RegCloseKey(hkeyPrinters);
1092 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1093 ERR("OpenPrinter failing\n");
1099 /*****************************************************************************
1100 * AddPrinterA [WINSPOOL.@]
1102 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1105 PRINTER_INFO_2W *piW;
1106 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1109 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1111 ERR("Level = %ld, unsupported!\n", Level);
1112 SetLastError(ERROR_INVALID_LEVEL);
1115 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
1116 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1118 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
1120 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1121 HeapFree(GetProcessHeap(),0,pNameW);
1126 /*****************************************************************************
1127 * ClosePrinter [WINSPOOL.@]
1129 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1131 int i = (int)hPrinter;
1133 TRACE("Handle %d\n", hPrinter);
1135 if ((i <= 0) || (i > nb_printers)) return FALSE;
1136 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1137 printer_array[i - 1] = NULL;
1141 /*****************************************************************************
1142 * DeleteFormA [WINSPOOL.@]
1144 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1146 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
1150 /*****************************************************************************
1151 * DeleteFormW [WINSPOOL.@]
1153 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1155 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
1159 /*****************************************************************************
1160 * DeletePrinter [WINSPOOL.@]
1162 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1164 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1167 if(!lpNameW) return FALSE;
1168 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1170 ERR("Can't open Printers key\n");
1174 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1175 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1176 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1177 RegCloseKey(hkeyPrinters);
1181 ClosePrinter(hPrinter);
1185 /*****************************************************************************
1186 * SetPrinterA [WINSPOOL.@]
1188 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1191 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1195 /*****************************************************************************
1196 * SetJobA [WINSPOOL.@]
1198 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1199 LPBYTE pJob, DWORD Command)
1201 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1206 /*****************************************************************************
1207 * SetJobW [WINSPOOL.@]
1209 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1210 LPBYTE pJob, DWORD Command)
1212 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1217 /*****************************************************************************
1218 * GetFormA [WINSPOOL.@]
1220 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1221 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1223 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1224 Level,pForm,cbBuf,pcbNeeded);
1228 /*****************************************************************************
1229 * GetFormW [WINSPOOL.@]
1231 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1232 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1234 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1235 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1239 /*****************************************************************************
1240 * SetFormA [WINSPOOL.@]
1242 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1245 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1249 /*****************************************************************************
1250 * SetFormW [WINSPOOL.@]
1252 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1255 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1259 /*****************************************************************************
1260 * ReadPrinter [WINSPOOL.@]
1262 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1263 LPDWORD pNoBytesRead)
1265 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1269 /*****************************************************************************
1270 * ResetPrinterA [WINSPOOL.@]
1272 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1274 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1278 /*****************************************************************************
1279 * ResetPrinterW [WINSPOOL.@]
1281 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1283 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1287 /*****************************************************************************
1288 * WINSPOOL_GetDWORDFromReg
1290 * Return DWORD associated with ValueName from hkey.
1292 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1294 DWORD sz = sizeof(DWORD), type, value = 0;
1297 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1299 if(ret != ERROR_SUCCESS) {
1300 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1303 if(type != REG_DWORD) {
1304 ERR("Got type %ld\n", type);
1310 /*****************************************************************************
1311 * WINSPOOL_GetStringFromReg
1313 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1314 * String is stored either as unicode or ascii.
1315 * Bit of a hack here to get the ValueName if we want ascii.
1317 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1318 DWORD buflen, DWORD *needed,
1321 DWORD sz = buflen, type;
1325 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1327 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1328 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1329 HeapFree(GetProcessHeap(),0,ValueNameA);
1331 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1332 WARN("Got ret = %ld\n", ret);
1340 /*****************************************************************************
1341 * WINSPOOL_GetDevModeFromReg
1343 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1344 * DevMode is stored either as unicode or ascii.
1346 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1348 DWORD buflen, DWORD *needed,
1351 DWORD sz = buflen, type;
1354 if (ptr) memset(ptr, 0, sizeof(DEVMODEA));
1355 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1356 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1357 if (sz < sizeof(DEVMODEA))
1359 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1362 /* ensures that dmSize is not erratically bogus if registry is invalid */
1363 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1364 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1366 sz += (CCHDEVICENAME + CCHFORMNAME);
1368 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1369 memcpy(ptr, dmW, sz);
1370 HeapFree(GetProcessHeap(),0,dmW);
1377 /*********************************************************************
1378 * WINSPOOL_GetPrinter_2
1380 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1381 * The strings are either stored as unicode or ascii.
1383 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1384 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1387 DWORD size, left = cbBuf;
1388 BOOL space = (cbBuf > 0);
1393 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1395 if(space && size <= left) {
1396 pi2->pPrinterName = (LPWSTR)ptr;
1403 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1405 if(space && size <= left) {
1406 pi2->pShareName = (LPWSTR)ptr;
1413 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1415 if(space && size <= left) {
1416 pi2->pPortName = (LPWSTR)ptr;
1423 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1425 if(space && size <= left) {
1426 pi2->pDriverName = (LPWSTR)ptr;
1433 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1435 if(space && size <= left) {
1436 pi2->pComment = (LPWSTR)ptr;
1443 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1445 if(space && size <= left) {
1446 pi2->pLocation = (LPWSTR)ptr;
1453 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1455 if(space && size <= left) {
1456 pi2->pDevMode = (LPDEVMODEW)ptr;
1463 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1465 if(space && size <= left) {
1466 pi2->pSepFile = (LPWSTR)ptr;
1473 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1475 if(space && size <= left) {
1476 pi2->pPrintProcessor = (LPWSTR)ptr;
1483 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1485 if(space && size <= left) {
1486 pi2->pDatatype = (LPWSTR)ptr;
1493 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1495 if(space && size <= left) {
1496 pi2->pParameters = (LPWSTR)ptr;
1504 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1505 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1506 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1507 "Default Priority");
1508 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1509 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1512 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1513 memset(pi2, 0, sizeof(*pi2));
1518 /*********************************************************************
1519 * WINSPOOL_GetPrinter_4
1521 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1523 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1524 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1527 DWORD size, left = cbBuf;
1528 BOOL space = (cbBuf > 0);
1533 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1535 if(space && size <= left) {
1536 pi4->pPrinterName = (LPWSTR)ptr;
1544 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1547 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1548 memset(pi4, 0, sizeof(*pi4));
1553 /*********************************************************************
1554 * WINSPOOL_GetPrinter_5
1556 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1558 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1559 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1562 DWORD size, left = cbBuf;
1563 BOOL space = (cbBuf > 0);
1568 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1570 if(space && size <= left) {
1571 pi5->pPrinterName = (LPWSTR)ptr;
1578 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1580 if(space && size <= left) {
1581 pi5->pPortName = (LPWSTR)ptr;
1589 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1590 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1592 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1596 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1597 memset(pi5, 0, sizeof(*pi5));
1602 /*****************************************************************************
1603 * WINSPOOL_GetPrinter
1605 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1606 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1607 * just a collection of pointers to strings.
1609 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1610 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1613 DWORD size, needed = 0;
1615 HKEY hkeyPrinter, hkeyPrinters;
1618 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1620 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1622 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1624 ERR("Can't create Printers key\n");
1627 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1629 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1630 RegCloseKey(hkeyPrinters);
1631 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1638 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1640 size = sizeof(PRINTER_INFO_2W);
1642 ptr = pPrinter + size;
1644 memset(pPrinter, 0, size);
1649 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1657 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1659 size = sizeof(PRINTER_INFO_4W);
1661 ptr = pPrinter + size;
1663 memset(pPrinter, 0, size);
1668 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1677 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1679 size = sizeof(PRINTER_INFO_5W);
1681 ptr = pPrinter + size;
1683 memset(pPrinter, 0, size);
1689 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1696 FIXME("Unimplemented level %ld\n", Level);
1697 SetLastError(ERROR_INVALID_LEVEL);
1698 RegCloseKey(hkeyPrinters);
1699 RegCloseKey(hkeyPrinter);
1703 RegCloseKey(hkeyPrinter);
1704 RegCloseKey(hkeyPrinters);
1706 TRACE("returing %d needed = %ld\n", ret, needed);
1707 if(pcbNeeded) *pcbNeeded = needed;
1709 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1713 /*****************************************************************************
1714 * GetPrinterW [WINSPOOL.@]
1716 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1717 DWORD cbBuf, LPDWORD pcbNeeded)
1719 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1723 /*****************************************************************************
1724 * GetPrinterA [WINSPOOL.@]
1726 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1727 DWORD cbBuf, LPDWORD pcbNeeded)
1729 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1733 /*****************************************************************************
1734 * WINSPOOL_EnumPrinters
1736 * Implementation of EnumPrintersA|W
1738 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1739 DWORD dwLevel, LPBYTE lpbPrinters,
1740 DWORD cbBuf, LPDWORD lpdwNeeded,
1741 LPDWORD lpdwReturned, BOOL unicode)
1744 HKEY hkeyPrinters, hkeyPrinter;
1745 WCHAR PrinterName[255];
1746 DWORD needed = 0, number = 0;
1747 DWORD used, i, left;
1751 memset(lpbPrinters, 0, cbBuf);
1757 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1758 if(dwType == PRINTER_ENUM_DEFAULT)
1761 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1762 FIXME("dwType = %08lx\n", dwType);
1763 SetLastError(ERROR_INVALID_FLAGS);
1767 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1769 ERR("Can't create Printers key\n");
1773 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1774 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1775 RegCloseKey(hkeyPrinters);
1776 ERR("Can't query Printers key\n");
1779 TRACE("Found %ld printers\n", number);
1783 RegCloseKey(hkeyPrinters);
1785 *lpdwReturned = number;
1789 used = number * sizeof(PRINTER_INFO_2W);
1792 used = number * sizeof(PRINTER_INFO_4W);
1795 used = number * sizeof(PRINTER_INFO_5W);
1799 SetLastError(ERROR_INVALID_LEVEL);
1800 RegCloseKey(hkeyPrinters);
1803 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1805 for(i = 0; i < number; i++) {
1806 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1808 ERR("Can't enum key number %ld\n", i);
1809 RegCloseKey(hkeyPrinters);
1812 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1813 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1815 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1816 RegCloseKey(hkeyPrinters);
1821 buf = lpbPrinters + used;
1822 left = cbBuf - used;
1830 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1831 left, &needed, unicode);
1833 if(pi) pi += sizeof(PRINTER_INFO_2W);
1836 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1837 left, &needed, unicode);
1839 if(pi) pi += sizeof(PRINTER_INFO_4W);
1842 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1843 left, &needed, unicode);
1845 if(pi) pi += sizeof(PRINTER_INFO_5W);
1848 ERR("Shouldn't be here!\n");
1849 RegCloseKey(hkeyPrinter);
1850 RegCloseKey(hkeyPrinters);
1853 RegCloseKey(hkeyPrinter);
1855 RegCloseKey(hkeyPrinters);
1862 memset(lpbPrinters, 0, cbBuf);
1863 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1867 *lpdwReturned = number;
1868 SetLastError(ERROR_SUCCESS);
1873 /******************************************************************
1874 * EnumPrintersW [WINSPOOL.@]
1876 * Enumerates the available printers, print servers and print
1877 * providers, depending on the specified flags, name and level.
1881 * If level is set to 1:
1882 * Not implemented yet!
1883 * Returns TRUE with an empty list.
1885 * If level is set to 2:
1886 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1887 * Returns an array of PRINTER_INFO_2 data structures in the
1888 * lpbPrinters buffer. Note that according to MSDN also an
1889 * OpenPrinter should be performed on every remote printer.
1891 * If level is set to 4 (officially WinNT only):
1892 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1893 * Fast: Only the registry is queried to retrieve printer names,
1894 * no connection to the driver is made.
1895 * Returns an array of PRINTER_INFO_4 data structures in the
1896 * lpbPrinters buffer.
1898 * If level is set to 5 (officially WinNT4/Win9x only):
1899 * Fast: Only the registry is queried to retrieve printer names,
1900 * no connection to the driver is made.
1901 * Returns an array of PRINTER_INFO_5 data structures in the
1902 * lpbPrinters buffer.
1904 * If level set to 3 or 6+:
1905 * returns zero (failure!)
1907 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
1911 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
1912 * - Only levels 2, 4 and 5 are implemented at the moment.
1913 * - 16-bit printer drivers are not enumerated.
1914 * - Returned amount of bytes used/needed does not match the real Windoze
1915 * implementation (as in this implementation, all strings are part
1916 * of the buffer, whereas Win32 keeps them somewhere else)
1917 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1920 * - In a regular Wine installation, no registry settings for printers
1921 * exist, which makes this function return an empty list.
1923 BOOL WINAPI EnumPrintersW(
1924 DWORD dwType, /* [in] Types of print objects to enumerate */
1925 LPWSTR lpszName, /* [in] name of objects to enumerate */
1926 DWORD dwLevel, /* [in] type of printer info structure */
1927 LPBYTE lpbPrinters, /* [out] buffer which receives info */
1928 DWORD cbBuf, /* [in] max size of buffer in bytes */
1929 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
1930 LPDWORD lpdwReturned /* [out] number of entries returned */
1933 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
1934 lpdwNeeded, lpdwReturned, TRUE);
1937 /******************************************************************
1938 * EnumPrintersA [WINSPOOL.@]
1941 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1942 DWORD dwLevel, LPBYTE lpbPrinters,
1943 DWORD cbBuf, LPDWORD lpdwNeeded,
1944 LPDWORD lpdwReturned)
1947 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1949 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
1950 lpdwNeeded, lpdwReturned, FALSE);
1951 HeapFree(GetProcessHeap(),0,lpszNameW);
1955 /*****************************************************************************
1956 * WINSPOOL_GetDriverInfoFromReg [internal]
1958 * Enters the information from the registry into the DRIVER_INFO struct
1961 * zero if the printer driver does not exist in the registry
1962 * (only if Level > 1) otherwise nonzero
1964 static BOOL WINSPOOL_GetDriverInfoFromReg(
1967 LPWSTR pEnvironment,
1969 LPBYTE ptr, /* DRIVER_INFO */
1970 LPBYTE pDriverStrings, /* strings buffer */
1971 DWORD cbBuf, /* size of string buffer */
1972 LPDWORD pcbNeeded, /* space needed for str. */
1973 BOOL unicode) /* type of strings */
1974 { DWORD dw, size, tmp, type;
1976 LPBYTE strPtr = pDriverStrings;
1978 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
1979 debugstr_w(DriverName), debugstr_w(pEnvironment),
1980 Level, ptr, pDriverStrings, cbBuf, unicode);
1983 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1984 if (*pcbNeeded <= cbBuf)
1985 strcpyW((LPWSTR)strPtr, DriverName);
1987 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1989 if(*pcbNeeded <= cbBuf)
1990 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
1995 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
1999 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2000 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2003 if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2004 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
2005 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2010 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2012 WARN("Can't get Version\n");
2014 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2017 pEnvironment = DefaultEnvironmentW;
2019 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2021 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2024 if(*pcbNeeded <= cbBuf) {
2026 strcpyW((LPWSTR)strPtr, pEnvironment);
2028 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2031 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2032 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2035 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2038 if(*pcbNeeded <= cbBuf)
2039 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2042 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2043 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2046 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2049 if(*pcbNeeded <= cbBuf)
2050 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2053 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2054 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2057 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2058 0, &size, unicode)) {
2060 if(*pcbNeeded <= cbBuf)
2061 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2062 size, &tmp, unicode);
2064 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2065 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2069 RegCloseKey(hkeyDriver);
2070 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2074 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2077 if(*pcbNeeded <= cbBuf)
2078 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2079 size, &tmp, unicode);
2081 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2082 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2085 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2088 if(*pcbNeeded <= cbBuf)
2089 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2090 size, &tmp, unicode);
2092 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2093 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2096 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2099 if(*pcbNeeded <= cbBuf)
2100 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2101 size, &tmp, unicode);
2103 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2104 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2107 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2110 if(*pcbNeeded <= cbBuf)
2111 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2112 size, &tmp, unicode);
2114 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2115 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2118 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2119 RegCloseKey(hkeyDriver);
2123 /*****************************************************************************
2124 * WINSPOOL_GetPrinterDriver
2126 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2127 DWORD Level, LPBYTE pDriverInfo,
2128 DWORD cbBuf, LPDWORD pcbNeeded,
2132 WCHAR DriverName[100];
2133 DWORD ret, type, size, needed = 0;
2135 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2137 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2138 Level,pDriverInfo,cbBuf, pcbNeeded);
2140 ZeroMemory(pDriverInfo, cbBuf);
2142 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2144 if(Level < 1 || Level > 3) {
2145 SetLastError(ERROR_INVALID_LEVEL);
2148 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2150 ERR("Can't create Printers key\n");
2153 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2155 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2156 RegCloseKey(hkeyPrinters);
2157 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2160 size = sizeof(DriverName);
2161 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2162 (LPBYTE)DriverName, &size);
2163 RegCloseKey(hkeyPrinter);
2164 RegCloseKey(hkeyPrinters);
2165 if(ret != ERROR_SUCCESS) {
2166 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2170 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2172 ERR("Can't create Drivers key\n");
2178 size = sizeof(DRIVER_INFO_1W);
2181 size = sizeof(DRIVER_INFO_2W);
2184 size = sizeof(DRIVER_INFO_3W);
2187 ERR("Invalid level\n");
2192 ptr = pDriverInfo + size;
2194 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2195 pEnvironment, Level, pDriverInfo,
2196 (cbBuf < size) ? NULL : ptr,
2197 (cbBuf < size) ? 0 : cbBuf - size,
2198 &needed, unicode)) {
2199 RegCloseKey(hkeyDrivers);
2203 RegCloseKey(hkeyDrivers);
2205 if(pcbNeeded) *pcbNeeded = size + needed;
2206 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2207 if(cbBuf >= needed) return TRUE;
2208 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2212 /*****************************************************************************
2213 * GetPrinterDriverA [WINSPOOL.@]
2215 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2216 DWORD Level, LPBYTE pDriverInfo,
2217 DWORD cbBuf, LPDWORD pcbNeeded)
2220 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2221 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2222 cbBuf, pcbNeeded, FALSE);
2223 HeapFree(GetProcessHeap(),0,pEnvW);
2226 /*****************************************************************************
2227 * GetPrinterDriverW [WINSPOOL.@]
2229 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2230 DWORD Level, LPBYTE pDriverInfo,
2231 DWORD cbBuf, LPDWORD pcbNeeded)
2233 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2234 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2237 /*****************************************************************************
2238 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2240 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2241 DWORD Level, LPBYTE pDriverDirectory,
2242 DWORD cbBuf, LPDWORD pcbNeeded)
2246 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2247 pDriverDirectory, cbBuf, pcbNeeded);
2249 FIXME("pName = `%s' - unsupported\n", pName);
2250 SetLastError(ERROR_INVALID_PARAMETER);
2253 if(pEnvironment != NULL) {
2254 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2255 SetLastError(ERROR_INVALID_ENVIRONMENT);
2258 if(Level != 1) /* win95 ignores this so we just carry on */
2259 WARN("Level = %ld - assuming 1\n", Level);
2261 /* FIXME should read from registry */
2262 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2265 *pcbNeeded = needed;
2266 if(needed > cbBuf) {
2267 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2274 /*****************************************************************************
2275 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2277 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2278 DWORD Level, LPBYTE pDriverDirectory,
2279 DWORD cbBuf, LPDWORD pcbNeeded)
2281 LPSTR pNameA = NULL, pEnvironmentA = NULL;
2285 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2287 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2288 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2289 pDriverDirectory, cbBuf, pcbNeeded );
2291 HeapFree( GetProcessHeap(), 0, pNameA );
2293 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2298 /*****************************************************************************
2299 * AddPrinterDriverA [WINSPOOL.@]
2301 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2304 HKEY hkeyDrivers, hkeyName;
2306 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
2308 if(level != 2 && level != 3) {
2309 SetLastError(ERROR_INVALID_LEVEL);
2313 FIXME("pName= `%s' - unsupported\n", pName);
2314 SetLastError(ERROR_INVALID_PARAMETER);
2318 WARN("pDriverInfo == NULL\n");
2319 SetLastError(ERROR_INVALID_PARAMETER);
2324 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2326 memset(&di3, 0, sizeof(di3));
2327 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2330 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2332 SetLastError(ERROR_INVALID_PARAMETER);
2335 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2336 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2337 if(!di3.pHelpFile) di3.pHelpFile = "";
2338 if(!di3.pMonitorName) di3.pMonitorName = "";
2340 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2343 ERR("Can't create Drivers key\n");
2347 if(level == 2) { /* apparently can't overwrite with level2 */
2348 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2349 RegCloseKey(hkeyName);
2350 RegCloseKey(hkeyDrivers);
2351 WARN("Trying to create existing printer driver `%s'\n", di3.pName);
2352 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2356 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2357 RegCloseKey(hkeyDrivers);
2358 ERR("Can't create Name key\n");
2361 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2363 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2364 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2365 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2367 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2368 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2369 di3.pDependentFiles, 0);
2370 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2371 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2372 RegCloseKey(hkeyName);
2373 RegCloseKey(hkeyDrivers);
2377 /*****************************************************************************
2378 * AddPrinterDriverW [WINSPOOL.@]
2380 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2383 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2389 /*****************************************************************************
2390 * PrinterProperties [WINSPOOL.@]
2392 * Displays a dialog to set the properties of the printer.
2395 * nonzero on success or zero on failure
2398 * implemented as stub only
2400 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2401 HANDLE hPrinter /* [in] handle to printer object */
2403 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2404 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2408 /*****************************************************************************
2409 * EnumJobsA [WINSPOOL.@]
2412 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2413 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2417 if(pcbNeeded) *pcbNeeded = 0;
2418 if(pcReturned) *pcReturned = 0;
2423 /*****************************************************************************
2424 * EnumJobsW [WINSPOOL.@]
2427 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2428 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2432 if(pcbNeeded) *pcbNeeded = 0;
2433 if(pcReturned) *pcReturned = 0;
2437 /*****************************************************************************
2438 * WINSPOOL_EnumPrinterDrivers [internal]
2440 * Delivers information about all printer drivers installed on the
2441 * localhost or a given server
2444 * nonzero on success or zero on failure. If the buffer for the returned
2445 * information is too small the function will return an error
2448 * - only implemented for localhost, foreign hosts will return an error
2450 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2451 DWORD Level, LPBYTE pDriverInfo,
2452 DWORD cbBuf, LPDWORD pcbNeeded,
2453 LPDWORD pcReturned, BOOL unicode)
2456 DWORD i, needed, number = 0, size = 0;
2457 WCHAR DriverNameW[255];
2460 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2461 debugstr_w(pName), debugstr_w(pEnvironment),
2462 Level, pDriverInfo, cbBuf, unicode);
2464 /* check for local drivers */
2466 ERR("remote drivers unsupported! Current remote host is %s\n",
2471 /* check input parameter */
2472 if((Level < 1) || (Level > 3)) {
2473 ERR("unsupported level %ld \n", Level);
2477 /* initialize return values */
2479 memset( pDriverInfo, 0, cbBuf);
2483 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2485 ERR("Can't open Drivers key\n");
2489 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2490 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2491 RegCloseKey(hkeyDrivers);
2492 ERR("Can't query Drivers key\n");
2495 TRACE("Found %ld Drivers\n", number);
2497 /* get size of single struct
2498 * unicode and ascii structure have the same size
2502 size = sizeof(DRIVER_INFO_1A);
2505 size = sizeof(DRIVER_INFO_2A);
2508 size = sizeof(DRIVER_INFO_3A);
2512 /* calculate required buffer size */
2513 *pcbNeeded = size * number;
2515 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2517 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2518 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2520 ERR("Can't enum key number %ld\n", i);
2521 RegCloseKey(hkeyDrivers);
2524 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2525 pEnvironment, Level, ptr,
2526 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2527 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2528 &needed, unicode)) {
2529 RegCloseKey(hkeyDrivers);
2532 (*pcbNeeded) += needed;
2535 RegCloseKey(hkeyDrivers);
2537 if(cbBuf < *pcbNeeded){
2538 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2545 /*****************************************************************************
2546 * EnumPrinterDriversW [WINSPOOL.@]
2548 * see function EnumPrinterDrivers for RETURNS, BUGS
2550 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2551 LPBYTE pDriverInfo, DWORD cbBuf,
2552 LPDWORD pcbNeeded, LPDWORD pcReturned)
2554 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2555 cbBuf, pcbNeeded, pcReturned, TRUE);
2558 /*****************************************************************************
2559 * EnumPrinterDriversA [WINSPOOL.@]
2561 * see function EnumPrinterDrivers for RETURNS, BUGS
2563 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2564 LPBYTE pDriverInfo, DWORD cbBuf,
2565 LPDWORD pcbNeeded, LPDWORD pcReturned)
2567 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2570 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2572 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2574 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2575 cbBuf, pcbNeeded, pcReturned, FALSE);
2577 HeapFree(GetProcessHeap(), 0, pNameW);
2579 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2585 /******************************************************************************
2586 * EnumPortsA (WINSPOOL.@)
2588 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2589 LPDWORD bufneeded,LPDWORD bufreturned)
2591 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2595 /******************************************************************************
2596 * SetPrinterDataExA (WINSPOOL.@)
2598 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2599 LPSTR pValueName, DWORD Type,
2600 LPBYTE pData, DWORD cbData)
2602 HKEY hkeyPrinter, hkeySubkey;
2605 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2606 debugstr_a(pValueName), Type, pData, cbData);
2608 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2612 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2614 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2615 RegCloseKey(hkeyPrinter);
2618 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2619 RegCloseKey(hkeySubkey);
2620 RegCloseKey(hkeyPrinter);
2624 /******************************************************************************
2625 * SetPrinterDataExW (WINSPOOL.@)
2627 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2628 LPWSTR pValueName, DWORD Type,
2629 LPBYTE pData, DWORD cbData)
2631 HKEY hkeyPrinter, hkeySubkey;
2634 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2635 debugstr_w(pValueName), Type, pData, cbData);
2637 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2641 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2643 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2644 RegCloseKey(hkeyPrinter);
2647 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2648 RegCloseKey(hkeySubkey);
2649 RegCloseKey(hkeyPrinter);
2653 /******************************************************************************
2654 * SetPrinterDataA (WINSPOOL.@)
2656 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2657 LPBYTE pData, DWORD cbData)
2659 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2663 /******************************************************************************
2664 * SetPrinterDataW (WINSPOOL.@)
2666 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2667 LPBYTE pData, DWORD cbData)
2669 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2673 /******************************************************************************
2674 * GetPrinterDataExA (WINSPOOL.@)
2676 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2677 LPSTR pValueName, LPDWORD pType,
2678 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2680 HKEY hkeyPrinter, hkeySubkey;
2683 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2684 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2687 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2691 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2693 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2694 RegCloseKey(hkeyPrinter);
2698 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2699 RegCloseKey(hkeySubkey);
2700 RegCloseKey(hkeyPrinter);
2704 /******************************************************************************
2705 * GetPrinterDataExW (WINSPOOL.@)
2707 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2708 LPWSTR pValueName, LPDWORD pType,
2709 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2711 HKEY hkeyPrinter, hkeySubkey;
2714 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2715 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2718 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2722 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2724 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2725 RegCloseKey(hkeyPrinter);
2729 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2730 RegCloseKey(hkeySubkey);
2731 RegCloseKey(hkeyPrinter);
2735 /******************************************************************************
2736 * GetPrinterDataA (WINSPOOL.@)
2738 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
2739 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2741 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
2742 pData, nSize, pcbNeeded);
2745 /******************************************************************************
2746 * GetPrinterDataW (WINSPOOL.@)
2748 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
2749 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2751 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
2752 pData, nSize, pcbNeeded);
2755 /*******************************************************************************
2756 * EnumPrinterDataExW [WINSPOOL.@]
2758 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
2759 LPBYTE pEnumValues, DWORD cbEnumValues,
2760 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2762 HKEY hkPrinter, hkSubKey;
2763 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
2764 cbValueNameLen, cbMaxValueLen, cbValueLen,
2769 PPRINTER_ENUM_VALUESW ppev;
2771 TRACE ("%08x %s\n", hPrinter, debugstr_w (pKeyName));
2773 if (pKeyName == NULL || *pKeyName == 0)
2774 return ERROR_INVALID_PARAMETER;
2776 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
2777 if (ret != ERROR_SUCCESS)
2779 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%08x) returned %li\n",
2784 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
2785 if (ret != ERROR_SUCCESS)
2787 r = RegCloseKey (hkPrinter);
2788 if (r != ERROR_SUCCESS)
2789 WARN ("RegCloseKey returned %li\n", r);
2790 TRACE ("RegOpenKeyExW (%08x, %s) returned %li\n", hPrinter,
2791 debugstr_w (pKeyName), ret);
2795 ret = RegCloseKey (hkPrinter);
2796 if (ret != ERROR_SUCCESS)
2798 ERR ("RegCloseKey returned %li\n", ret);
2799 r = RegCloseKey (hkSubKey);
2800 if (r != ERROR_SUCCESS)
2801 WARN ("RegCloseKey returned %li\n", r);
2805 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
2806 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
2807 if (ret != ERROR_SUCCESS)
2809 r = RegCloseKey (hkSubKey);
2810 if (r != ERROR_SUCCESS)
2811 WARN ("RegCloseKey returned %li\n", r);
2812 TRACE ("RegQueryInfoKeyW (%08x) returned %li\n", hkSubKey, ret);
2816 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
2817 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
2819 if (cValues == 0) /* empty key */
2821 r = RegCloseKey (hkSubKey);
2822 if (r != ERROR_SUCCESS)
2823 WARN ("RegCloseKey returned %li\n", r);
2824 *pcbEnumValues = *pnEnumValues = 0;
2825 return ERROR_SUCCESS;
2828 ++cbMaxValueNameLen; /* allow for trailing '\0' */
2830 hHeap = GetProcessHeap ();
2831 if (hHeap == (HANDLE) NULL)
2833 ERR ("GetProcessHeap failed\n");
2834 r = RegCloseKey (hkSubKey);
2835 if (r != ERROR_SUCCESS)
2836 WARN ("RegCloseKey returned %li\n", r);
2837 return ERROR_OUTOFMEMORY;
2840 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
2841 if (lpValueName == NULL)
2843 ERR ("Failed to allocate %li bytes from process heap\n",
2844 cbMaxValueNameLen * sizeof (WCHAR));
2845 r = RegCloseKey (hkSubKey);
2846 if (r != ERROR_SUCCESS)
2847 WARN ("RegCloseKey returned %li\n", r);
2848 return ERROR_OUTOFMEMORY;
2851 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
2852 if (lpValue == NULL)
2854 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
2855 if (HeapFree (hHeap, 0, lpValueName) == 0)
2856 WARN ("HeapFree failed with code %li\n", GetLastError ());
2857 r = RegCloseKey (hkSubKey);
2858 if (r != ERROR_SUCCESS)
2859 WARN ("RegCloseKey returned %li\n", r);
2860 return ERROR_OUTOFMEMORY;
2863 TRACE ("pass 1: calculating buffer required for all names and values\n");
2865 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
2867 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
2869 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2871 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2872 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2873 NULL, NULL, lpValue, &cbValueLen);
2874 if (ret != ERROR_SUCCESS)
2876 if (HeapFree (hHeap, 0, lpValue) == 0)
2877 WARN ("HeapFree failed with code %li\n", GetLastError ());
2878 if (HeapFree (hHeap, 0, lpValueName) == 0)
2879 WARN ("HeapFree failed with code %li\n", GetLastError ());
2880 r = RegCloseKey (hkSubKey);
2881 if (r != ERROR_SUCCESS)
2882 WARN ("RegCloseKey returned %li\n", r);
2883 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2887 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
2888 debugstr_w (lpValueName), dwIndex,
2889 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
2891 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
2892 cbBufSize += cbValueLen;
2895 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
2897 *pcbEnumValues = cbBufSize;
2898 *pnEnumValues = cValues;
2900 if (cbEnumValues < cbBufSize) /* buffer too small */
2902 if (HeapFree (hHeap, 0, lpValue) == 0)
2903 WARN ("HeapFree failed with code %li\n", GetLastError ());
2904 if (HeapFree (hHeap, 0, lpValueName) == 0)
2905 WARN ("HeapFree failed with code %li\n", GetLastError ());
2906 r = RegCloseKey (hkSubKey);
2907 if (r != ERROR_SUCCESS)
2908 WARN ("RegCloseKey returned %li\n", r);
2909 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
2910 return ERROR_MORE_DATA;
2913 TRACE ("pass 2: copying all names and values to buffer\n");
2915 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
2916 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
2918 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2920 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2921 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2922 NULL, &dwType, lpValue, &cbValueLen);
2923 if (ret != ERROR_SUCCESS)
2925 if (HeapFree (hHeap, 0, lpValue) == 0)
2926 WARN ("HeapFree failed with code %li\n", GetLastError ());
2927 if (HeapFree (hHeap, 0, lpValueName) == 0)
2928 WARN ("HeapFree failed with code %li\n", GetLastError ());
2929 r = RegCloseKey (hkSubKey);
2930 if (r != ERROR_SUCCESS)
2931 WARN ("RegCloseKey returned %li\n", r);
2932 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2936 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
2937 memcpy (pEnumValues, lpValueName, cbValueNameLen);
2938 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
2939 pEnumValues += cbValueNameLen;
2941 /* return # of *bytes* (including trailing \0), not # of chars */
2942 ppev[dwIndex].cbValueName = cbValueNameLen;
2944 ppev[dwIndex].dwType = dwType;
2946 memcpy (pEnumValues, lpValue, cbValueLen);
2947 ppev[dwIndex].pData = pEnumValues;
2948 pEnumValues += cbValueLen;
2950 ppev[dwIndex].cbData = cbValueLen;
2952 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
2953 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
2956 if (HeapFree (hHeap, 0, lpValue) == 0)
2958 ret = GetLastError ();
2959 ERR ("HeapFree failed with code %li\n", ret);
2960 if (HeapFree (hHeap, 0, lpValueName) == 0)
2961 WARN ("HeapFree failed with code %li\n", GetLastError ());
2962 r = RegCloseKey (hkSubKey);
2963 if (r != ERROR_SUCCESS)
2964 WARN ("RegCloseKey returned %li\n", r);
2968 if (HeapFree (hHeap, 0, lpValueName) == 0)
2970 ret = GetLastError ();
2971 ERR ("HeapFree failed with code %li\n", ret);
2972 r = RegCloseKey (hkSubKey);
2973 if (r != ERROR_SUCCESS)
2974 WARN ("RegCloseKey returned %li\n", r);
2978 ret = RegCloseKey (hkSubKey);
2979 if (ret != ERROR_SUCCESS)
2981 ERR ("RegCloseKey returned %li\n", ret);
2985 return ERROR_SUCCESS;
2988 /*******************************************************************************
2989 * EnumPrinterDataExA [WINSPOOL.@]
2991 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
2992 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
2993 * what Windows 2000 SP1 does.
2996 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
2997 LPBYTE pEnumValues, DWORD cbEnumValues,
2998 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3002 DWORD ret, dwIndex, dwBufSize;
3006 TRACE ("%08x %s\n", hPrinter, pKeyName);
3008 if (pKeyName == NULL || *pKeyName == 0)
3009 return ERROR_INVALID_PARAMETER;
3011 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3014 ret = GetLastError ();
3015 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3019 hHeap = GetProcessHeap ();
3020 if (hHeap == (HANDLE) NULL)
3022 ERR ("GetProcessHeap failed\n");
3023 return ERROR_OUTOFMEMORY;
3026 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3027 if (pKeyNameW == NULL)
3029 ERR ("Failed to allocate %li bytes from process heap\n",
3030 (LONG) len * sizeof (WCHAR));
3031 return ERROR_OUTOFMEMORY;
3034 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3036 ret = GetLastError ();
3037 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3038 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3039 WARN ("HeapFree failed with code %li\n", GetLastError ());
3043 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3044 pcbEnumValues, pnEnumValues);
3045 if (ret != ERROR_SUCCESS)
3047 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3048 WARN ("HeapFree failed with code %li\n", GetLastError ());
3049 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3053 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3055 ret = GetLastError ();
3056 ERR ("HeapFree failed with code %li\n", ret);
3060 if (*pnEnumValues == 0) /* empty key */
3061 return ERROR_SUCCESS;
3064 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3066 PPRINTER_ENUM_VALUESW ppev =
3067 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3069 if (dwBufSize < ppev->cbValueName)
3070 dwBufSize = ppev->cbValueName;
3072 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3073 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3074 dwBufSize = ppev->cbData;
3077 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3079 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3080 if (pBuffer == NULL)
3082 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3083 return ERROR_OUTOFMEMORY;
3086 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3088 PPRINTER_ENUM_VALUESW ppev =
3089 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3091 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3092 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3096 ret = GetLastError ();
3097 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3098 if (HeapFree (hHeap, 0, pBuffer) == 0)
3099 WARN ("HeapFree failed with code %li\n", GetLastError ());
3103 memcpy (ppev->pValueName, pBuffer, len);
3105 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3107 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3108 ppev->dwType != REG_MULTI_SZ)
3111 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3112 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3115 ret = GetLastError ();
3116 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3117 if (HeapFree (hHeap, 0, pBuffer) == 0)
3118 WARN ("HeapFree failed with code %li\n", GetLastError ());
3122 memcpy (ppev->pData, pBuffer, len);
3124 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3125 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3128 if (HeapFree (hHeap, 0, pBuffer) == 0)
3130 ret = GetLastError ();
3131 ERR ("HeapFree failed with code %li\n", ret);
3135 return ERROR_SUCCESS;