Do not pass unnecessary flags to wrc in generated makefiles.
[wine/multimedia.git] / dlls / winspool / info.c
blob0a647c5b7f13a4de2582031ad00842e8bc241d68
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 SONAME_LIBCUPS
36 # define SONAME_LIBCUPS "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);
108 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
109 if passed a NULL string. This returns NULLs to the result.
111 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
113 if ( (src) )
115 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
116 return usBufferPtr->Buffer;
118 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
119 return NULL;
122 static void
123 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
124 char qbuf[200];
126 /* If forcing, or no profile string entry for device yet, set the entry
128 * The always change entry if not WINEPS yet is discussable.
130 if (force ||
131 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
132 !strcmp(qbuf,"*") ||
133 !strstr(qbuf,"WINEPS")
135 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
137 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
138 WriteProfileStringA("windows","device",buf);
139 HeapFree(GetProcessHeap(),0,buf);
143 #ifdef HAVE_CUPS_CUPS_H
144 BOOL
145 CUPS_LoadPrinters(void) {
146 typeof(cupsGetPrinters) *pcupsGetPrinters = NULL;
147 typeof(cupsGetDefault) *pcupsGetDefault = NULL;
148 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
149 char **printers;
150 int i,nrofdests,hadprinter = FALSE;
151 PRINTER_INFO_2A pinfo2a;
152 const char* def;
153 void *cupshandle = NULL;
154 const char *ppd;
155 char *port,*devline;
156 UNICODE_STRING lpszNameW;
157 PWSTR pwstrNameW;
158 HKEY hkeyPrinters, hkeyPrinter;
160 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
161 if (!cupshandle)
162 return FALSE;
164 #define DYNCUPS(x) \
165 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
166 if (!p##x) return FALSE;
168 DYNCUPS(cupsGetDefault);
169 DYNCUPS(cupsGetPPD);
170 DYNCUPS(cupsGetPrinters);
171 #undef DYNCUPS
173 def = pcupsGetDefault();
175 if (def && !strcmp(def,"none")) /* CUPS has "none" for no default printer */
176 def = NULL;
178 nrofdests = pcupsGetPrinters(&printers);
179 for (i=0;i<nrofdests;i++) {
180 /* First check that the printer doesn't exist already */
181 pwstrNameW = asciitounicode(&lpszNameW, printers[i]);
182 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) ==
183 ERROR_SUCCESS) {
184 if (RegOpenKeyW(hkeyPrinters, pwstrNameW, &hkeyPrinter) ==
185 ERROR_SUCCESS) {
186 /* We know this printer already */
187 RegCloseKey(hkeyPrinter);
188 RegCloseKey(hkeyPrinters);
189 RtlFreeUnicodeString(&lpszNameW);
190 TRACE("Printer %s already known. Skipping detection\n", printers[i]);
191 continue;
193 RegCloseKey(hkeyPrinters);
195 RtlFreeUnicodeString(&lpszNameW);
197 /* OK, we haven't seen this one yet. Request PPD for it */
198 ppd = pcupsGetPPD(printers[i]);
199 if (!ppd) {
200 WARN("No ppd file for %s.\n",printers[i]);
201 /* If this was going to be the default printer,
202 * forget it and use another one.
204 if (def && !strcmp(def,printers[i]))
205 def = NULL;
206 continue;
208 unlink(ppd);
210 hadprinter = TRUE;
212 if (def && !strcmp(def,printers[i]))
213 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
215 /* The default printer has no PPD file, just use the first one
216 * which has one.
218 if (!def) {
219 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
220 def = printers[i];
222 memset(&pinfo2a,0,sizeof(pinfo2a));
223 pinfo2a.pPrinterName = printers[i];
224 pinfo2a.pDatatype = "RAW";
225 pinfo2a.pPrintProcessor = "WinPrint";
226 pinfo2a.pDriverName = "PS Driver";
227 pinfo2a.pComment = "WINEPS Printer using CUPS";
228 pinfo2a.pLocation = "<physical location of printer>";
229 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
230 sprintf(port,"LPR:%s",printers[i]);
231 pinfo2a.pPortName = port;
232 pinfo2a.pParameters = "<parameters?>";
233 pinfo2a.pShareName = "<share name?>";
234 pinfo2a.pSepFile = "<sep file?>";
236 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
237 sprintf(devline,"WINEPS,%s",port);
238 WriteProfileStringA("devices",printers[i],devline);
239 HeapFree(GetProcessHeap(),0,devline);
241 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
242 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
243 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
245 HeapFree(GetProcessHeap(),0,port);
247 wine_dlclose(cupshandle, NULL, 0);
248 return hadprinter;
250 #endif
252 static BOOL
253 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
254 PRINTER_INFO_2A pinfo2a;
255 char *s,*name,*prettyname,*devname;
256 BOOL isps = FALSE;
257 char *port,*devline;
259 while (isspace(*pent)) pent++;
260 s = strchr(pent,':');
261 if (!s) return FALSE;
262 *s='\0';
263 name = pent;
264 pent = s+1;
265 TRACE("%s\n",name);
267 /* Determine whether this is a postscript printer. */
269 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
270 if (strstr(name,"ps") ||
271 strstr(name,"pd") || /* postscript double page */
272 strstr(name,"postscript") ||
273 strstr(name,"PostScript")
275 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
276 isps = TRUE;
278 /* 2. Check if this is a remote printer. These usually are postscript
279 * capable
281 if (strstr(pent,":rm")) {
282 isps = TRUE;
283 TRACE("%s is remote, assuming postscript.\n",name);
285 /* 3. Check if we have an input filter program. If we have one, it
286 * most likely is one capable of converting postscript.
287 * (Could probably check for occurrence of 'gs' or 'ghostscript'
288 * in the if file itself.)
290 if (strstr(pent,":if=/")) {
291 isps = TRUE;
292 TRACE("%s has inputfilter program, assuming postscript.\n",name);
295 /* If it is not a postscript printer, we cannot use it. */
296 if (!isps)
297 return FALSE;
299 prettyname = name;
300 /* Get longest name, usually the one at the right for later display. */
301 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
302 s=strchr(name,'|');if (s) *s='\0';
304 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
305 * if it is too long, we use it as comment below. */
306 devname = prettyname;
307 if (strlen(devname)>=CCHDEVICENAME-1)
308 devname = name;
309 if (strlen(devname)>=CCHDEVICENAME-1)
310 return FALSE;
312 if (isfirst) /* set first entry as default */
313 WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
315 memset(&pinfo2a,0,sizeof(pinfo2a));
316 pinfo2a.pPrinterName = devname;
317 pinfo2a.pDatatype = "RAW";
318 pinfo2a.pPrintProcessor = "WinPrint";
319 pinfo2a.pDriverName = "PS Driver";
320 pinfo2a.pComment = "WINEPS Printer using LPR";
321 pinfo2a.pLocation = prettyname;
322 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
323 sprintf(port,"LPR:%s",name);
324 pinfo2a.pPortName = port;
325 pinfo2a.pParameters = "<parameters?>";
326 pinfo2a.pShareName = "<share name?>";
327 pinfo2a.pSepFile = "<sep file?>";
329 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
330 sprintf(devline,"WINEPS,%s",port);
331 WriteProfileStringA("devices",devname,devline);
332 HeapFree(GetProcessHeap(),0,devline);
334 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
335 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
336 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
338 HeapFree(GetProcessHeap(),0,port);
339 return TRUE;
342 static BOOL
343 PRINTCAP_LoadPrinters(void) {
344 BOOL hadprinter = FALSE, isfirst = TRUE;
345 char buf[200];
346 FILE *f;
348 f = fopen("/etc/printcap","r");
349 if (!f)
350 return FALSE;
352 while (fgets(buf,sizeof(buf),f)) {
353 char *pent = NULL;
354 do {
355 char *s;
356 s=strchr(buf,'\n'); if (s) *s='\0';
357 if ((buf[0]=='#') || (buf[0]=='\0'))
358 continue;
360 if (pent) {
361 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
362 strcat(pent,buf);
363 } else {
364 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
365 strcpy(pent,buf);
368 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
369 pent[strlen(pent)-1] = '\0';
370 else
371 break;
372 } while (fgets(buf,sizeof(buf),f));
373 if (pent)
374 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
375 isfirst = FALSE;
376 if (pent) HeapFree(GetProcessHeap(),0,pent);
377 pent = NULL;
378 if (feof(f)) break;
380 fclose(f);
381 return hadprinter;
384 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
386 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
387 lstrlenW(value) * sizeof(WCHAR));
390 void
391 WINSPOOL_LoadSystemPrinters() {
392 HKEY hkPPD;
393 DRIVER_INFO_3A di3a;
394 di3a.cVersion = 0x400;
395 di3a.pName = "PS Driver";
396 di3a.pEnvironment = NULL; /* NULL means auto */
397 di3a.pDriverPath = "wineps16";
398 di3a.pDataFile = "<datafile?>";
399 di3a.pConfigFile = "wineps16";
400 di3a.pHelpFile = "<helpfile?>";
401 di3a.pDependentFiles = "<dependend files?>";
402 di3a.pMonitorName = "<monitor name?>";
403 di3a.pDefaultDataType = "RAW";
405 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
406 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
407 return;
409 #ifdef HAVE_CUPS_CUPS_H
410 /* If we have any CUPS based printers, skip looking for printcap printers */
411 if (CUPS_LoadPrinters())
412 return;
413 #endif
415 /* Check for [ppd] section in config file before parsing /etc/printcap */
417 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
418 &hkPPD) == ERROR_SUCCESS)
420 RegCloseKey(hkPPD);
421 PRINTCAP_LoadPrinters();
426 /******************************************************************
427 * WINSPOOL_GetOpenedPrinterEntry
428 * Get the first place empty in the opened printer table
430 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
432 int i;
434 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
436 if (i >= nb_printers)
438 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
439 (nb_printers + 16) * sizeof(*new_array) );
440 if (!new_array) return 0;
441 printer_array = new_array;
442 nb_printers += 16;
445 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
447 strcpyW( printer_array[i], name );
448 return (HANDLE)(i + 1);
450 return 0;
453 /******************************************************************
454 * WINSPOOL_GetOpenedPrinter
455 * Get the pointer to the opened printer referred by the handle
457 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
459 int idx = (int)printerHandle;
460 if ((idx <= 0) || (idx > nb_printers))
462 SetLastError(ERROR_INVALID_HANDLE);
463 return NULL;
465 return printer_array[idx - 1];
468 /******************************************************************
469 * WINSPOOL_GetOpenedPrinterRegKey
472 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
474 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
475 DWORD ret;
476 HKEY hkeyPrinters;
478 if(!name) return ERROR_INVALID_HANDLE;
480 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
481 ERROR_SUCCESS)
482 return ret;
484 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
486 ERR("Can't find opened printer %s in registry\n",
487 debugstr_w(name));
488 RegCloseKey(hkeyPrinters);
489 return ERROR_INVALID_PRINTER_NAME; /* ? */
491 RegCloseKey(hkeyPrinters);
492 return ERROR_SUCCESS;
495 /***********************************************************
496 * DEVMODEcpyAtoW
498 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
500 BOOL Formname;
501 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
502 DWORD size;
504 Formname = (dmA->dmSize > off_formname);
505 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
506 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
507 CCHDEVICENAME);
508 if(!Formname) {
509 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
510 dmA->dmSize - CCHDEVICENAME);
511 } else {
512 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
513 off_formname - CCHDEVICENAME);
514 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
515 CCHFORMNAME);
516 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
517 (off_formname + CCHFORMNAME));
519 dmW->dmSize = size;
520 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
521 dmA->dmDriverExtra);
522 return dmW;
525 /***********************************************************
526 * DEVMODEdupAtoW
527 * Creates a unicode copy of supplied devmode on heap
529 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
531 LPDEVMODEW dmW;
532 DWORD size;
533 BOOL Formname;
534 ptrdiff_t off_formname;
536 TRACE("\n");
537 if(!dmA) return NULL;
539 off_formname = (char *)dmA->dmFormName - (char *)dmA;
540 Formname = (dmA->dmSize > off_formname);
541 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
542 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
543 return DEVMODEcpyAtoW(dmW, dmA);
546 /***********************************************************
547 * DEVMODEdupWtoA
548 * Creates an ascii copy of supplied devmode on heap
550 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
552 LPDEVMODEA dmA;
553 DWORD size;
554 BOOL Formname;
555 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
557 if(!dmW) return NULL;
558 Formname = (dmW->dmSize > off_formname);
559 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
560 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
561 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
562 CCHDEVICENAME, NULL, NULL);
563 if(!Formname) {
564 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
565 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
566 } else {
567 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
568 off_formname - CCHDEVICENAME * sizeof(WCHAR));
569 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
570 CCHFORMNAME, NULL, NULL);
571 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
572 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
574 dmA->dmSize = size;
575 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
576 dmW->dmDriverExtra);
577 return dmA;
580 /***********************************************************
581 * PRINTER_INFO_2AtoW
582 * Creates a unicode copy of PRINTER_INFO_2A on heap
584 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
586 LPPRINTER_INFO_2W piW;
587 UNICODE_STRING usBuffer;
589 if(!piA) return NULL;
590 piW = HeapAlloc(heap, 0, sizeof(*piW));
591 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
593 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
594 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
595 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
596 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
597 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
598 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
599 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
600 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
601 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
602 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
603 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
604 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
605 return piW;
608 /***********************************************************
609 * FREE_PRINTER_INFO_2W
610 * Free PRINTER_INFO_2W and all strings
612 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
614 if(!piW) return;
616 HeapFree(heap,0,piW->pServerName);
617 HeapFree(heap,0,piW->pPrinterName);
618 HeapFree(heap,0,piW->pShareName);
619 HeapFree(heap,0,piW->pPortName);
620 HeapFree(heap,0,piW->pDriverName);
621 HeapFree(heap,0,piW->pComment);
622 HeapFree(heap,0,piW->pLocation);
623 HeapFree(heap,0,piW->pDevMode);
624 HeapFree(heap,0,piW->pSepFile);
625 HeapFree(heap,0,piW->pPrintProcessor);
626 HeapFree(heap,0,piW->pDatatype);
627 HeapFree(heap,0,piW->pParameters);
628 HeapFree(heap,0,piW);
629 return;
632 /******************************************************************
633 * DeviceCapabilities [WINSPOOL.@]
634 * DeviceCapabilitiesA [WINSPOOL.@]
637 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
638 LPSTR pOutput, LPDEVMODEA lpdm)
640 INT ret;
642 if (!GDI_CallDeviceCapabilities16)
644 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
645 (LPCSTR)104 );
646 if (!GDI_CallDeviceCapabilities16) return -1;
648 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
650 /* If DC_PAPERSIZE map POINT16s to POINTs */
651 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
652 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
653 POINT *pt = (POINT *)pOutput;
654 INT i;
655 memcpy(tmp, pOutput, ret * sizeof(POINT16));
656 for(i = 0; i < ret; i++, pt++)
658 pt->x = tmp[i].x;
659 pt->y = tmp[i].y;
661 HeapFree( GetProcessHeap(), 0, tmp );
663 return ret;
667 /*****************************************************************************
668 * DeviceCapabilitiesW [WINSPOOL.@]
670 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
673 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
674 WORD fwCapability, LPWSTR pOutput,
675 const DEVMODEW *pDevMode)
677 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
678 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
679 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
680 INT ret;
682 if(pOutput && (fwCapability == DC_BINNAMES ||
683 fwCapability == DC_FILEDEPENDENCIES ||
684 fwCapability == DC_PAPERNAMES)) {
685 /* These need A -> W translation */
686 INT size = 0, i;
687 LPSTR pOutputA;
688 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
689 dmA);
690 if(ret == -1)
691 return ret;
692 switch(fwCapability) {
693 case DC_BINNAMES:
694 size = 24;
695 break;
696 case DC_PAPERNAMES:
697 case DC_FILEDEPENDENCIES:
698 size = 64;
699 break;
701 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
702 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
703 dmA);
704 for(i = 0; i < ret; i++)
705 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
706 pOutput + (i * size), size);
707 HeapFree(GetProcessHeap(), 0, pOutputA);
708 } else {
709 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
710 (LPSTR)pOutput, dmA);
712 HeapFree(GetProcessHeap(),0,pPortA);
713 HeapFree(GetProcessHeap(),0,pDeviceA);
714 HeapFree(GetProcessHeap(),0,dmA);
715 return ret;
718 /******************************************************************
719 * DocumentPropertiesA [WINSPOOL.@]
722 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
723 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
724 LPDEVMODEA pDevModeInput,DWORD fMode )
726 LPSTR lpName = pDeviceName;
727 LONG ret;
729 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
730 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
733 if(!pDeviceName) {
734 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
735 if(!lpNameW) {
736 ERR("no name from hPrinter?\n");
737 return -1;
739 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
742 if (!GDI_CallExtDeviceMode16)
744 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
745 (LPCSTR)102 );
746 if (!GDI_CallExtDeviceMode16) {
747 ERR("No CallExtDeviceMode16?\n");
748 return -1;
751 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
752 pDevModeInput, NULL, fMode);
754 if(!pDeviceName)
755 HeapFree(GetProcessHeap(),0,lpName);
756 return ret;
760 /*****************************************************************************
761 * DocumentPropertiesW (WINSPOOL.@)
763 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
764 LPWSTR pDeviceName,
765 LPDEVMODEW pDevModeOutput,
766 LPDEVMODEW pDevModeInput, DWORD fMode)
769 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
770 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
771 LPDEVMODEA pDevModeOutputA = NULL;
772 LONG ret;
774 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
775 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
776 fMode);
777 if(pDevModeOutput) {
778 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
779 if(ret < 0) return ret;
780 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
782 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
783 pDevModeInputA, fMode);
784 if(pDevModeOutput) {
785 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
786 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
788 if(fMode == 0 && ret > 0)
789 ret += (CCHDEVICENAME + CCHFORMNAME);
790 HeapFree(GetProcessHeap(),0,pDevModeInputA);
791 HeapFree(GetProcessHeap(),0,pDeviceNameA);
792 return ret;
795 /******************************************************************
796 * OpenPrinterA [WINSPOOL.@]
799 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
800 LPPRINTER_DEFAULTSA pDefault)
802 UNICODE_STRING lpPrinterNameW;
803 UNICODE_STRING usBuffer;
804 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
805 PWSTR pwstrPrinterNameW;
806 BOOL ret;
808 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
810 if(pDefault) {
811 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
812 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
813 pDefault->pDevMode);
814 DefaultW.DesiredAccess = pDefault->DesiredAccess;
815 pDefaultW = &DefaultW;
817 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
818 if(pDefault) {
819 RtlFreeUnicodeString(&usBuffer);
820 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
822 RtlFreeUnicodeString(&lpPrinterNameW);
823 return ret;
826 /******************************************************************
827 * OpenPrinterW [WINSPOOL.@]
830 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
831 LPPRINTER_DEFAULTSW pDefault)
833 HKEY hkeyPrinters, hkeyPrinter;
835 if (!lpPrinterName) {
836 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
837 SetLastError(ERROR_INVALID_PARAMETER);
838 return FALSE;
841 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
842 pDefault);
844 /* Check Printer exists */
845 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
846 ERROR_SUCCESS) {
847 ERR("Can't create Printers key\n");
848 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
849 return FALSE;
852 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
853 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
854 != ERROR_SUCCESS) {
855 TRACE("Can't find printer %s in registry\n",
856 debugstr_w(lpPrinterName));
857 RegCloseKey(hkeyPrinters);
858 SetLastError(ERROR_INVALID_PRINTER_NAME);
859 return FALSE;
861 RegCloseKey(hkeyPrinter);
862 RegCloseKey(hkeyPrinters);
864 if(!phPrinter) /* This seems to be what win95 does anyway */
865 return TRUE;
867 /* Get the unique handle of the printer*/
868 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
870 if (pDefault != NULL)
871 FIXME("Not handling pDefault\n");
873 return TRUE;
876 /******************************************************************
877 * AddMonitorA [WINSPOOL.@]
880 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
882 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
883 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
884 return FALSE;
887 /******************************************************************
888 * DeletePrinterDriverA [WINSPOOL.@]
891 BOOL WINAPI
892 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
894 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
895 debugstr_a(pDriverName));
896 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
897 return FALSE;
901 /******************************************************************
902 * DeleteMonitorA [WINSPOOL.@]
905 BOOL WINAPI
906 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
908 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
909 debugstr_a(pMonitorName));
910 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
911 return FALSE;
915 /******************************************************************
916 * DeletePortA [WINSPOOL.@]
919 BOOL WINAPI
920 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
922 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
923 debugstr_a(pPortName));
924 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
925 return FALSE;
928 /******************************************************************************
929 * SetPrinterW [WINSPOOL.@]
931 BOOL WINAPI
932 SetPrinterW(
933 HANDLE hPrinter,
934 DWORD Level,
935 LPBYTE pPrinter,
936 DWORD Command) {
938 FIXME("():stub\n");
939 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
940 return FALSE;
943 /******************************************************************************
944 * WritePrinter [WINSPOOL.@]
946 BOOL WINAPI
947 WritePrinter(
948 HANDLE hPrinter,
949 LPVOID pBuf,
950 DWORD cbBuf,
951 LPDWORD pcWritten) {
953 FIXME("():stub\n");
954 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
955 return FALSE;
958 /*****************************************************************************
959 * AddFormA [WINSPOOL.@]
961 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
963 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
964 return 1;
967 /*****************************************************************************
968 * AddFormW [WINSPOOL.@]
970 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
972 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
973 return 1;
976 /*****************************************************************************
977 * AddJobA [WINSPOOL.@]
979 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
980 DWORD cbBuf, LPDWORD pcbNeeded)
982 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
983 pcbNeeded);
984 return 1;
987 /*****************************************************************************
988 * AddJobW [WINSPOOL.@]
990 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
991 LPDWORD pcbNeeded)
993 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
994 pcbNeeded);
995 return 1;
998 /*****************************************************************************
999 * WINSPOOL_OpenDriverReg [internal]
1001 * opens the registry for the printer drivers depending on the given input
1002 * variable pEnvironment
1004 * RETURNS:
1005 * the opened hkey on success
1006 * NULL on error
1008 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1009 { HKEY retval;
1010 LPSTR lpKey, p = NULL;
1012 TRACE("%s\n",
1013 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1015 if(pEnvironment)
1016 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1017 pEnvironment;
1018 else {
1019 OSVERSIONINFOA ver;
1020 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1022 if(!GetVersionExA( &ver))
1023 return 0;
1025 switch (ver.dwPlatformId) {
1026 case VER_PLATFORM_WIN32s:
1027 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1028 return 0;
1030 case VER_PLATFORM_WIN32_NT:
1031 p = "Windows NT x86";
1032 break;
1033 default:
1034 p = "Windows 4.0";
1035 break;
1037 TRACE("set environment to %s\n", p);
1040 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1041 strlen(p) + strlen(Drivers));
1042 sprintf( lpKey, Drivers, p);
1044 TRACE("%s\n", lpKey);
1046 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1047 ERROR_SUCCESS)
1048 retval = 0;
1050 if(pEnvironment && unicode)
1051 HeapFree( GetProcessHeap(), 0, p);
1052 HeapFree( GetProcessHeap(), 0, lpKey);
1054 return retval;
1057 /*****************************************************************************
1058 * AddPrinterW [WINSPOOL.@]
1060 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1062 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1063 LPDEVMODEA dmA;
1064 LPDEVMODEW dmW;
1065 HANDLE retval;
1066 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1067 LONG size;
1069 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1071 if(pName != NULL) {
1072 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1073 SetLastError(ERROR_INVALID_PARAMETER);
1074 return 0;
1076 if(Level != 2) {
1077 ERR("Level = %ld, unsupported!\n", Level);
1078 SetLastError(ERROR_INVALID_LEVEL);
1079 return 0;
1081 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1082 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1083 debugstr_w(pi->pPrinterName)
1085 SetLastError(ERROR_INVALID_LEVEL);
1086 return 0;
1088 if(!pPrinter) {
1089 SetLastError(ERROR_INVALID_PARAMETER);
1090 return 0;
1092 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1093 ERROR_SUCCESS) {
1094 ERR("Can't create Printers key\n");
1095 return 0;
1097 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1098 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1099 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1100 RegCloseKey(hkeyPrinter);
1101 RegCloseKey(hkeyPrinters);
1102 return 0;
1104 RegCloseKey(hkeyPrinter);
1106 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1107 if(!hkeyDrivers) {
1108 ERR("Can't create Drivers key\n");
1109 RegCloseKey(hkeyPrinters);
1110 return 0;
1112 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1113 ERROR_SUCCESS) {
1114 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1115 RegCloseKey(hkeyPrinters);
1116 RegCloseKey(hkeyDrivers);
1117 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1118 return 0;
1120 RegCloseKey(hkeyDriver);
1121 RegCloseKey(hkeyDrivers);
1123 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1124 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1125 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1126 RegCloseKey(hkeyPrinters);
1127 return 0;
1130 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1131 ERROR_SUCCESS) {
1132 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1133 SetLastError(ERROR_INVALID_PRINTER_NAME);
1134 RegCloseKey(hkeyPrinters);
1135 return 0;
1137 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1138 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1139 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1141 /* See if we can load the driver. We may need the devmode structure anyway
1143 * FIXME:
1144 * Note that DocumentPropertiesW will briefly try to open the printer we
1145 * just create to find a DEVMODEA struct (it will use the WINEPS default
1146 * one in case it is not there, so we are ok).
1148 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1149 if(size < 0) {
1150 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1151 size = sizeof(DEVMODEW);
1153 if(pi->pDevMode)
1154 dmW = pi->pDevMode;
1155 else {
1156 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1157 dmW->dmSize = size;
1158 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1159 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1160 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1161 return 0;
1163 /* set devmode to printer name */
1164 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1167 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1168 and we support these drivers. NT writes DEVMODEW so somehow
1169 we'll need to distinguish between these when we support NT
1170 drivers */
1171 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1172 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1173 dmA->dmSize + dmA->dmDriverExtra);
1174 HeapFree(GetProcessHeap(), 0, dmA);
1175 if(!pi->pDevMode)
1176 HeapFree(GetProcessHeap(), 0, dmW);
1177 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1178 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1179 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1180 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1182 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1183 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1184 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1185 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1186 (LPBYTE)&pi->Priority, sizeof(DWORD));
1187 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1188 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1189 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1190 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1191 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1192 (LPBYTE)&pi->Status, sizeof(DWORD));
1193 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1194 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1196 RegCloseKey(hkeyPrinter);
1197 RegCloseKey(hkeyPrinters);
1198 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1199 ERR("OpenPrinter failing\n");
1200 return 0;
1202 return retval;
1205 /*****************************************************************************
1206 * AddPrinterA [WINSPOOL.@]
1208 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1210 UNICODE_STRING pNameW;
1211 PWSTR pwstrNameW;
1212 PRINTER_INFO_2W *piW;
1213 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1214 HANDLE ret;
1216 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1217 if(Level != 2) {
1218 ERR("Level = %ld, unsupported!\n", Level);
1219 SetLastError(ERROR_INVALID_LEVEL);
1220 return 0;
1222 pwstrNameW = asciitounicode(&pNameW,pName);
1223 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1225 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1227 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1228 RtlFreeUnicodeString(&pNameW);
1229 return ret;
1233 /*****************************************************************************
1234 * ClosePrinter [WINSPOOL.@]
1236 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1238 int i = (int)hPrinter;
1240 TRACE("Handle %p\n", hPrinter);
1242 if ((i <= 0) || (i > nb_printers)) return FALSE;
1243 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1244 printer_array[i - 1] = NULL;
1245 return TRUE;
1248 /*****************************************************************************
1249 * DeleteFormA [WINSPOOL.@]
1251 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1253 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1254 return 1;
1257 /*****************************************************************************
1258 * DeleteFormW [WINSPOOL.@]
1260 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1262 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1263 return 1;
1266 /*****************************************************************************
1267 * DeletePrinter [WINSPOOL.@]
1269 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1271 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1272 HKEY hkeyPrinters;
1274 if(!lpNameW) return FALSE;
1275 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1276 ERROR_SUCCESS) {
1277 ERR("Can't open Printers key\n");
1278 return 0;
1281 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1282 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1283 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1284 RegCloseKey(hkeyPrinters);
1285 return 0;
1288 ClosePrinter(hPrinter);
1289 return TRUE;
1292 /*****************************************************************************
1293 * SetPrinterA [WINSPOOL.@]
1295 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1296 DWORD Command)
1298 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1299 return FALSE;
1302 /*****************************************************************************
1303 * SetJobA [WINSPOOL.@]
1305 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1306 LPBYTE pJob, DWORD Command)
1308 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1309 Command);
1310 return FALSE;
1313 /*****************************************************************************
1314 * SetJobW [WINSPOOL.@]
1316 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1317 LPBYTE pJob, DWORD Command)
1319 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1320 Command);
1321 return FALSE;
1324 /*****************************************************************************
1325 * EndDocPrinter [WINSPOOL.@]
1327 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1329 FIXME("(hPrinter=%p): stub\n", hPrinter);
1330 return FALSE;
1333 /*****************************************************************************
1334 * EndPagePrinter [WINSPOOL.@]
1336 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1338 FIXME("(hPrinter=%p): stub\n", hPrinter);
1339 return FALSE;
1342 /*****************************************************************************
1343 * StartDocPrinterA [WINSPOOL.@]
1345 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1347 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1348 return FALSE;
1351 /*****************************************************************************
1352 * StartDocPrinterW [WINSPOOL.@]
1354 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1356 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1357 return FALSE;
1360 /*****************************************************************************
1361 * StartPagePrinter [WINSPOOL.@]
1363 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1365 FIXME("(hPrinter=%p): stub\n", hPrinter);
1366 return FALSE;
1369 /*****************************************************************************
1370 * GetFormA [WINSPOOL.@]
1372 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1373 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1375 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1376 Level,pForm,cbBuf,pcbNeeded);
1377 return FALSE;
1380 /*****************************************************************************
1381 * GetFormW [WINSPOOL.@]
1383 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1384 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1386 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1387 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1388 return FALSE;
1391 /*****************************************************************************
1392 * SetFormA [WINSPOOL.@]
1394 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1395 LPBYTE pForm)
1397 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1398 return FALSE;
1401 /*****************************************************************************
1402 * SetFormW [WINSPOOL.@]
1404 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1405 LPBYTE pForm)
1407 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1408 return FALSE;
1411 /*****************************************************************************
1412 * ReadPrinter [WINSPOOL.@]
1414 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1415 LPDWORD pNoBytesRead)
1417 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1418 return FALSE;
1421 /*****************************************************************************
1422 * ResetPrinterA [WINSPOOL.@]
1424 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1426 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1427 return FALSE;
1430 /*****************************************************************************
1431 * ResetPrinterW [WINSPOOL.@]
1433 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1435 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1436 return FALSE;
1439 /*****************************************************************************
1440 * WINSPOOL_GetDWORDFromReg
1442 * Return DWORD associated with ValueName from hkey.
1444 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1446 DWORD sz = sizeof(DWORD), type, value = 0;
1447 LONG ret;
1449 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1451 if(ret != ERROR_SUCCESS) {
1452 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1453 return 0;
1455 if(type != REG_DWORD) {
1456 ERR("Got type %ld\n", type);
1457 return 0;
1459 return value;
1462 /*****************************************************************************
1463 * WINSPOOL_GetStringFromReg
1465 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1466 * String is stored either as unicode or ascii.
1467 * Bit of a hack here to get the ValueName if we want ascii.
1469 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1470 DWORD buflen, DWORD *needed,
1471 BOOL unicode)
1473 DWORD sz = buflen, type;
1474 LONG ret;
1476 if(unicode)
1477 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1478 else {
1479 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1480 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1481 HeapFree(GetProcessHeap(),0,ValueNameA);
1483 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1484 WARN("Got ret = %ld\n", ret);
1485 *needed = 0;
1486 return FALSE;
1488 *needed = sz;
1489 return TRUE;
1492 /*****************************************************************************
1493 * WINSPOOL_GetDefaultDevMode
1495 * Get a default DevMode values for wineps.
1496 * FIXME - use ppd.
1499 static void WINSPOOL_GetDefaultDevMode(
1500 LPBYTE ptr,
1501 DWORD buflen, DWORD *needed,
1502 BOOL unicode)
1504 DEVMODEA dm;
1506 /* fill default DEVMODE - should be read from ppd... */
1507 ZeroMemory( &dm, sizeof(dm) );
1508 strcpy(dm.dmDeviceName,"wineps");
1509 dm.dmSpecVersion = DM_SPECVERSION;
1510 dm.dmDriverVersion = 1;
1511 dm.dmSize = sizeof(DEVMODEA);
1512 dm.dmDriverExtra = 0;
1513 dm.dmFields =
1514 DM_ORIENTATION | DM_PAPERSIZE |
1515 DM_PAPERLENGTH | DM_PAPERWIDTH |
1516 DM_SCALE |
1517 DM_COPIES |
1518 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1519 DM_YRESOLUTION | DM_TTOPTION;
1521 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1522 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1523 dm.u1.s1.dmPaperLength = 2970;
1524 dm.u1.s1.dmPaperWidth = 2100;
1526 dm.dmScale = 100;
1527 dm.dmCopies = 1;
1528 dm.dmDefaultSource = DMBIN_AUTO;
1529 dm.dmPrintQuality = DMRES_MEDIUM;
1530 /* dm.dmColor */
1531 /* dm.dmDuplex */
1532 dm.dmYResolution = 300; /* 300dpi */
1533 dm.dmTTOption = DMTT_BITMAP;
1534 /* dm.dmCollate */
1535 /* dm.dmFormName */
1536 /* dm.dmLogPixels */
1537 /* dm.dmBitsPerPel */
1538 /* dm.dmPelsWidth */
1539 /* dm.dmPelsHeight */
1540 /* dm.dmDisplayFlags */
1541 /* dm.dmDisplayFrequency */
1542 /* dm.dmICMMethod */
1543 /* dm.dmICMIntent */
1544 /* dm.dmMediaType */
1545 /* dm.dmDitherType */
1546 /* dm.dmReserved1 */
1547 /* dm.dmReserved2 */
1548 /* dm.dmPanningWidth */
1549 /* dm.dmPanningHeight */
1551 if(unicode) {
1552 if(buflen >= sizeof(DEVMODEW)) {
1553 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1554 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1555 HeapFree(GetProcessHeap(),0,pdmW);
1557 *needed = sizeof(DEVMODEW);
1559 else
1561 if(buflen >= sizeof(DEVMODEA)) {
1562 memcpy(ptr, &dm, sizeof(DEVMODEA));
1564 *needed = sizeof(DEVMODEA);
1568 /*****************************************************************************
1569 * WINSPOOL_GetDevModeFromReg
1571 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1572 * DevMode is stored either as unicode or ascii.
1574 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1575 LPBYTE ptr,
1576 DWORD buflen, DWORD *needed,
1577 BOOL unicode)
1579 DWORD sz = buflen, type;
1580 LONG ret;
1582 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1583 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1584 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1585 if (sz < sizeof(DEVMODEA))
1587 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1588 return FALSE;
1590 /* ensures that dmSize is not erratically bogus if registry is invalid */
1591 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1592 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1593 if(unicode) {
1594 sz += (CCHDEVICENAME + CCHFORMNAME);
1595 if(buflen >= sz) {
1596 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1597 memcpy(ptr, dmW, sz);
1598 HeapFree(GetProcessHeap(),0,dmW);
1601 *needed = sz;
1602 return TRUE;
1605 /*********************************************************************
1606 * WINSPOOL_GetPrinter_2
1608 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1609 * The strings are either stored as unicode or ascii.
1611 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1612 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1613 BOOL unicode)
1615 DWORD size, left = cbBuf;
1616 BOOL space = (cbBuf > 0);
1617 LPBYTE ptr = buf;
1619 *pcbNeeded = 0;
1621 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1622 unicode)) {
1623 if(space && size <= left) {
1624 pi2->pPrinterName = (LPWSTR)ptr;
1625 ptr += size;
1626 left -= size;
1627 } else
1628 space = FALSE;
1629 *pcbNeeded += size;
1631 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1632 unicode)) {
1633 if(space && size <= left) {
1634 pi2->pShareName = (LPWSTR)ptr;
1635 ptr += size;
1636 left -= size;
1637 } else
1638 space = FALSE;
1639 *pcbNeeded += size;
1641 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1642 unicode)) {
1643 if(space && size <= left) {
1644 pi2->pPortName = (LPWSTR)ptr;
1645 ptr += size;
1646 left -= size;
1647 } else
1648 space = FALSE;
1649 *pcbNeeded += size;
1651 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1652 &size, unicode)) {
1653 if(space && size <= left) {
1654 pi2->pDriverName = (LPWSTR)ptr;
1655 ptr += size;
1656 left -= size;
1657 } else
1658 space = FALSE;
1659 *pcbNeeded += size;
1661 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1662 unicode)) {
1663 if(space && size <= left) {
1664 pi2->pComment = (LPWSTR)ptr;
1665 ptr += size;
1666 left -= size;
1667 } else
1668 space = FALSE;
1669 *pcbNeeded += size;
1671 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1672 unicode)) {
1673 if(space && size <= left) {
1674 pi2->pLocation = (LPWSTR)ptr;
1675 ptr += size;
1676 left -= size;
1677 } else
1678 space = FALSE;
1679 *pcbNeeded += size;
1681 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1682 &size, unicode)) {
1683 if(space && size <= left) {
1684 pi2->pDevMode = (LPDEVMODEW)ptr;
1685 ptr += size;
1686 left -= size;
1687 } else
1688 space = FALSE;
1689 *pcbNeeded += size;
1691 else
1693 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1694 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
1695 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1696 if(space && size <= left) {
1697 pi2->pDevMode = (LPDEVMODEW)ptr;
1698 ptr += size;
1699 left -= size;
1700 } else
1701 space = FALSE;
1702 *pcbNeeded += size;
1704 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1705 &size, unicode)) {
1706 if(space && size <= left) {
1707 pi2->pSepFile = (LPWSTR)ptr;
1708 ptr += size;
1709 left -= size;
1710 } else
1711 space = FALSE;
1712 *pcbNeeded += size;
1714 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1715 &size, unicode)) {
1716 if(space && size <= left) {
1717 pi2->pPrintProcessor = (LPWSTR)ptr;
1718 ptr += size;
1719 left -= size;
1720 } else
1721 space = FALSE;
1722 *pcbNeeded += size;
1724 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1725 &size, unicode)) {
1726 if(space && size <= left) {
1727 pi2->pDatatype = (LPWSTR)ptr;
1728 ptr += size;
1729 left -= size;
1730 } else
1731 space = FALSE;
1732 *pcbNeeded += size;
1734 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1735 &size, unicode)) {
1736 if(space && size <= left) {
1737 pi2->pParameters = (LPWSTR)ptr;
1738 ptr += size;
1739 left -= size;
1740 } else
1741 space = FALSE;
1742 *pcbNeeded += size;
1744 if(pi2) {
1745 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1746 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1747 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1748 "Default Priority");
1749 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1750 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1753 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1754 memset(pi2, 0, sizeof(*pi2));
1756 return space;
1759 /*********************************************************************
1760 * WINSPOOL_GetPrinter_4
1762 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1764 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1765 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1766 BOOL unicode)
1768 DWORD size, left = cbBuf;
1769 BOOL space = (cbBuf > 0);
1770 LPBYTE ptr = buf;
1772 *pcbNeeded = 0;
1774 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1775 unicode)) {
1776 if(space && size <= left) {
1777 pi4->pPrinterName = (LPWSTR)ptr;
1778 ptr += size;
1779 left -= size;
1780 } else
1781 space = FALSE;
1782 *pcbNeeded += size;
1784 if(pi4) {
1785 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1788 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1789 memset(pi4, 0, sizeof(*pi4));
1791 return space;
1794 /*********************************************************************
1795 * WINSPOOL_GetPrinter_5
1797 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1799 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1800 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1801 BOOL unicode)
1803 DWORD size, left = cbBuf;
1804 BOOL space = (cbBuf > 0);
1805 LPBYTE ptr = buf;
1807 *pcbNeeded = 0;
1809 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1810 unicode)) {
1811 if(space && size <= left) {
1812 pi5->pPrinterName = (LPWSTR)ptr;
1813 ptr += size;
1814 left -= size;
1815 } else
1816 space = FALSE;
1817 *pcbNeeded += size;
1819 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1820 unicode)) {
1821 if(space && size <= left) {
1822 pi5->pPortName = (LPWSTR)ptr;
1823 ptr += size;
1824 left -= size;
1825 } else
1826 space = FALSE;
1827 *pcbNeeded += size;
1829 if(pi5) {
1830 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1831 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1832 "dnsTimeout");
1833 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1834 "txTimeout");
1837 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1838 memset(pi5, 0, sizeof(*pi5));
1840 return space;
1843 /*****************************************************************************
1844 * WINSPOOL_GetPrinter
1846 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1847 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1848 * just a collection of pointers to strings.
1850 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1851 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1853 LPCWSTR name;
1854 DWORD size, needed = 0;
1855 LPBYTE ptr = NULL;
1856 HKEY hkeyPrinter, hkeyPrinters;
1857 BOOL ret;
1859 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1861 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1863 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1864 ERROR_SUCCESS) {
1865 ERR("Can't create Printers key\n");
1866 return FALSE;
1868 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1870 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1871 RegCloseKey(hkeyPrinters);
1872 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1873 return FALSE;
1876 switch(Level) {
1877 case 2:
1879 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1881 size = sizeof(PRINTER_INFO_2W);
1882 if(size <= cbBuf) {
1883 ptr = pPrinter + size;
1884 cbBuf -= size;
1885 memset(pPrinter, 0, size);
1886 } else {
1887 pi2 = NULL;
1888 cbBuf = 0;
1890 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1891 unicode);
1892 needed += size;
1893 break;
1896 case 4:
1898 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1900 size = sizeof(PRINTER_INFO_4W);
1901 if(size <= cbBuf) {
1902 ptr = pPrinter + size;
1903 cbBuf -= size;
1904 memset(pPrinter, 0, size);
1905 } else {
1906 pi4 = NULL;
1907 cbBuf = 0;
1909 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1910 unicode);
1911 needed += size;
1912 break;
1916 case 5:
1918 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1920 size = sizeof(PRINTER_INFO_5W);
1921 if(size <= cbBuf) {
1922 ptr = pPrinter + size;
1923 cbBuf -= size;
1924 memset(pPrinter, 0, size);
1925 } else {
1926 pi5 = NULL;
1927 cbBuf = 0;
1930 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1931 unicode);
1932 needed += size;
1933 break;
1936 default:
1937 FIXME("Unimplemented level %ld\n", Level);
1938 SetLastError(ERROR_INVALID_LEVEL);
1939 RegCloseKey(hkeyPrinters);
1940 RegCloseKey(hkeyPrinter);
1941 return FALSE;
1944 RegCloseKey(hkeyPrinter);
1945 RegCloseKey(hkeyPrinters);
1947 TRACE("returning %d needed = %ld\n", ret, needed);
1948 if(pcbNeeded) *pcbNeeded = needed;
1949 if(!ret)
1950 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1951 return ret;
1954 /*****************************************************************************
1955 * GetPrinterW [WINSPOOL.@]
1957 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1958 DWORD cbBuf, LPDWORD pcbNeeded)
1960 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1961 TRUE);
1964 /*****************************************************************************
1965 * GetPrinterA [WINSPOOL.@]
1967 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1968 DWORD cbBuf, LPDWORD pcbNeeded)
1970 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1971 FALSE);
1974 /*****************************************************************************
1975 * WINSPOOL_EnumPrinters
1977 * Implementation of EnumPrintersA|W
1979 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1980 DWORD dwLevel, LPBYTE lpbPrinters,
1981 DWORD cbBuf, LPDWORD lpdwNeeded,
1982 LPDWORD lpdwReturned, BOOL unicode)
1985 HKEY hkeyPrinters, hkeyPrinter;
1986 WCHAR PrinterName[255];
1987 DWORD needed = 0, number = 0;
1988 DWORD used, i, left;
1989 PBYTE pi, buf;
1991 if(lpbPrinters)
1992 memset(lpbPrinters, 0, cbBuf);
1993 if(lpdwReturned)
1994 *lpdwReturned = 0;
1995 if(lpdwNeeded)
1996 *lpdwNeeded = 0;
1998 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1999 if(dwType == PRINTER_ENUM_DEFAULT)
2000 return TRUE;
2002 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2003 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
2004 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
2005 dwType |= PRINTER_ENUM_LOCAL;
2008 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2009 FIXME("dwType = %08lx\n", dwType);
2010 SetLastError(ERROR_INVALID_FLAGS);
2011 return FALSE;
2014 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2015 ERROR_SUCCESS) {
2016 ERR("Can't create Printers key\n");
2017 return FALSE;
2020 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2021 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2022 RegCloseKey(hkeyPrinters);
2023 ERR("Can't query Printers key\n");
2024 return FALSE;
2026 TRACE("Found %ld printers\n", number);
2028 switch(dwLevel) {
2029 case 1:
2030 RegCloseKey(hkeyPrinters);
2031 if (lpdwReturned)
2032 *lpdwReturned = number;
2033 return TRUE;
2035 case 2:
2036 used = number * sizeof(PRINTER_INFO_2W);
2037 break;
2038 case 4:
2039 used = number * sizeof(PRINTER_INFO_4W);
2040 break;
2041 case 5:
2042 used = number * sizeof(PRINTER_INFO_5W);
2043 break;
2045 default:
2046 SetLastError(ERROR_INVALID_LEVEL);
2047 RegCloseKey(hkeyPrinters);
2048 return FALSE;
2050 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2052 for(i = 0; i < number; i++) {
2053 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2054 ERROR_SUCCESS) {
2055 ERR("Can't enum key number %ld\n", i);
2056 RegCloseKey(hkeyPrinters);
2057 return FALSE;
2059 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2060 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2061 ERROR_SUCCESS) {
2062 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2063 RegCloseKey(hkeyPrinters);
2064 return FALSE;
2067 if(cbBuf > used) {
2068 buf = lpbPrinters + used;
2069 left = cbBuf - used;
2070 } else {
2071 buf = NULL;
2072 left = 0;
2075 switch(dwLevel) {
2076 case 2:
2077 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2078 left, &needed, unicode);
2079 used += needed;
2080 if(pi) pi += sizeof(PRINTER_INFO_2W);
2081 break;
2082 case 4:
2083 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2084 left, &needed, unicode);
2085 used += needed;
2086 if(pi) pi += sizeof(PRINTER_INFO_4W);
2087 break;
2088 case 5:
2089 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2090 left, &needed, unicode);
2091 used += needed;
2092 if(pi) pi += sizeof(PRINTER_INFO_5W);
2093 break;
2094 default:
2095 ERR("Shouldn't be here!\n");
2096 RegCloseKey(hkeyPrinter);
2097 RegCloseKey(hkeyPrinters);
2098 return FALSE;
2100 RegCloseKey(hkeyPrinter);
2102 RegCloseKey(hkeyPrinters);
2104 if(lpdwNeeded)
2105 *lpdwNeeded = used;
2107 if(used > cbBuf) {
2108 if(lpbPrinters)
2109 memset(lpbPrinters, 0, cbBuf);
2110 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2111 return FALSE;
2113 if(lpdwReturned)
2114 *lpdwReturned = number;
2115 SetLastError(ERROR_SUCCESS);
2116 return TRUE;
2120 /******************************************************************
2121 * EnumPrintersW [WINSPOOL.@]
2123 * Enumerates the available printers, print servers and print
2124 * providers, depending on the specified flags, name and level.
2126 * RETURNS:
2128 * If level is set to 1:
2129 * Not implemented yet!
2130 * Returns TRUE with an empty list.
2132 * If level is set to 2:
2133 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2134 * Returns an array of PRINTER_INFO_2 data structures in the
2135 * lpbPrinters buffer. Note that according to MSDN also an
2136 * OpenPrinter should be performed on every remote printer.
2138 * If level is set to 4 (officially WinNT only):
2139 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2140 * Fast: Only the registry is queried to retrieve printer names,
2141 * no connection to the driver is made.
2142 * Returns an array of PRINTER_INFO_4 data structures in the
2143 * lpbPrinters buffer.
2145 * If level is set to 5 (officially WinNT4/Win9x only):
2146 * Fast: Only the registry is queried to retrieve printer names,
2147 * no connection to the driver is made.
2148 * Returns an array of PRINTER_INFO_5 data structures in the
2149 * lpbPrinters buffer.
2151 * If level set to 3 or 6+:
2152 * returns zero (failure!)
2154 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2155 * for information.
2157 * BUGS:
2158 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2159 * - Only levels 2, 4 and 5 are implemented at the moment.
2160 * - 16-bit printer drivers are not enumerated.
2161 * - Returned amount of bytes used/needed does not match the real Windoze
2162 * implementation (as in this implementation, all strings are part
2163 * of the buffer, whereas Win32 keeps them somewhere else)
2164 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2166 * NOTE:
2167 * - In a regular Wine installation, no registry settings for printers
2168 * exist, which makes this function return an empty list.
2170 BOOL WINAPI EnumPrintersW(
2171 DWORD dwType, /* [in] Types of print objects to enumerate */
2172 LPWSTR lpszName, /* [in] name of objects to enumerate */
2173 DWORD dwLevel, /* [in] type of printer info structure */
2174 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2175 DWORD cbBuf, /* [in] max size of buffer in bytes */
2176 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2177 LPDWORD lpdwReturned /* [out] number of entries returned */
2180 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2181 lpdwNeeded, lpdwReturned, TRUE);
2184 /******************************************************************
2185 * EnumPrintersA [WINSPOOL.@]
2188 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2189 DWORD dwLevel, LPBYTE lpbPrinters,
2190 DWORD cbBuf, LPDWORD lpdwNeeded,
2191 LPDWORD lpdwReturned)
2193 BOOL ret;
2194 UNICODE_STRING lpszNameW;
2195 PWSTR pwstrNameW;
2197 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2198 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2199 lpdwNeeded, lpdwReturned, FALSE);
2200 RtlFreeUnicodeString(&lpszNameW);
2201 return ret;
2204 /*****************************************************************************
2205 * WINSPOOL_GetDriverInfoFromReg [internal]
2207 * Enters the information from the registry into the DRIVER_INFO struct
2209 * RETURNS
2210 * zero if the printer driver does not exist in the registry
2211 * (only if Level > 1) otherwise nonzero
2213 static BOOL WINSPOOL_GetDriverInfoFromReg(
2214 HKEY hkeyDrivers,
2215 LPWSTR DriverName,
2216 LPWSTR pEnvironment,
2217 DWORD Level,
2218 LPBYTE ptr, /* DRIVER_INFO */
2219 LPBYTE pDriverStrings, /* strings buffer */
2220 DWORD cbBuf, /* size of string buffer */
2221 LPDWORD pcbNeeded, /* space needed for str. */
2222 BOOL unicode) /* type of strings */
2223 { DWORD dw, size, tmp, type;
2224 HKEY hkeyDriver;
2225 LPBYTE strPtr = pDriverStrings;
2227 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2228 debugstr_w(DriverName), debugstr_w(pEnvironment),
2229 Level, ptr, pDriverStrings, cbBuf, unicode);
2231 if(unicode) {
2232 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2233 if (*pcbNeeded <= cbBuf)
2234 strcpyW((LPWSTR)strPtr, DriverName);
2235 } else {
2236 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2237 NULL, NULL);
2238 if(*pcbNeeded <= cbBuf)
2239 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2240 NULL, NULL);
2242 if(Level == 1) {
2243 if(ptr)
2244 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2245 return TRUE;
2246 } else {
2247 if(ptr)
2248 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2249 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2252 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2253 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2254 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2255 return FALSE;
2258 size = sizeof(dw);
2259 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2260 ERROR_SUCCESS)
2261 WARN("Can't get Version\n");
2262 else if(ptr)
2263 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2265 if(!pEnvironment)
2266 pEnvironment = DefaultEnvironmentW;
2267 if(unicode)
2268 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2269 else
2270 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2271 NULL, NULL);
2272 *pcbNeeded += size;
2273 if(*pcbNeeded <= cbBuf) {
2274 if(unicode)
2275 strcpyW((LPWSTR)strPtr, pEnvironment);
2276 else
2277 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2278 NULL, NULL);
2279 if(ptr)
2280 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2281 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2284 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2285 unicode)) {
2286 *pcbNeeded += size;
2287 if(*pcbNeeded <= cbBuf)
2288 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2289 unicode);
2290 if(ptr)
2291 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2292 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2295 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2296 unicode)) {
2297 *pcbNeeded += size;
2298 if(*pcbNeeded <= cbBuf)
2299 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2300 &tmp, unicode);
2301 if(ptr)
2302 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2303 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2306 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2307 0, &size, unicode)) {
2308 *pcbNeeded += size;
2309 if(*pcbNeeded <= cbBuf)
2310 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2311 size, &tmp, unicode);
2312 if(ptr)
2313 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2314 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2317 if(Level == 2 ) {
2318 RegCloseKey(hkeyDriver);
2319 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2320 return TRUE;
2323 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2324 unicode)) {
2325 *pcbNeeded += size;
2326 if(*pcbNeeded <= cbBuf)
2327 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2328 size, &tmp, unicode);
2329 if(ptr)
2330 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2331 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2334 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2335 &size, unicode)) {
2336 *pcbNeeded += size;
2337 if(*pcbNeeded <= cbBuf)
2338 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2339 size, &tmp, unicode);
2340 if(ptr)
2341 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2342 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2345 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2346 unicode)) {
2347 *pcbNeeded += size;
2348 if(*pcbNeeded <= cbBuf)
2349 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2350 size, &tmp, unicode);
2351 if(ptr)
2352 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2353 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2356 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2357 unicode)) {
2358 *pcbNeeded += size;
2359 if(*pcbNeeded <= cbBuf)
2360 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2361 size, &tmp, unicode);
2362 if(ptr)
2363 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2364 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2367 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2368 RegCloseKey(hkeyDriver);
2369 return TRUE;
2372 /*****************************************************************************
2373 * WINSPOOL_GetPrinterDriver
2375 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2376 DWORD Level, LPBYTE pDriverInfo,
2377 DWORD cbBuf, LPDWORD pcbNeeded,
2378 BOOL unicode)
2380 LPCWSTR name;
2381 WCHAR DriverName[100];
2382 DWORD ret, type, size, needed = 0;
2383 LPBYTE ptr = NULL;
2384 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2386 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2387 Level,pDriverInfo,cbBuf, pcbNeeded);
2389 ZeroMemory(pDriverInfo, cbBuf);
2391 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2393 if(Level < 1 || Level > 3) {
2394 SetLastError(ERROR_INVALID_LEVEL);
2395 return FALSE;
2397 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2398 ERROR_SUCCESS) {
2399 ERR("Can't create Printers key\n");
2400 return FALSE;
2402 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2403 != ERROR_SUCCESS) {
2404 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2405 RegCloseKey(hkeyPrinters);
2406 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2407 return FALSE;
2409 size = sizeof(DriverName);
2410 DriverName[0] = 0;
2411 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2412 (LPBYTE)DriverName, &size);
2413 RegCloseKey(hkeyPrinter);
2414 RegCloseKey(hkeyPrinters);
2415 if(ret != ERROR_SUCCESS) {
2416 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2417 return FALSE;
2420 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2421 if(!hkeyDrivers) {
2422 ERR("Can't create Drivers key\n");
2423 return FALSE;
2426 switch(Level) {
2427 case 1:
2428 size = sizeof(DRIVER_INFO_1W);
2429 break;
2430 case 2:
2431 size = sizeof(DRIVER_INFO_2W);
2432 break;
2433 case 3:
2434 size = sizeof(DRIVER_INFO_3W);
2435 break;
2436 default:
2437 ERR("Invalid level\n");
2438 return FALSE;
2441 if(size <= cbBuf)
2442 ptr = pDriverInfo + size;
2444 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2445 pEnvironment, Level, pDriverInfo,
2446 (cbBuf < size) ? NULL : ptr,
2447 (cbBuf < size) ? 0 : cbBuf - size,
2448 &needed, unicode)) {
2449 RegCloseKey(hkeyDrivers);
2450 return FALSE;
2453 RegCloseKey(hkeyDrivers);
2455 if(pcbNeeded) *pcbNeeded = size + needed;
2456 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2457 if(cbBuf >= needed) return TRUE;
2458 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2459 return FALSE;
2462 /*****************************************************************************
2463 * GetPrinterDriverA [WINSPOOL.@]
2465 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2466 DWORD Level, LPBYTE pDriverInfo,
2467 DWORD cbBuf, LPDWORD pcbNeeded)
2469 BOOL ret;
2470 UNICODE_STRING pEnvW;
2471 PWSTR pwstrEnvW;
2473 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2474 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2475 cbBuf, pcbNeeded, FALSE);
2476 RtlFreeUnicodeString(&pEnvW);
2477 return ret;
2479 /*****************************************************************************
2480 * GetPrinterDriverW [WINSPOOL.@]
2482 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2483 DWORD Level, LPBYTE pDriverInfo,
2484 DWORD cbBuf, LPDWORD pcbNeeded)
2486 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2487 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2490 /*****************************************************************************
2491 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2493 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2494 DWORD Level, LPBYTE pDriverDirectory,
2495 DWORD cbBuf, LPDWORD pcbNeeded)
2497 DWORD needed;
2499 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2500 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2501 if(pName != NULL) {
2502 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2503 SetLastError(ERROR_INVALID_PARAMETER);
2504 return FALSE;
2506 if(pEnvironment != NULL) {
2507 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2508 SetLastError(ERROR_INVALID_ENVIRONMENT);
2509 return FALSE;
2511 if(Level != 1) /* win95 ignores this so we just carry on */
2512 WARN("Level = %ld - assuming 1\n", Level);
2514 /* FIXME should read from registry */
2515 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2516 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2517 * adjust this now
2519 needed++;
2520 needed*=sizeof(WCHAR);
2522 if(pcbNeeded)
2523 *pcbNeeded = needed;
2524 TRACE("required <%08lx>\n", *pcbNeeded);
2525 if(needed > cbBuf) {
2526 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2527 return FALSE;
2529 return TRUE;
2533 /*****************************************************************************
2534 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2536 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2537 DWORD Level, LPBYTE pDriverDirectory,
2538 DWORD cbBuf, LPDWORD pcbNeeded)
2540 UNICODE_STRING nameW, environmentW;
2541 BOOL ret;
2542 DWORD pcbNeededW;
2543 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2544 WCHAR *driverDirectoryW = NULL;
2546 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2548 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2549 else nameW.Buffer = NULL;
2550 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2551 else environmentW.Buffer = NULL;
2553 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2554 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2555 if (ret) {
2556 DWORD needed;
2557 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2558 pDriverDirectory, cbBuf, NULL, NULL);
2559 if(pcbNeeded)
2560 *pcbNeeded = needed;
2561 ret = (needed <= cbBuf) ? TRUE : FALSE;
2562 } else
2563 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2565 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2567 if(driverDirectoryW)
2568 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2569 RtlFreeUnicodeString(&environmentW);
2570 RtlFreeUnicodeString(&nameW);
2572 return ret;
2575 /*****************************************************************************
2576 * AddPrinterDriverA [WINSPOOL.@]
2578 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2580 DRIVER_INFO_3A di3;
2581 HKEY hkeyDrivers, hkeyName;
2583 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2585 if(level != 2 && level != 3) {
2586 SetLastError(ERROR_INVALID_LEVEL);
2587 return FALSE;
2589 if(pName != NULL) {
2590 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2591 SetLastError(ERROR_INVALID_PARAMETER);
2592 return FALSE;
2594 if(!pDriverInfo) {
2595 WARN("pDriverInfo == NULL\n");
2596 SetLastError(ERROR_INVALID_PARAMETER);
2597 return FALSE;
2600 if(level == 3)
2601 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2602 else {
2603 memset(&di3, 0, sizeof(di3));
2604 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2607 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2608 !di3.pDataFile) {
2609 SetLastError(ERROR_INVALID_PARAMETER);
2610 return FALSE;
2612 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2613 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2614 if(!di3.pHelpFile) di3.pHelpFile = "";
2615 if(!di3.pMonitorName) di3.pMonitorName = "";
2617 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2619 if(!hkeyDrivers) {
2620 ERR("Can't create Drivers key\n");
2621 return FALSE;
2624 if(level == 2) { /* apparently can't overwrite with level2 */
2625 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2626 RegCloseKey(hkeyName);
2627 RegCloseKey(hkeyDrivers);
2628 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2629 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2630 return FALSE;
2633 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2634 RegCloseKey(hkeyDrivers);
2635 ERR("Can't create Name key\n");
2636 return FALSE;
2638 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2640 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2641 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2642 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2643 sizeof(DWORD));
2644 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2645 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2646 di3.pDependentFiles, 0);
2647 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2648 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2649 RegCloseKey(hkeyName);
2650 RegCloseKey(hkeyDrivers);
2652 return TRUE;
2654 /*****************************************************************************
2655 * AddPrinterDriverW [WINSPOOL.@]
2657 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2658 LPBYTE pDriverInfo)
2660 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2661 level,pDriverInfo);
2662 return FALSE;
2666 /*****************************************************************************
2667 * PrinterProperties [WINSPOOL.@]
2669 * Displays a dialog to set the properties of the printer.
2671 * RETURNS
2672 * nonzero on success or zero on failure
2674 * BUGS
2675 * implemented as stub only
2677 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2678 HANDLE hPrinter /* [in] handle to printer object */
2680 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2681 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2682 return FALSE;
2685 /*****************************************************************************
2686 * EnumJobsA [WINSPOOL.@]
2689 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2690 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2691 LPDWORD pcReturned)
2693 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2694 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2696 if(pcbNeeded) *pcbNeeded = 0;
2697 if(pcReturned) *pcReturned = 0;
2698 return FALSE;
2702 /*****************************************************************************
2703 * EnumJobsW [WINSPOOL.@]
2706 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2707 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2708 LPDWORD pcReturned)
2710 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2711 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2713 if(pcbNeeded) *pcbNeeded = 0;
2714 if(pcReturned) *pcReturned = 0;
2715 return FALSE;
2718 /*****************************************************************************
2719 * WINSPOOL_EnumPrinterDrivers [internal]
2721 * Delivers information about all printer drivers installed on the
2722 * localhost or a given server
2724 * RETURNS
2725 * nonzero on success or zero on failure. If the buffer for the returned
2726 * information is too small the function will return an error
2728 * BUGS
2729 * - only implemented for localhost, foreign hosts will return an error
2731 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2732 DWORD Level, LPBYTE pDriverInfo,
2733 DWORD cbBuf, LPDWORD pcbNeeded,
2734 LPDWORD pcReturned, BOOL unicode)
2736 { HKEY hkeyDrivers;
2737 DWORD i, needed, number = 0, size = 0;
2738 WCHAR DriverNameW[255];
2739 PBYTE ptr;
2741 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2742 debugstr_w(pName), debugstr_w(pEnvironment),
2743 Level, pDriverInfo, cbBuf, unicode);
2745 /* check for local drivers */
2746 if(pName) {
2747 ERR("remote drivers unsupported! Current remote host is %s\n",
2748 debugstr_w(pName));
2749 return FALSE;
2752 /* check input parameter */
2753 if((Level < 1) || (Level > 3)) {
2754 ERR("unsupported level %ld \n", Level);
2755 return FALSE;
2758 /* initialize return values */
2759 if(pDriverInfo)
2760 memset( pDriverInfo, 0, cbBuf);
2761 *pcbNeeded = 0;
2762 *pcReturned = 0;
2764 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2765 if(!hkeyDrivers) {
2766 ERR("Can't open Drivers key\n");
2767 return FALSE;
2770 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2771 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2772 RegCloseKey(hkeyDrivers);
2773 ERR("Can't query Drivers key\n");
2774 return FALSE;
2776 TRACE("Found %ld Drivers\n", number);
2778 /* get size of single struct
2779 * unicode and ascii structure have the same size
2781 switch (Level) {
2782 case 1:
2783 size = sizeof(DRIVER_INFO_1A);
2784 break;
2785 case 2:
2786 size = sizeof(DRIVER_INFO_2A);
2787 break;
2788 case 3:
2789 size = sizeof(DRIVER_INFO_3A);
2790 break;
2793 /* calculate required buffer size */
2794 *pcbNeeded = size * number;
2796 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2797 i < number;
2798 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2799 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2800 != ERROR_SUCCESS) {
2801 ERR("Can't enum key number %ld\n", i);
2802 RegCloseKey(hkeyDrivers);
2803 return FALSE;
2805 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2806 pEnvironment, Level, ptr,
2807 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2808 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2809 &needed, unicode)) {
2810 RegCloseKey(hkeyDrivers);
2811 return FALSE;
2813 (*pcbNeeded) += needed;
2816 RegCloseKey(hkeyDrivers);
2818 if(cbBuf < *pcbNeeded){
2819 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2820 return FALSE;
2823 return TRUE;
2826 /*****************************************************************************
2827 * EnumPrinterDriversW [WINSPOOL.@]
2829 * see function EnumPrinterDrivers for RETURNS, BUGS
2831 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2832 LPBYTE pDriverInfo, DWORD cbBuf,
2833 LPDWORD pcbNeeded, LPDWORD pcReturned)
2835 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2836 cbBuf, pcbNeeded, pcReturned, TRUE);
2839 /*****************************************************************************
2840 * EnumPrinterDriversA [WINSPOOL.@]
2842 * see function EnumPrinterDrivers for RETURNS, BUGS
2844 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2845 LPBYTE pDriverInfo, DWORD cbBuf,
2846 LPDWORD pcbNeeded, LPDWORD pcReturned)
2847 { BOOL ret;
2848 UNICODE_STRING pNameW, pEnvironmentW;
2849 PWSTR pwstrNameW, pwstrEnvironmentW;
2851 pwstrNameW = asciitounicode(&pNameW, pName);
2852 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
2854 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
2855 Level, pDriverInfo, cbBuf, pcbNeeded,
2856 pcReturned, FALSE);
2857 RtlFreeUnicodeString(&pNameW);
2858 RtlFreeUnicodeString(&pEnvironmentW);
2860 return ret;
2864 /******************************************************************************
2865 * EnumPortsA (WINSPOOL.@)
2867 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2868 LPDWORD bufneeded,LPDWORD bufreturned)
2870 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2871 return FALSE;
2874 /******************************************************************************
2875 * GetDefaultPrinterA (WINSPOOL.@)
2877 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2879 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
2881 char *ptr;
2883 if (*namesize < 1)
2885 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2886 return FALSE;
2889 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
2891 SetLastError (ERROR_FILE_NOT_FOUND);
2892 return FALSE;
2895 if ((ptr = strchr (name, ',')) == NULL)
2897 SetLastError (ERROR_FILE_NOT_FOUND);
2898 return FALSE;
2901 *ptr = '\0';
2902 *namesize = strlen (name) + 1;
2903 return TRUE;
2907 /******************************************************************************
2908 * GetDefaultPrinterW (WINSPOOL.@)
2910 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
2912 char *buf;
2913 BOOL ret;
2915 if (*namesize < 1)
2917 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2918 return FALSE;
2921 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
2922 ret = GetDefaultPrinterA (buf, namesize);
2923 if (ret)
2925 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
2926 if (!len)
2928 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2929 ret = FALSE;
2931 else *namesize = len;
2934 HeapFree (GetProcessHeap (), 0, buf);
2935 return ret;
2939 /******************************************************************************
2940 * SetPrinterDataExA (WINSPOOL.@)
2942 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2943 LPSTR pValueName, DWORD Type,
2944 LPBYTE pData, DWORD cbData)
2946 HKEY hkeyPrinter, hkeySubkey;
2947 DWORD ret;
2949 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2950 debugstr_a(pValueName), Type, pData, cbData);
2952 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2953 != ERROR_SUCCESS)
2954 return ret;
2956 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2957 != ERROR_SUCCESS) {
2958 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2959 RegCloseKey(hkeyPrinter);
2960 return ret;
2962 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2963 RegCloseKey(hkeySubkey);
2964 RegCloseKey(hkeyPrinter);
2965 return ret;
2968 /******************************************************************************
2969 * SetPrinterDataExW (WINSPOOL.@)
2971 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2972 LPWSTR pValueName, DWORD Type,
2973 LPBYTE pData, DWORD cbData)
2975 HKEY hkeyPrinter, hkeySubkey;
2976 DWORD ret;
2978 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2979 debugstr_w(pValueName), Type, pData, cbData);
2981 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2982 != ERROR_SUCCESS)
2983 return ret;
2985 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2986 != ERROR_SUCCESS) {
2987 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2988 RegCloseKey(hkeyPrinter);
2989 return ret;
2991 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2992 RegCloseKey(hkeySubkey);
2993 RegCloseKey(hkeyPrinter);
2994 return ret;
2997 /******************************************************************************
2998 * SetPrinterDataA (WINSPOOL.@)
3000 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3001 LPBYTE pData, DWORD cbData)
3003 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3004 pData, cbData);
3007 /******************************************************************************
3008 * SetPrinterDataW (WINSPOOL.@)
3010 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3011 LPBYTE pData, DWORD cbData)
3013 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3014 pData, cbData);
3017 /******************************************************************************
3018 * GetPrinterDataExA (WINSPOOL.@)
3020 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
3021 LPSTR pValueName, LPDWORD pType,
3022 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3024 HKEY hkeyPrinter, hkeySubkey;
3025 DWORD ret;
3027 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3028 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3029 pcbNeeded);
3031 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3032 != ERROR_SUCCESS)
3033 return ret;
3035 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3036 != ERROR_SUCCESS) {
3037 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3038 RegCloseKey(hkeyPrinter);
3039 return ret;
3041 *pcbNeeded = nSize;
3042 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3043 RegCloseKey(hkeySubkey);
3044 RegCloseKey(hkeyPrinter);
3045 return ret;
3048 /******************************************************************************
3049 * GetPrinterDataExW (WINSPOOL.@)
3051 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
3052 LPWSTR pValueName, LPDWORD pType,
3053 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3055 HKEY hkeyPrinter, hkeySubkey;
3056 DWORD ret;
3058 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3059 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3060 pcbNeeded);
3062 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3063 != ERROR_SUCCESS)
3064 return ret;
3066 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3067 != ERROR_SUCCESS) {
3068 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3069 RegCloseKey(hkeyPrinter);
3070 return ret;
3072 *pcbNeeded = nSize;
3073 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3074 RegCloseKey(hkeySubkey);
3075 RegCloseKey(hkeyPrinter);
3076 return ret;
3079 /******************************************************************************
3080 * GetPrinterDataA (WINSPOOL.@)
3082 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3083 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3085 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3086 pData, nSize, pcbNeeded);
3089 /******************************************************************************
3090 * GetPrinterDataW (WINSPOOL.@)
3092 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3093 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3095 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3096 pData, nSize, pcbNeeded);
3099 /*******************************************************************************
3100 * EnumPrinterDataExW [WINSPOOL.@]
3102 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3103 LPBYTE pEnumValues, DWORD cbEnumValues,
3104 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3106 HKEY hkPrinter, hkSubKey;
3107 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3108 cbValueNameLen, cbMaxValueLen, cbValueLen,
3109 cbBufSize, dwType;
3110 LPWSTR lpValueName;
3111 HANDLE hHeap;
3112 PBYTE lpValue;
3113 PPRINTER_ENUM_VALUESW ppev;
3115 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3117 if (pKeyName == NULL || *pKeyName == 0)
3118 return ERROR_INVALID_PARAMETER;
3120 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3121 if (ret != ERROR_SUCCESS)
3123 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3124 hPrinter, ret);
3125 return ret;
3128 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3129 if (ret != ERROR_SUCCESS)
3131 r = RegCloseKey (hkPrinter);
3132 if (r != ERROR_SUCCESS)
3133 WARN ("RegCloseKey returned %li\n", r);
3134 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3135 debugstr_w (pKeyName), ret);
3136 return ret;
3139 ret = RegCloseKey (hkPrinter);
3140 if (ret != ERROR_SUCCESS)
3142 ERR ("RegCloseKey returned %li\n", ret);
3143 r = RegCloseKey (hkSubKey);
3144 if (r != ERROR_SUCCESS)
3145 WARN ("RegCloseKey returned %li\n", r);
3146 return ret;
3149 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3150 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3151 if (ret != ERROR_SUCCESS)
3153 r = RegCloseKey (hkSubKey);
3154 if (r != ERROR_SUCCESS)
3155 WARN ("RegCloseKey returned %li\n", r);
3156 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3157 return ret;
3160 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3161 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3163 if (cValues == 0) /* empty key */
3165 r = RegCloseKey (hkSubKey);
3166 if (r != ERROR_SUCCESS)
3167 WARN ("RegCloseKey returned %li\n", r);
3168 *pcbEnumValues = *pnEnumValues = 0;
3169 return ERROR_SUCCESS;
3172 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3174 hHeap = GetProcessHeap ();
3175 if (hHeap == NULL)
3177 ERR ("GetProcessHeap failed\n");
3178 r = RegCloseKey (hkSubKey);
3179 if (r != ERROR_SUCCESS)
3180 WARN ("RegCloseKey returned %li\n", r);
3181 return ERROR_OUTOFMEMORY;
3184 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3185 if (lpValueName == NULL)
3187 ERR ("Failed to allocate %li bytes from process heap\n",
3188 cbMaxValueNameLen * sizeof (WCHAR));
3189 r = RegCloseKey (hkSubKey);
3190 if (r != ERROR_SUCCESS)
3191 WARN ("RegCloseKey returned %li\n", r);
3192 return ERROR_OUTOFMEMORY;
3195 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3196 if (lpValue == NULL)
3198 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3199 if (HeapFree (hHeap, 0, lpValueName) == 0)
3200 WARN ("HeapFree failed with code %li\n", GetLastError ());
3201 r = RegCloseKey (hkSubKey);
3202 if (r != ERROR_SUCCESS)
3203 WARN ("RegCloseKey returned %li\n", r);
3204 return ERROR_OUTOFMEMORY;
3207 TRACE ("pass 1: calculating buffer required for all names and values\n");
3209 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3211 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3213 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3215 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3216 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3217 NULL, NULL, lpValue, &cbValueLen);
3218 if (ret != ERROR_SUCCESS)
3220 if (HeapFree (hHeap, 0, lpValue) == 0)
3221 WARN ("HeapFree failed with code %li\n", GetLastError ());
3222 if (HeapFree (hHeap, 0, lpValueName) == 0)
3223 WARN ("HeapFree failed with code %li\n", GetLastError ());
3224 r = RegCloseKey (hkSubKey);
3225 if (r != ERROR_SUCCESS)
3226 WARN ("RegCloseKey returned %li\n", r);
3227 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3228 return ret;
3231 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3232 debugstr_w (lpValueName), dwIndex,
3233 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3235 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3236 cbBufSize += cbValueLen;
3239 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3241 *pcbEnumValues = cbBufSize;
3242 *pnEnumValues = cValues;
3244 if (cbEnumValues < cbBufSize) /* buffer too small */
3246 if (HeapFree (hHeap, 0, lpValue) == 0)
3247 WARN ("HeapFree failed with code %li\n", GetLastError ());
3248 if (HeapFree (hHeap, 0, lpValueName) == 0)
3249 WARN ("HeapFree failed with code %li\n", GetLastError ());
3250 r = RegCloseKey (hkSubKey);
3251 if (r != ERROR_SUCCESS)
3252 WARN ("RegCloseKey returned %li\n", r);
3253 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3254 return ERROR_MORE_DATA;
3257 TRACE ("pass 2: copying all names and values to buffer\n");
3259 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3260 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3262 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3264 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3265 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3266 NULL, &dwType, lpValue, &cbValueLen);
3267 if (ret != ERROR_SUCCESS)
3269 if (HeapFree (hHeap, 0, lpValue) == 0)
3270 WARN ("HeapFree failed with code %li\n", GetLastError ());
3271 if (HeapFree (hHeap, 0, lpValueName) == 0)
3272 WARN ("HeapFree failed with code %li\n", GetLastError ());
3273 r = RegCloseKey (hkSubKey);
3274 if (r != ERROR_SUCCESS)
3275 WARN ("RegCloseKey returned %li\n", r);
3276 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3277 return ret;
3280 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3281 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3282 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3283 pEnumValues += cbValueNameLen;
3285 /* return # of *bytes* (including trailing \0), not # of chars */
3286 ppev[dwIndex].cbValueName = cbValueNameLen;
3288 ppev[dwIndex].dwType = dwType;
3290 memcpy (pEnumValues, lpValue, cbValueLen);
3291 ppev[dwIndex].pData = pEnumValues;
3292 pEnumValues += cbValueLen;
3294 ppev[dwIndex].cbData = cbValueLen;
3296 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3297 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3300 if (HeapFree (hHeap, 0, lpValue) == 0)
3302 ret = GetLastError ();
3303 ERR ("HeapFree failed with code %li\n", ret);
3304 if (HeapFree (hHeap, 0, lpValueName) == 0)
3305 WARN ("HeapFree failed with code %li\n", GetLastError ());
3306 r = RegCloseKey (hkSubKey);
3307 if (r != ERROR_SUCCESS)
3308 WARN ("RegCloseKey returned %li\n", r);
3309 return ret;
3312 if (HeapFree (hHeap, 0, lpValueName) == 0)
3314 ret = GetLastError ();
3315 ERR ("HeapFree failed with code %li\n", ret);
3316 r = RegCloseKey (hkSubKey);
3317 if (r != ERROR_SUCCESS)
3318 WARN ("RegCloseKey returned %li\n", r);
3319 return ret;
3322 ret = RegCloseKey (hkSubKey);
3323 if (ret != ERROR_SUCCESS)
3325 ERR ("RegCloseKey returned %li\n", ret);
3326 return ret;
3329 return ERROR_SUCCESS;
3332 /*******************************************************************************
3333 * EnumPrinterDataExA [WINSPOOL.@]
3335 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3336 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3337 * what Windows 2000 SP1 does.
3340 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3341 LPBYTE pEnumValues, DWORD cbEnumValues,
3342 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3344 INT len;
3345 LPWSTR pKeyNameW;
3346 DWORD ret, dwIndex, dwBufSize;
3347 HANDLE hHeap;
3348 LPSTR pBuffer;
3350 TRACE ("%p %s\n", hPrinter, pKeyName);
3352 if (pKeyName == NULL || *pKeyName == 0)
3353 return ERROR_INVALID_PARAMETER;
3355 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3356 if (len == 0)
3358 ret = GetLastError ();
3359 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3360 return ret;
3363 hHeap = GetProcessHeap ();
3364 if (hHeap == NULL)
3366 ERR ("GetProcessHeap failed\n");
3367 return ERROR_OUTOFMEMORY;
3370 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3371 if (pKeyNameW == NULL)
3373 ERR ("Failed to allocate %li bytes from process heap\n",
3374 (LONG) len * sizeof (WCHAR));
3375 return ERROR_OUTOFMEMORY;
3378 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3380 ret = GetLastError ();
3381 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3382 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3383 WARN ("HeapFree failed with code %li\n", GetLastError ());
3384 return ret;
3387 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3388 pcbEnumValues, pnEnumValues);
3389 if (ret != ERROR_SUCCESS)
3391 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3392 WARN ("HeapFree failed with code %li\n", GetLastError ());
3393 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3394 return ret;
3397 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3399 ret = GetLastError ();
3400 ERR ("HeapFree failed with code %li\n", ret);
3401 return ret;
3404 if (*pnEnumValues == 0) /* empty key */
3405 return ERROR_SUCCESS;
3407 dwBufSize = 0;
3408 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3410 PPRINTER_ENUM_VALUESW ppev =
3411 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3413 if (dwBufSize < ppev->cbValueName)
3414 dwBufSize = ppev->cbValueName;
3416 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3417 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3418 dwBufSize = ppev->cbData;
3421 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3423 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3424 if (pBuffer == NULL)
3426 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3427 return ERROR_OUTOFMEMORY;
3430 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3432 PPRINTER_ENUM_VALUESW ppev =
3433 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3435 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3436 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3437 NULL);
3438 if (len == 0)
3440 ret = GetLastError ();
3441 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3442 if (HeapFree (hHeap, 0, pBuffer) == 0)
3443 WARN ("HeapFree failed with code %li\n", GetLastError ());
3444 return ret;
3447 memcpy (ppev->pValueName, pBuffer, len);
3449 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3451 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3452 ppev->dwType != REG_MULTI_SZ)
3453 continue;
3455 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3456 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3457 if (len == 0)
3459 ret = GetLastError ();
3460 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3461 if (HeapFree (hHeap, 0, pBuffer) == 0)
3462 WARN ("HeapFree failed with code %li\n", GetLastError ());
3463 return ret;
3466 memcpy (ppev->pData, pBuffer, len);
3468 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3469 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3472 if (HeapFree (hHeap, 0, pBuffer) == 0)
3474 ret = GetLastError ();
3475 ERR ("HeapFree failed with code %li\n", ret);
3476 return ret;
3479 return ERROR_SUCCESS;