Regenerated with latest widl.
[wine/multimedia.git] / dlls / winspool / info.c
blob2edf9d49c11ab3958f9f36ca77321aea2fd7c58d
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"
26 #include "wine/port.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <stddef.h>
33 #ifdef HAVE_CUPS_CUPS_H
34 # include <cups/cups.h>
35 # ifndef CUPS_SONAME
36 # define CUPS_SONAME "libcups.so"
37 # endif
38 #endif
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "wine/library.h"
43 #include "winbase.h"
44 #include "winerror.h"
45 #include "winreg.h"
46 #include "wingdi.h"
47 #include "winspool.h"
48 #include "winternl.h"
49 #include "wine/windef16.h"
50 #include "wine/unicode.h"
51 #include "wine/debug.h"
52 #include "heap.h"
53 #include "winnls.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
57 static LPWSTR *printer_array;
58 static int nb_printers;
60 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
61 WORD fwCapability, LPSTR lpszOutput,
62 LPDEVMODEA lpdm );
63 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
64 LPSTR lpszDevice, LPSTR lpszPort,
65 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
66 DWORD fwMode );
68 static char Printers[] =
69 "System\\CurrentControlSet\\control\\Print\\Printers\\";
70 static char Drivers[] =
71 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
73 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
75 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
76 'i','o','n',' ','F','i','l','e',0};
77 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
78 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
79 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
80 'M','o','d','e',0};
81 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
82 'i','l','e','s',0};
83 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
84 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
85 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
86 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
87 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
88 static WCHAR NameW[] = {'N','a','m','e',0};
89 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
90 static WCHAR PortW[] = {'P','o','r','t',0};
91 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
92 's','s','o','r',0};
93 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
94 'v','e','r',0};
95 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
96 'v','e','r','D','a','t','a',0};
97 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
98 'i','l','e',0};
99 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
100 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
102 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
103 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
104 DWORD Level, LPBYTE pDriverInfo,
105 DWORD cbBuf, LPDWORD pcbNeeded,
106 BOOL unicode);
107 static void
108 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
109 char qbuf[200];
111 /* If forcing, or no profile string entry for device yet, set the entry
113 * The always change entry if not WINEPS yet is discussable.
115 if (force ||
116 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
117 !strcmp(qbuf,"*") ||
118 !strstr(qbuf,"WINEPS")
120 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
122 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
123 WriteProfileStringA("windows","device",buf);
124 HeapFree(GetProcessHeap(),0,buf);
128 #ifdef HAVE_CUPS_CUPS_H
129 BOOL
130 CUPS_LoadPrinters(void) {
131 typeof(cupsGetPrinters) *pcupsGetPrinters = NULL;
132 typeof(cupsGetDefault) *pcupsGetDefault = NULL;
133 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
134 char **printers;
135 int i,nrofdests,hadprinter = FALSE;
136 PRINTER_INFO_2A pinfo2a;
137 const char* def;
138 void *cupshandle = NULL;
140 cupshandle = wine_dlopen(CUPS_SONAME, RTLD_NOW, NULL, 0);
141 if (!cupshandle)
142 return FALSE;
144 #define DYNCUPS(x) \
145 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
146 if (!p##x) return FALSE;
148 DYNCUPS(cupsGetDefault);
149 DYNCUPS(cupsGetPPD);
150 DYNCUPS(cupsGetPrinters);
151 #undef DYNCUPS
153 def = pcupsGetDefault();
155 if (def && !strcmp(def,"none")) /* CUPS has "none" for no default printer */
156 def = NULL;
158 nrofdests = pcupsGetPrinters(&printers);
159 for (i=0;i<nrofdests;i++) {
160 const char *ppd = pcupsGetPPD(printers[i]);
161 char *port,*devline;
163 if (!ppd) {
164 WARN("No ppd file for %s.\n",printers[i]);
165 /* If this was going to be the default printer,
166 * forget it and use another one.
168 if (def && !strcmp(def,printers[i]))
169 def = NULL;
170 continue;
172 unlink(ppd);
174 hadprinter = TRUE;
176 if (def && !strcmp(def,printers[i]))
177 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
179 /* The default printer has no PPD file, just use the first one
180 * which has one.
182 if (!def) {
183 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
184 def = printers[i];
186 memset(&pinfo2a,0,sizeof(pinfo2a));
187 pinfo2a.pPrinterName = printers[i];
188 pinfo2a.pDatatype = "RAW";
189 pinfo2a.pPrintProcessor = "WinPrint";
190 pinfo2a.pDriverName = "PS Driver";
191 pinfo2a.pComment = "WINEPS Printer using CUPS";
192 pinfo2a.pLocation = "<physical location of printer>";
193 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
194 sprintf(port,"LPR:%s",printers[i]);
195 pinfo2a.pPortName = port;
196 pinfo2a.pParameters = "<parameters?>";
197 pinfo2a.pShareName = "<share name?>";
198 pinfo2a.pSepFile = "<sep file?>";
200 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
201 sprintf(devline,"WINEPS,%s",port);
202 WriteProfileStringA("devices",printers[i],devline);
203 HeapFree(GetProcessHeap(),0,devline);
205 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
206 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
207 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
209 HeapFree(GetProcessHeap(),0,port);
211 wine_dlclose(cupshandle, NULL, 0);
212 return hadprinter;
214 #endif
216 static BOOL
217 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
218 PRINTER_INFO_2A pinfo2a;
219 char *s,*name,*prettyname,*devname;
220 BOOL isps = FALSE;
221 char *port,*devline;
223 while (isspace(*pent)) pent++;
224 s = strchr(pent,':');
225 if (!s) return FALSE;
226 *s='\0';
227 name = pent;
228 pent = s+1;
229 TRACE("%s\n",name);
231 /* Determine whether this is a postscript printer. */
233 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
234 if (strstr(name,"ps") ||
235 strstr(name,"pd") || /* postscript double page */
236 strstr(name,"postscript") ||
237 strstr(name,"PostScript")
239 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
240 isps = TRUE;
242 /* 2. Check if this is a remote printer. These usually are postscript
243 * capable
245 if (strstr(pent,":rm")) {
246 isps = TRUE;
247 TRACE("%s is remote, assuming postscript.\n",name);
249 /* 3. Check if we have an input filter program. If we have one, it
250 * most likely is one capable of converting postscript.
251 * (Could probably check for occurrence of 'gs' or 'ghostscript'
252 * in the if file itself.)
254 if (strstr(pent,":if=/")) {
255 isps = TRUE;
256 TRACE("%s has inputfilter program, assuming postscript.\n",name);
259 /* If it is not a postscript printer, we cannot use it. */
260 if (!isps)
261 return FALSE;
263 prettyname = name;
264 /* Get longest name, usually the one at the right for later display. */
265 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
266 s=strchr(name,'|');if (s) *s='\0';
268 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
269 * if it is too long, we use it as comment below. */
270 devname = prettyname;
271 if (strlen(devname)>=CCHDEVICENAME-1)
272 devname = name;
273 if (strlen(devname)>=CCHDEVICENAME-1)
274 return FALSE;
276 if (isfirst) /* set first entry as default */
277 WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
279 memset(&pinfo2a,0,sizeof(pinfo2a));
280 pinfo2a.pPrinterName = devname;
281 pinfo2a.pDatatype = "RAW";
282 pinfo2a.pPrintProcessor = "WinPrint";
283 pinfo2a.pDriverName = "PS Driver";
284 pinfo2a.pComment = "WINEPS Printer using LPR";
285 pinfo2a.pLocation = prettyname;
286 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
287 sprintf(port,"LPR:%s",name);
288 pinfo2a.pPortName = port;
289 pinfo2a.pParameters = "<parameters?>";
290 pinfo2a.pShareName = "<share name?>";
291 pinfo2a.pSepFile = "<sep file?>";
293 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
294 sprintf(devline,"WINEPS,%s",port);
295 WriteProfileStringA("devices",devname,devline);
296 HeapFree(GetProcessHeap(),0,devline);
298 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
299 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
300 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
302 HeapFree(GetProcessHeap(),0,port);
303 return TRUE;
306 static BOOL
307 PRINTCAP_LoadPrinters(void) {
308 BOOL hadprinter = FALSE, isfirst = TRUE;
309 char buf[200];
310 FILE *f;
312 f = fopen("/etc/printcap","r");
313 if (!f)
314 return FALSE;
316 while (fgets(buf,sizeof(buf),f)) {
317 char *pent = NULL;
318 do {
319 char *s;
320 s=strchr(buf,'\n'); if (s) *s='\0';
321 if ((buf[0]=='#') || (buf[0]=='\0'))
322 continue;
324 if (pent) {
325 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
326 strcat(pent,buf);
327 } else {
328 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
329 strcpy(pent,buf);
332 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
333 pent[strlen(pent)-1] = '\0';
334 else
335 break;
336 } while (fgets(buf,sizeof(buf),f));
337 if (pent)
338 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
339 isfirst = FALSE;
340 if (pent) HeapFree(GetProcessHeap(),0,pent);
341 pent = NULL;
342 if (feof(f)) break;
344 fclose(f);
345 return hadprinter;
348 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
350 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
351 lstrlenW(value) * sizeof(WCHAR));
354 void
355 WINSPOOL_LoadSystemPrinters() {
356 HKEY hkPPD;
357 DRIVER_INFO_3A di3a;
358 di3a.cVersion = 0x400;
359 di3a.pName = "PS Driver";
360 di3a.pEnvironment = NULL; /* NULL means auto */
361 di3a.pDriverPath = "wineps16";
362 di3a.pDataFile = "<datafile?>";
363 di3a.pConfigFile = "wineps16";
364 di3a.pHelpFile = "<helpfile?>";
365 di3a.pDependentFiles = "<dependend files?>";
366 di3a.pMonitorName = "<monitor name?>";
367 di3a.pDefaultDataType = "RAW";
369 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
370 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
371 return;
373 #ifdef HAVE_CUPS_CUPS_H
374 /* If we have any CUPS based printers, skip looking for printcap printers */
375 if (CUPS_LoadPrinters())
376 return;
377 #endif
379 /* Check for [ppd] section in config file before parsing /etc/printcap */
381 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
382 &hkPPD) == ERROR_SUCCESS)
384 RegCloseKey(hkPPD);
385 PRINTCAP_LoadPrinters();
390 /******************************************************************
391 * WINSPOOL_GetOpenedPrinterEntry
392 * Get the first place empty in the opened printer table
394 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
396 int i;
398 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
400 if (i >= nb_printers)
402 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
403 (nb_printers + 16) * sizeof(*new_array) );
404 if (!new_array) return 0;
405 printer_array = new_array;
406 nb_printers += 16;
409 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
411 strcpyW( printer_array[i], name );
412 return (HANDLE)(i + 1);
414 return 0;
417 /******************************************************************
418 * WINSPOOL_GetOpenedPrinter
419 * Get the pointer to the opened printer referred by the handle
421 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
423 int idx = (int)printerHandle;
424 if ((idx <= 0) || (idx > nb_printers))
426 SetLastError(ERROR_INVALID_HANDLE);
427 return NULL;
429 return printer_array[idx - 1];
432 /******************************************************************
433 * WINSPOOL_GetOpenedPrinterRegKey
436 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
438 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
439 DWORD ret;
440 HKEY hkeyPrinters;
442 if(!name) return ERROR_INVALID_HANDLE;
444 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
445 ERROR_SUCCESS)
446 return ret;
448 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
450 ERR("Can't find opened printer %s in registry\n",
451 debugstr_w(name));
452 RegCloseKey(hkeyPrinters);
453 return ERROR_INVALID_PRINTER_NAME; /* ? */
455 RegCloseKey(hkeyPrinters);
456 return ERROR_SUCCESS;
459 /***********************************************************
460 * DEVMODEcpyAtoW
462 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
464 BOOL Formname;
465 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
466 DWORD size;
468 Formname = (dmA->dmSize > off_formname);
469 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
470 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
471 CCHDEVICENAME);
472 if(!Formname) {
473 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
474 dmA->dmSize - CCHDEVICENAME);
475 } else {
476 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
477 off_formname - CCHDEVICENAME);
478 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
479 CCHFORMNAME);
480 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
481 (off_formname + CCHFORMNAME));
483 dmW->dmSize = size;
484 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
485 dmA->dmDriverExtra);
486 return dmW;
489 /***********************************************************
490 * DEVMODEdupAtoW
491 * Creates a unicode copy of supplied devmode on heap
493 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
495 LPDEVMODEW dmW;
496 DWORD size;
497 BOOL Formname;
498 ptrdiff_t off_formname;
500 TRACE("\n");
501 if(!dmA) return NULL;
503 off_formname = (char *)dmA->dmFormName - (char *)dmA;
504 Formname = (dmA->dmSize > off_formname);
505 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
506 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
507 return DEVMODEcpyAtoW(dmW, dmA);
510 /***********************************************************
511 * DEVMODEdupWtoA
512 * Creates an ascii copy of supplied devmode on heap
514 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
516 LPDEVMODEA dmA;
517 DWORD size;
518 BOOL Formname;
519 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
521 if(!dmW) return NULL;
522 Formname = (dmW->dmSize > off_formname);
523 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
524 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
525 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
526 CCHDEVICENAME, NULL, NULL);
527 if(!Formname) {
528 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
529 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
530 } else {
531 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
532 off_formname - CCHDEVICENAME * sizeof(WCHAR));
533 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
534 CCHFORMNAME, NULL, NULL);
535 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
536 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
538 dmA->dmSize = size;
539 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
540 dmW->dmDriverExtra);
541 return dmA;
544 /***********************************************************
545 * PRINTER_INFO_2AtoW
546 * Creates a unicode copy of PRINTER_INFO_2A on heap
548 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
550 LPPRINTER_INFO_2W piW;
551 if(!piA) return NULL;
552 piW = HeapAlloc(heap, 0, sizeof(*piW));
553 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
554 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
555 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
556 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
557 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
558 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
559 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
560 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
561 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
562 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
563 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
564 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
565 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
566 return piW;
569 /***********************************************************
570 * FREE_PRINTER_INFO_2W
571 * Free PRINTER_INFO_2W and all strings
573 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
575 if(!piW) return;
577 HeapFree(heap,0,piW->pServerName);
578 HeapFree(heap,0,piW->pPrinterName);
579 HeapFree(heap,0,piW->pShareName);
580 HeapFree(heap,0,piW->pPortName);
581 HeapFree(heap,0,piW->pDriverName);
582 HeapFree(heap,0,piW->pComment);
583 HeapFree(heap,0,piW->pLocation);
584 HeapFree(heap,0,piW->pDevMode);
585 HeapFree(heap,0,piW->pSepFile);
586 HeapFree(heap,0,piW->pPrintProcessor);
587 HeapFree(heap,0,piW->pDatatype);
588 HeapFree(heap,0,piW->pParameters);
589 HeapFree(heap,0,piW);
590 return;
593 /******************************************************************
594 * DeviceCapabilities [WINSPOOL.@]
595 * DeviceCapabilitiesA [WINSPOOL.@]
598 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
599 LPSTR pOutput, LPDEVMODEA lpdm)
601 INT ret;
603 if (!GDI_CallDeviceCapabilities16)
605 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
606 (LPCSTR)104 );
607 if (!GDI_CallDeviceCapabilities16) return -1;
609 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
611 /* If DC_PAPERSIZE map POINT16s to POINTs */
612 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
613 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
614 POINT *pt = (POINT *)pOutput;
615 INT i;
616 memcpy(tmp, pOutput, ret * sizeof(POINT16));
617 for(i = 0; i < ret; i++, pt++)
619 pt->x = tmp[i].x;
620 pt->y = tmp[i].y;
622 HeapFree( GetProcessHeap(), 0, tmp );
624 return ret;
628 /*****************************************************************************
629 * DeviceCapabilitiesW [WINSPOOL.@]
631 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
634 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
635 WORD fwCapability, LPWSTR pOutput,
636 const DEVMODEW *pDevMode)
638 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
639 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
640 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
641 INT ret;
643 if(pOutput && (fwCapability == DC_BINNAMES ||
644 fwCapability == DC_FILEDEPENDENCIES ||
645 fwCapability == DC_PAPERNAMES)) {
646 /* These need A -> W translation */
647 INT size = 0, i;
648 LPSTR pOutputA;
649 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
650 dmA);
651 if(ret == -1)
652 return ret;
653 switch(fwCapability) {
654 case DC_BINNAMES:
655 size = 24;
656 break;
657 case DC_PAPERNAMES:
658 case DC_FILEDEPENDENCIES:
659 size = 64;
660 break;
662 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
663 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
664 dmA);
665 for(i = 0; i < ret; i++)
666 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
667 pOutput + (i * size), size);
668 HeapFree(GetProcessHeap(), 0, pOutputA);
669 } else {
670 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
671 (LPSTR)pOutput, dmA);
673 HeapFree(GetProcessHeap(),0,pPortA);
674 HeapFree(GetProcessHeap(),0,pDeviceA);
675 HeapFree(GetProcessHeap(),0,dmA);
676 return ret;
679 /******************************************************************
680 * DocumentPropertiesA [WINSPOOL.@]
683 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
684 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
685 LPDEVMODEA pDevModeInput,DWORD fMode )
687 LPSTR lpName = pDeviceName;
688 LONG ret;
690 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
691 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
694 if(!pDeviceName) {
695 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
696 if(!lpNameW) {
697 ERR("no name from hPrinter?\n");
698 return -1;
700 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
703 if (!GDI_CallExtDeviceMode16)
705 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
706 (LPCSTR)102 );
707 if (!GDI_CallExtDeviceMode16) {
708 ERR("No CallExtDeviceMode16?\n");
709 return -1;
712 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
713 pDevModeInput, NULL, fMode);
715 if(!pDeviceName)
716 HeapFree(GetProcessHeap(),0,lpName);
717 return ret;
721 /*****************************************************************************
722 * DocumentPropertiesW (WINSPOOL.@)
724 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
725 LPWSTR pDeviceName,
726 LPDEVMODEW pDevModeOutput,
727 LPDEVMODEW pDevModeInput, DWORD fMode)
730 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
731 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
732 LPDEVMODEA pDevModeOutputA = NULL;
733 LONG ret;
735 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
736 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
737 fMode);
738 if(pDevModeOutput) {
739 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
740 if(ret < 0) return ret;
741 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
743 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
744 pDevModeInputA, fMode);
745 if(pDevModeOutput) {
746 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
747 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
749 if(fMode == 0 && ret > 0)
750 ret += (CCHDEVICENAME + CCHFORMNAME);
751 HeapFree(GetProcessHeap(),0,pDevModeInputA);
752 HeapFree(GetProcessHeap(),0,pDeviceNameA);
753 return ret;
756 /******************************************************************
757 * OpenPrinterA [WINSPOOL.@]
760 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
761 LPPRINTER_DEFAULTSA pDefault)
763 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
764 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
765 BOOL ret;
767 if(pDefault) {
768 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
769 pDefault->pDatatype);
770 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
771 pDefault->pDevMode);
772 DefaultW.DesiredAccess = pDefault->DesiredAccess;
773 pDefaultW = &DefaultW;
775 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
776 if(pDefault) {
777 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
778 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
780 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
781 return ret;
784 /******************************************************************
785 * OpenPrinterW [WINSPOOL.@]
788 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
789 LPPRINTER_DEFAULTSW pDefault)
791 HKEY hkeyPrinters, hkeyPrinter;
793 if (!lpPrinterName) {
794 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
795 SetLastError(ERROR_INVALID_PARAMETER);
796 return FALSE;
799 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
800 pDefault);
802 /* Check Printer exists */
803 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
804 ERROR_SUCCESS) {
805 ERR("Can't create Printers key\n");
806 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
807 return FALSE;
810 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
811 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
812 != ERROR_SUCCESS) {
813 TRACE("Can't find printer %s in registry\n",
814 debugstr_w(lpPrinterName));
815 RegCloseKey(hkeyPrinters);
816 SetLastError(ERROR_INVALID_PRINTER_NAME);
817 return FALSE;
819 RegCloseKey(hkeyPrinter);
820 RegCloseKey(hkeyPrinters);
822 if(!phPrinter) /* This seems to be what win95 does anyway */
823 return TRUE;
825 /* Get the unique handle of the printer*/
826 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
828 if (pDefault != NULL)
829 FIXME("Not handling pDefault\n");
831 return TRUE;
834 /******************************************************************
835 * AddMonitorA [WINSPOOL.@]
838 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
840 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
841 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
842 return FALSE;
845 /******************************************************************
846 * DeletePrinterDriverA [WINSPOOL.@]
849 BOOL WINAPI
850 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
852 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
853 debugstr_a(pDriverName));
854 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
855 return FALSE;
859 /******************************************************************
860 * DeleteMonitorA [WINSPOOL.@]
863 BOOL WINAPI
864 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
866 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
867 debugstr_a(pMonitorName));
868 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
869 return FALSE;
873 /******************************************************************
874 * DeletePortA [WINSPOOL.@]
877 BOOL WINAPI
878 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
880 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
881 debugstr_a(pPortName));
882 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
883 return FALSE;
886 /******************************************************************************
887 * SetPrinterW [WINSPOOL.@]
889 BOOL WINAPI
890 SetPrinterW(
891 HANDLE hPrinter,
892 DWORD Level,
893 LPBYTE pPrinter,
894 DWORD Command) {
896 FIXME("():stub\n");
897 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
898 return FALSE;
901 /******************************************************************************
902 * WritePrinter [WINSPOOL.@]
904 BOOL WINAPI
905 WritePrinter(
906 HANDLE hPrinter,
907 LPVOID pBuf,
908 DWORD cbBuf,
909 LPDWORD pcWritten) {
911 FIXME("():stub\n");
912 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
913 return FALSE;
916 /*****************************************************************************
917 * AddFormA [WINSPOOL.@]
919 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
921 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
922 return 1;
925 /*****************************************************************************
926 * AddFormW [WINSPOOL.@]
928 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
930 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
931 return 1;
934 /*****************************************************************************
935 * AddJobA [WINSPOOL.@]
937 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
938 DWORD cbBuf, LPDWORD pcbNeeded)
940 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
941 pcbNeeded);
942 return 1;
945 /*****************************************************************************
946 * AddJobW [WINSPOOL.@]
948 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
949 LPDWORD pcbNeeded)
951 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
952 pcbNeeded);
953 return 1;
956 /*****************************************************************************
957 * WINSPOOL_OpenDriverReg [internal]
959 * opens the registry for the printer drivers depending on the given input
960 * variable pEnvironment
962 * RETURNS:
963 * the opened hkey on success
964 * NULL on error
966 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
967 { HKEY retval;
968 LPSTR lpKey, p = NULL;
970 TRACE("%s\n",
971 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
973 if(pEnvironment)
974 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
975 pEnvironment;
976 else {
977 OSVERSIONINFOA ver;
978 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
980 if(!GetVersionExA( &ver))
981 return 0;
983 switch (ver.dwPlatformId) {
984 case VER_PLATFORM_WIN32s:
985 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
986 return 0;
988 case VER_PLATFORM_WIN32_NT:
989 p = "Windows NT x86";
990 break;
991 default:
992 p = "Windows 4.0";
993 break;
995 TRACE("set environment to %s\n", p);
998 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
999 strlen(p) + strlen(Drivers));
1000 sprintf( lpKey, Drivers, p);
1002 TRACE("%s\n", lpKey);
1004 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1005 ERROR_SUCCESS)
1006 retval = 0;
1008 if(pEnvironment && unicode)
1009 HeapFree( GetProcessHeap(), 0, p);
1010 HeapFree( GetProcessHeap(), 0, lpKey);
1012 return retval;
1015 /*****************************************************************************
1016 * AddPrinterW [WINSPOOL.@]
1018 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1020 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1021 LPDEVMODEA dmA;
1022 LPDEVMODEW dmW;
1023 HANDLE retval;
1024 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1025 LONG size;
1027 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1029 if(pName != NULL) {
1030 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1031 SetLastError(ERROR_INVALID_PARAMETER);
1032 return 0;
1034 if(Level != 2) {
1035 ERR("Level = %ld, unsupported!\n", Level);
1036 SetLastError(ERROR_INVALID_LEVEL);
1037 return 0;
1039 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1040 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1041 debugstr_w(pi->pPrinterName)
1043 SetLastError(ERROR_INVALID_LEVEL);
1044 return 0;
1046 if(!pPrinter) {
1047 SetLastError(ERROR_INVALID_PARAMETER);
1048 return 0;
1050 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1051 ERROR_SUCCESS) {
1052 ERR("Can't create Printers key\n");
1053 return 0;
1055 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1056 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1057 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1058 RegCloseKey(hkeyPrinter);
1059 RegCloseKey(hkeyPrinters);
1060 return 0;
1062 RegCloseKey(hkeyPrinter);
1064 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1065 if(!hkeyDrivers) {
1066 ERR("Can't create Drivers key\n");
1067 RegCloseKey(hkeyPrinters);
1068 return 0;
1070 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1071 ERROR_SUCCESS) {
1072 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1073 RegCloseKey(hkeyPrinters);
1074 RegCloseKey(hkeyDrivers);
1075 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1076 return 0;
1078 RegCloseKey(hkeyDriver);
1079 RegCloseKey(hkeyDrivers);
1081 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1082 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1083 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1084 RegCloseKey(hkeyPrinters);
1085 return 0;
1088 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1089 ERROR_SUCCESS) {
1090 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1091 SetLastError(ERROR_INVALID_PRINTER_NAME);
1092 RegCloseKey(hkeyPrinters);
1093 return 0;
1095 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1096 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1097 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1099 /* See if we can load the driver. We may need the devmode structure anyway
1101 * FIXME:
1102 * Note that DocumentPropertiesW will briefly try to open the printer we
1103 * just create to find a DEVMODEA struct (it will use the WINEPS default
1104 * one in case it is not there, so we are ok).
1106 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1107 if(size < 0) {
1108 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1109 size = sizeof(DEVMODEW);
1111 if(pi->pDevMode)
1112 dmW = pi->pDevMode;
1113 else {
1114 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1115 dmW->dmSize = size;
1116 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1117 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1118 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1119 return 0;
1121 /* set devmode to printer name */
1122 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1125 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1126 and we support these drivers. NT writes DEVMODEW so somehow
1127 we'll need to distinguish between these when we support NT
1128 drivers */
1129 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1130 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1131 dmA->dmSize + dmA->dmDriverExtra);
1132 HeapFree(GetProcessHeap(), 0, dmA);
1133 if(!pi->pDevMode)
1134 HeapFree(GetProcessHeap(), 0, dmW);
1135 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1136 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1137 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1138 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1140 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1141 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1142 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1143 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1144 (LPBYTE)&pi->Priority, sizeof(DWORD));
1145 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1146 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1147 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1148 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1149 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1150 (LPBYTE)&pi->Status, sizeof(DWORD));
1151 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1152 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1154 RegCloseKey(hkeyPrinter);
1155 RegCloseKey(hkeyPrinters);
1156 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1157 ERR("OpenPrinter failing\n");
1158 return 0;
1160 return retval;
1163 /*****************************************************************************
1164 * AddPrinterA [WINSPOOL.@]
1166 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1168 WCHAR *pNameW;
1169 PRINTER_INFO_2W *piW;
1170 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1171 HANDLE ret;
1173 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1174 if(Level != 2) {
1175 ERR("Level = %ld, unsupported!\n", Level);
1176 SetLastError(ERROR_INVALID_LEVEL);
1177 return 0;
1179 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
1180 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1182 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
1184 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1185 HeapFree(GetProcessHeap(),0,pNameW);
1186 return ret;
1190 /*****************************************************************************
1191 * ClosePrinter [WINSPOOL.@]
1193 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1195 int i = (int)hPrinter;
1197 TRACE("Handle %p\n", hPrinter);
1199 if ((i <= 0) || (i > nb_printers)) return FALSE;
1200 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1201 printer_array[i - 1] = NULL;
1202 return TRUE;
1205 /*****************************************************************************
1206 * DeleteFormA [WINSPOOL.@]
1208 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1210 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1211 return 1;
1214 /*****************************************************************************
1215 * DeleteFormW [WINSPOOL.@]
1217 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1219 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1220 return 1;
1223 /*****************************************************************************
1224 * DeletePrinter [WINSPOOL.@]
1226 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1228 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1229 HKEY hkeyPrinters;
1231 if(!lpNameW) return FALSE;
1232 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1233 ERROR_SUCCESS) {
1234 ERR("Can't open Printers key\n");
1235 return 0;
1238 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1239 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1240 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1241 RegCloseKey(hkeyPrinters);
1242 return 0;
1245 ClosePrinter(hPrinter);
1246 return TRUE;
1249 /*****************************************************************************
1250 * SetPrinterA [WINSPOOL.@]
1252 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1253 DWORD Command)
1255 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1256 return FALSE;
1259 /*****************************************************************************
1260 * SetJobA [WINSPOOL.@]
1262 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1263 LPBYTE pJob, DWORD Command)
1265 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1266 Command);
1267 return FALSE;
1270 /*****************************************************************************
1271 * SetJobW [WINSPOOL.@]
1273 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1274 LPBYTE pJob, DWORD Command)
1276 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1277 Command);
1278 return FALSE;
1281 /*****************************************************************************
1282 * EndDocPrinter [WINSPOOL.@]
1284 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1286 FIXME("(hPrinter=%p): stub\n", hPrinter);
1287 return FALSE;
1290 /*****************************************************************************
1291 * EndPagePrinter [WINSPOOL.@]
1293 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1295 FIXME("(hPrinter=%p): stub\n", hPrinter);
1296 return FALSE;
1299 /*****************************************************************************
1300 * StartDocPrinterA [WINSPOOL.@]
1302 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1304 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1305 return FALSE;
1308 /*****************************************************************************
1309 * StartDocPrinterW [WINSPOOL.@]
1311 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1313 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1314 return FALSE;
1317 /*****************************************************************************
1318 * StartPagePrinter [WINSPOOL.@]
1320 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1322 FIXME("(hPrinter=%p): stub\n", hPrinter);
1323 return FALSE;
1326 /*****************************************************************************
1327 * GetFormA [WINSPOOL.@]
1329 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1330 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1332 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1333 Level,pForm,cbBuf,pcbNeeded);
1334 return FALSE;
1337 /*****************************************************************************
1338 * GetFormW [WINSPOOL.@]
1340 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1341 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1343 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1344 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1345 return FALSE;
1348 /*****************************************************************************
1349 * SetFormA [WINSPOOL.@]
1351 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1352 LPBYTE pForm)
1354 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1355 return FALSE;
1358 /*****************************************************************************
1359 * SetFormW [WINSPOOL.@]
1361 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1362 LPBYTE pForm)
1364 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1365 return FALSE;
1368 /*****************************************************************************
1369 * ReadPrinter [WINSPOOL.@]
1371 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1372 LPDWORD pNoBytesRead)
1374 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1375 return FALSE;
1378 /*****************************************************************************
1379 * ResetPrinterA [WINSPOOL.@]
1381 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1383 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1384 return FALSE;
1387 /*****************************************************************************
1388 * ResetPrinterW [WINSPOOL.@]
1390 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1392 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1393 return FALSE;
1396 /*****************************************************************************
1397 * WINSPOOL_GetDWORDFromReg
1399 * Return DWORD associated with ValueName from hkey.
1401 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1403 DWORD sz = sizeof(DWORD), type, value = 0;
1404 LONG ret;
1406 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1408 if(ret != ERROR_SUCCESS) {
1409 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1410 return 0;
1412 if(type != REG_DWORD) {
1413 ERR("Got type %ld\n", type);
1414 return 0;
1416 return value;
1419 /*****************************************************************************
1420 * WINSPOOL_GetStringFromReg
1422 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1423 * String is stored either as unicode or ascii.
1424 * Bit of a hack here to get the ValueName if we want ascii.
1426 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1427 DWORD buflen, DWORD *needed,
1428 BOOL unicode)
1430 DWORD sz = buflen, type;
1431 LONG ret;
1433 if(unicode)
1434 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1435 else {
1436 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1437 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1438 HeapFree(GetProcessHeap(),0,ValueNameA);
1440 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1441 WARN("Got ret = %ld\n", ret);
1442 *needed = 0;
1443 return FALSE;
1445 *needed = sz;
1446 return TRUE;
1449 /*****************************************************************************
1450 * WINSPOOL_GetDefaultDevMode
1452 * Get a default DevMode values for wineps.
1453 * FIXME - use ppd.
1456 static void WINSPOOL_GetDefaultDevMode(
1457 LPBYTE ptr,
1458 DWORD buflen, DWORD *needed,
1459 BOOL unicode)
1461 DEVMODEA dm;
1463 /* fill default DEVMODE - should be read from ppd... */
1464 ZeroMemory( &dm, sizeof(dm) );
1465 strcpy(dm.dmDeviceName,"wineps");
1466 dm.dmSpecVersion = DM_SPECVERSION;
1467 dm.dmDriverVersion = 1;
1468 dm.dmSize = sizeof(DEVMODEA);
1469 dm.dmDriverExtra = 0;
1470 dm.dmFields =
1471 DM_ORIENTATION | DM_PAPERSIZE |
1472 DM_PAPERLENGTH | DM_PAPERWIDTH |
1473 DM_SCALE |
1474 DM_COPIES |
1475 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1476 DM_YRESOLUTION | DM_TTOPTION;
1478 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1479 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1480 dm.u1.s1.dmPaperLength = 2970;
1481 dm.u1.s1.dmPaperWidth = 2100;
1483 dm.dmScale = 100;
1484 dm.dmCopies = 1;
1485 dm.dmDefaultSource = DMBIN_AUTO;
1486 dm.dmPrintQuality = DMRES_MEDIUM;
1487 /* dm.dmColor */
1488 /* dm.dmDuplex */
1489 dm.dmYResolution = 300; /* 300dpi */
1490 dm.dmTTOption = DMTT_BITMAP;
1491 /* dm.dmCollate */
1492 /* dm.dmFormName */
1493 /* dm.dmLogPixels */
1494 /* dm.dmBitsPerPel */
1495 /* dm.dmPelsWidth */
1496 /* dm.dmPelsHeight */
1497 /* dm.dmDisplayFlags */
1498 /* dm.dmDisplayFrequency */
1499 /* dm.dmICMMethod */
1500 /* dm.dmICMIntent */
1501 /* dm.dmMediaType */
1502 /* dm.dmDitherType */
1503 /* dm.dmReserved1 */
1504 /* dm.dmReserved2 */
1505 /* dm.dmPanningWidth */
1506 /* dm.dmPanningHeight */
1508 if(unicode) {
1509 if(buflen >= sizeof(DEVMODEW)) {
1510 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1511 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1512 HeapFree(GetProcessHeap(),0,pdmW);
1514 *needed = sizeof(DEVMODEW);
1516 else
1518 if(buflen >= sizeof(DEVMODEA)) {
1519 memcpy(ptr, &dm, sizeof(DEVMODEA));
1521 *needed = sizeof(DEVMODEA);
1525 /*****************************************************************************
1526 * WINSPOOL_GetDevModeFromReg
1528 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1529 * DevMode is stored either as unicode or ascii.
1531 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1532 LPBYTE ptr,
1533 DWORD buflen, DWORD *needed,
1534 BOOL unicode)
1536 DWORD sz = buflen, type;
1537 LONG ret;
1539 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1540 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1541 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1542 if (sz < sizeof(DEVMODEA))
1544 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1545 return FALSE;
1547 /* ensures that dmSize is not erratically bogus if registry is invalid */
1548 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1549 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1550 if(unicode) {
1551 sz += (CCHDEVICENAME + CCHFORMNAME);
1552 if(buflen >= sz) {
1553 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1554 memcpy(ptr, dmW, sz);
1555 HeapFree(GetProcessHeap(),0,dmW);
1558 *needed = sz;
1559 return TRUE;
1562 /*********************************************************************
1563 * WINSPOOL_GetPrinter_2
1565 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1566 * The strings are either stored as unicode or ascii.
1568 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1569 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1570 BOOL unicode)
1572 DWORD size, left = cbBuf;
1573 BOOL space = (cbBuf > 0);
1574 LPBYTE ptr = buf;
1576 *pcbNeeded = 0;
1578 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1579 unicode)) {
1580 if(space && size <= left) {
1581 pi2->pPrinterName = (LPWSTR)ptr;
1582 ptr += size;
1583 left -= size;
1584 } else
1585 space = FALSE;
1586 *pcbNeeded += size;
1588 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1589 unicode)) {
1590 if(space && size <= left) {
1591 pi2->pShareName = (LPWSTR)ptr;
1592 ptr += size;
1593 left -= size;
1594 } else
1595 space = FALSE;
1596 *pcbNeeded += size;
1598 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1599 unicode)) {
1600 if(space && size <= left) {
1601 pi2->pPortName = (LPWSTR)ptr;
1602 ptr += size;
1603 left -= size;
1604 } else
1605 space = FALSE;
1606 *pcbNeeded += size;
1608 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1609 &size, unicode)) {
1610 if(space && size <= left) {
1611 pi2->pDriverName = (LPWSTR)ptr;
1612 ptr += size;
1613 left -= size;
1614 } else
1615 space = FALSE;
1616 *pcbNeeded += size;
1618 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1619 unicode)) {
1620 if(space && size <= left) {
1621 pi2->pComment = (LPWSTR)ptr;
1622 ptr += size;
1623 left -= size;
1624 } else
1625 space = FALSE;
1626 *pcbNeeded += size;
1628 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1629 unicode)) {
1630 if(space && size <= left) {
1631 pi2->pLocation = (LPWSTR)ptr;
1632 ptr += size;
1633 left -= size;
1634 } else
1635 space = FALSE;
1636 *pcbNeeded += size;
1638 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1639 &size, unicode)) {
1640 if(space && size <= left) {
1641 pi2->pDevMode = (LPDEVMODEW)ptr;
1642 ptr += size;
1643 left -= size;
1644 } else
1645 space = FALSE;
1646 *pcbNeeded += size;
1648 else
1650 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1651 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
1652 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1653 if(space && size <= left) {
1654 pi2->pDevMode = (LPDEVMODEW)ptr;
1655 ptr += size;
1656 left -= size;
1657 } else
1658 space = FALSE;
1659 *pcbNeeded += size;
1661 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1662 &size, unicode)) {
1663 if(space && size <= left) {
1664 pi2->pSepFile = (LPWSTR)ptr;
1665 ptr += size;
1666 left -= size;
1667 } else
1668 space = FALSE;
1669 *pcbNeeded += size;
1671 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1672 &size, unicode)) {
1673 if(space && size <= left) {
1674 pi2->pPrintProcessor = (LPWSTR)ptr;
1675 ptr += size;
1676 left -= size;
1677 } else
1678 space = FALSE;
1679 *pcbNeeded += size;
1681 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1682 &size, unicode)) {
1683 if(space && size <= left) {
1684 pi2->pDatatype = (LPWSTR)ptr;
1685 ptr += size;
1686 left -= size;
1687 } else
1688 space = FALSE;
1689 *pcbNeeded += size;
1691 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1692 &size, unicode)) {
1693 if(space && size <= left) {
1694 pi2->pParameters = (LPWSTR)ptr;
1695 ptr += size;
1696 left -= size;
1697 } else
1698 space = FALSE;
1699 *pcbNeeded += size;
1701 if(pi2) {
1702 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1703 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1704 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1705 "Default Priority");
1706 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1707 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1710 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1711 memset(pi2, 0, sizeof(*pi2));
1713 return space;
1716 /*********************************************************************
1717 * WINSPOOL_GetPrinter_4
1719 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1721 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1722 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1723 BOOL unicode)
1725 DWORD size, left = cbBuf;
1726 BOOL space = (cbBuf > 0);
1727 LPBYTE ptr = buf;
1729 *pcbNeeded = 0;
1731 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1732 unicode)) {
1733 if(space && size <= left) {
1734 pi4->pPrinterName = (LPWSTR)ptr;
1735 ptr += size;
1736 left -= size;
1737 } else
1738 space = FALSE;
1739 *pcbNeeded += size;
1741 if(pi4) {
1742 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1745 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1746 memset(pi4, 0, sizeof(*pi4));
1748 return space;
1751 /*********************************************************************
1752 * WINSPOOL_GetPrinter_5
1754 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1756 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1757 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1758 BOOL unicode)
1760 DWORD size, left = cbBuf;
1761 BOOL space = (cbBuf > 0);
1762 LPBYTE ptr = buf;
1764 *pcbNeeded = 0;
1766 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1767 unicode)) {
1768 if(space && size <= left) {
1769 pi5->pPrinterName = (LPWSTR)ptr;
1770 ptr += size;
1771 left -= size;
1772 } else
1773 space = FALSE;
1774 *pcbNeeded += size;
1776 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1777 unicode)) {
1778 if(space && size <= left) {
1779 pi5->pPortName = (LPWSTR)ptr;
1780 ptr += size;
1781 left -= size;
1782 } else
1783 space = FALSE;
1784 *pcbNeeded += size;
1786 if(pi5) {
1787 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1788 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1789 "dnsTimeout");
1790 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1791 "txTimeout");
1794 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1795 memset(pi5, 0, sizeof(*pi5));
1797 return space;
1800 /*****************************************************************************
1801 * WINSPOOL_GetPrinter
1803 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1804 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1805 * just a collection of pointers to strings.
1807 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1808 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1810 LPCWSTR name;
1811 DWORD size, needed = 0;
1812 LPBYTE ptr = NULL;
1813 HKEY hkeyPrinter, hkeyPrinters;
1814 BOOL ret;
1816 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1818 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1820 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1821 ERROR_SUCCESS) {
1822 ERR("Can't create Printers key\n");
1823 return FALSE;
1825 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1827 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1828 RegCloseKey(hkeyPrinters);
1829 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1830 return FALSE;
1833 switch(Level) {
1834 case 2:
1836 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1838 size = sizeof(PRINTER_INFO_2W);
1839 if(size <= cbBuf) {
1840 ptr = pPrinter + size;
1841 cbBuf -= size;
1842 memset(pPrinter, 0, size);
1843 } else {
1844 pi2 = NULL;
1845 cbBuf = 0;
1847 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1848 unicode);
1849 needed += size;
1850 break;
1853 case 4:
1855 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1857 size = sizeof(PRINTER_INFO_4W);
1858 if(size <= cbBuf) {
1859 ptr = pPrinter + size;
1860 cbBuf -= size;
1861 memset(pPrinter, 0, size);
1862 } else {
1863 pi4 = NULL;
1864 cbBuf = 0;
1866 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1867 unicode);
1868 needed += size;
1869 break;
1873 case 5:
1875 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1877 size = sizeof(PRINTER_INFO_5W);
1878 if(size <= cbBuf) {
1879 ptr = pPrinter + size;
1880 cbBuf -= size;
1881 memset(pPrinter, 0, size);
1882 } else {
1883 pi5 = NULL;
1884 cbBuf = 0;
1887 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1888 unicode);
1889 needed += size;
1890 break;
1893 default:
1894 FIXME("Unimplemented level %ld\n", Level);
1895 SetLastError(ERROR_INVALID_LEVEL);
1896 RegCloseKey(hkeyPrinters);
1897 RegCloseKey(hkeyPrinter);
1898 return FALSE;
1901 RegCloseKey(hkeyPrinter);
1902 RegCloseKey(hkeyPrinters);
1904 TRACE("returning %d needed = %ld\n", ret, needed);
1905 if(pcbNeeded) *pcbNeeded = needed;
1906 if(!ret)
1907 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1908 return ret;
1911 /*****************************************************************************
1912 * GetPrinterW [WINSPOOL.@]
1914 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1915 DWORD cbBuf, LPDWORD pcbNeeded)
1917 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1918 TRUE);
1921 /*****************************************************************************
1922 * GetPrinterA [WINSPOOL.@]
1924 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1925 DWORD cbBuf, LPDWORD pcbNeeded)
1927 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1928 FALSE);
1931 /*****************************************************************************
1932 * WINSPOOL_EnumPrinters
1934 * Implementation of EnumPrintersA|W
1936 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1937 DWORD dwLevel, LPBYTE lpbPrinters,
1938 DWORD cbBuf, LPDWORD lpdwNeeded,
1939 LPDWORD lpdwReturned, BOOL unicode)
1942 HKEY hkeyPrinters, hkeyPrinter;
1943 WCHAR PrinterName[255];
1944 DWORD needed = 0, number = 0;
1945 DWORD used, i, left;
1946 PBYTE pi, buf;
1948 if(lpbPrinters)
1949 memset(lpbPrinters, 0, cbBuf);
1950 if(lpdwReturned)
1951 *lpdwReturned = 0;
1952 if(lpdwNeeded)
1953 *lpdwNeeded = 0;
1955 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1956 if(dwType == PRINTER_ENUM_DEFAULT)
1957 return TRUE;
1959 if (dwType & PRINTER_ENUM_CONNECTIONS) {
1960 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
1961 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
1962 dwType |= PRINTER_ENUM_LOCAL;
1965 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1966 FIXME("dwType = %08lx\n", dwType);
1967 SetLastError(ERROR_INVALID_FLAGS);
1968 return FALSE;
1971 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1972 ERROR_SUCCESS) {
1973 ERR("Can't create Printers key\n");
1974 return FALSE;
1977 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1978 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1979 RegCloseKey(hkeyPrinters);
1980 ERR("Can't query Printers key\n");
1981 return FALSE;
1983 TRACE("Found %ld printers\n", number);
1985 switch(dwLevel) {
1986 case 1:
1987 RegCloseKey(hkeyPrinters);
1988 if (lpdwReturned)
1989 *lpdwReturned = number;
1990 return TRUE;
1992 case 2:
1993 used = number * sizeof(PRINTER_INFO_2W);
1994 break;
1995 case 4:
1996 used = number * sizeof(PRINTER_INFO_4W);
1997 break;
1998 case 5:
1999 used = number * sizeof(PRINTER_INFO_5W);
2000 break;
2002 default:
2003 SetLastError(ERROR_INVALID_LEVEL);
2004 RegCloseKey(hkeyPrinters);
2005 return FALSE;
2007 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2009 for(i = 0; i < number; i++) {
2010 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2011 ERROR_SUCCESS) {
2012 ERR("Can't enum key number %ld\n", i);
2013 RegCloseKey(hkeyPrinters);
2014 return FALSE;
2016 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2017 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2018 ERROR_SUCCESS) {
2019 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2020 RegCloseKey(hkeyPrinters);
2021 return FALSE;
2024 if(cbBuf > used) {
2025 buf = lpbPrinters + used;
2026 left = cbBuf - used;
2027 } else {
2028 buf = NULL;
2029 left = 0;
2032 switch(dwLevel) {
2033 case 2:
2034 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2035 left, &needed, unicode);
2036 used += needed;
2037 if(pi) pi += sizeof(PRINTER_INFO_2W);
2038 break;
2039 case 4:
2040 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2041 left, &needed, unicode);
2042 used += needed;
2043 if(pi) pi += sizeof(PRINTER_INFO_4W);
2044 break;
2045 case 5:
2046 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2047 left, &needed, unicode);
2048 used += needed;
2049 if(pi) pi += sizeof(PRINTER_INFO_5W);
2050 break;
2051 default:
2052 ERR("Shouldn't be here!\n");
2053 RegCloseKey(hkeyPrinter);
2054 RegCloseKey(hkeyPrinters);
2055 return FALSE;
2057 RegCloseKey(hkeyPrinter);
2059 RegCloseKey(hkeyPrinters);
2061 if(lpdwNeeded)
2062 *lpdwNeeded = used;
2064 if(used > cbBuf) {
2065 if(lpbPrinters)
2066 memset(lpbPrinters, 0, cbBuf);
2067 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2068 return FALSE;
2070 if(lpdwReturned)
2071 *lpdwReturned = number;
2072 SetLastError(ERROR_SUCCESS);
2073 return TRUE;
2077 /******************************************************************
2078 * EnumPrintersW [WINSPOOL.@]
2080 * Enumerates the available printers, print servers and print
2081 * providers, depending on the specified flags, name and level.
2083 * RETURNS:
2085 * If level is set to 1:
2086 * Not implemented yet!
2087 * Returns TRUE with an empty list.
2089 * If level is set to 2:
2090 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2091 * Returns an array of PRINTER_INFO_2 data structures in the
2092 * lpbPrinters buffer. Note that according to MSDN also an
2093 * OpenPrinter should be performed on every remote printer.
2095 * If level is set to 4 (officially WinNT only):
2096 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2097 * Fast: Only the registry is queried to retrieve printer names,
2098 * no connection to the driver is made.
2099 * Returns an array of PRINTER_INFO_4 data structures in the
2100 * lpbPrinters buffer.
2102 * If level is set to 5 (officially WinNT4/Win9x only):
2103 * Fast: Only the registry is queried to retrieve printer names,
2104 * no connection to the driver is made.
2105 * Returns an array of PRINTER_INFO_5 data structures in the
2106 * lpbPrinters buffer.
2108 * If level set to 3 or 6+:
2109 * returns zero (failure!)
2111 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2112 * for information.
2114 * BUGS:
2115 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2116 * - Only levels 2, 4 and 5 are implemented at the moment.
2117 * - 16-bit printer drivers are not enumerated.
2118 * - Returned amount of bytes used/needed does not match the real Windoze
2119 * implementation (as in this implementation, all strings are part
2120 * of the buffer, whereas Win32 keeps them somewhere else)
2121 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2123 * NOTE:
2124 * - In a regular Wine installation, no registry settings for printers
2125 * exist, which makes this function return an empty list.
2127 BOOL WINAPI EnumPrintersW(
2128 DWORD dwType, /* [in] Types of print objects to enumerate */
2129 LPWSTR lpszName, /* [in] name of objects to enumerate */
2130 DWORD dwLevel, /* [in] type of printer info structure */
2131 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2132 DWORD cbBuf, /* [in] max size of buffer in bytes */
2133 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2134 LPDWORD lpdwReturned /* [out] number of entries returned */
2137 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2138 lpdwNeeded, lpdwReturned, TRUE);
2141 /******************************************************************
2142 * EnumPrintersA [WINSPOOL.@]
2145 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2146 DWORD dwLevel, LPBYTE lpbPrinters,
2147 DWORD cbBuf, LPDWORD lpdwNeeded,
2148 LPDWORD lpdwReturned)
2150 BOOL ret;
2151 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
2153 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
2154 lpdwNeeded, lpdwReturned, FALSE);
2155 HeapFree(GetProcessHeap(),0,lpszNameW);
2156 return ret;
2159 /*****************************************************************************
2160 * WINSPOOL_GetDriverInfoFromReg [internal]
2162 * Enters the information from the registry into the DRIVER_INFO struct
2164 * RETURNS
2165 * zero if the printer driver does not exist in the registry
2166 * (only if Level > 1) otherwise nonzero
2168 static BOOL WINSPOOL_GetDriverInfoFromReg(
2169 HKEY hkeyDrivers,
2170 LPWSTR DriverName,
2171 LPWSTR pEnvironment,
2172 DWORD Level,
2173 LPBYTE ptr, /* DRIVER_INFO */
2174 LPBYTE pDriverStrings, /* strings buffer */
2175 DWORD cbBuf, /* size of string buffer */
2176 LPDWORD pcbNeeded, /* space needed for str. */
2177 BOOL unicode) /* type of strings */
2178 { DWORD dw, size, tmp, type;
2179 HKEY hkeyDriver;
2180 LPBYTE strPtr = pDriverStrings;
2182 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2183 debugstr_w(DriverName), debugstr_w(pEnvironment),
2184 Level, ptr, pDriverStrings, cbBuf, unicode);
2186 if(unicode) {
2187 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2188 if (*pcbNeeded <= cbBuf)
2189 strcpyW((LPWSTR)strPtr, DriverName);
2190 } else {
2191 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2192 NULL, NULL);
2193 if(*pcbNeeded <= cbBuf)
2194 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2195 NULL, NULL);
2197 if(Level == 1) {
2198 if(ptr)
2199 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2200 return TRUE;
2201 } else {
2202 if(ptr)
2203 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2204 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2207 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2208 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2209 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2210 return FALSE;
2213 size = sizeof(dw);
2214 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2215 ERROR_SUCCESS)
2216 WARN("Can't get Version\n");
2217 else if(ptr)
2218 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2220 if(!pEnvironment)
2221 pEnvironment = DefaultEnvironmentW;
2222 if(unicode)
2223 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2224 else
2225 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2226 NULL, NULL);
2227 *pcbNeeded += size;
2228 if(*pcbNeeded <= cbBuf) {
2229 if(unicode)
2230 strcpyW((LPWSTR)strPtr, pEnvironment);
2231 else
2232 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2233 NULL, NULL);
2234 if(ptr)
2235 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2236 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2239 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2240 unicode)) {
2241 *pcbNeeded += size;
2242 if(*pcbNeeded <= cbBuf)
2243 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2244 unicode);
2245 if(ptr)
2246 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2247 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2250 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2251 unicode)) {
2252 *pcbNeeded += size;
2253 if(*pcbNeeded <= cbBuf)
2254 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2255 &tmp, unicode);
2256 if(ptr)
2257 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2258 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2261 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2262 0, &size, unicode)) {
2263 *pcbNeeded += size;
2264 if(*pcbNeeded <= cbBuf)
2265 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2266 size, &tmp, unicode);
2267 if(ptr)
2268 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2269 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2272 if(Level == 2 ) {
2273 RegCloseKey(hkeyDriver);
2274 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2275 return TRUE;
2278 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2279 unicode)) {
2280 *pcbNeeded += size;
2281 if(*pcbNeeded <= cbBuf)
2282 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2283 size, &tmp, unicode);
2284 if(ptr)
2285 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2286 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2289 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2290 &size, unicode)) {
2291 *pcbNeeded += size;
2292 if(*pcbNeeded <= cbBuf)
2293 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2294 size, &tmp, unicode);
2295 if(ptr)
2296 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2297 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2300 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2301 unicode)) {
2302 *pcbNeeded += size;
2303 if(*pcbNeeded <= cbBuf)
2304 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2305 size, &tmp, unicode);
2306 if(ptr)
2307 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2308 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2311 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2312 unicode)) {
2313 *pcbNeeded += size;
2314 if(*pcbNeeded <= cbBuf)
2315 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2316 size, &tmp, unicode);
2317 if(ptr)
2318 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2319 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2322 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2323 RegCloseKey(hkeyDriver);
2324 return TRUE;
2327 /*****************************************************************************
2328 * WINSPOOL_GetPrinterDriver
2330 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2331 DWORD Level, LPBYTE pDriverInfo,
2332 DWORD cbBuf, LPDWORD pcbNeeded,
2333 BOOL unicode)
2335 LPCWSTR name;
2336 WCHAR DriverName[100];
2337 DWORD ret, type, size, needed = 0;
2338 LPBYTE ptr = NULL;
2339 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2341 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2342 Level,pDriverInfo,cbBuf, pcbNeeded);
2344 ZeroMemory(pDriverInfo, cbBuf);
2346 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2348 if(Level < 1 || Level > 3) {
2349 SetLastError(ERROR_INVALID_LEVEL);
2350 return FALSE;
2352 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2353 ERROR_SUCCESS) {
2354 ERR("Can't create Printers key\n");
2355 return FALSE;
2357 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2358 != ERROR_SUCCESS) {
2359 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2360 RegCloseKey(hkeyPrinters);
2361 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2362 return FALSE;
2364 size = sizeof(DriverName);
2365 DriverName[0] = 0;
2366 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2367 (LPBYTE)DriverName, &size);
2368 RegCloseKey(hkeyPrinter);
2369 RegCloseKey(hkeyPrinters);
2370 if(ret != ERROR_SUCCESS) {
2371 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2372 return FALSE;
2375 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2376 if(!hkeyDrivers) {
2377 ERR("Can't create Drivers key\n");
2378 return FALSE;
2381 switch(Level) {
2382 case 1:
2383 size = sizeof(DRIVER_INFO_1W);
2384 break;
2385 case 2:
2386 size = sizeof(DRIVER_INFO_2W);
2387 break;
2388 case 3:
2389 size = sizeof(DRIVER_INFO_3W);
2390 break;
2391 default:
2392 ERR("Invalid level\n");
2393 return FALSE;
2396 if(size <= cbBuf)
2397 ptr = pDriverInfo + size;
2399 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2400 pEnvironment, Level, pDriverInfo,
2401 (cbBuf < size) ? NULL : ptr,
2402 (cbBuf < size) ? 0 : cbBuf - size,
2403 &needed, unicode)) {
2404 RegCloseKey(hkeyDrivers);
2405 return FALSE;
2408 RegCloseKey(hkeyDrivers);
2410 if(pcbNeeded) *pcbNeeded = size + needed;
2411 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2412 if(cbBuf >= needed) return TRUE;
2413 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2414 return FALSE;
2417 /*****************************************************************************
2418 * GetPrinterDriverA [WINSPOOL.@]
2420 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2421 DWORD Level, LPBYTE pDriverInfo,
2422 DWORD cbBuf, LPDWORD pcbNeeded)
2424 BOOL ret;
2425 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2426 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2427 cbBuf, pcbNeeded, FALSE);
2428 HeapFree(GetProcessHeap(),0,pEnvW);
2429 return ret;
2431 /*****************************************************************************
2432 * GetPrinterDriverW [WINSPOOL.@]
2434 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2435 DWORD Level, LPBYTE pDriverInfo,
2436 DWORD cbBuf, LPDWORD pcbNeeded)
2438 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2439 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2442 /*****************************************************************************
2443 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2445 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2446 DWORD Level, LPBYTE pDriverDirectory,
2447 DWORD cbBuf, LPDWORD pcbNeeded)
2449 DWORD needed;
2451 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2452 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2453 if(pName != NULL) {
2454 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2455 SetLastError(ERROR_INVALID_PARAMETER);
2456 return FALSE;
2458 if(pEnvironment != NULL) {
2459 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2460 SetLastError(ERROR_INVALID_ENVIRONMENT);
2461 return FALSE;
2463 if(Level != 1) /* win95 ignores this so we just carry on */
2464 WARN("Level = %ld - assuming 1\n", Level);
2466 /* FIXME should read from registry */
2467 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2468 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2469 * adjust this now
2471 needed++;
2472 needed*=sizeof(WCHAR);
2474 if(pcbNeeded)
2475 *pcbNeeded = needed;
2476 TRACE("required <%08lx>\n", *pcbNeeded);
2477 if(needed > cbBuf) {
2478 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2479 return FALSE;
2481 return TRUE;
2485 /*****************************************************************************
2486 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2488 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2489 DWORD Level, LPBYTE pDriverDirectory,
2490 DWORD cbBuf, LPDWORD pcbNeeded)
2492 UNICODE_STRING nameW, environmentW;
2493 BOOL ret;
2494 DWORD pcbNeededW;
2495 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2496 WCHAR *driverDirectoryW = NULL;
2498 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2500 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2501 else nameW.Buffer = NULL;
2502 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2503 else environmentW.Buffer = NULL;
2505 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2506 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2507 if (ret) {
2508 ret = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2509 pDriverDirectory, cbBuf, NULL, NULL);
2510 if(pcbNeeded)
2511 *pcbNeeded = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2512 NULL, 0, NULL, NULL);
2513 } else
2514 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2516 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2518 if(driverDirectoryW)
2519 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2520 RtlFreeUnicodeString(&environmentW);
2521 RtlFreeUnicodeString(&nameW);
2523 return ret;
2526 /*****************************************************************************
2527 * AddPrinterDriverA [WINSPOOL.@]
2529 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2531 DRIVER_INFO_3A di3;
2532 HKEY hkeyDrivers, hkeyName;
2534 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2536 if(level != 2 && level != 3) {
2537 SetLastError(ERROR_INVALID_LEVEL);
2538 return FALSE;
2540 if(pName != NULL) {
2541 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2542 SetLastError(ERROR_INVALID_PARAMETER);
2543 return FALSE;
2545 if(!pDriverInfo) {
2546 WARN("pDriverInfo == NULL\n");
2547 SetLastError(ERROR_INVALID_PARAMETER);
2548 return FALSE;
2551 if(level == 3)
2552 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2553 else {
2554 memset(&di3, 0, sizeof(di3));
2555 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2558 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2559 !di3.pDataFile) {
2560 SetLastError(ERROR_INVALID_PARAMETER);
2561 return FALSE;
2563 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2564 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2565 if(!di3.pHelpFile) di3.pHelpFile = "";
2566 if(!di3.pMonitorName) di3.pMonitorName = "";
2568 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2570 if(!hkeyDrivers) {
2571 ERR("Can't create Drivers key\n");
2572 return FALSE;
2575 if(level == 2) { /* apparently can't overwrite with level2 */
2576 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2577 RegCloseKey(hkeyName);
2578 RegCloseKey(hkeyDrivers);
2579 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2580 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2581 return FALSE;
2584 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2585 RegCloseKey(hkeyDrivers);
2586 ERR("Can't create Name key\n");
2587 return FALSE;
2589 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2591 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2592 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2593 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2594 sizeof(DWORD));
2595 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2596 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2597 di3.pDependentFiles, 0);
2598 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2599 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2600 RegCloseKey(hkeyName);
2601 RegCloseKey(hkeyDrivers);
2603 return TRUE;
2605 /*****************************************************************************
2606 * AddPrinterDriverW [WINSPOOL.@]
2608 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2609 LPBYTE pDriverInfo)
2611 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2612 level,pDriverInfo);
2613 return FALSE;
2617 /*****************************************************************************
2618 * PrinterProperties [WINSPOOL.@]
2620 * Displays a dialog to set the properties of the printer.
2622 * RETURNS
2623 * nonzero on success or zero on failure
2625 * BUGS
2626 * implemented as stub only
2628 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2629 HANDLE hPrinter /* [in] handle to printer object */
2631 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2632 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2633 return FALSE;
2636 /*****************************************************************************
2637 * EnumJobsA [WINSPOOL.@]
2640 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2641 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2642 LPDWORD pcReturned)
2644 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2645 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2647 if(pcbNeeded) *pcbNeeded = 0;
2648 if(pcReturned) *pcReturned = 0;
2649 return FALSE;
2653 /*****************************************************************************
2654 * EnumJobsW [WINSPOOL.@]
2657 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2658 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2659 LPDWORD pcReturned)
2661 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2662 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2664 if(pcbNeeded) *pcbNeeded = 0;
2665 if(pcReturned) *pcReturned = 0;
2666 return FALSE;
2669 /*****************************************************************************
2670 * WINSPOOL_EnumPrinterDrivers [internal]
2672 * Delivers information about all printer drivers installed on the
2673 * localhost or a given server
2675 * RETURNS
2676 * nonzero on success or zero on failure. If the buffer for the returned
2677 * information is too small the function will return an error
2679 * BUGS
2680 * - only implemented for localhost, foreign hosts will return an error
2682 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2683 DWORD Level, LPBYTE pDriverInfo,
2684 DWORD cbBuf, LPDWORD pcbNeeded,
2685 LPDWORD pcReturned, BOOL unicode)
2687 { HKEY hkeyDrivers;
2688 DWORD i, needed, number = 0, size = 0;
2689 WCHAR DriverNameW[255];
2690 PBYTE ptr;
2692 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2693 debugstr_w(pName), debugstr_w(pEnvironment),
2694 Level, pDriverInfo, cbBuf, unicode);
2696 /* check for local drivers */
2697 if(pName) {
2698 ERR("remote drivers unsupported! Current remote host is %s\n",
2699 debugstr_w(pName));
2700 return FALSE;
2703 /* check input parameter */
2704 if((Level < 1) || (Level > 3)) {
2705 ERR("unsupported level %ld \n", Level);
2706 return FALSE;
2709 /* initialize return values */
2710 if(pDriverInfo)
2711 memset( pDriverInfo, 0, cbBuf);
2712 *pcbNeeded = 0;
2713 *pcReturned = 0;
2715 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2716 if(!hkeyDrivers) {
2717 ERR("Can't open Drivers key\n");
2718 return FALSE;
2721 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2722 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2723 RegCloseKey(hkeyDrivers);
2724 ERR("Can't query Drivers key\n");
2725 return FALSE;
2727 TRACE("Found %ld Drivers\n", number);
2729 /* get size of single struct
2730 * unicode and ascii structure have the same size
2732 switch (Level) {
2733 case 1:
2734 size = sizeof(DRIVER_INFO_1A);
2735 break;
2736 case 2:
2737 size = sizeof(DRIVER_INFO_2A);
2738 break;
2739 case 3:
2740 size = sizeof(DRIVER_INFO_3A);
2741 break;
2744 /* calculate required buffer size */
2745 *pcbNeeded = size * number;
2747 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2748 i < number;
2749 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2750 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2751 != ERROR_SUCCESS) {
2752 ERR("Can't enum key number %ld\n", i);
2753 RegCloseKey(hkeyDrivers);
2754 return FALSE;
2756 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2757 pEnvironment, Level, ptr,
2758 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2759 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2760 &needed, unicode)) {
2761 RegCloseKey(hkeyDrivers);
2762 return FALSE;
2764 (*pcbNeeded) += needed;
2767 RegCloseKey(hkeyDrivers);
2769 if(cbBuf < *pcbNeeded){
2770 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2771 return FALSE;
2774 return TRUE;
2777 /*****************************************************************************
2778 * EnumPrinterDriversW [WINSPOOL.@]
2780 * see function EnumPrinterDrivers for RETURNS, BUGS
2782 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2783 LPBYTE pDriverInfo, DWORD cbBuf,
2784 LPDWORD pcbNeeded, LPDWORD pcReturned)
2786 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2787 cbBuf, pcbNeeded, pcReturned, TRUE);
2790 /*****************************************************************************
2791 * EnumPrinterDriversA [WINSPOOL.@]
2793 * see function EnumPrinterDrivers for RETURNS, BUGS
2795 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2796 LPBYTE pDriverInfo, DWORD cbBuf,
2797 LPDWORD pcbNeeded, LPDWORD pcReturned)
2798 { BOOL ret;
2799 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2801 if(pName)
2802 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2803 if(pEnvironment)
2804 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2806 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2807 cbBuf, pcbNeeded, pcReturned, FALSE);
2808 if(pNameW)
2809 HeapFree(GetProcessHeap(), 0, pNameW);
2810 if(pEnvironmentW)
2811 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2813 return ret;
2817 /******************************************************************************
2818 * EnumPortsA (WINSPOOL.@)
2820 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2821 LPDWORD bufneeded,LPDWORD bufreturned)
2823 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2824 return FALSE;
2827 /******************************************************************************
2828 * GetDefaultPrinterA (WINSPOOL.@)
2830 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2832 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
2834 char *ptr;
2836 if (*namesize < 1)
2838 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2839 return FALSE;
2842 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
2844 SetLastError (ERROR_FILE_NOT_FOUND);
2845 return FALSE;
2848 if ((ptr = strchr (name, ',')) == NULL)
2850 SetLastError (ERROR_FILE_NOT_FOUND);
2851 return FALSE;
2854 *ptr = '\0';
2855 *namesize = strlen (name) + 1;
2856 return TRUE;
2860 /******************************************************************************
2861 * GetDefaultPrinterW (WINSPOOL.@)
2863 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
2865 char *buf;
2866 BOOL ret;
2868 if (*namesize < 1)
2870 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2871 return FALSE;
2874 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
2875 ret = GetDefaultPrinterA (buf, namesize);
2876 if (ret)
2878 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
2879 if (!len)
2881 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2882 ret = FALSE;
2884 else *namesize = len;
2887 HeapFree (GetProcessHeap (), 0, buf);
2888 return ret;
2892 /******************************************************************************
2893 * SetPrinterDataExA (WINSPOOL.@)
2895 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2896 LPSTR pValueName, DWORD Type,
2897 LPBYTE pData, DWORD cbData)
2899 HKEY hkeyPrinter, hkeySubkey;
2900 DWORD ret;
2902 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2903 debugstr_a(pValueName), Type, pData, cbData);
2905 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2906 != ERROR_SUCCESS)
2907 return ret;
2909 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2910 != ERROR_SUCCESS) {
2911 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2912 RegCloseKey(hkeyPrinter);
2913 return ret;
2915 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2916 RegCloseKey(hkeySubkey);
2917 RegCloseKey(hkeyPrinter);
2918 return ret;
2921 /******************************************************************************
2922 * SetPrinterDataExW (WINSPOOL.@)
2924 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2925 LPWSTR pValueName, DWORD Type,
2926 LPBYTE pData, DWORD cbData)
2928 HKEY hkeyPrinter, hkeySubkey;
2929 DWORD ret;
2931 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2932 debugstr_w(pValueName), Type, pData, cbData);
2934 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2935 != ERROR_SUCCESS)
2936 return ret;
2938 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2939 != ERROR_SUCCESS) {
2940 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2941 RegCloseKey(hkeyPrinter);
2942 return ret;
2944 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2945 RegCloseKey(hkeySubkey);
2946 RegCloseKey(hkeyPrinter);
2947 return ret;
2950 /******************************************************************************
2951 * SetPrinterDataA (WINSPOOL.@)
2953 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2954 LPBYTE pData, DWORD cbData)
2956 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2957 pData, cbData);
2960 /******************************************************************************
2961 * SetPrinterDataW (WINSPOOL.@)
2963 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2964 LPBYTE pData, DWORD cbData)
2966 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2967 pData, cbData);
2970 /******************************************************************************
2971 * GetPrinterDataExA (WINSPOOL.@)
2973 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2974 LPSTR pValueName, LPDWORD pType,
2975 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2977 HKEY hkeyPrinter, hkeySubkey;
2978 DWORD ret;
2980 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2981 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2982 pcbNeeded);
2984 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2985 != ERROR_SUCCESS)
2986 return ret;
2988 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2989 != ERROR_SUCCESS) {
2990 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2991 RegCloseKey(hkeyPrinter);
2992 return ret;
2994 *pcbNeeded = nSize;
2995 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2996 RegCloseKey(hkeySubkey);
2997 RegCloseKey(hkeyPrinter);
2998 return ret;
3001 /******************************************************************************
3002 * GetPrinterDataExW (WINSPOOL.@)
3004 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
3005 LPWSTR pValueName, LPDWORD pType,
3006 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3008 HKEY hkeyPrinter, hkeySubkey;
3009 DWORD ret;
3011 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3012 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3013 pcbNeeded);
3015 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3016 != ERROR_SUCCESS)
3017 return ret;
3019 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3020 != ERROR_SUCCESS) {
3021 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3022 RegCloseKey(hkeyPrinter);
3023 return ret;
3025 *pcbNeeded = nSize;
3026 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3027 RegCloseKey(hkeySubkey);
3028 RegCloseKey(hkeyPrinter);
3029 return ret;
3032 /******************************************************************************
3033 * GetPrinterDataA (WINSPOOL.@)
3035 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3036 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3038 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3039 pData, nSize, pcbNeeded);
3042 /******************************************************************************
3043 * GetPrinterDataW (WINSPOOL.@)
3045 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3046 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3048 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3049 pData, nSize, pcbNeeded);
3052 /*******************************************************************************
3053 * EnumPrinterDataExW [WINSPOOL.@]
3055 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3056 LPBYTE pEnumValues, DWORD cbEnumValues,
3057 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3059 HKEY hkPrinter, hkSubKey;
3060 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3061 cbValueNameLen, cbMaxValueLen, cbValueLen,
3062 cbBufSize, dwType;
3063 LPWSTR lpValueName;
3064 HANDLE hHeap;
3065 PBYTE lpValue;
3066 PPRINTER_ENUM_VALUESW ppev;
3068 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3070 if (pKeyName == NULL || *pKeyName == 0)
3071 return ERROR_INVALID_PARAMETER;
3073 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3074 if (ret != ERROR_SUCCESS)
3076 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3077 hPrinter, ret);
3078 return ret;
3081 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3082 if (ret != ERROR_SUCCESS)
3084 r = RegCloseKey (hkPrinter);
3085 if (r != ERROR_SUCCESS)
3086 WARN ("RegCloseKey returned %li\n", r);
3087 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3088 debugstr_w (pKeyName), ret);
3089 return ret;
3092 ret = RegCloseKey (hkPrinter);
3093 if (ret != ERROR_SUCCESS)
3095 ERR ("RegCloseKey returned %li\n", ret);
3096 r = RegCloseKey (hkSubKey);
3097 if (r != ERROR_SUCCESS)
3098 WARN ("RegCloseKey returned %li\n", r);
3099 return ret;
3102 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3103 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3104 if (ret != ERROR_SUCCESS)
3106 r = RegCloseKey (hkSubKey);
3107 if (r != ERROR_SUCCESS)
3108 WARN ("RegCloseKey returned %li\n", r);
3109 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3110 return ret;
3113 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3114 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3116 if (cValues == 0) /* empty key */
3118 r = RegCloseKey (hkSubKey);
3119 if (r != ERROR_SUCCESS)
3120 WARN ("RegCloseKey returned %li\n", r);
3121 *pcbEnumValues = *pnEnumValues = 0;
3122 return ERROR_SUCCESS;
3125 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3127 hHeap = GetProcessHeap ();
3128 if (hHeap == (HANDLE) NULL)
3130 ERR ("GetProcessHeap failed\n");
3131 r = RegCloseKey (hkSubKey);
3132 if (r != ERROR_SUCCESS)
3133 WARN ("RegCloseKey returned %li\n", r);
3134 return ERROR_OUTOFMEMORY;
3137 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3138 if (lpValueName == NULL)
3140 ERR ("Failed to allocate %li bytes from process heap\n",
3141 cbMaxValueNameLen * sizeof (WCHAR));
3142 r = RegCloseKey (hkSubKey);
3143 if (r != ERROR_SUCCESS)
3144 WARN ("RegCloseKey returned %li\n", r);
3145 return ERROR_OUTOFMEMORY;
3148 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3149 if (lpValue == NULL)
3151 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3152 if (HeapFree (hHeap, 0, lpValueName) == 0)
3153 WARN ("HeapFree failed with code %li\n", GetLastError ());
3154 r = RegCloseKey (hkSubKey);
3155 if (r != ERROR_SUCCESS)
3156 WARN ("RegCloseKey returned %li\n", r);
3157 return ERROR_OUTOFMEMORY;
3160 TRACE ("pass 1: calculating buffer required for all names and values\n");
3162 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3164 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3166 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3168 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3169 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3170 NULL, NULL, lpValue, &cbValueLen);
3171 if (ret != ERROR_SUCCESS)
3173 if (HeapFree (hHeap, 0, lpValue) == 0)
3174 WARN ("HeapFree failed with code %li\n", GetLastError ());
3175 if (HeapFree (hHeap, 0, lpValueName) == 0)
3176 WARN ("HeapFree failed with code %li\n", GetLastError ());
3177 r = RegCloseKey (hkSubKey);
3178 if (r != ERROR_SUCCESS)
3179 WARN ("RegCloseKey returned %li\n", r);
3180 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3181 return ret;
3184 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3185 debugstr_w (lpValueName), dwIndex,
3186 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3188 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3189 cbBufSize += cbValueLen;
3192 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3194 *pcbEnumValues = cbBufSize;
3195 *pnEnumValues = cValues;
3197 if (cbEnumValues < cbBufSize) /* buffer too small */
3199 if (HeapFree (hHeap, 0, lpValue) == 0)
3200 WARN ("HeapFree failed with code %li\n", GetLastError ());
3201 if (HeapFree (hHeap, 0, lpValueName) == 0)
3202 WARN ("HeapFree failed with code %li\n", GetLastError ());
3203 r = RegCloseKey (hkSubKey);
3204 if (r != ERROR_SUCCESS)
3205 WARN ("RegCloseKey returned %li\n", r);
3206 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3207 return ERROR_MORE_DATA;
3210 TRACE ("pass 2: copying all names and values to buffer\n");
3212 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3213 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3215 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3217 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3218 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3219 NULL, &dwType, lpValue, &cbValueLen);
3220 if (ret != ERROR_SUCCESS)
3222 if (HeapFree (hHeap, 0, lpValue) == 0)
3223 WARN ("HeapFree failed with code %li\n", GetLastError ());
3224 if (HeapFree (hHeap, 0, lpValueName) == 0)
3225 WARN ("HeapFree failed with code %li\n", GetLastError ());
3226 r = RegCloseKey (hkSubKey);
3227 if (r != ERROR_SUCCESS)
3228 WARN ("RegCloseKey returned %li\n", r);
3229 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3230 return ret;
3233 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3234 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3235 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3236 pEnumValues += cbValueNameLen;
3238 /* return # of *bytes* (including trailing \0), not # of chars */
3239 ppev[dwIndex].cbValueName = cbValueNameLen;
3241 ppev[dwIndex].dwType = dwType;
3243 memcpy (pEnumValues, lpValue, cbValueLen);
3244 ppev[dwIndex].pData = pEnumValues;
3245 pEnumValues += cbValueLen;
3247 ppev[dwIndex].cbData = cbValueLen;
3249 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3250 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3253 if (HeapFree (hHeap, 0, lpValue) == 0)
3255 ret = GetLastError ();
3256 ERR ("HeapFree failed with code %li\n", ret);
3257 if (HeapFree (hHeap, 0, lpValueName) == 0)
3258 WARN ("HeapFree failed with code %li\n", GetLastError ());
3259 r = RegCloseKey (hkSubKey);
3260 if (r != ERROR_SUCCESS)
3261 WARN ("RegCloseKey returned %li\n", r);
3262 return ret;
3265 if (HeapFree (hHeap, 0, lpValueName) == 0)
3267 ret = GetLastError ();
3268 ERR ("HeapFree failed with code %li\n", ret);
3269 r = RegCloseKey (hkSubKey);
3270 if (r != ERROR_SUCCESS)
3271 WARN ("RegCloseKey returned %li\n", r);
3272 return ret;
3275 ret = RegCloseKey (hkSubKey);
3276 if (ret != ERROR_SUCCESS)
3278 ERR ("RegCloseKey returned %li\n", ret);
3279 return ret;
3282 return ERROR_SUCCESS;
3285 /*******************************************************************************
3286 * EnumPrinterDataExA [WINSPOOL.@]
3288 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3289 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3290 * what Windows 2000 SP1 does.
3293 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3294 LPBYTE pEnumValues, DWORD cbEnumValues,
3295 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3297 INT len;
3298 LPWSTR pKeyNameW;
3299 DWORD ret, dwIndex, dwBufSize;
3300 HANDLE hHeap;
3301 LPSTR pBuffer;
3303 TRACE ("%p %s\n", hPrinter, pKeyName);
3305 if (pKeyName == NULL || *pKeyName == 0)
3306 return ERROR_INVALID_PARAMETER;
3308 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3309 if (len == 0)
3311 ret = GetLastError ();
3312 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3313 return ret;
3316 hHeap = GetProcessHeap ();
3317 if (hHeap == (HANDLE) NULL)
3319 ERR ("GetProcessHeap failed\n");
3320 return ERROR_OUTOFMEMORY;
3323 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3324 if (pKeyNameW == NULL)
3326 ERR ("Failed to allocate %li bytes from process heap\n",
3327 (LONG) len * sizeof (WCHAR));
3328 return ERROR_OUTOFMEMORY;
3331 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3333 ret = GetLastError ();
3334 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3335 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3336 WARN ("HeapFree failed with code %li\n", GetLastError ());
3337 return ret;
3340 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3341 pcbEnumValues, pnEnumValues);
3342 if (ret != ERROR_SUCCESS)
3344 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3345 WARN ("HeapFree failed with code %li\n", GetLastError ());
3346 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3347 return ret;
3350 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3352 ret = GetLastError ();
3353 ERR ("HeapFree failed with code %li\n", ret);
3354 return ret;
3357 if (*pnEnumValues == 0) /* empty key */
3358 return ERROR_SUCCESS;
3360 dwBufSize = 0;
3361 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3363 PPRINTER_ENUM_VALUESW ppev =
3364 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3366 if (dwBufSize < ppev->cbValueName)
3367 dwBufSize = ppev->cbValueName;
3369 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3370 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3371 dwBufSize = ppev->cbData;
3374 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3376 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3377 if (pBuffer == NULL)
3379 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3380 return ERROR_OUTOFMEMORY;
3383 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3385 PPRINTER_ENUM_VALUESW ppev =
3386 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3388 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3389 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3390 NULL);
3391 if (len == 0)
3393 ret = GetLastError ();
3394 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3395 if (HeapFree (hHeap, 0, pBuffer) == 0)
3396 WARN ("HeapFree failed with code %li\n", GetLastError ());
3397 return ret;
3400 memcpy (ppev->pValueName, pBuffer, len);
3402 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3404 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3405 ppev->dwType != REG_MULTI_SZ)
3406 continue;
3408 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3409 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3410 if (len == 0)
3412 ret = GetLastError ();
3413 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3414 if (HeapFree (hHeap, 0, pBuffer) == 0)
3415 WARN ("HeapFree failed with code %li\n", GetLastError ());
3416 return ret;
3419 memcpy (ppev->pData, pBuffer, len);
3421 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3422 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3425 if (HeapFree (hHeap, 0, pBuffer) == 0)
3427 ret = GetLastError ();
3428 ERR ("HeapFree failed with code %li\n", ret);
3429 return ret;
3432 return ERROR_SUCCESS;