Documentation ordinal fixes.
[wine/wine64.git] / dlls / winspool / info.c
blob387170ed133c1f575d38fc0f8bd8aa28e891d009
1 /*
2 * WINSPOOL functions
3 *
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
9 */
11 #include "config.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <stddef.h>
18 #ifdef HAVE_CUPS
19 # include <cups/cups.h>
20 #endif
21 #include "winspool.h"
22 #include "winbase.h"
23 #include "winerror.h"
24 #include "winreg.h"
25 #include "wine/windef16.h"
26 #include "wine/unicode.h"
27 #include "debugtools.h"
28 #include "heap.h"
29 #include "winnls.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,
38 LPDEVMODEA lpdm );
39 static INT WINAPI (*GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
40 LPSTR lpszDevice, LPSTR lpszPort,
41 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
42 DWORD fwMode );
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',
56 'M','o','d','e',0};
57 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
58 'i','l','e','s',0};
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',
68 's','s','o','r',0};
69 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
70 'v','e','r',0};
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',
74 'i','l','e',0};
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,
82 BOOL unicode);
83 static void
84 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
85 char qbuf[200];
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.
91 if (force ||
92 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
93 !strcmp(qbuf,"*") ||
94 !strstr(qbuf,"WINEPS")
95 ) {
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);
104 #ifdef HAVE_CUPS
105 BOOL
106 CUPS_LoadPrinters(void) {
107 char **printers;
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]);
116 char *port,*devline;
118 if (!ppd) {
119 WARN("No ppd file for %s.\n",printers[i]);
120 continue;
122 unlink(ppd);
124 hadprinter = TRUE;
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);
153 return hadprinter;
155 #endif
157 static BOOL
158 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
159 PRINTER_INFO_2A pinfo2a;
160 char *s,*name,*prettyname,*devname;
161 BOOL isps = FALSE;
162 char *port,*devline;
164 s = strchr(pent,':');
165 if (!s) return FALSE;
166 *s='\0';
167 name = pent;
168 pent = s+1;
169 TRACE("%s\n",name);
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);
180 isps = TRUE;
182 /* 2. Check if this is a remote printer. These usually are postscript
183 * capable
185 if (strstr(pent,":rm")) {
186 isps = TRUE;
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=/")) {
195 isps = TRUE;
196 TRACE("%s has inputfilter program, assuming postscript.\n",name);
199 /* If it is not a postscript printer, we cannot use it. */
200 if (!isps)
201 return FALSE;
203 prettyname = name;
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)
212 devname = name;
213 if (strlen(devname)>=CCHDEVICENAME-1)
214 return FALSE;
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);
243 return TRUE;
246 static BOOL
247 PRINTCAP_LoadPrinters(void) {
248 BOOL hadprinter = FALSE, isfirst = TRUE;
249 char buf[200];
250 FILE *f;
252 f = fopen("/etc/printcap","r");
253 if (!f)
254 return FALSE;
256 while (fgets(buf,sizeof(buf),f)) {
257 char *pent = NULL;
258 do {
259 char *s;
260 s=strchr(buf,'\n'); if (s) *s='\0';
261 if ((buf[0]=='#') || (buf[0]=='\0'))
262 continue;
264 if (pent) {
265 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
266 strcat(pent,buf);
267 } else {
268 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
269 strcpy(pent,buf);
272 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
273 pent[strlen(pent)-1] = '\0';
274 else
275 break;
276 } while (fgets(buf,sizeof(buf),f));
277 if (pent)
278 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
279 isfirst = FALSE;
280 if (pent) HeapFree(GetProcessHeap(),0,pent);
281 pent = NULL;
282 if (feof(f)) break;
284 fclose(f);
285 return hadprinter;
288 void
289 WINSPOOL_LoadSystemPrinters() {
290 HKEY hkPPD;
291 DRIVER_INFO_3A di3a;
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());
305 return;
307 #ifdef HAVE_CUPS
308 /* If we have any CUPS based printers, skip looking for printcap printers */
309 if (CUPS_LoadPrinters())
310 return;
311 #endif
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)
318 RegCloseKey(hkPPD);
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 )
330 int i;
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;
340 nb_printers += 16;
343 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
345 strcpyW( printer_array[i], name );
346 return (HANDLE)(i + 1);
348 return 0;
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);
361 return NULL;
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);
373 DWORD ret;
374 HKEY hkeyPrinters;
376 if(!name) return ERROR_INVALID_HANDLE;
378 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
379 ERROR_SUCCESS)
380 return ret;
382 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
384 ERR("Can't find opened printer %s in registry\n",
385 debugstr_w(name));
386 RegCloseKey(hkeyPrinters);
387 return ERROR_INVALID_PRINTER_NAME; /* ? */
389 RegCloseKey(hkeyPrinters);
390 return ERROR_SUCCESS;
393 /***********************************************************
394 * DEVMODEcpyAtoW
396 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
398 BOOL Formname;
399 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
400 DWORD size;
402 Formname = (dmA->dmSize > off_formname);
403 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
404 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
405 CCHDEVICENAME);
406 if(!Formname) {
407 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
408 dmA->dmSize - CCHDEVICENAME);
409 } else {
410 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
411 off_formname - CCHDEVICENAME);
412 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
413 CCHFORMNAME);
414 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
415 (off_formname + CCHFORMNAME));
417 dmW->dmSize = size;
418 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
419 dmA->dmDriverExtra);
420 return dmW;
423 /***********************************************************
424 * DEVMODEdupAtoW
425 * Creates a unicode copy of supplied devmode on heap
427 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
429 LPDEVMODEW dmW;
430 DWORD size;
431 BOOL Formname;
432 ptrdiff_t off_formname;
434 TRACE("\n");
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 /***********************************************************
445 * DEVMODEdupWtoA
446 * Creates an ascii copy of supplied devmode on heap
448 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
450 LPDEVMODEA dmA;
451 DWORD size;
452 BOOL Formname;
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);
461 if(!Formname) {
462 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
463 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
464 } else {
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)));
472 dmA->dmSize = size;
473 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
474 dmW->dmDriverExtra);
475 return dmA;
478 /***********************************************************
479 * PRINTER_INFO_2AtoW
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);
500 return piW;
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)
509 if(!piW) return;
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);
524 return;
527 /******************************************************************
528 * DeviceCapabilitiesA [WINSPOOL.150 & WINSPOOL.151]
531 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
532 LPSTR pOutput, LPDEVMODEA lpdm)
534 INT ret;
536 if (!GDI_CallDeviceCapabilities16)
538 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
539 (LPCSTR)104 );
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;
548 INT i;
549 memcpy(tmp, pOutput, ret * sizeof(POINT16));
550 for(i = 0; i < ret; i++, pt++)
552 pt->x = tmp[i].x;
553 pt->y = tmp[i].y;
555 HeapFree( GetProcessHeap(), 0, tmp );
557 return ret;
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);
574 INT ret;
576 if(pOutput && (fwCapability == DC_BINNAMES ||
577 fwCapability == DC_FILEDEPENDENCIES ||
578 fwCapability == DC_PAPERNAMES)) {
579 /* These need A -> W translation */
580 INT size = 0, i;
581 LPSTR pOutputA;
582 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
583 dmA);
584 if(ret == -1)
585 return ret;
586 switch(fwCapability) {
587 case DC_BINNAMES:
588 size = 24;
589 break;
590 case DC_PAPERNAMES:
591 case DC_FILEDEPENDENCIES:
592 size = 64;
593 break;
595 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
596 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
597 dmA);
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);
602 } else {
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);
609 return ret;
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;
621 LONG ret;
623 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
624 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
627 if(!pDeviceName) {
628 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
629 if(!lpNameW) {
630 ERR("no name from hPrinter?\n");
631 return -1;
633 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
636 if (!GDI_CallExtDeviceMode16)
638 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
639 (LPCSTR)102 );
640 if (!GDI_CallExtDeviceMode16) {
641 ERR("No CallExtDeviceMode16?\n");
642 return -1;
645 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
646 pDevModeInput, NULL, fMode);
648 if(!pDeviceName)
649 HeapFree(GetProcessHeap(),0,lpName);
650 return ret;
654 /*****************************************************************************
655 * DocumentPropertiesW (WINSPOOL.@)
657 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
658 LPWSTR pDeviceName,
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;
666 LONG ret;
668 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
669 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
670 fMode);
671 if(pDevModeOutput) {
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);
678 if(pDevModeOutput) {
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);
686 return ret;
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;
698 BOOL ret;
700 if(pDefault) {
701 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
702 pDefault->pDatatype);
703 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
704 pDefault->pDevMode);
705 DefaultW.DesiredAccess = pDefault->DesiredAccess;
706 pDefaultW = &DefaultW;
708 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
709 if(pDefault) {
710 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
711 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
713 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
714 return ret;
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);
729 return FALSE;
732 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
733 pDefault);
735 /* Check Printer exists */
736 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
737 ERROR_SUCCESS) {
738 ERR("Can't create Printers key\n");
739 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
740 return FALSE;
743 if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
744 != ERROR_SUCCESS) {
745 ERR("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
746 RegCloseKey(hkeyPrinters);
747 SetLastError(ERROR_INVALID_PARAMETER);
748 return FALSE;
750 RegCloseKey(hkeyPrinter);
751 RegCloseKey(hkeyPrinters);
753 if(!phPrinter) /* This seems to be what win95 does anyway */
754 return TRUE;
756 /* Get the unique handle of the printer*/
757 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
759 if (pDefault != NULL)
760 FIXME("Not handling pDefault\n");
762 return TRUE;
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);
773 return FALSE;
776 /******************************************************************
777 * DeletePrinterDriverA [WINSPOOL.@]
780 BOOL WINAPI
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);
786 return FALSE;
790 /******************************************************************
791 * DeleteMonitorA [WINSPOOL.@]
794 BOOL WINAPI
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);
800 return FALSE;
804 /******************************************************************
805 * DeletePortA [WINSPOOL.@]
808 BOOL WINAPI
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);
814 return FALSE;
817 /******************************************************************************
818 * SetPrinterW [WINSPOOL.@]
820 BOOL WINAPI
821 SetPrinterW(
822 HANDLE hPrinter,
823 DWORD Level,
824 LPBYTE pPrinter,
825 DWORD Command) {
827 FIXME("():stub\n");
828 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
829 return FALSE;
832 /******************************************************************************
833 * WritePrinter [WINSPOOL.@]
835 BOOL WINAPI
836 WritePrinter(
837 HANDLE hPrinter,
838 LPVOID pBuf,
839 DWORD cbBuf,
840 LPDWORD pcWritten) {
842 FIXME("():stub\n");
843 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
844 return FALSE;
847 /*****************************************************************************
848 * AddFormA [WINSPOOL.@]
850 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
852 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
853 return 1;
856 /*****************************************************************************
857 * AddFormW [WINSPOOL.@]
859 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
861 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
862 return 1;
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,
872 pcbNeeded);
873 return 1;
876 /*****************************************************************************
877 * AddJobW [WINSPOOL.@]
879 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
880 LPDWORD pcbNeeded)
882 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
883 pcbNeeded);
884 return 1;
887 /*****************************************************************************
888 * WINSPOOL_OpenDriverReg [internal]
890 * opens the registry for the printer drivers depending on the given input
891 * variable pEnvironment
893 * RETURNS:
894 * the opened hkey on success
895 * NULL on error
897 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
898 { HKEY retval;
899 LPSTR lpKey, p = NULL;
901 TRACE("%s\n",
902 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
904 if(pEnvironment)
905 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
906 pEnvironment;
907 else {
908 OSVERSIONINFOA ver;
909 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
911 if(!GetVersionExA( &ver))
912 return 0;
914 switch (ver.dwPlatformId) {
915 case VER_PLATFORM_WIN32s:
916 return 0;
917 case VER_PLATFORM_WIN32_NT:
918 p = "Windows NT x86";
919 break;
920 default:
921 p = "Windows 4.0";
922 break;
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) !=
934 ERROR_SUCCESS)
935 retval = 0;
937 if(pEnvironment && unicode)
938 HeapFree( GetProcessHeap(), 0, p);
939 HeapFree( GetProcessHeap(), 0, lpKey);
941 return retval;
944 /*****************************************************************************
945 * AddPrinterW [WINSPOOL.@]
947 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
949 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
950 LPDEVMODEA dmA;
951 LPDEVMODEW dmW;
952 HANDLE retval;
953 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
954 LONG size;
956 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
958 if(pName != NULL) {
959 ERR("pName = %s - unsupported\n", debugstr_w(pName));
960 SetLastError(ERROR_INVALID_PARAMETER);
961 return 0;
963 if(Level != 2) {
964 ERR("Level = %ld, unsupported!\n", Level);
965 SetLastError(ERROR_INVALID_LEVEL);
966 return 0;
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);
973 return 0;
975 if(!pPrinter) {
976 SetLastError(ERROR_INVALID_PARAMETER);
977 return 0;
979 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
980 ERROR_SUCCESS) {
981 ERR("Can't create Printers key\n");
982 return 0;
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);
989 return 0;
991 RegCloseKey(hkeyPrinter);
993 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
994 if(!hkeyDrivers) {
995 ERR("Can't create Drivers key\n");
996 RegCloseKey(hkeyPrinters);
997 return 0;
999 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1000 ERROR_SUCCESS) {
1001 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1002 RegCloseKey(hkeyPrinters);
1003 RegCloseKey(hkeyDrivers);
1004 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1005 return 0;
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);
1014 return 0;
1017 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1018 ERROR_SUCCESS) {
1019 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1020 SetLastError(ERROR_INVALID_PRINTER_NAME);
1021 RegCloseKey(hkeyPrinters);
1022 return 0;
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
1031 * FIXME:
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);
1037 if(size < 0) {
1038 FIXME("DocumentProperties fails\n");
1039 size = sizeof(DEVMODEW);
1041 if(pi->pDevMode)
1042 dmW = pi->pDevMode;
1043 else {
1044 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1045 dmW->dmSize = 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);
1049 return 0;
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
1058 drivers */
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);
1063 if(!pi->pDevMode)
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");
1094 return 0;
1096 return retval;
1099 /*****************************************************************************
1100 * AddPrinterA [WINSPOOL.@]
1102 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1104 WCHAR *pNameW;
1105 PRINTER_INFO_2W *piW;
1106 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1107 HANDLE ret;
1109 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1110 if(Level != 2) {
1111 ERR("Level = %ld, unsupported!\n", Level);
1112 SetLastError(ERROR_INVALID_LEVEL);
1113 return 0;
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);
1122 return ret;
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;
1138 return TRUE;
1141 /*****************************************************************************
1142 * DeleteFormA [WINSPOOL.@]
1144 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1146 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
1147 return 1;
1150 /*****************************************************************************
1151 * DeleteFormW [WINSPOOL.@]
1153 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1155 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
1156 return 1;
1159 /*****************************************************************************
1160 * DeletePrinter [WINSPOOL.@]
1162 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1164 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1165 HKEY hkeyPrinters;
1167 if(!lpNameW) return FALSE;
1168 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1169 ERROR_SUCCESS) {
1170 ERR("Can't open Printers key\n");
1171 return 0;
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);
1178 return 0;
1181 ClosePrinter(hPrinter);
1182 return TRUE;
1185 /*****************************************************************************
1186 * SetPrinterA [WINSPOOL.@]
1188 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1189 DWORD Command)
1191 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1192 return FALSE;
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,
1202 Command);
1203 return FALSE;
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,
1213 Command);
1214 return FALSE;
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);
1225 return FALSE;
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);
1236 return FALSE;
1239 /*****************************************************************************
1240 * SetFormA [WINSPOOL.@]
1242 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1243 LPBYTE pForm)
1245 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1246 return FALSE;
1249 /*****************************************************************************
1250 * SetFormW [WINSPOOL.@]
1252 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1253 LPBYTE pForm)
1255 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1256 return FALSE;
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);
1266 return FALSE;
1269 /*****************************************************************************
1270 * ResetPrinterA [WINSPOOL.@]
1272 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1274 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1275 return FALSE;
1278 /*****************************************************************************
1279 * ResetPrinterW [WINSPOOL.@]
1281 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1283 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1284 return FALSE;
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;
1295 LONG ret;
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);
1301 return 0;
1303 if(type != REG_DWORD) {
1304 ERR("Got type %ld\n", type);
1305 return 0;
1307 return value;
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,
1319 BOOL unicode)
1321 DWORD sz = buflen, type;
1322 LONG ret;
1324 if(unicode)
1325 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1326 else {
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);
1333 *needed = 0;
1334 return FALSE;
1336 *needed = sz;
1337 return TRUE;
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,
1347 LPBYTE ptr,
1348 DWORD buflen, DWORD *needed,
1349 BOOL unicode)
1351 DWORD sz = buflen, type;
1352 LONG ret;
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);
1360 return FALSE;
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);
1365 if(unicode) {
1366 sz += (CCHDEVICENAME + CCHFORMNAME);
1367 if(buflen >= sz) {
1368 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1369 memcpy(ptr, dmW, sz);
1370 HeapFree(GetProcessHeap(),0,dmW);
1373 *needed = sz;
1374 return TRUE;
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,
1385 BOOL unicode)
1387 DWORD size, left = cbBuf;
1388 BOOL space = (cbBuf > 0);
1389 LPBYTE ptr = buf;
1391 *pcbNeeded = 0;
1393 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1394 unicode)) {
1395 if(space && size <= left) {
1396 pi2->pPrinterName = (LPWSTR)ptr;
1397 ptr += size;
1398 left -= size;
1399 } else
1400 space = FALSE;
1401 *pcbNeeded += size;
1403 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1404 unicode)) {
1405 if(space && size <= left) {
1406 pi2->pShareName = (LPWSTR)ptr;
1407 ptr += size;
1408 left -= size;
1409 } else
1410 space = FALSE;
1411 *pcbNeeded += size;
1413 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1414 unicode)) {
1415 if(space && size <= left) {
1416 pi2->pPortName = (LPWSTR)ptr;
1417 ptr += size;
1418 left -= size;
1419 } else
1420 space = FALSE;
1421 *pcbNeeded += size;
1423 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1424 &size, unicode)) {
1425 if(space && size <= left) {
1426 pi2->pDriverName = (LPWSTR)ptr;
1427 ptr += size;
1428 left -= size;
1429 } else
1430 space = FALSE;
1431 *pcbNeeded += size;
1433 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1434 unicode)) {
1435 if(space && size <= left) {
1436 pi2->pComment = (LPWSTR)ptr;
1437 ptr += size;
1438 left -= size;
1439 } else
1440 space = FALSE;
1441 *pcbNeeded += size;
1443 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1444 unicode)) {
1445 if(space && size <= left) {
1446 pi2->pLocation = (LPWSTR)ptr;
1447 ptr += size;
1448 left -= size;
1449 } else
1450 space = FALSE;
1451 *pcbNeeded += size;
1453 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1454 &size, unicode)) {
1455 if(space && size <= left) {
1456 pi2->pDevMode = (LPDEVMODEW)ptr;
1457 ptr += size;
1458 left -= size;
1459 } else
1460 space = FALSE;
1461 *pcbNeeded += size;
1463 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1464 &size, unicode)) {
1465 if(space && size <= left) {
1466 pi2->pSepFile = (LPWSTR)ptr;
1467 ptr += size;
1468 left -= size;
1469 } else
1470 space = FALSE;
1471 *pcbNeeded += size;
1473 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1474 &size, unicode)) {
1475 if(space && size <= left) {
1476 pi2->pPrintProcessor = (LPWSTR)ptr;
1477 ptr += size;
1478 left -= size;
1479 } else
1480 space = FALSE;
1481 *pcbNeeded += size;
1483 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1484 &size, unicode)) {
1485 if(space && size <= left) {
1486 pi2->pDatatype = (LPWSTR)ptr;
1487 ptr += size;
1488 left -= size;
1489 } else
1490 space = FALSE;
1491 *pcbNeeded += size;
1493 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1494 &size, unicode)) {
1495 if(space && size <= left) {
1496 pi2->pParameters = (LPWSTR)ptr;
1497 ptr += size;
1498 left -= size;
1499 } else
1500 space = FALSE;
1501 *pcbNeeded += size;
1503 if(pi2) {
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));
1515 return space;
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,
1525 BOOL unicode)
1527 DWORD size, left = cbBuf;
1528 BOOL space = (cbBuf > 0);
1529 LPBYTE ptr = buf;
1531 *pcbNeeded = 0;
1533 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1534 unicode)) {
1535 if(space && size <= left) {
1536 pi4->pPrinterName = (LPWSTR)ptr;
1537 ptr += size;
1538 left -= size;
1539 } else
1540 space = FALSE;
1541 *pcbNeeded += size;
1543 if(pi4) {
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));
1550 return space;
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,
1560 BOOL unicode)
1562 DWORD size, left = cbBuf;
1563 BOOL space = (cbBuf > 0);
1564 LPBYTE ptr = buf;
1566 *pcbNeeded = 0;
1568 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1569 unicode)) {
1570 if(space && size <= left) {
1571 pi5->pPrinterName = (LPWSTR)ptr;
1572 ptr += size;
1573 left -= size;
1574 } else
1575 space = FALSE;
1576 *pcbNeeded += size;
1578 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1579 unicode)) {
1580 if(space && size <= left) {
1581 pi5->pPortName = (LPWSTR)ptr;
1582 ptr += size;
1583 left -= size;
1584 } else
1585 space = FALSE;
1586 *pcbNeeded += size;
1588 if(pi5) {
1589 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1590 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1591 "dnsTimeout");
1592 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1593 "txTimeout");
1596 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1597 memset(pi5, 0, sizeof(*pi5));
1599 return space;
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)
1612 LPCWSTR name;
1613 DWORD size, needed = 0;
1614 LPBYTE ptr = NULL;
1615 HKEY hkeyPrinter, hkeyPrinters;
1616 BOOL ret;
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) !=
1623 ERROR_SUCCESS) {
1624 ERR("Can't create Printers key\n");
1625 return FALSE;
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); /* ? */
1632 return FALSE;
1635 switch(Level) {
1636 case 2:
1638 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1640 size = sizeof(PRINTER_INFO_2W);
1641 if(size <= cbBuf) {
1642 ptr = pPrinter + size;
1643 cbBuf -= size;
1644 memset(pPrinter, 0, size);
1645 } else {
1646 pi2 = NULL;
1647 cbBuf = 0;
1649 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1650 unicode);
1651 needed += size;
1652 break;
1655 case 4:
1657 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1659 size = sizeof(PRINTER_INFO_4W);
1660 if(size <= cbBuf) {
1661 ptr = pPrinter + size;
1662 cbBuf -= size;
1663 memset(pPrinter, 0, size);
1664 } else {
1665 pi4 = NULL;
1666 cbBuf = 0;
1668 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1669 unicode);
1670 needed += size;
1671 break;
1675 case 5:
1677 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1679 size = sizeof(PRINTER_INFO_5W);
1680 if(size <= cbBuf) {
1681 ptr = pPrinter + size;
1682 cbBuf -= size;
1683 memset(pPrinter, 0, size);
1684 } else {
1685 pi5 = NULL;
1686 cbBuf = 0;
1689 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1690 unicode);
1691 needed += size;
1692 break;
1695 default:
1696 FIXME("Unimplemented level %ld\n", Level);
1697 SetLastError(ERROR_INVALID_LEVEL);
1698 RegCloseKey(hkeyPrinters);
1699 RegCloseKey(hkeyPrinter);
1700 return FALSE;
1703 RegCloseKey(hkeyPrinter);
1704 RegCloseKey(hkeyPrinters);
1706 TRACE("returing %d needed = %ld\n", ret, needed);
1707 if(pcbNeeded) *pcbNeeded = needed;
1708 if(!ret)
1709 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1710 return ret;
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,
1720 TRUE);
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,
1730 FALSE);
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;
1748 PBYTE pi, buf;
1750 if(lpbPrinters)
1751 memset(lpbPrinters, 0, cbBuf);
1752 if(lpdwReturned)
1753 *lpdwReturned = 0;
1754 if(lpdwNeeded)
1755 *lpdwNeeded = 0;
1757 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1758 if(dwType == PRINTER_ENUM_DEFAULT)
1759 return TRUE;
1761 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1762 FIXME("dwType = %08lx\n", dwType);
1763 SetLastError(ERROR_INVALID_FLAGS);
1764 return FALSE;
1767 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1768 ERROR_SUCCESS) {
1769 ERR("Can't create Printers key\n");
1770 return FALSE;
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");
1777 return FALSE;
1779 TRACE("Found %ld printers\n", number);
1781 switch(dwLevel) {
1782 case 1:
1783 RegCloseKey(hkeyPrinters);
1784 if (lpdwReturned)
1785 *lpdwReturned = number;
1786 return TRUE;
1788 case 2:
1789 used = number * sizeof(PRINTER_INFO_2W);
1790 break;
1791 case 4:
1792 used = number * sizeof(PRINTER_INFO_4W);
1793 break;
1794 case 5:
1795 used = number * sizeof(PRINTER_INFO_5W);
1796 break;
1798 default:
1799 SetLastError(ERROR_INVALID_LEVEL);
1800 RegCloseKey(hkeyPrinters);
1801 return FALSE;
1803 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1805 for(i = 0; i < number; i++) {
1806 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1807 ERROR_SUCCESS) {
1808 ERR("Can't enum key number %ld\n", i);
1809 RegCloseKey(hkeyPrinters);
1810 return FALSE;
1812 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1813 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1814 ERROR_SUCCESS) {
1815 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1816 RegCloseKey(hkeyPrinters);
1817 return FALSE;
1820 if(cbBuf > used) {
1821 buf = lpbPrinters + used;
1822 left = cbBuf - used;
1823 } else {
1824 buf = NULL;
1825 left = 0;
1828 switch(dwLevel) {
1829 case 2:
1830 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1831 left, &needed, unicode);
1832 used += needed;
1833 if(pi) pi += sizeof(PRINTER_INFO_2W);
1834 break;
1835 case 4:
1836 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1837 left, &needed, unicode);
1838 used += needed;
1839 if(pi) pi += sizeof(PRINTER_INFO_4W);
1840 break;
1841 case 5:
1842 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1843 left, &needed, unicode);
1844 used += needed;
1845 if(pi) pi += sizeof(PRINTER_INFO_5W);
1846 break;
1847 default:
1848 ERR("Shouldn't be here!\n");
1849 RegCloseKey(hkeyPrinter);
1850 RegCloseKey(hkeyPrinters);
1851 return FALSE;
1853 RegCloseKey(hkeyPrinter);
1855 RegCloseKey(hkeyPrinters);
1857 if(lpdwNeeded)
1858 *lpdwNeeded = used;
1860 if(used > cbBuf) {
1861 if(lpbPrinters)
1862 memset(lpbPrinters, 0, cbBuf);
1863 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1864 return FALSE;
1866 if(lpdwReturned)
1867 *lpdwReturned = number;
1868 SetLastError(ERROR_SUCCESS);
1869 return TRUE;
1873 /******************************************************************
1874 * EnumPrintersW [WINSPOOL.@]
1876 * Enumerates the available printers, print servers and print
1877 * providers, depending on the specified flags, name and level.
1879 * RETURNS:
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
1908 * for information.
1910 * BUGS:
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.
1919 * NOTE:
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)
1946 BOOL ret;
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);
1952 return ret;
1955 /*****************************************************************************
1956 * WINSPOOL_GetDriverInfoFromReg [internal]
1958 * Enters the information from the registry into the DRIVER_INFO struct
1960 * RETURNS
1961 * zero if the printer driver does not exist in the registry
1962 * (only if Level > 1) otherwise nonzero
1964 static BOOL WINSPOOL_GetDriverInfoFromReg(
1965 HKEY hkeyDrivers,
1966 LPWSTR DriverName,
1967 LPWSTR pEnvironment,
1968 DWORD Level,
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;
1975 HKEY hkeyDriver;
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);
1982 if(unicode) {
1983 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1984 if (*pcbNeeded <= cbBuf)
1985 strcpyW((LPWSTR)strPtr, DriverName);
1986 } else {
1987 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1988 NULL, NULL);
1989 if(*pcbNeeded <= cbBuf)
1990 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
1991 NULL, NULL);
1993 if(Level == 1) {
1994 if(ptr)
1995 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
1996 return TRUE;
1997 } else {
1998 if(ptr)
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); /* ? */
2006 return FALSE;
2009 size = sizeof(dw);
2010 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2011 ERROR_SUCCESS)
2012 WARN("Can't get Version\n");
2013 else if(ptr)
2014 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2016 if(!pEnvironment)
2017 pEnvironment = DefaultEnvironmentW;
2018 if(unicode)
2019 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2020 else
2021 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2022 NULL, NULL);
2023 *pcbNeeded += size;
2024 if(*pcbNeeded <= cbBuf) {
2025 if(unicode)
2026 strcpyW((LPWSTR)strPtr, pEnvironment);
2027 else
2028 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2029 NULL, NULL);
2030 if(ptr)
2031 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2032 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2035 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2036 unicode)) {
2037 *pcbNeeded += size;
2038 if(*pcbNeeded <= cbBuf)
2039 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2040 unicode);
2041 if(ptr)
2042 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2043 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2046 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2047 unicode)) {
2048 *pcbNeeded += size;
2049 if(*pcbNeeded <= cbBuf)
2050 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2051 &tmp, unicode);
2052 if(ptr)
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)) {
2059 *pcbNeeded += size;
2060 if(*pcbNeeded <= cbBuf)
2061 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2062 size, &tmp, unicode);
2063 if(ptr)
2064 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2065 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2068 if(Level == 2 ) {
2069 RegCloseKey(hkeyDriver);
2070 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2071 return TRUE;
2074 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2075 unicode)) {
2076 *pcbNeeded += size;
2077 if(*pcbNeeded <= cbBuf)
2078 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2079 size, &tmp, unicode);
2080 if(ptr)
2081 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2082 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2085 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2086 &size, unicode)) {
2087 *pcbNeeded += size;
2088 if(*pcbNeeded <= cbBuf)
2089 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2090 size, &tmp, unicode);
2091 if(ptr)
2092 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2093 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2096 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2097 unicode)) {
2098 *pcbNeeded += size;
2099 if(*pcbNeeded <= cbBuf)
2100 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2101 size, &tmp, unicode);
2102 if(ptr)
2103 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2104 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2107 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2108 unicode)) {
2109 *pcbNeeded += size;
2110 if(*pcbNeeded <= cbBuf)
2111 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2112 size, &tmp, unicode);
2113 if(ptr)
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);
2120 return TRUE;
2123 /*****************************************************************************
2124 * WINSPOOL_GetPrinterDriver
2126 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2127 DWORD Level, LPBYTE pDriverInfo,
2128 DWORD cbBuf, LPDWORD pcbNeeded,
2129 BOOL unicode)
2131 LPCWSTR name;
2132 WCHAR DriverName[100];
2133 DWORD ret, type, size, needed = 0;
2134 LPBYTE ptr = NULL;
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);
2146 return FALSE;
2148 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2149 ERROR_SUCCESS) {
2150 ERR("Can't create Printers key\n");
2151 return FALSE;
2153 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2154 != ERROR_SUCCESS) {
2155 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2156 RegCloseKey(hkeyPrinters);
2157 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2158 return FALSE;
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));
2167 return FALSE;
2170 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2171 if(!hkeyDrivers) {
2172 ERR("Can't create Drivers key\n");
2173 return FALSE;
2176 switch(Level) {
2177 case 1:
2178 size = sizeof(DRIVER_INFO_1W);
2179 break;
2180 case 2:
2181 size = sizeof(DRIVER_INFO_2W);
2182 break;
2183 case 3:
2184 size = sizeof(DRIVER_INFO_3W);
2185 break;
2186 default:
2187 ERR("Invalid level\n");
2188 return FALSE;
2191 if(size <= cbBuf)
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);
2200 return FALSE;
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);
2209 return FALSE;
2212 /*****************************************************************************
2213 * GetPrinterDriverA [WINSPOOL.@]
2215 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2216 DWORD Level, LPBYTE pDriverInfo,
2217 DWORD cbBuf, LPDWORD pcbNeeded)
2219 BOOL ret;
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);
2224 return ret;
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)
2244 DWORD needed;
2246 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2247 pDriverDirectory, cbBuf, pcbNeeded);
2248 if(pName != NULL) {
2249 FIXME("pName = `%s' - unsupported\n", pName);
2250 SetLastError(ERROR_INVALID_PARAMETER);
2251 return FALSE;
2253 if(pEnvironment != NULL) {
2254 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2255 SetLastError(ERROR_INVALID_ENVIRONMENT);
2256 return FALSE;
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);
2263 needed++;
2264 if(pcbNeeded)
2265 *pcbNeeded = needed;
2266 if(needed > cbBuf) {
2267 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2268 return FALSE;
2270 return TRUE;
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;
2282 BOOL ret;
2284 if(pName)
2285 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2286 if(pEnvironment)
2287 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2288 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2289 pDriverDirectory, cbBuf, pcbNeeded );
2290 if(pNameA)
2291 HeapFree( GetProcessHeap(), 0, pNameA );
2292 if(pEnvironmentA)
2293 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2295 return ret;
2298 /*****************************************************************************
2299 * AddPrinterDriverA [WINSPOOL.@]
2301 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2303 DRIVER_INFO_3A di3;
2304 HKEY hkeyDrivers, hkeyName;
2306 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
2308 if(level != 2 && level != 3) {
2309 SetLastError(ERROR_INVALID_LEVEL);
2310 return FALSE;
2312 if(pName != NULL) {
2313 FIXME("pName= `%s' - unsupported\n", pName);
2314 SetLastError(ERROR_INVALID_PARAMETER);
2315 return FALSE;
2317 if(!pDriverInfo) {
2318 WARN("pDriverInfo == NULL\n");
2319 SetLastError(ERROR_INVALID_PARAMETER);
2320 return FALSE;
2323 if(level == 3)
2324 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2325 else {
2326 memset(&di3, 0, sizeof(di3));
2327 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2330 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2331 !di3.pDataFile) {
2332 SetLastError(ERROR_INVALID_PARAMETER);
2333 return FALSE;
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);
2342 if(!hkeyDrivers) {
2343 ERR("Can't create Drivers key\n");
2344 return FALSE;
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);
2353 return FALSE;
2356 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2357 RegCloseKey(hkeyDrivers);
2358 ERR("Can't create Name key\n");
2359 return FALSE;
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,
2366 sizeof(DWORD));
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);
2375 return TRUE;
2377 /*****************************************************************************
2378 * AddPrinterDriverW [WINSPOOL.@]
2380 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2381 LPBYTE pDriverInfo)
2383 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2384 level,pDriverInfo);
2385 return FALSE;
2389 /*****************************************************************************
2390 * PrinterProperties [WINSPOOL.@]
2392 * Displays a dialog to set the properties of the printer.
2394 * RETURNS
2395 * nonzero on success or zero on failure
2397 * BUGS
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);
2405 return FALSE;
2408 /*****************************************************************************
2409 * EnumJobsA [WINSPOOL.@]
2412 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2413 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2414 LPDWORD pcReturned)
2416 FIXME("stub\n");
2417 if(pcbNeeded) *pcbNeeded = 0;
2418 if(pcReturned) *pcReturned = 0;
2419 return TRUE;
2423 /*****************************************************************************
2424 * EnumJobsW [WINSPOOL.@]
2427 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2428 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2429 LPDWORD pcReturned)
2431 FIXME("stub\n");
2432 if(pcbNeeded) *pcbNeeded = 0;
2433 if(pcReturned) *pcReturned = 0;
2434 return TRUE;
2437 /*****************************************************************************
2438 * WINSPOOL_EnumPrinterDrivers [internal]
2440 * Delivers information about all printer drivers installed on the
2441 * localhost or a given server
2443 * RETURNS
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
2447 * BUGS
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)
2455 { HKEY hkeyDrivers;
2456 DWORD i, needed, number = 0, size = 0;
2457 WCHAR DriverNameW[255];
2458 PBYTE ptr;
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 */
2465 if(pName) {
2466 ERR("remote drivers unsupported! Current remote host is %s\n",
2467 debugstr_w(pName));
2468 return FALSE;
2471 /* check input parameter */
2472 if((Level < 1) || (Level > 3)) {
2473 ERR("unsupported level %ld \n", Level);
2474 return FALSE;
2477 /* initialize return values */
2478 if(pDriverInfo)
2479 memset( pDriverInfo, 0, cbBuf);
2480 *pcbNeeded = 0;
2481 *pcReturned = 0;
2483 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2484 if(!hkeyDrivers) {
2485 ERR("Can't open Drivers key\n");
2486 return FALSE;
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");
2493 return FALSE;
2495 TRACE("Found %ld Drivers\n", number);
2497 /* get size of single struct
2498 * unicode and ascii structure have the same size
2500 switch (Level) {
2501 case 1:
2502 size = sizeof(DRIVER_INFO_1A);
2503 break;
2504 case 2:
2505 size = sizeof(DRIVER_INFO_2A);
2506 break;
2507 case 3:
2508 size = sizeof(DRIVER_INFO_3A);
2509 break;
2512 /* calculate required buffer size */
2513 *pcbNeeded = size * number;
2515 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2516 i < number;
2517 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2518 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2519 != ERROR_SUCCESS) {
2520 ERR("Can't enum key number %ld\n", i);
2521 RegCloseKey(hkeyDrivers);
2522 return FALSE;
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);
2530 return FALSE;
2532 (*pcbNeeded) += needed;
2535 RegCloseKey(hkeyDrivers);
2537 if(cbBuf < *pcbNeeded){
2538 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2539 return FALSE;
2542 return TRUE;
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)
2566 { BOOL ret;
2567 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2569 if(pName)
2570 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2571 if(pEnvironment)
2572 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2574 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2575 cbBuf, pcbNeeded, pcReturned, FALSE);
2576 if(pNameW)
2577 HeapFree(GetProcessHeap(), 0, pNameW);
2578 if(pEnvironmentW)
2579 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2581 return ret;
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);
2592 return FALSE;
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;
2603 DWORD ret;
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))
2609 != ERROR_SUCCESS)
2610 return ret;
2612 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2613 != ERROR_SUCCESS) {
2614 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2615 RegCloseKey(hkeyPrinter);
2616 return ret;
2618 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2619 RegCloseKey(hkeySubkey);
2620 RegCloseKey(hkeyPrinter);
2621 return ret;
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;
2632 DWORD ret;
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))
2638 != ERROR_SUCCESS)
2639 return ret;
2641 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2642 != ERROR_SUCCESS) {
2643 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2644 RegCloseKey(hkeyPrinter);
2645 return ret;
2647 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2648 RegCloseKey(hkeySubkey);
2649 RegCloseKey(hkeyPrinter);
2650 return ret;
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,
2660 pData, cbData);
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,
2670 pData, cbData);
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;
2681 DWORD ret;
2683 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2684 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2685 pcbNeeded);
2687 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2688 != ERROR_SUCCESS)
2689 return ret;
2691 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2692 != ERROR_SUCCESS) {
2693 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2694 RegCloseKey(hkeyPrinter);
2695 return ret;
2697 *pcbNeeded = nSize;
2698 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2699 RegCloseKey(hkeySubkey);
2700 RegCloseKey(hkeyPrinter);
2701 return ret;
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;
2712 DWORD ret;
2714 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2715 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2716 pcbNeeded);
2718 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2719 != ERROR_SUCCESS)
2720 return ret;
2722 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2723 != ERROR_SUCCESS) {
2724 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2725 RegCloseKey(hkeyPrinter);
2726 return ret;
2728 *pcbNeeded = nSize;
2729 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2730 RegCloseKey(hkeySubkey);
2731 RegCloseKey(hkeyPrinter);
2732 return ret;
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,
2765 cbBufSize, dwType;
2766 LPWSTR lpValueName;
2767 HANDLE hHeap;
2768 PBYTE lpValue;
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",
2780 hPrinter, ret);
2781 return ret;
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);
2792 return 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);
2802 return ret;
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);
2813 return 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);
2884 return 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);
2933 return 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);
2965 return ret;
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);
2975 return ret;
2978 ret = RegCloseKey (hkSubKey);
2979 if (ret != ERROR_SUCCESS)
2981 ERR ("RegCloseKey returned %li\n", ret);
2982 return 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)
3000 INT len;
3001 LPWSTR pKeyNameW;
3002 DWORD ret, dwIndex, dwBufSize;
3003 HANDLE hHeap;
3004 LPSTR pBuffer;
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);
3012 if (len == 0)
3014 ret = GetLastError ();
3015 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3016 return 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 ());
3040 return ret;
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);
3050 return ret;
3053 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3055 ret = GetLastError ();
3056 ERR ("HeapFree failed with code %li\n", ret);
3057 return ret;
3060 if (*pnEnumValues == 0) /* empty key */
3061 return ERROR_SUCCESS;
3063 dwBufSize = 0;
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,
3093 NULL);
3094 if (len == 0)
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 ());
3100 return ret;
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)
3109 continue;
3111 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3112 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3113 if (len == 0)
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 ());
3119 return ret;
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);
3132 return ret;
3135 return ERROR_SUCCESS;