Fixed "conditional expr is always true due to being unsigned < 0"
[wine/dcerpc.git] / dlls / winspool / info.c
blob96500ff87a0275e5092b5788bf09892063c6dd8b
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stddef.h>
32 #ifdef HAVE_CUPS
33 # include <cups/cups.h>
34 #endif
35 #include "winspool.h"
36 #include "winbase.h"
37 #include "winerror.h"
38 #include "winreg.h"
39 #include "wine/windef16.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42 #include "heap.h"
43 #include "winnls.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
47 static LPWSTR *printer_array;
48 static int nb_printers;
50 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
51 WORD fwCapability, LPSTR lpszOutput,
52 LPDEVMODEA lpdm );
53 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
54 LPSTR lpszDevice, LPSTR lpszPort,
55 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
56 DWORD fwMode );
58 static char Printers[] =
59 "System\\CurrentControlSet\\control\\Print\\Printers\\";
60 static char Drivers[] =
61 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
63 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
65 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
66 'i','o','n',' ','F','i','l','e',0};
67 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
68 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
69 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
70 'M','o','d','e',0};
71 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
72 'i','l','e','s',0};
73 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
74 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
75 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
76 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
77 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
78 static WCHAR NameW[] = {'N','a','m','e',0};
79 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
80 static WCHAR PortW[] = {'P','o','r','t',0};
81 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
82 's','s','o','r',0};
83 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
84 'v','e','r',0};
85 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
86 'v','e','r','D','a','t','a',0};
87 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
88 'i','l','e',0};
89 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
90 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
92 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
93 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
94 DWORD Level, LPBYTE pDriverInfo,
95 DWORD cbBuf, LPDWORD pcbNeeded,
96 BOOL unicode);
97 static void
98 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
99 char qbuf[200];
101 /* If forcing, or no profile string entry for device yet, set the entry
103 * The always change entry if not WINEPS yet is discussable.
105 if (force ||
106 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
107 !strcmp(qbuf,"*") ||
108 !strstr(qbuf,"WINEPS")
110 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
112 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
113 WriteProfileStringA("windows","device",buf);
114 HeapFree(GetProcessHeap(),0,buf);
118 #ifdef HAVE_CUPS
119 BOOL
120 CUPS_LoadPrinters(void) {
121 char **printers;
122 int i,nrofdests,hadprinter = FALSE;
123 PRINTER_INFO_2A pinfo2a;
124 const char* def = cupsGetDefault();
126 nrofdests = cupsGetPrinters(&printers);
128 if (def && !strcmp(def,"none")) /* CUPS has "none" for no default printer */
129 def = NULL;
131 for (i=0;i<nrofdests;i++) {
132 const char *ppd = cupsGetPPD(printers[i]);
133 char *port,*devline;
135 if (!ppd) {
136 WARN("No ppd file for %s.\n",printers[i]);
137 /* If this was going to be the default printer,
138 * forget it and use another one.
140 if (def && !strcmp(def,printers[i]))
141 def = NULL;
142 continue;
144 unlink(ppd);
146 hadprinter = TRUE;
148 if (def && !strcmp(def,printers[i]))
149 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
151 /* The default printer has no PPD file, just use the first one
152 * which has one.
154 if (!def) {
155 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
156 def = printers[i];
158 memset(&pinfo2a,0,sizeof(pinfo2a));
159 pinfo2a.pPrinterName = printers[i];
160 pinfo2a.pDatatype = "RAW";
161 pinfo2a.pPrintProcessor = "WinPrint";
162 pinfo2a.pDriverName = "PS Driver";
163 pinfo2a.pComment = "WINEPS Printer using CUPS";
164 pinfo2a.pLocation = "<physical location of printer>";
165 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
166 sprintf(port,"LPR:%s",printers[i]);
167 pinfo2a.pPortName = port;
168 pinfo2a.pParameters = "<parameters?>";
169 pinfo2a.pShareName = "<share name?>";
170 pinfo2a.pSepFile = "<sep file?>";
172 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
173 sprintf(devline,"WINEPS,%s",port);
174 WriteProfileStringA("devices",printers[i],devline);
175 HeapFree(GetProcessHeap(),0,devline);
177 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
178 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
179 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
181 HeapFree(GetProcessHeap(),0,port);
183 return hadprinter;
185 #endif
187 static BOOL
188 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
189 PRINTER_INFO_2A pinfo2a;
190 char *s,*name,*prettyname,*devname;
191 BOOL isps = FALSE;
192 char *port,*devline;
194 while (isspace(*pent)) pent++;
195 s = strchr(pent,':');
196 if (!s) return FALSE;
197 *s='\0';
198 name = pent;
199 pent = s+1;
200 TRACE("%s\n",name);
202 /* Determine whether this is a postscript printer. */
204 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
205 if (strstr(name,"ps") ||
206 strstr(name,"pd") || /* postscript double page */
207 strstr(name,"postscript") ||
208 strstr(name,"PostScript")
210 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
211 isps = TRUE;
213 /* 2. Check if this is a remote printer. These usually are postscript
214 * capable
216 if (strstr(pent,":rm")) {
217 isps = TRUE;
218 TRACE("%s is remote, assuming postscript.\n",name);
220 /* 3. Check if we have an input filter program. If we have one, it
221 * most likely is one capable of converting postscript.
222 * (Could probably check for occurrence of 'gs' or 'ghostscript'
223 * in the if file itself.)
225 if (strstr(pent,":if=/")) {
226 isps = TRUE;
227 TRACE("%s has inputfilter program, assuming postscript.\n",name);
230 /* If it is not a postscript printer, we cannot use it. */
231 if (!isps)
232 return FALSE;
234 prettyname = name;
235 /* Get longest name, usually the one at the right for later display. */
236 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
237 s=strchr(name,'|');if (s) *s='\0';
239 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
240 * if it is too long, we use it as comment below. */
241 devname = prettyname;
242 if (strlen(devname)>=CCHDEVICENAME-1)
243 devname = name;
244 if (strlen(devname)>=CCHDEVICENAME-1)
245 return FALSE;
247 if (isfirst) /* set first entry as default */
248 WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
250 memset(&pinfo2a,0,sizeof(pinfo2a));
251 pinfo2a.pPrinterName = devname;
252 pinfo2a.pDatatype = "RAW";
253 pinfo2a.pPrintProcessor = "WinPrint";
254 pinfo2a.pDriverName = "PS Driver";
255 pinfo2a.pComment = "WINEPS Printer using LPR";
256 pinfo2a.pLocation = prettyname;
257 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
258 sprintf(port,"LPR:%s",name);
259 pinfo2a.pPortName = port;
260 pinfo2a.pParameters = "<parameters?>";
261 pinfo2a.pShareName = "<share name?>";
262 pinfo2a.pSepFile = "<sep file?>";
264 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
265 sprintf(devline,"WINEPS,%s",port);
266 WriteProfileStringA("devices",devname,devline);
267 HeapFree(GetProcessHeap(),0,devline);
269 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
270 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
271 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
273 HeapFree(GetProcessHeap(),0,port);
274 return TRUE;
277 static BOOL
278 PRINTCAP_LoadPrinters(void) {
279 BOOL hadprinter = FALSE, isfirst = TRUE;
280 char buf[200];
281 FILE *f;
283 f = fopen("/etc/printcap","r");
284 if (!f)
285 return FALSE;
287 while (fgets(buf,sizeof(buf),f)) {
288 char *pent = NULL;
289 do {
290 char *s;
291 s=strchr(buf,'\n'); if (s) *s='\0';
292 if ((buf[0]=='#') || (buf[0]=='\0'))
293 continue;
295 if (pent) {
296 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
297 strcat(pent,buf);
298 } else {
299 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
300 strcpy(pent,buf);
303 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
304 pent[strlen(pent)-1] = '\0';
305 else
306 break;
307 } while (fgets(buf,sizeof(buf),f));
308 if (pent)
309 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
310 isfirst = FALSE;
311 if (pent) HeapFree(GetProcessHeap(),0,pent);
312 pent = NULL;
313 if (feof(f)) break;
315 fclose(f);
316 return hadprinter;
319 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
321 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
322 lstrlenW(value) * sizeof(WCHAR));
325 void
326 WINSPOOL_LoadSystemPrinters() {
327 HKEY hkPPD;
328 DRIVER_INFO_3A di3a;
329 di3a.cVersion = 0x400;
330 di3a.pName = "PS Driver";
331 di3a.pEnvironment = NULL; /* NULL means auto */
332 di3a.pDriverPath = "wineps.drv";
333 di3a.pDataFile = "<datafile?>";
334 di3a.pConfigFile = "wineps.drv";
335 di3a.pHelpFile = "<helpfile?>";
336 di3a.pDependentFiles = "<dependend files?>";
337 di3a.pMonitorName = "<monitor name?>";
338 di3a.pDefaultDataType = "RAW";
340 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
341 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
342 return;
344 #ifdef HAVE_CUPS
345 /* If we have any CUPS based printers, skip looking for printcap printers */
346 if (CUPS_LoadPrinters())
347 return;
348 #endif
350 /* Check for [ppd] section in config file before parsing /etc/printcap */
352 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
353 &hkPPD) == ERROR_SUCCESS)
355 RegCloseKey(hkPPD);
356 PRINTCAP_LoadPrinters();
361 /******************************************************************
362 * WINSPOOL_GetOpenedPrinterEntry
363 * Get the first place empty in the opened printer table
365 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
367 int i;
369 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
371 if (i >= nb_printers)
373 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
374 (nb_printers + 16) * sizeof(*new_array) );
375 if (!new_array) return 0;
376 printer_array = new_array;
377 nb_printers += 16;
380 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
382 strcpyW( printer_array[i], name );
383 return (HANDLE)(i + 1);
385 return 0;
388 /******************************************************************
389 * WINSPOOL_GetOpenedPrinter
390 * Get the pointer to the opened printer referred by the handle
392 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
394 int idx = (int)printerHandle;
395 if ((idx <= 0) || (idx > nb_printers))
397 SetLastError(ERROR_INVALID_HANDLE);
398 return NULL;
400 return printer_array[idx - 1];
403 /******************************************************************
404 * WINSPOOL_GetOpenedPrinterRegKey
407 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
409 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
410 DWORD ret;
411 HKEY hkeyPrinters;
413 if(!name) return ERROR_INVALID_HANDLE;
415 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
416 ERROR_SUCCESS)
417 return ret;
419 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
421 ERR("Can't find opened printer %s in registry\n",
422 debugstr_w(name));
423 RegCloseKey(hkeyPrinters);
424 return ERROR_INVALID_PRINTER_NAME; /* ? */
426 RegCloseKey(hkeyPrinters);
427 return ERROR_SUCCESS;
430 /***********************************************************
431 * DEVMODEcpyAtoW
433 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
435 BOOL Formname;
436 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
437 DWORD size;
439 Formname = (dmA->dmSize > off_formname);
440 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
441 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
442 CCHDEVICENAME);
443 if(!Formname) {
444 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
445 dmA->dmSize - CCHDEVICENAME);
446 } else {
447 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
448 off_formname - CCHDEVICENAME);
449 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
450 CCHFORMNAME);
451 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
452 (off_formname + CCHFORMNAME));
454 dmW->dmSize = size;
455 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
456 dmA->dmDriverExtra);
457 return dmW;
460 /***********************************************************
461 * DEVMODEdupAtoW
462 * Creates a unicode copy of supplied devmode on heap
464 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
466 LPDEVMODEW dmW;
467 DWORD size;
468 BOOL Formname;
469 ptrdiff_t off_formname;
471 TRACE("\n");
472 if(!dmA) return NULL;
474 off_formname = (char *)dmA->dmFormName - (char *)dmA;
475 Formname = (dmA->dmSize > off_formname);
476 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
477 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
478 return DEVMODEcpyAtoW(dmW, dmA);
481 /***********************************************************
482 * DEVMODEdupWtoA
483 * Creates an ascii copy of supplied devmode on heap
485 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
487 LPDEVMODEA dmA;
488 DWORD size;
489 BOOL Formname;
490 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
492 if(!dmW) return NULL;
493 Formname = (dmW->dmSize > off_formname);
494 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
495 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
496 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
497 CCHDEVICENAME, NULL, NULL);
498 if(!Formname) {
499 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
500 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
501 } else {
502 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
503 off_formname - CCHDEVICENAME * sizeof(WCHAR));
504 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
505 CCHFORMNAME, NULL, NULL);
506 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
507 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
509 dmA->dmSize = size;
510 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
511 dmW->dmDriverExtra);
512 return dmA;
515 /***********************************************************
516 * PRINTER_INFO_2AtoW
517 * Creates a unicode copy of PRINTER_INFO_2A on heap
519 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
521 LPPRINTER_INFO_2W piW;
522 if(!piA) return NULL;
523 piW = HeapAlloc(heap, 0, sizeof(*piW));
524 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
525 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
526 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
527 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
528 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
529 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
530 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
531 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
532 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
533 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
534 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
535 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
536 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
537 return piW;
540 /***********************************************************
541 * FREE_PRINTER_INFO_2W
542 * Free PRINTER_INFO_2W and all strings
544 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
546 if(!piW) return;
548 HeapFree(heap,0,piW->pServerName);
549 HeapFree(heap,0,piW->pPrinterName);
550 HeapFree(heap,0,piW->pShareName);
551 HeapFree(heap,0,piW->pPortName);
552 HeapFree(heap,0,piW->pDriverName);
553 HeapFree(heap,0,piW->pComment);
554 HeapFree(heap,0,piW->pLocation);
555 HeapFree(heap,0,piW->pDevMode);
556 HeapFree(heap,0,piW->pSepFile);
557 HeapFree(heap,0,piW->pPrintProcessor);
558 HeapFree(heap,0,piW->pDatatype);
559 HeapFree(heap,0,piW->pParameters);
560 HeapFree(heap,0,piW);
561 return;
564 /******************************************************************
565 * DeviceCapabilities [WINSPOOL.@]
566 * DeviceCapabilitiesA [WINSPOOL.@]
569 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
570 LPSTR pOutput, LPDEVMODEA lpdm)
572 INT ret;
574 if (!GDI_CallDeviceCapabilities16)
576 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
577 (LPCSTR)104 );
578 if (!GDI_CallDeviceCapabilities16) return -1;
580 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
582 /* If DC_PAPERSIZE map POINT16s to POINTs */
583 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
584 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
585 POINT *pt = (POINT *)pOutput;
586 INT i;
587 memcpy(tmp, pOutput, ret * sizeof(POINT16));
588 for(i = 0; i < ret; i++, pt++)
590 pt->x = tmp[i].x;
591 pt->y = tmp[i].y;
593 HeapFree( GetProcessHeap(), 0, tmp );
595 return ret;
599 /*****************************************************************************
600 * DeviceCapabilitiesW [WINSPOOL.@]
602 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
605 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
606 WORD fwCapability, LPWSTR pOutput,
607 const DEVMODEW *pDevMode)
609 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
610 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
611 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
612 INT ret;
614 if(pOutput && (fwCapability == DC_BINNAMES ||
615 fwCapability == DC_FILEDEPENDENCIES ||
616 fwCapability == DC_PAPERNAMES)) {
617 /* These need A -> W translation */
618 INT size = 0, i;
619 LPSTR pOutputA;
620 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
621 dmA);
622 if(ret == -1)
623 return ret;
624 switch(fwCapability) {
625 case DC_BINNAMES:
626 size = 24;
627 break;
628 case DC_PAPERNAMES:
629 case DC_FILEDEPENDENCIES:
630 size = 64;
631 break;
633 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
634 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
635 dmA);
636 for(i = 0; i < ret; i++)
637 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
638 pOutput + (i * size), size);
639 HeapFree(GetProcessHeap(), 0, pOutputA);
640 } else {
641 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
642 (LPSTR)pOutput, dmA);
644 HeapFree(GetProcessHeap(),0,pPortA);
645 HeapFree(GetProcessHeap(),0,pDeviceA);
646 HeapFree(GetProcessHeap(),0,dmA);
647 return ret;
650 /******************************************************************
651 * DocumentPropertiesA [WINSPOOL.@]
654 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
655 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
656 LPDEVMODEA pDevModeInput,DWORD fMode )
658 LPSTR lpName = pDeviceName;
659 LONG ret;
661 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
662 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
665 if(!pDeviceName) {
666 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
667 if(!lpNameW) {
668 ERR("no name from hPrinter?\n");
669 return -1;
671 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
674 if (!GDI_CallExtDeviceMode16)
676 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
677 (LPCSTR)102 );
678 if (!GDI_CallExtDeviceMode16) {
679 ERR("No CallExtDeviceMode16?\n");
680 return -1;
683 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
684 pDevModeInput, NULL, fMode);
686 if(!pDeviceName)
687 HeapFree(GetProcessHeap(),0,lpName);
688 return ret;
692 /*****************************************************************************
693 * DocumentPropertiesW (WINSPOOL.@)
695 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
696 LPWSTR pDeviceName,
697 LPDEVMODEW pDevModeOutput,
698 LPDEVMODEW pDevModeInput, DWORD fMode)
701 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
702 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
703 LPDEVMODEA pDevModeOutputA = NULL;
704 LONG ret;
706 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
707 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
708 fMode);
709 if(pDevModeOutput) {
710 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
711 if(ret < 0) return ret;
712 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
714 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
715 pDevModeInputA, fMode);
716 if(pDevModeOutput) {
717 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
718 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
720 if(fMode == 0 && ret > 0)
721 ret += (CCHDEVICENAME + CCHFORMNAME);
722 HeapFree(GetProcessHeap(),0,pDevModeInputA);
723 HeapFree(GetProcessHeap(),0,pDeviceNameA);
724 return ret;
727 /******************************************************************
728 * OpenPrinterA [WINSPOOL.@]
731 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
732 LPPRINTER_DEFAULTSA pDefault)
734 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
735 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
736 BOOL ret;
738 if(pDefault) {
739 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
740 pDefault->pDatatype);
741 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
742 pDefault->pDevMode);
743 DefaultW.DesiredAccess = pDefault->DesiredAccess;
744 pDefaultW = &DefaultW;
746 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
747 if(pDefault) {
748 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
749 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
751 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
752 return ret;
755 /******************************************************************
756 * OpenPrinterW [WINSPOOL.@]
759 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
760 LPPRINTER_DEFAULTSW pDefault)
762 HKEY hkeyPrinters, hkeyPrinter;
764 if (!lpPrinterName) {
765 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
766 SetLastError(ERROR_INVALID_PARAMETER);
767 return FALSE;
770 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
771 pDefault);
773 /* Check Printer exists */
774 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
775 ERROR_SUCCESS) {
776 ERR("Can't create Printers key\n");
777 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
778 return FALSE;
781 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
782 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
783 != ERROR_SUCCESS) {
784 TRACE("Can't find printer %s in registry\n",
785 debugstr_w(lpPrinterName));
786 RegCloseKey(hkeyPrinters);
787 SetLastError(ERROR_INVALID_PRINTER_NAME);
788 return FALSE;
790 RegCloseKey(hkeyPrinter);
791 RegCloseKey(hkeyPrinters);
793 if(!phPrinter) /* This seems to be what win95 does anyway */
794 return TRUE;
796 /* Get the unique handle of the printer*/
797 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
799 if (pDefault != NULL)
800 FIXME("Not handling pDefault\n");
802 return TRUE;
805 /******************************************************************
806 * AddMonitorA [WINSPOOL.@]
809 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
811 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
812 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
813 return FALSE;
816 /******************************************************************
817 * DeletePrinterDriverA [WINSPOOL.@]
820 BOOL WINAPI
821 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
823 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
824 debugstr_a(pDriverName));
825 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
826 return FALSE;
830 /******************************************************************
831 * DeleteMonitorA [WINSPOOL.@]
834 BOOL WINAPI
835 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
837 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
838 debugstr_a(pMonitorName));
839 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
840 return FALSE;
844 /******************************************************************
845 * DeletePortA [WINSPOOL.@]
848 BOOL WINAPI
849 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
851 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
852 debugstr_a(pPortName));
853 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
854 return FALSE;
857 /******************************************************************************
858 * SetPrinterW [WINSPOOL.@]
860 BOOL WINAPI
861 SetPrinterW(
862 HANDLE hPrinter,
863 DWORD Level,
864 LPBYTE pPrinter,
865 DWORD Command) {
867 FIXME("():stub\n");
868 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
869 return FALSE;
872 /******************************************************************************
873 * WritePrinter [WINSPOOL.@]
875 BOOL WINAPI
876 WritePrinter(
877 HANDLE hPrinter,
878 LPVOID pBuf,
879 DWORD cbBuf,
880 LPDWORD pcWritten) {
882 FIXME("():stub\n");
883 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
884 return FALSE;
887 /*****************************************************************************
888 * AddFormA [WINSPOOL.@]
890 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
892 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
893 return 1;
896 /*****************************************************************************
897 * AddFormW [WINSPOOL.@]
899 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
901 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
902 return 1;
905 /*****************************************************************************
906 * AddJobA [WINSPOOL.@]
908 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
909 DWORD cbBuf, LPDWORD pcbNeeded)
911 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
912 pcbNeeded);
913 return 1;
916 /*****************************************************************************
917 * AddJobW [WINSPOOL.@]
919 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
920 LPDWORD pcbNeeded)
922 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
923 pcbNeeded);
924 return 1;
927 /*****************************************************************************
928 * WINSPOOL_OpenDriverReg [internal]
930 * opens the registry for the printer drivers depending on the given input
931 * variable pEnvironment
933 * RETURNS:
934 * the opened hkey on success
935 * NULL on error
937 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
938 { HKEY retval;
939 LPSTR lpKey, p = NULL;
941 TRACE("%s\n",
942 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
944 if(pEnvironment)
945 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
946 pEnvironment;
947 else {
948 OSVERSIONINFOA ver;
949 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
951 if(!GetVersionExA( &ver))
952 return 0;
954 switch (ver.dwPlatformId) {
955 case VER_PLATFORM_WIN32s:
956 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
957 return 0;
959 case VER_PLATFORM_WIN32_NT:
960 p = "Windows NT x86";
961 break;
962 default:
963 p = "Windows 4.0";
964 break;
966 TRACE("set environment to %s\n", p);
969 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
970 strlen(p) + strlen(Drivers));
971 sprintf( lpKey, Drivers, p);
973 TRACE("%s\n", lpKey);
975 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
976 ERROR_SUCCESS)
977 retval = 0;
979 if(pEnvironment && unicode)
980 HeapFree( GetProcessHeap(), 0, p);
981 HeapFree( GetProcessHeap(), 0, lpKey);
983 return retval;
986 /*****************************************************************************
987 * AddPrinterW [WINSPOOL.@]
989 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
991 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
992 LPDEVMODEA dmA;
993 LPDEVMODEW dmW;
994 HANDLE retval;
995 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
996 LONG size;
998 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1000 if(pName != NULL) {
1001 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1002 SetLastError(ERROR_INVALID_PARAMETER);
1003 return 0;
1005 if(Level != 2) {
1006 ERR("Level = %ld, unsupported!\n", Level);
1007 SetLastError(ERROR_INVALID_LEVEL);
1008 return 0;
1010 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1011 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1012 debugstr_w(pi->pPrinterName)
1014 SetLastError(ERROR_INVALID_LEVEL);
1015 return 0;
1017 if(!pPrinter) {
1018 SetLastError(ERROR_INVALID_PARAMETER);
1019 return 0;
1021 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1022 ERROR_SUCCESS) {
1023 ERR("Can't create Printers key\n");
1024 return 0;
1026 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1027 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1028 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1029 RegCloseKey(hkeyPrinter);
1030 RegCloseKey(hkeyPrinters);
1031 return 0;
1033 RegCloseKey(hkeyPrinter);
1035 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1036 if(!hkeyDrivers) {
1037 ERR("Can't create Drivers key\n");
1038 RegCloseKey(hkeyPrinters);
1039 return 0;
1041 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1042 ERROR_SUCCESS) {
1043 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1044 RegCloseKey(hkeyPrinters);
1045 RegCloseKey(hkeyDrivers);
1046 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1047 return 0;
1049 RegCloseKey(hkeyDriver);
1050 RegCloseKey(hkeyDrivers);
1052 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1053 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1054 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1055 RegCloseKey(hkeyPrinters);
1056 return 0;
1059 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1060 ERROR_SUCCESS) {
1061 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1062 SetLastError(ERROR_INVALID_PRINTER_NAME);
1063 RegCloseKey(hkeyPrinters);
1064 return 0;
1066 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1067 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1068 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1070 /* See if we can load the driver. We may need the devmode structure anyway
1072 * FIXME:
1073 * Note that DocumentPropertiesW will briefly try to open the printer we
1074 * just create to find a DEVMODEA struct (it will use the WINEPS default
1075 * one in case it is not there, so we are ok).
1077 size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
1078 if(size < 0) {
1079 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1080 size = sizeof(DEVMODEW);
1082 if(pi->pDevMode)
1083 dmW = pi->pDevMode;
1084 else {
1085 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1086 dmW->dmSize = size;
1087 if (0>DocumentPropertiesW(0,-1,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1088 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1089 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1090 return 0;
1092 /* set devmode to printer name */
1093 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1096 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1097 and we support these drivers. NT writes DEVMODEW so somehow
1098 we'll need to distinguish between these when we support NT
1099 drivers */
1100 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1101 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1102 dmA->dmSize + dmA->dmDriverExtra);
1103 HeapFree(GetProcessHeap(), 0, dmA);
1104 if(!pi->pDevMode)
1105 HeapFree(GetProcessHeap(), 0, dmW);
1106 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1107 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1108 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1109 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1111 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1112 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1113 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1114 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1115 (LPBYTE)&pi->Priority, sizeof(DWORD));
1116 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1117 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1118 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1119 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1120 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1121 (LPBYTE)&pi->Status, sizeof(DWORD));
1122 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1123 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1125 RegCloseKey(hkeyPrinter);
1126 RegCloseKey(hkeyPrinters);
1127 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1128 ERR("OpenPrinter failing\n");
1129 return 0;
1131 return retval;
1134 /*****************************************************************************
1135 * AddPrinterA [WINSPOOL.@]
1137 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1139 WCHAR *pNameW;
1140 PRINTER_INFO_2W *piW;
1141 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1142 HANDLE ret;
1144 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1145 if(Level != 2) {
1146 ERR("Level = %ld, unsupported!\n", Level);
1147 SetLastError(ERROR_INVALID_LEVEL);
1148 return 0;
1150 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
1151 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1153 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
1155 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1156 HeapFree(GetProcessHeap(),0,pNameW);
1157 return ret;
1161 /*****************************************************************************
1162 * ClosePrinter [WINSPOOL.@]
1164 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1166 int i = (int)hPrinter;
1168 TRACE("Handle %d\n", hPrinter);
1170 if ((i <= 0) || (i > nb_printers)) return FALSE;
1171 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1172 printer_array[i - 1] = NULL;
1173 return TRUE;
1176 /*****************************************************************************
1177 * DeleteFormA [WINSPOOL.@]
1179 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1181 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
1182 return 1;
1185 /*****************************************************************************
1186 * DeleteFormW [WINSPOOL.@]
1188 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1190 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
1191 return 1;
1194 /*****************************************************************************
1195 * DeletePrinter [WINSPOOL.@]
1197 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1199 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1200 HKEY hkeyPrinters;
1202 if(!lpNameW) return FALSE;
1203 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1204 ERROR_SUCCESS) {
1205 ERR("Can't open Printers key\n");
1206 return 0;
1209 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1210 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1211 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1212 RegCloseKey(hkeyPrinters);
1213 return 0;
1216 ClosePrinter(hPrinter);
1217 return TRUE;
1220 /*****************************************************************************
1221 * SetPrinterA [WINSPOOL.@]
1223 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1224 DWORD Command)
1226 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1227 return FALSE;
1230 /*****************************************************************************
1231 * SetJobA [WINSPOOL.@]
1233 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1234 LPBYTE pJob, DWORD Command)
1236 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1237 Command);
1238 return FALSE;
1241 /*****************************************************************************
1242 * SetJobW [WINSPOOL.@]
1244 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1245 LPBYTE pJob, DWORD Command)
1247 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1248 Command);
1249 return FALSE;
1252 /*****************************************************************************
1253 * GetFormA [WINSPOOL.@]
1255 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1256 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1258 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1259 Level,pForm,cbBuf,pcbNeeded);
1260 return FALSE;
1263 /*****************************************************************************
1264 * GetFormW [WINSPOOL.@]
1266 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1267 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1269 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1270 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1271 return FALSE;
1274 /*****************************************************************************
1275 * SetFormA [WINSPOOL.@]
1277 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1278 LPBYTE pForm)
1280 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1281 return FALSE;
1284 /*****************************************************************************
1285 * SetFormW [WINSPOOL.@]
1287 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1288 LPBYTE pForm)
1290 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1291 return FALSE;
1294 /*****************************************************************************
1295 * ReadPrinter [WINSPOOL.@]
1297 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1298 LPDWORD pNoBytesRead)
1300 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1301 return FALSE;
1304 /*****************************************************************************
1305 * ResetPrinterA [WINSPOOL.@]
1307 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1309 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1310 return FALSE;
1313 /*****************************************************************************
1314 * ResetPrinterW [WINSPOOL.@]
1316 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1318 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1319 return FALSE;
1322 /*****************************************************************************
1323 * WINSPOOL_GetDWORDFromReg
1325 * Return DWORD associated with ValueName from hkey.
1327 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1329 DWORD sz = sizeof(DWORD), type, value = 0;
1330 LONG ret;
1332 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1334 if(ret != ERROR_SUCCESS) {
1335 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1336 return 0;
1338 if(type != REG_DWORD) {
1339 ERR("Got type %ld\n", type);
1340 return 0;
1342 return value;
1345 /*****************************************************************************
1346 * WINSPOOL_GetStringFromReg
1348 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1349 * String is stored either as unicode or ascii.
1350 * Bit of a hack here to get the ValueName if we want ascii.
1352 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1353 DWORD buflen, DWORD *needed,
1354 BOOL unicode)
1356 DWORD sz = buflen, type;
1357 LONG ret;
1359 if(unicode)
1360 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1361 else {
1362 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1363 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1364 HeapFree(GetProcessHeap(),0,ValueNameA);
1366 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1367 WARN("Got ret = %ld\n", ret);
1368 *needed = 0;
1369 return FALSE;
1371 *needed = sz;
1372 return TRUE;
1375 /*****************************************************************************
1376 * WINSPOOL_GetDefaultDevMode
1378 * Get a default DevMode values for wineps.
1379 * FIXME - use ppd.
1382 static void WINSPOOL_GetDefaultDevMode(
1383 LPBYTE ptr,
1384 DWORD buflen, DWORD *needed,
1385 BOOL unicode)
1387 DEVMODEA dm;
1389 /* fill default DEVMODE - should be read from ppd... */
1390 ZeroMemory( &dm, sizeof(dm) );
1391 strcpy(dm.dmDeviceName,"wineps");
1392 dm.dmSpecVersion = DM_SPECVERSION;
1393 dm.dmDriverVersion = 1;
1394 dm.dmSize = sizeof(DEVMODEA);
1395 dm.dmDriverExtra = 0;
1396 dm.dmFields =
1397 DM_ORIENTATION | DM_PAPERSIZE |
1398 DM_PAPERLENGTH | DM_PAPERWIDTH |
1399 DM_SCALE |
1400 DM_COPIES |
1401 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1402 DM_YRESOLUTION | DM_TTOPTION;
1404 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1405 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1406 dm.u1.s1.dmPaperLength = 2970;
1407 dm.u1.s1.dmPaperWidth = 2100;
1409 dm.dmScale = 100;
1410 dm.dmCopies = 1;
1411 dm.dmDefaultSource = DMBIN_AUTO;
1412 dm.dmPrintQuality = DMRES_MEDIUM;
1413 /* dm.dmColor */
1414 /* dm.dmDuplex */
1415 dm.dmYResolution = 300; /* 300dpi */
1416 dm.dmTTOption = DMTT_BITMAP;
1417 /* dm.dmCollate */
1418 /* dm.dmFormName */
1419 /* dm.dmLogPixels */
1420 /* dm.dmBitsPerPel */
1421 /* dm.dmPelsWidth */
1422 /* dm.dmPelsHeight */
1423 /* dm.dmDisplayFlags */
1424 /* dm.dmDisplayFrequency */
1425 /* dm.dmICMMethod */
1426 /* dm.dmICMIntent */
1427 /* dm.dmMediaType */
1428 /* dm.dmDitherType */
1429 /* dm.dmReserved1 */
1430 /* dm.dmReserved2 */
1431 /* dm.dmPanningWidth */
1432 /* dm.dmPanningHeight */
1434 if(unicode) {
1435 if(buflen >= sizeof(DEVMODEW)) {
1436 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1437 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1438 HeapFree(GetProcessHeap(),0,pdmW);
1440 *needed = sizeof(DEVMODEW);
1442 else
1444 if(buflen >= sizeof(DEVMODEA)) {
1445 memcpy(ptr, &dm, sizeof(DEVMODEA));
1447 *needed = sizeof(DEVMODEA);
1451 /*****************************************************************************
1452 * WINSPOOL_GetDevModeFromReg
1454 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1455 * DevMode is stored either as unicode or ascii.
1457 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1458 LPBYTE ptr,
1459 DWORD buflen, DWORD *needed,
1460 BOOL unicode)
1462 DWORD sz = buflen, type;
1463 LONG ret;
1465 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1466 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1467 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1468 if (sz < sizeof(DEVMODEA))
1470 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1471 return FALSE;
1473 /* ensures that dmSize is not erratically bogus if registry is invalid */
1474 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1475 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1476 if(unicode) {
1477 sz += (CCHDEVICENAME + CCHFORMNAME);
1478 if(buflen >= sz) {
1479 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1480 memcpy(ptr, dmW, sz);
1481 HeapFree(GetProcessHeap(),0,dmW);
1484 *needed = sz;
1485 return TRUE;
1488 /*********************************************************************
1489 * WINSPOOL_GetPrinter_2
1491 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1492 * The strings are either stored as unicode or ascii.
1494 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1495 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1496 BOOL unicode)
1498 DWORD size, left = cbBuf;
1499 BOOL space = (cbBuf > 0);
1500 LPBYTE ptr = buf;
1502 *pcbNeeded = 0;
1504 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1505 unicode)) {
1506 if(space && size <= left) {
1507 pi2->pPrinterName = (LPWSTR)ptr;
1508 ptr += size;
1509 left -= size;
1510 } else
1511 space = FALSE;
1512 *pcbNeeded += size;
1514 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1515 unicode)) {
1516 if(space && size <= left) {
1517 pi2->pShareName = (LPWSTR)ptr;
1518 ptr += size;
1519 left -= size;
1520 } else
1521 space = FALSE;
1522 *pcbNeeded += size;
1524 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1525 unicode)) {
1526 if(space && size <= left) {
1527 pi2->pPortName = (LPWSTR)ptr;
1528 ptr += size;
1529 left -= size;
1530 } else
1531 space = FALSE;
1532 *pcbNeeded += size;
1534 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1535 &size, unicode)) {
1536 if(space && size <= left) {
1537 pi2->pDriverName = (LPWSTR)ptr;
1538 ptr += size;
1539 left -= size;
1540 } else
1541 space = FALSE;
1542 *pcbNeeded += size;
1544 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1545 unicode)) {
1546 if(space && size <= left) {
1547 pi2->pComment = (LPWSTR)ptr;
1548 ptr += size;
1549 left -= size;
1550 } else
1551 space = FALSE;
1552 *pcbNeeded += size;
1554 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1555 unicode)) {
1556 if(space && size <= left) {
1557 pi2->pLocation = (LPWSTR)ptr;
1558 ptr += size;
1559 left -= size;
1560 } else
1561 space = FALSE;
1562 *pcbNeeded += size;
1564 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1565 &size, unicode)) {
1566 if(space && size <= left) {
1567 pi2->pDevMode = (LPDEVMODEW)ptr;
1568 ptr += size;
1569 left -= size;
1570 } else
1571 space = FALSE;
1572 *pcbNeeded += size;
1574 else
1576 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1577 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
1578 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1579 if(space && size <= left) {
1580 pi2->pDevMode = (LPDEVMODEW)ptr;
1581 ptr += size;
1582 left -= size;
1583 } else
1584 space = FALSE;
1585 *pcbNeeded += size;
1587 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1588 &size, unicode)) {
1589 if(space && size <= left) {
1590 pi2->pSepFile = (LPWSTR)ptr;
1591 ptr += size;
1592 left -= size;
1593 } else
1594 space = FALSE;
1595 *pcbNeeded += size;
1597 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1598 &size, unicode)) {
1599 if(space && size <= left) {
1600 pi2->pPrintProcessor = (LPWSTR)ptr;
1601 ptr += size;
1602 left -= size;
1603 } else
1604 space = FALSE;
1605 *pcbNeeded += size;
1607 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1608 &size, unicode)) {
1609 if(space && size <= left) {
1610 pi2->pDatatype = (LPWSTR)ptr;
1611 ptr += size;
1612 left -= size;
1613 } else
1614 space = FALSE;
1615 *pcbNeeded += size;
1617 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1618 &size, unicode)) {
1619 if(space && size <= left) {
1620 pi2->pParameters = (LPWSTR)ptr;
1621 ptr += size;
1622 left -= size;
1623 } else
1624 space = FALSE;
1625 *pcbNeeded += size;
1627 if(pi2) {
1628 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1629 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1630 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1631 "Default Priority");
1632 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1633 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1636 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1637 memset(pi2, 0, sizeof(*pi2));
1639 return space;
1642 /*********************************************************************
1643 * WINSPOOL_GetPrinter_4
1645 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1647 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1648 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1649 BOOL unicode)
1651 DWORD size, left = cbBuf;
1652 BOOL space = (cbBuf > 0);
1653 LPBYTE ptr = buf;
1655 *pcbNeeded = 0;
1657 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1658 unicode)) {
1659 if(space && size <= left) {
1660 pi4->pPrinterName = (LPWSTR)ptr;
1661 ptr += size;
1662 left -= size;
1663 } else
1664 space = FALSE;
1665 *pcbNeeded += size;
1667 if(pi4) {
1668 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1671 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1672 memset(pi4, 0, sizeof(*pi4));
1674 return space;
1677 /*********************************************************************
1678 * WINSPOOL_GetPrinter_5
1680 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1682 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1683 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1684 BOOL unicode)
1686 DWORD size, left = cbBuf;
1687 BOOL space = (cbBuf > 0);
1688 LPBYTE ptr = buf;
1690 *pcbNeeded = 0;
1692 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1693 unicode)) {
1694 if(space && size <= left) {
1695 pi5->pPrinterName = (LPWSTR)ptr;
1696 ptr += size;
1697 left -= size;
1698 } else
1699 space = FALSE;
1700 *pcbNeeded += size;
1702 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1703 unicode)) {
1704 if(space && size <= left) {
1705 pi5->pPortName = (LPWSTR)ptr;
1706 ptr += size;
1707 left -= size;
1708 } else
1709 space = FALSE;
1710 *pcbNeeded += size;
1712 if(pi5) {
1713 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1714 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1715 "dnsTimeout");
1716 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1717 "txTimeout");
1720 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1721 memset(pi5, 0, sizeof(*pi5));
1723 return space;
1726 /*****************************************************************************
1727 * WINSPOOL_GetPrinter
1729 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1730 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1731 * just a collection of pointers to strings.
1733 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1734 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1736 LPCWSTR name;
1737 DWORD size, needed = 0;
1738 LPBYTE ptr = NULL;
1739 HKEY hkeyPrinter, hkeyPrinters;
1740 BOOL ret;
1742 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1744 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1746 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1747 ERROR_SUCCESS) {
1748 ERR("Can't create Printers key\n");
1749 return FALSE;
1751 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1753 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1754 RegCloseKey(hkeyPrinters);
1755 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1756 return FALSE;
1759 switch(Level) {
1760 case 2:
1762 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1764 size = sizeof(PRINTER_INFO_2W);
1765 if(size <= cbBuf) {
1766 ptr = pPrinter + size;
1767 cbBuf -= size;
1768 memset(pPrinter, 0, size);
1769 } else {
1770 pi2 = NULL;
1771 cbBuf = 0;
1773 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1774 unicode);
1775 needed += size;
1776 break;
1779 case 4:
1781 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1783 size = sizeof(PRINTER_INFO_4W);
1784 if(size <= cbBuf) {
1785 ptr = pPrinter + size;
1786 cbBuf -= size;
1787 memset(pPrinter, 0, size);
1788 } else {
1789 pi4 = NULL;
1790 cbBuf = 0;
1792 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1793 unicode);
1794 needed += size;
1795 break;
1799 case 5:
1801 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1803 size = sizeof(PRINTER_INFO_5W);
1804 if(size <= cbBuf) {
1805 ptr = pPrinter + size;
1806 cbBuf -= size;
1807 memset(pPrinter, 0, size);
1808 } else {
1809 pi5 = NULL;
1810 cbBuf = 0;
1813 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1814 unicode);
1815 needed += size;
1816 break;
1819 default:
1820 FIXME("Unimplemented level %ld\n", Level);
1821 SetLastError(ERROR_INVALID_LEVEL);
1822 RegCloseKey(hkeyPrinters);
1823 RegCloseKey(hkeyPrinter);
1824 return FALSE;
1827 RegCloseKey(hkeyPrinter);
1828 RegCloseKey(hkeyPrinters);
1830 TRACE("returing %d needed = %ld\n", ret, needed);
1831 if(pcbNeeded) *pcbNeeded = needed;
1832 if(!ret)
1833 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1834 return ret;
1837 /*****************************************************************************
1838 * GetPrinterW [WINSPOOL.@]
1840 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1841 DWORD cbBuf, LPDWORD pcbNeeded)
1843 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1844 TRUE);
1847 /*****************************************************************************
1848 * GetPrinterA [WINSPOOL.@]
1850 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1851 DWORD cbBuf, LPDWORD pcbNeeded)
1853 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1854 FALSE);
1857 /*****************************************************************************
1858 * WINSPOOL_EnumPrinters
1860 * Implementation of EnumPrintersA|W
1862 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1863 DWORD dwLevel, LPBYTE lpbPrinters,
1864 DWORD cbBuf, LPDWORD lpdwNeeded,
1865 LPDWORD lpdwReturned, BOOL unicode)
1868 HKEY hkeyPrinters, hkeyPrinter;
1869 WCHAR PrinterName[255];
1870 DWORD needed = 0, number = 0;
1871 DWORD used, i, left;
1872 PBYTE pi, buf;
1874 if(lpbPrinters)
1875 memset(lpbPrinters, 0, cbBuf);
1876 if(lpdwReturned)
1877 *lpdwReturned = 0;
1878 if(lpdwNeeded)
1879 *lpdwNeeded = 0;
1881 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1882 if(dwType == PRINTER_ENUM_DEFAULT)
1883 return TRUE;
1885 if (dwType & PRINTER_ENUM_CONNECTIONS) {
1886 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
1887 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
1888 dwType |= PRINTER_ENUM_LOCAL;
1891 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1892 FIXME("dwType = %08lx\n", dwType);
1893 SetLastError(ERROR_INVALID_FLAGS);
1894 return FALSE;
1897 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1898 ERROR_SUCCESS) {
1899 ERR("Can't create Printers key\n");
1900 return FALSE;
1903 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1904 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1905 RegCloseKey(hkeyPrinters);
1906 ERR("Can't query Printers key\n");
1907 return FALSE;
1909 TRACE("Found %ld printers\n", number);
1911 switch(dwLevel) {
1912 case 1:
1913 RegCloseKey(hkeyPrinters);
1914 if (lpdwReturned)
1915 *lpdwReturned = number;
1916 return TRUE;
1918 case 2:
1919 used = number * sizeof(PRINTER_INFO_2W);
1920 break;
1921 case 4:
1922 used = number * sizeof(PRINTER_INFO_4W);
1923 break;
1924 case 5:
1925 used = number * sizeof(PRINTER_INFO_5W);
1926 break;
1928 default:
1929 SetLastError(ERROR_INVALID_LEVEL);
1930 RegCloseKey(hkeyPrinters);
1931 return FALSE;
1933 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1935 for(i = 0; i < number; i++) {
1936 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1937 ERROR_SUCCESS) {
1938 ERR("Can't enum key number %ld\n", i);
1939 RegCloseKey(hkeyPrinters);
1940 return FALSE;
1942 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1943 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1944 ERROR_SUCCESS) {
1945 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1946 RegCloseKey(hkeyPrinters);
1947 return FALSE;
1950 if(cbBuf > used) {
1951 buf = lpbPrinters + used;
1952 left = cbBuf - used;
1953 } else {
1954 buf = NULL;
1955 left = 0;
1958 switch(dwLevel) {
1959 case 2:
1960 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1961 left, &needed, unicode);
1962 used += needed;
1963 if(pi) pi += sizeof(PRINTER_INFO_2W);
1964 break;
1965 case 4:
1966 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1967 left, &needed, unicode);
1968 used += needed;
1969 if(pi) pi += sizeof(PRINTER_INFO_4W);
1970 break;
1971 case 5:
1972 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1973 left, &needed, unicode);
1974 used += needed;
1975 if(pi) pi += sizeof(PRINTER_INFO_5W);
1976 break;
1977 default:
1978 ERR("Shouldn't be here!\n");
1979 RegCloseKey(hkeyPrinter);
1980 RegCloseKey(hkeyPrinters);
1981 return FALSE;
1983 RegCloseKey(hkeyPrinter);
1985 RegCloseKey(hkeyPrinters);
1987 if(lpdwNeeded)
1988 *lpdwNeeded = used;
1990 if(used > cbBuf) {
1991 if(lpbPrinters)
1992 memset(lpbPrinters, 0, cbBuf);
1993 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1994 return FALSE;
1996 if(lpdwReturned)
1997 *lpdwReturned = number;
1998 SetLastError(ERROR_SUCCESS);
1999 return TRUE;
2003 /******************************************************************
2004 * EnumPrintersW [WINSPOOL.@]
2006 * Enumerates the available printers, print servers and print
2007 * providers, depending on the specified flags, name and level.
2009 * RETURNS:
2011 * If level is set to 1:
2012 * Not implemented yet!
2013 * Returns TRUE with an empty list.
2015 * If level is set to 2:
2016 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2017 * Returns an array of PRINTER_INFO_2 data structures in the
2018 * lpbPrinters buffer. Note that according to MSDN also an
2019 * OpenPrinter should be performed on every remote printer.
2021 * If level is set to 4 (officially WinNT only):
2022 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2023 * Fast: Only the registry is queried to retrieve printer names,
2024 * no connection to the driver is made.
2025 * Returns an array of PRINTER_INFO_4 data structures in the
2026 * lpbPrinters buffer.
2028 * If level is set to 5 (officially WinNT4/Win9x only):
2029 * Fast: Only the registry is queried to retrieve printer names,
2030 * no connection to the driver is made.
2031 * Returns an array of PRINTER_INFO_5 data structures in the
2032 * lpbPrinters buffer.
2034 * If level set to 3 or 6+:
2035 * returns zero (failure!)
2037 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2038 * for information.
2040 * BUGS:
2041 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2042 * - Only levels 2, 4 and 5 are implemented at the moment.
2043 * - 16-bit printer drivers are not enumerated.
2044 * - Returned amount of bytes used/needed does not match the real Windoze
2045 * implementation (as in this implementation, all strings are part
2046 * of the buffer, whereas Win32 keeps them somewhere else)
2047 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2049 * NOTE:
2050 * - In a regular Wine installation, no registry settings for printers
2051 * exist, which makes this function return an empty list.
2053 BOOL WINAPI EnumPrintersW(
2054 DWORD dwType, /* [in] Types of print objects to enumerate */
2055 LPWSTR lpszName, /* [in] name of objects to enumerate */
2056 DWORD dwLevel, /* [in] type of printer info structure */
2057 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2058 DWORD cbBuf, /* [in] max size of buffer in bytes */
2059 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2060 LPDWORD lpdwReturned /* [out] number of entries returned */
2063 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2064 lpdwNeeded, lpdwReturned, TRUE);
2067 /******************************************************************
2068 * EnumPrintersA [WINSPOOL.@]
2071 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2072 DWORD dwLevel, LPBYTE lpbPrinters,
2073 DWORD cbBuf, LPDWORD lpdwNeeded,
2074 LPDWORD lpdwReturned)
2076 BOOL ret;
2077 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
2079 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
2080 lpdwNeeded, lpdwReturned, FALSE);
2081 HeapFree(GetProcessHeap(),0,lpszNameW);
2082 return ret;
2085 /*****************************************************************************
2086 * WINSPOOL_GetDriverInfoFromReg [internal]
2088 * Enters the information from the registry into the DRIVER_INFO struct
2090 * RETURNS
2091 * zero if the printer driver does not exist in the registry
2092 * (only if Level > 1) otherwise nonzero
2094 static BOOL WINSPOOL_GetDriverInfoFromReg(
2095 HKEY hkeyDrivers,
2096 LPWSTR DriverName,
2097 LPWSTR pEnvironment,
2098 DWORD Level,
2099 LPBYTE ptr, /* DRIVER_INFO */
2100 LPBYTE pDriverStrings, /* strings buffer */
2101 DWORD cbBuf, /* size of string buffer */
2102 LPDWORD pcbNeeded, /* space needed for str. */
2103 BOOL unicode) /* type of strings */
2104 { DWORD dw, size, tmp, type;
2105 HKEY hkeyDriver;
2106 LPBYTE strPtr = pDriverStrings;
2108 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2109 debugstr_w(DriverName), debugstr_w(pEnvironment),
2110 Level, ptr, pDriverStrings, cbBuf, unicode);
2112 if(unicode) {
2113 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2114 if (*pcbNeeded <= cbBuf)
2115 strcpyW((LPWSTR)strPtr, DriverName);
2116 } else {
2117 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2118 NULL, NULL);
2119 if(*pcbNeeded <= cbBuf)
2120 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2121 NULL, NULL);
2123 if(Level == 1) {
2124 if(ptr)
2125 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2126 return TRUE;
2127 } else {
2128 if(ptr)
2129 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2130 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2133 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2134 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2135 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2136 return FALSE;
2139 size = sizeof(dw);
2140 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2141 ERROR_SUCCESS)
2142 WARN("Can't get Version\n");
2143 else if(ptr)
2144 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2146 if(!pEnvironment)
2147 pEnvironment = DefaultEnvironmentW;
2148 if(unicode)
2149 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2150 else
2151 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2152 NULL, NULL);
2153 *pcbNeeded += size;
2154 if(*pcbNeeded <= cbBuf) {
2155 if(unicode)
2156 strcpyW((LPWSTR)strPtr, pEnvironment);
2157 else
2158 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2159 NULL, NULL);
2160 if(ptr)
2161 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2162 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2165 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2166 unicode)) {
2167 *pcbNeeded += size;
2168 if(*pcbNeeded <= cbBuf)
2169 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2170 unicode);
2171 if(ptr)
2172 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2173 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2176 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2177 unicode)) {
2178 *pcbNeeded += size;
2179 if(*pcbNeeded <= cbBuf)
2180 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2181 &tmp, unicode);
2182 if(ptr)
2183 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2184 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2187 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2188 0, &size, unicode)) {
2189 *pcbNeeded += size;
2190 if(*pcbNeeded <= cbBuf)
2191 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2192 size, &tmp, unicode);
2193 if(ptr)
2194 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2195 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2198 if(Level == 2 ) {
2199 RegCloseKey(hkeyDriver);
2200 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2201 return TRUE;
2204 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2205 unicode)) {
2206 *pcbNeeded += size;
2207 if(*pcbNeeded <= cbBuf)
2208 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2209 size, &tmp, unicode);
2210 if(ptr)
2211 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2212 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2215 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2216 &size, unicode)) {
2217 *pcbNeeded += size;
2218 if(*pcbNeeded <= cbBuf)
2219 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2220 size, &tmp, unicode);
2221 if(ptr)
2222 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2223 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2226 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2227 unicode)) {
2228 *pcbNeeded += size;
2229 if(*pcbNeeded <= cbBuf)
2230 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2231 size, &tmp, unicode);
2232 if(ptr)
2233 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2234 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2237 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2238 unicode)) {
2239 *pcbNeeded += size;
2240 if(*pcbNeeded <= cbBuf)
2241 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2242 size, &tmp, unicode);
2243 if(ptr)
2244 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2245 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2248 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2249 RegCloseKey(hkeyDriver);
2250 return TRUE;
2253 /*****************************************************************************
2254 * WINSPOOL_GetPrinterDriver
2256 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2257 DWORD Level, LPBYTE pDriverInfo,
2258 DWORD cbBuf, LPDWORD pcbNeeded,
2259 BOOL unicode)
2261 LPCWSTR name;
2262 WCHAR DriverName[100];
2263 DWORD ret, type, size, needed = 0;
2264 LPBYTE ptr = NULL;
2265 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2267 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2268 Level,pDriverInfo,cbBuf, pcbNeeded);
2270 ZeroMemory(pDriverInfo, cbBuf);
2272 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2274 if(Level < 1 || Level > 3) {
2275 SetLastError(ERROR_INVALID_LEVEL);
2276 return FALSE;
2278 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2279 ERROR_SUCCESS) {
2280 ERR("Can't create Printers key\n");
2281 return FALSE;
2283 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2284 != ERROR_SUCCESS) {
2285 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2286 RegCloseKey(hkeyPrinters);
2287 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2288 return FALSE;
2290 size = sizeof(DriverName);
2291 DriverName[0] = 0;
2292 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2293 (LPBYTE)DriverName, &size);
2294 RegCloseKey(hkeyPrinter);
2295 RegCloseKey(hkeyPrinters);
2296 if(ret != ERROR_SUCCESS) {
2297 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2298 return FALSE;
2301 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2302 if(!hkeyDrivers) {
2303 ERR("Can't create Drivers key\n");
2304 return FALSE;
2307 switch(Level) {
2308 case 1:
2309 size = sizeof(DRIVER_INFO_1W);
2310 break;
2311 case 2:
2312 size = sizeof(DRIVER_INFO_2W);
2313 break;
2314 case 3:
2315 size = sizeof(DRIVER_INFO_3W);
2316 break;
2317 default:
2318 ERR("Invalid level\n");
2319 return FALSE;
2322 if(size <= cbBuf)
2323 ptr = pDriverInfo + size;
2325 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2326 pEnvironment, Level, pDriverInfo,
2327 (cbBuf < size) ? NULL : ptr,
2328 (cbBuf < size) ? 0 : cbBuf - size,
2329 &needed, unicode)) {
2330 RegCloseKey(hkeyDrivers);
2331 return FALSE;
2334 RegCloseKey(hkeyDrivers);
2336 if(pcbNeeded) *pcbNeeded = size + needed;
2337 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2338 if(cbBuf >= needed) return TRUE;
2339 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2340 return FALSE;
2343 /*****************************************************************************
2344 * GetPrinterDriverA [WINSPOOL.@]
2346 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2347 DWORD Level, LPBYTE pDriverInfo,
2348 DWORD cbBuf, LPDWORD pcbNeeded)
2350 BOOL ret;
2351 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2352 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2353 cbBuf, pcbNeeded, FALSE);
2354 HeapFree(GetProcessHeap(),0,pEnvW);
2355 return ret;
2357 /*****************************************************************************
2358 * GetPrinterDriverW [WINSPOOL.@]
2360 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2361 DWORD Level, LPBYTE pDriverInfo,
2362 DWORD cbBuf, LPDWORD pcbNeeded)
2364 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2365 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2368 /*****************************************************************************
2369 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2371 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2372 DWORD Level, LPBYTE pDriverDirectory,
2373 DWORD cbBuf, LPDWORD pcbNeeded)
2375 DWORD needed;
2377 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2378 pDriverDirectory, cbBuf, pcbNeeded);
2379 if(pName != NULL) {
2380 FIXME("pName = `%s' - unsupported\n", pName);
2381 SetLastError(ERROR_INVALID_PARAMETER);
2382 return FALSE;
2384 if(pEnvironment != NULL) {
2385 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2386 SetLastError(ERROR_INVALID_ENVIRONMENT);
2387 return FALSE;
2389 if(Level != 1) /* win95 ignores this so we just carry on */
2390 WARN("Level = %ld - assuming 1\n", Level);
2392 /* FIXME should read from registry */
2393 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2394 needed++;
2395 if(pcbNeeded)
2396 *pcbNeeded = needed;
2397 if(needed > cbBuf) {
2398 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2399 return FALSE;
2401 return TRUE;
2405 /*****************************************************************************
2406 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2408 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2409 DWORD Level, LPBYTE pDriverDirectory,
2410 DWORD cbBuf, LPDWORD pcbNeeded)
2412 LPSTR pNameA = NULL, pEnvironmentA = NULL;
2413 BOOL ret;
2415 if(pName)
2416 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2417 if(pEnvironment)
2418 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2419 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2420 pDriverDirectory, cbBuf, pcbNeeded );
2421 if(pNameA)
2422 HeapFree( GetProcessHeap(), 0, pNameA );
2423 if(pEnvironmentA)
2424 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2426 return ret;
2429 /*****************************************************************************
2430 * AddPrinterDriverA [WINSPOOL.@]
2432 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2434 DRIVER_INFO_3A di3;
2435 HKEY hkeyDrivers, hkeyName;
2437 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2439 if(level != 2 && level != 3) {
2440 SetLastError(ERROR_INVALID_LEVEL);
2441 return FALSE;
2443 if(pName != NULL) {
2444 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2445 SetLastError(ERROR_INVALID_PARAMETER);
2446 return FALSE;
2448 if(!pDriverInfo) {
2449 WARN("pDriverInfo == NULL\n");
2450 SetLastError(ERROR_INVALID_PARAMETER);
2451 return FALSE;
2454 if(level == 3)
2455 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2456 else {
2457 memset(&di3, 0, sizeof(di3));
2458 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2461 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2462 !di3.pDataFile) {
2463 SetLastError(ERROR_INVALID_PARAMETER);
2464 return FALSE;
2466 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2467 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2468 if(!di3.pHelpFile) di3.pHelpFile = "";
2469 if(!di3.pMonitorName) di3.pMonitorName = "";
2471 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2473 if(!hkeyDrivers) {
2474 ERR("Can't create Drivers key\n");
2475 return FALSE;
2478 if(level == 2) { /* apparently can't overwrite with level2 */
2479 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2480 RegCloseKey(hkeyName);
2481 RegCloseKey(hkeyDrivers);
2482 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2483 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2484 return FALSE;
2487 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2488 RegCloseKey(hkeyDrivers);
2489 ERR("Can't create Name key\n");
2490 return FALSE;
2492 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2494 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2495 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2496 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2497 sizeof(DWORD));
2498 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2499 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2500 di3.pDependentFiles, 0);
2501 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2502 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2503 RegCloseKey(hkeyName);
2504 RegCloseKey(hkeyDrivers);
2506 return TRUE;
2508 /*****************************************************************************
2509 * AddPrinterDriverW [WINSPOOL.@]
2511 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2512 LPBYTE pDriverInfo)
2514 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2515 level,pDriverInfo);
2516 return FALSE;
2520 /*****************************************************************************
2521 * PrinterProperties [WINSPOOL.@]
2523 * Displays a dialog to set the properties of the printer.
2525 * RETURNS
2526 * nonzero on success or zero on failure
2528 * BUGS
2529 * implemented as stub only
2531 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2532 HANDLE hPrinter /* [in] handle to printer object */
2534 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2535 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2536 return FALSE;
2539 /*****************************************************************************
2540 * EnumJobsA [WINSPOOL.@]
2543 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2544 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2545 LPDWORD pcReturned)
2547 FIXME("stub\n");
2548 if(pcbNeeded) *pcbNeeded = 0;
2549 if(pcReturned) *pcReturned = 0;
2550 return TRUE;
2554 /*****************************************************************************
2555 * EnumJobsW [WINSPOOL.@]
2558 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2559 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2560 LPDWORD pcReturned)
2562 FIXME("stub\n");
2563 if(pcbNeeded) *pcbNeeded = 0;
2564 if(pcReturned) *pcReturned = 0;
2565 return TRUE;
2568 /*****************************************************************************
2569 * WINSPOOL_EnumPrinterDrivers [internal]
2571 * Delivers information about all printer drivers installed on the
2572 * localhost or a given server
2574 * RETURNS
2575 * nonzero on success or zero on failure. If the buffer for the returned
2576 * information is too small the function will return an error
2578 * BUGS
2579 * - only implemented for localhost, foreign hosts will return an error
2581 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2582 DWORD Level, LPBYTE pDriverInfo,
2583 DWORD cbBuf, LPDWORD pcbNeeded,
2584 LPDWORD pcReturned, BOOL unicode)
2586 { HKEY hkeyDrivers;
2587 DWORD i, needed, number = 0, size = 0;
2588 WCHAR DriverNameW[255];
2589 PBYTE ptr;
2591 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2592 debugstr_w(pName), debugstr_w(pEnvironment),
2593 Level, pDriverInfo, cbBuf, unicode);
2595 /* check for local drivers */
2596 if(pName) {
2597 ERR("remote drivers unsupported! Current remote host is %s\n",
2598 debugstr_w(pName));
2599 return FALSE;
2602 /* check input parameter */
2603 if((Level < 1) || (Level > 3)) {
2604 ERR("unsupported level %ld \n", Level);
2605 return FALSE;
2608 /* initialize return values */
2609 if(pDriverInfo)
2610 memset( pDriverInfo, 0, cbBuf);
2611 *pcbNeeded = 0;
2612 *pcReturned = 0;
2614 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2615 if(!hkeyDrivers) {
2616 ERR("Can't open Drivers key\n");
2617 return FALSE;
2620 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2621 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2622 RegCloseKey(hkeyDrivers);
2623 ERR("Can't query Drivers key\n");
2624 return FALSE;
2626 TRACE("Found %ld Drivers\n", number);
2628 /* get size of single struct
2629 * unicode and ascii structure have the same size
2631 switch (Level) {
2632 case 1:
2633 size = sizeof(DRIVER_INFO_1A);
2634 break;
2635 case 2:
2636 size = sizeof(DRIVER_INFO_2A);
2637 break;
2638 case 3:
2639 size = sizeof(DRIVER_INFO_3A);
2640 break;
2643 /* calculate required buffer size */
2644 *pcbNeeded = size * number;
2646 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2647 i < number;
2648 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2649 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2650 != ERROR_SUCCESS) {
2651 ERR("Can't enum key number %ld\n", i);
2652 RegCloseKey(hkeyDrivers);
2653 return FALSE;
2655 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2656 pEnvironment, Level, ptr,
2657 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2658 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2659 &needed, unicode)) {
2660 RegCloseKey(hkeyDrivers);
2661 return FALSE;
2663 (*pcbNeeded) += needed;
2666 RegCloseKey(hkeyDrivers);
2668 if(cbBuf < *pcbNeeded){
2669 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2670 return FALSE;
2673 return TRUE;
2676 /*****************************************************************************
2677 * EnumPrinterDriversW [WINSPOOL.@]
2679 * see function EnumPrinterDrivers for RETURNS, BUGS
2681 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2682 LPBYTE pDriverInfo, DWORD cbBuf,
2683 LPDWORD pcbNeeded, LPDWORD pcReturned)
2685 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2686 cbBuf, pcbNeeded, pcReturned, TRUE);
2689 /*****************************************************************************
2690 * EnumPrinterDriversA [WINSPOOL.@]
2692 * see function EnumPrinterDrivers for RETURNS, BUGS
2694 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2695 LPBYTE pDriverInfo, DWORD cbBuf,
2696 LPDWORD pcbNeeded, LPDWORD pcReturned)
2697 { BOOL ret;
2698 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2700 if(pName)
2701 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2702 if(pEnvironment)
2703 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2705 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2706 cbBuf, pcbNeeded, pcReturned, FALSE);
2707 if(pNameW)
2708 HeapFree(GetProcessHeap(), 0, pNameW);
2709 if(pEnvironmentW)
2710 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2712 return ret;
2716 /******************************************************************************
2717 * EnumPortsA (WINSPOOL.@)
2719 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2720 LPDWORD bufneeded,LPDWORD bufreturned)
2722 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2723 return FALSE;
2726 /******************************************************************************
2727 * GetDefaultPrinterA (WINSPOOL.@)
2729 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2731 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
2733 char *ptr;
2735 if (*namesize < 1)
2737 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2738 return FALSE;
2741 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
2743 SetLastError (ERROR_FILE_NOT_FOUND);
2744 return FALSE;
2747 if ((ptr = strchr (name, ',')) == NULL)
2749 SetLastError (ERROR_FILE_NOT_FOUND);
2750 return FALSE;
2753 *ptr = '\0';
2754 *namesize = strlen (name) + 1;
2755 return TRUE;
2759 /******************************************************************************
2760 * GetDefaultPrinterW (WINSPOOL.@)
2762 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
2764 char *buf;
2765 BOOL ret;
2767 if (*namesize < 1)
2769 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2770 return FALSE;
2773 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
2774 ret = GetDefaultPrinterA (buf, namesize);
2775 if (ret)
2777 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
2778 if (!len)
2780 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2781 ret = FALSE;
2783 else *namesize = len;
2786 HeapFree (GetProcessHeap (), 0, buf);
2787 return ret;
2791 /******************************************************************************
2792 * SetPrinterDataExA (WINSPOOL.@)
2794 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2795 LPSTR pValueName, DWORD Type,
2796 LPBYTE pData, DWORD cbData)
2798 HKEY hkeyPrinter, hkeySubkey;
2799 DWORD ret;
2801 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2802 debugstr_a(pValueName), Type, pData, cbData);
2804 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2805 != ERROR_SUCCESS)
2806 return ret;
2808 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2809 != ERROR_SUCCESS) {
2810 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2811 RegCloseKey(hkeyPrinter);
2812 return ret;
2814 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2815 RegCloseKey(hkeySubkey);
2816 RegCloseKey(hkeyPrinter);
2817 return ret;
2820 /******************************************************************************
2821 * SetPrinterDataExW (WINSPOOL.@)
2823 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2824 LPWSTR pValueName, DWORD Type,
2825 LPBYTE pData, DWORD cbData)
2827 HKEY hkeyPrinter, hkeySubkey;
2828 DWORD ret;
2830 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2831 debugstr_w(pValueName), Type, pData, cbData);
2833 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2834 != ERROR_SUCCESS)
2835 return ret;
2837 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2838 != ERROR_SUCCESS) {
2839 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2840 RegCloseKey(hkeyPrinter);
2841 return ret;
2843 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2844 RegCloseKey(hkeySubkey);
2845 RegCloseKey(hkeyPrinter);
2846 return ret;
2849 /******************************************************************************
2850 * SetPrinterDataA (WINSPOOL.@)
2852 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2853 LPBYTE pData, DWORD cbData)
2855 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2856 pData, cbData);
2859 /******************************************************************************
2860 * SetPrinterDataW (WINSPOOL.@)
2862 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2863 LPBYTE pData, DWORD cbData)
2865 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2866 pData, cbData);
2869 /******************************************************************************
2870 * GetPrinterDataExA (WINSPOOL.@)
2872 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2873 LPSTR pValueName, LPDWORD pType,
2874 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2876 HKEY hkeyPrinter, hkeySubkey;
2877 DWORD ret;
2879 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2880 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2881 pcbNeeded);
2883 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2884 != ERROR_SUCCESS)
2885 return ret;
2887 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2888 != ERROR_SUCCESS) {
2889 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2890 RegCloseKey(hkeyPrinter);
2891 return ret;
2893 *pcbNeeded = nSize;
2894 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2895 RegCloseKey(hkeySubkey);
2896 RegCloseKey(hkeyPrinter);
2897 return ret;
2900 /******************************************************************************
2901 * GetPrinterDataExW (WINSPOOL.@)
2903 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2904 LPWSTR pValueName, LPDWORD pType,
2905 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2907 HKEY hkeyPrinter, hkeySubkey;
2908 DWORD ret;
2910 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2911 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2912 pcbNeeded);
2914 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2915 != ERROR_SUCCESS)
2916 return ret;
2918 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2919 != ERROR_SUCCESS) {
2920 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2921 RegCloseKey(hkeyPrinter);
2922 return ret;
2924 *pcbNeeded = nSize;
2925 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2926 RegCloseKey(hkeySubkey);
2927 RegCloseKey(hkeyPrinter);
2928 return ret;
2931 /******************************************************************************
2932 * GetPrinterDataA (WINSPOOL.@)
2934 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
2935 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2937 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
2938 pData, nSize, pcbNeeded);
2941 /******************************************************************************
2942 * GetPrinterDataW (WINSPOOL.@)
2944 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
2945 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2947 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
2948 pData, nSize, pcbNeeded);
2951 /*******************************************************************************
2952 * EnumPrinterDataExW [WINSPOOL.@]
2954 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
2955 LPBYTE pEnumValues, DWORD cbEnumValues,
2956 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2958 HKEY hkPrinter, hkSubKey;
2959 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
2960 cbValueNameLen, cbMaxValueLen, cbValueLen,
2961 cbBufSize, dwType;
2962 LPWSTR lpValueName;
2963 HANDLE hHeap;
2964 PBYTE lpValue;
2965 PPRINTER_ENUM_VALUESW ppev;
2967 TRACE ("%08x %s\n", hPrinter, debugstr_w (pKeyName));
2969 if (pKeyName == NULL || *pKeyName == 0)
2970 return ERROR_INVALID_PARAMETER;
2972 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
2973 if (ret != ERROR_SUCCESS)
2975 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%08x) returned %li\n",
2976 hPrinter, ret);
2977 return ret;
2980 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
2981 if (ret != ERROR_SUCCESS)
2983 r = RegCloseKey (hkPrinter);
2984 if (r != ERROR_SUCCESS)
2985 WARN ("RegCloseKey returned %li\n", r);
2986 TRACE ("RegOpenKeyExW (%08x, %s) returned %li\n", hPrinter,
2987 debugstr_w (pKeyName), ret);
2988 return ret;
2991 ret = RegCloseKey (hkPrinter);
2992 if (ret != ERROR_SUCCESS)
2994 ERR ("RegCloseKey returned %li\n", ret);
2995 r = RegCloseKey (hkSubKey);
2996 if (r != ERROR_SUCCESS)
2997 WARN ("RegCloseKey returned %li\n", r);
2998 return ret;
3001 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3002 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3003 if (ret != ERROR_SUCCESS)
3005 r = RegCloseKey (hkSubKey);
3006 if (r != ERROR_SUCCESS)
3007 WARN ("RegCloseKey returned %li\n", r);
3008 TRACE ("RegQueryInfoKeyW (%08x) returned %li\n", hkSubKey, ret);
3009 return ret;
3012 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3013 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3015 if (cValues == 0) /* empty key */
3017 r = RegCloseKey (hkSubKey);
3018 if (r != ERROR_SUCCESS)
3019 WARN ("RegCloseKey returned %li\n", r);
3020 *pcbEnumValues = *pnEnumValues = 0;
3021 return ERROR_SUCCESS;
3024 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3026 hHeap = GetProcessHeap ();
3027 if (hHeap == (HANDLE) NULL)
3029 ERR ("GetProcessHeap failed\n");
3030 r = RegCloseKey (hkSubKey);
3031 if (r != ERROR_SUCCESS)
3032 WARN ("RegCloseKey returned %li\n", r);
3033 return ERROR_OUTOFMEMORY;
3036 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3037 if (lpValueName == NULL)
3039 ERR ("Failed to allocate %li bytes from process heap\n",
3040 cbMaxValueNameLen * sizeof (WCHAR));
3041 r = RegCloseKey (hkSubKey);
3042 if (r != ERROR_SUCCESS)
3043 WARN ("RegCloseKey returned %li\n", r);
3044 return ERROR_OUTOFMEMORY;
3047 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3048 if (lpValue == NULL)
3050 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3051 if (HeapFree (hHeap, 0, lpValueName) == 0)
3052 WARN ("HeapFree failed with code %li\n", GetLastError ());
3053 r = RegCloseKey (hkSubKey);
3054 if (r != ERROR_SUCCESS)
3055 WARN ("RegCloseKey returned %li\n", r);
3056 return ERROR_OUTOFMEMORY;
3059 TRACE ("pass 1: calculating buffer required for all names and values\n");
3061 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3063 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3065 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3067 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3068 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3069 NULL, NULL, lpValue, &cbValueLen);
3070 if (ret != ERROR_SUCCESS)
3072 if (HeapFree (hHeap, 0, lpValue) == 0)
3073 WARN ("HeapFree failed with code %li\n", GetLastError ());
3074 if (HeapFree (hHeap, 0, lpValueName) == 0)
3075 WARN ("HeapFree failed with code %li\n", GetLastError ());
3076 r = RegCloseKey (hkSubKey);
3077 if (r != ERROR_SUCCESS)
3078 WARN ("RegCloseKey returned %li\n", r);
3079 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3080 return ret;
3083 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3084 debugstr_w (lpValueName), dwIndex,
3085 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3087 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3088 cbBufSize += cbValueLen;
3091 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3093 *pcbEnumValues = cbBufSize;
3094 *pnEnumValues = cValues;
3096 if (cbEnumValues < cbBufSize) /* buffer too small */
3098 if (HeapFree (hHeap, 0, lpValue) == 0)
3099 WARN ("HeapFree failed with code %li\n", GetLastError ());
3100 if (HeapFree (hHeap, 0, lpValueName) == 0)
3101 WARN ("HeapFree failed with code %li\n", GetLastError ());
3102 r = RegCloseKey (hkSubKey);
3103 if (r != ERROR_SUCCESS)
3104 WARN ("RegCloseKey returned %li\n", r);
3105 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3106 return ERROR_MORE_DATA;
3109 TRACE ("pass 2: copying all names and values to buffer\n");
3111 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3112 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3114 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3116 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3117 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3118 NULL, &dwType, lpValue, &cbValueLen);
3119 if (ret != ERROR_SUCCESS)
3121 if (HeapFree (hHeap, 0, lpValue) == 0)
3122 WARN ("HeapFree failed with code %li\n", GetLastError ());
3123 if (HeapFree (hHeap, 0, lpValueName) == 0)
3124 WARN ("HeapFree failed with code %li\n", GetLastError ());
3125 r = RegCloseKey (hkSubKey);
3126 if (r != ERROR_SUCCESS)
3127 WARN ("RegCloseKey returned %li\n", r);
3128 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3129 return ret;
3132 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3133 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3134 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3135 pEnumValues += cbValueNameLen;
3137 /* return # of *bytes* (including trailing \0), not # of chars */
3138 ppev[dwIndex].cbValueName = cbValueNameLen;
3140 ppev[dwIndex].dwType = dwType;
3142 memcpy (pEnumValues, lpValue, cbValueLen);
3143 ppev[dwIndex].pData = pEnumValues;
3144 pEnumValues += cbValueLen;
3146 ppev[dwIndex].cbData = cbValueLen;
3148 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3149 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3152 if (HeapFree (hHeap, 0, lpValue) == 0)
3154 ret = GetLastError ();
3155 ERR ("HeapFree failed with code %li\n", ret);
3156 if (HeapFree (hHeap, 0, lpValueName) == 0)
3157 WARN ("HeapFree failed with code %li\n", GetLastError ());
3158 r = RegCloseKey (hkSubKey);
3159 if (r != ERROR_SUCCESS)
3160 WARN ("RegCloseKey returned %li\n", r);
3161 return ret;
3164 if (HeapFree (hHeap, 0, lpValueName) == 0)
3166 ret = GetLastError ();
3167 ERR ("HeapFree failed with code %li\n", ret);
3168 r = RegCloseKey (hkSubKey);
3169 if (r != ERROR_SUCCESS)
3170 WARN ("RegCloseKey returned %li\n", r);
3171 return ret;
3174 ret = RegCloseKey (hkSubKey);
3175 if (ret != ERROR_SUCCESS)
3177 ERR ("RegCloseKey returned %li\n", ret);
3178 return ret;
3181 return ERROR_SUCCESS;
3184 /*******************************************************************************
3185 * EnumPrinterDataExA [WINSPOOL.@]
3187 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3188 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3189 * what Windows 2000 SP1 does.
3192 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3193 LPBYTE pEnumValues, DWORD cbEnumValues,
3194 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3196 INT len;
3197 LPWSTR pKeyNameW;
3198 DWORD ret, dwIndex, dwBufSize;
3199 HANDLE hHeap;
3200 LPSTR pBuffer;
3202 TRACE ("%08x %s\n", hPrinter, pKeyName);
3204 if (pKeyName == NULL || *pKeyName == 0)
3205 return ERROR_INVALID_PARAMETER;
3207 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3208 if (len == 0)
3210 ret = GetLastError ();
3211 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3212 return ret;
3215 hHeap = GetProcessHeap ();
3216 if (hHeap == (HANDLE) NULL)
3218 ERR ("GetProcessHeap failed\n");
3219 return ERROR_OUTOFMEMORY;
3222 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3223 if (pKeyNameW == NULL)
3225 ERR ("Failed to allocate %li bytes from process heap\n",
3226 (LONG) len * sizeof (WCHAR));
3227 return ERROR_OUTOFMEMORY;
3230 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3232 ret = GetLastError ();
3233 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3234 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3235 WARN ("HeapFree failed with code %li\n", GetLastError ());
3236 return ret;
3239 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3240 pcbEnumValues, pnEnumValues);
3241 if (ret != ERROR_SUCCESS)
3243 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3244 WARN ("HeapFree failed with code %li\n", GetLastError ());
3245 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3246 return ret;
3249 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3251 ret = GetLastError ();
3252 ERR ("HeapFree failed with code %li\n", ret);
3253 return ret;
3256 if (*pnEnumValues == 0) /* empty key */
3257 return ERROR_SUCCESS;
3259 dwBufSize = 0;
3260 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3262 PPRINTER_ENUM_VALUESW ppev =
3263 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3265 if (dwBufSize < ppev->cbValueName)
3266 dwBufSize = ppev->cbValueName;
3268 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3269 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3270 dwBufSize = ppev->cbData;
3273 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3275 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3276 if (pBuffer == NULL)
3278 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3279 return ERROR_OUTOFMEMORY;
3282 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3284 PPRINTER_ENUM_VALUESW ppev =
3285 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3287 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3288 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3289 NULL);
3290 if (len == 0)
3292 ret = GetLastError ();
3293 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3294 if (HeapFree (hHeap, 0, pBuffer) == 0)
3295 WARN ("HeapFree failed with code %li\n", GetLastError ());
3296 return ret;
3299 memcpy (ppev->pValueName, pBuffer, len);
3301 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3303 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3304 ppev->dwType != REG_MULTI_SZ)
3305 continue;
3307 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3308 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3309 if (len == 0)
3311 ret = GetLastError ();
3312 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3313 if (HeapFree (hHeap, 0, pBuffer) == 0)
3314 WARN ("HeapFree failed with code %li\n", GetLastError ());
3315 return ret;
3318 memcpy (ppev->pData, pBuffer, len);
3320 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3321 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3324 if (HeapFree (hHeap, 0, pBuffer) == 0)
3326 ret = GetLastError ();
3327 ERR ("HeapFree failed with code %li\n", ret);
3328 return ret;
3331 return ERROR_SUCCESS;