Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / dlls / winspool / info.c
blob733e6ba877b29596be4686aea713d2b188f105eb
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 <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stddef.h>
34 #ifdef HAVE_CUPS_CUPS_H
35 # include <cups/cups.h>
36 # ifndef SONAME_LIBCUPS
37 # define SONAME_LIBCUPS "libcups.so"
38 # endif
39 #endif
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
43 #include "wine/library.h"
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winuser.h"
47 #include "winerror.h"
48 #include "winreg.h"
49 #include "wingdi.h"
50 #include "winspool.h"
51 #include "winternl.h"
52 #include "wine/windef16.h"
53 #include "wine/unicode.h"
54 #include "wine/debug.h"
55 #include "heap.h"
56 #include "winnls.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
60 static LPWSTR *printer_array;
61 static int nb_printers;
63 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
64 WORD fwCapability, LPSTR lpszOutput,
65 LPDEVMODEA lpdm );
66 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
67 LPSTR lpszDevice, LPSTR lpszPort,
68 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
69 DWORD fwMode );
71 static char Printers[] =
72 "System\\CurrentControlSet\\control\\Print\\Printers\\";
73 static char Drivers[] =
74 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
76 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
78 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
79 'i','o','n',' ','F','i','l','e',0};
80 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
81 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
82 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
83 'M','o','d','e',0};
84 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
85 'i','l','e','s',0};
86 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
87 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
88 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
89 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
90 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
91 static WCHAR NameW[] = {'N','a','m','e',0};
92 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
93 static WCHAR PortW[] = {'P','o','r','t',0};
94 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
95 's','s','o','r',0};
96 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
97 'v','e','r',0};
98 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
99 'v','e','r','D','a','t','a',0};
100 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
101 'i','l','e',0};
102 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
103 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
105 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
106 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
107 DWORD Level, LPBYTE pDriverInfo,
108 DWORD cbBuf, LPDWORD pcbNeeded,
109 BOOL unicode);
111 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
112 if passed a NULL string. This returns NULLs to the result.
114 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
116 if ( (src) )
118 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
119 return usBufferPtr->Buffer;
121 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
122 return NULL;
125 static void
126 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
127 char qbuf[200];
129 /* If forcing, or no profile string entry for device yet, set the entry
131 * The always change entry if not WINEPS yet is discussable.
133 if (force ||
134 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
135 !strcmp(qbuf,"*") ||
136 !strstr(qbuf,"WINEPS")
138 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
140 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
141 WriteProfileStringA("windows","device",buf);
142 HeapFree(GetProcessHeap(),0,buf);
146 #ifdef HAVE_CUPS_CUPS_H
147 BOOL
148 CUPS_LoadPrinters(void) {
149 typeof(cupsGetDests) *pcupsGetDests = NULL;
150 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
151 int i, nrofdests;
152 BOOL hadprinter = FALSE;
153 cups_dest_t *dests;
154 PRINTER_INFO_2A pinfo2a;
155 void *cupshandle = NULL;
156 const char *ppd;
157 char *port,*devline;
158 UNICODE_STRING lpszNameW;
159 PWSTR pwstrNameW;
160 HKEY hkeyPrinters, hkeyPrinter;
162 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
163 if (!cupshandle)
164 return FALSE;
165 TRACE("loaded %s\n", SONAME_LIBCUPS);
167 #define DYNCUPS(x) \
168 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
169 if (!p##x) return FALSE;
171 DYNCUPS(cupsGetPPD);
172 DYNCUPS(cupsGetDests);
173 #undef DYNCUPS
176 nrofdests = pcupsGetDests(&dests);
177 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
178 for (i=0;i<nrofdests;i++) {
179 /* First check that the printer doesn't exist already */
180 pwstrNameW = asciitounicode(&lpszNameW, dests[i].name);
181 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) ==
182 ERROR_SUCCESS) {
183 if (RegOpenKeyW(hkeyPrinters, pwstrNameW, &hkeyPrinter) ==
184 ERROR_SUCCESS) {
185 /* We know this printer already */
186 RegCloseKey(hkeyPrinter);
187 RegCloseKey(hkeyPrinters);
188 RtlFreeUnicodeString(&lpszNameW);
189 hadprinter = TRUE;
190 if(dests[i].is_default)
191 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
192 TRACE("Printer %s already known. Skipping detection\n", dests[i].name);
193 continue;
195 RegCloseKey(hkeyPrinters);
197 RtlFreeUnicodeString(&lpszNameW);
199 /* OK, we haven't seen this one yet. Request PPD for it */
200 ppd = pcupsGetPPD(dests[i].name);
201 if (!ppd) {
202 WARN("No ppd file for %s.\n",dests[i].name);
203 /* If this was going to be the default printer,
204 * forget it and use another one.
206 continue;
208 unlink(ppd);
210 memset(&pinfo2a,0,sizeof(pinfo2a));
211 pinfo2a.pPrinterName = dests[i].name;
212 pinfo2a.pDatatype = "RAW";
213 pinfo2a.pPrintProcessor = "WinPrint";
214 pinfo2a.pDriverName = "PS Driver";
215 pinfo2a.pComment = "WINEPS Printer using CUPS";
216 pinfo2a.pLocation = "<physical location of printer>";
217 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
218 sprintf(port,"LPR:%s",dests[i].name);
219 pinfo2a.pPortName = port;
220 pinfo2a.pParameters = "<parameters?>";
221 pinfo2a.pShareName = "<share name?>";
222 pinfo2a.pSepFile = "<sep file?>";
224 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
225 sprintf(devline,"WINEPS,%s",port);
226 WriteProfileStringA("devices",dests[i].name,devline);
227 HeapFree(GetProcessHeap(),0,devline);
229 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
230 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
231 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
233 HeapFree(GetProcessHeap(),0,port);
235 hadprinter = TRUE;
236 if (dests[i].is_default)
237 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
239 wine_dlclose(cupshandle, NULL, 0);
240 return hadprinter;
242 #endif
244 static BOOL
245 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
246 PRINTER_INFO_2A pinfo2a;
247 char *s,*name,*prettyname,*devname;
248 BOOL isps = FALSE;
249 char *port,*devline;
251 while (isspace(*pent)) pent++;
252 s = strchr(pent,':');
253 if (!s) return FALSE;
254 *s='\0';
255 name = pent;
256 pent = s+1;
257 TRACE("%s\n",name);
259 /* Determine whether this is a postscript printer. */
261 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
262 if (strstr(name,"ps") ||
263 strstr(name,"pd") || /* postscript double page */
264 strstr(name,"postscript") ||
265 strstr(name,"PostScript")
267 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
268 isps = TRUE;
270 /* 2. Check if this is a remote printer. These usually are postscript
271 * capable
273 if (strstr(pent,":rm")) {
274 isps = TRUE;
275 TRACE("%s is remote, assuming postscript.\n",name);
277 /* 3. Check if we have an input filter program. If we have one, it
278 * most likely is one capable of converting postscript.
279 * (Could probably check for occurrence of 'gs' or 'ghostscript'
280 * in the if file itself.)
282 if (strstr(pent,":if=/")) {
283 isps = TRUE;
284 TRACE("%s has inputfilter program, assuming postscript.\n",name);
287 /* If it is not a postscript printer, we cannot use it. */
288 if (!isps)
289 return FALSE;
291 prettyname = name;
292 /* Get longest name, usually the one at the right for later display. */
293 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
294 s=strchr(name,'|');if (s) *s='\0';
296 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
297 * if it is too long, we use it as comment below. */
298 devname = prettyname;
299 if (strlen(devname)>=CCHDEVICENAME-1)
300 devname = name;
301 if (strlen(devname)>=CCHDEVICENAME-1)
302 return FALSE;
304 if (isfirst) /* set first entry as default */
305 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
307 memset(&pinfo2a,0,sizeof(pinfo2a));
308 pinfo2a.pPrinterName = devname;
309 pinfo2a.pDatatype = "RAW";
310 pinfo2a.pPrintProcessor = "WinPrint";
311 pinfo2a.pDriverName = "PS Driver";
312 pinfo2a.pComment = "WINEPS Printer using LPR";
313 pinfo2a.pLocation = prettyname;
314 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
315 sprintf(port,"LPR:%s",name);
316 pinfo2a.pPortName = port;
317 pinfo2a.pParameters = "<parameters?>";
318 pinfo2a.pShareName = "<share name?>";
319 pinfo2a.pSepFile = "<sep file?>";
321 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
322 sprintf(devline,"WINEPS,%s",port);
323 WriteProfileStringA("devices",devname,devline);
324 HeapFree(GetProcessHeap(),0,devline);
326 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
327 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
328 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
330 HeapFree(GetProcessHeap(),0,port);
331 return TRUE;
334 static BOOL
335 PRINTCAP_LoadPrinters(void) {
336 BOOL hadprinter = FALSE, isfirst = TRUE;
337 char buf[200];
338 FILE *f;
340 f = fopen("/etc/printcap","r");
341 if (!f)
342 return FALSE;
344 while (fgets(buf,sizeof(buf),f)) {
345 char *pent = NULL;
346 do {
347 char *s;
348 s=strchr(buf,'\n'); if (s) *s='\0';
349 if ((buf[0]=='#') || (buf[0]=='\0'))
350 continue;
352 if (pent) {
353 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
354 strcat(pent,buf);
355 } else {
356 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
357 strcpy(pent,buf);
360 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
361 pent[strlen(pent)-1] = '\0';
362 else
363 break;
364 } while (fgets(buf,sizeof(buf),f));
365 if (pent)
366 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
367 isfirst = FALSE;
368 if (pent) HeapFree(GetProcessHeap(),0,pent);
369 pent = NULL;
370 if (feof(f)) break;
372 fclose(f);
373 return hadprinter;
376 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
378 if (value)
379 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
380 lstrlenW(value) * sizeof(WCHAR));
381 else
382 return ERROR_FILE_NOT_FOUND;
385 void
386 WINSPOOL_LoadSystemPrinters() {
387 HKEY hkPPD;
388 DRIVER_INFO_3A di3a;
389 di3a.cVersion = 0x400;
390 di3a.pName = "PS Driver";
391 di3a.pEnvironment = NULL; /* NULL means auto */
392 di3a.pDriverPath = "wineps16";
393 di3a.pDataFile = "<datafile?>";
394 di3a.pConfigFile = "wineps16";
395 di3a.pHelpFile = "<helpfile?>";
396 di3a.pDependentFiles = "<dependend files?>";
397 di3a.pMonitorName = "<monitor name?>";
398 di3a.pDefaultDataType = "RAW";
400 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
401 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
402 return;
404 #ifdef HAVE_CUPS_CUPS_H
405 /* If we have any CUPS based printers, skip looking for printcap printers */
406 if (CUPS_LoadPrinters())
407 return;
408 #endif
410 /* Check for [ppd] section in config file before parsing /etc/printcap */
412 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
413 &hkPPD) == ERROR_SUCCESS)
415 RegCloseKey(hkPPD);
416 PRINTCAP_LoadPrinters();
421 /******************************************************************
422 * WINSPOOL_GetOpenedPrinterEntry
423 * Get the first place empty in the opened printer table
425 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
427 int i;
429 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
431 if (i >= nb_printers)
433 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
434 (nb_printers + 16) * sizeof(*new_array) );
435 if (!new_array) return 0;
436 printer_array = new_array;
437 nb_printers += 16;
440 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
442 strcpyW( printer_array[i], name );
443 return (HANDLE)(i + 1);
445 return 0;
448 /******************************************************************
449 * WINSPOOL_GetOpenedPrinter
450 * Get the pointer to the opened printer referred by the handle
452 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
454 int idx = (int)printerHandle;
455 if ((idx <= 0) || (idx > nb_printers))
457 SetLastError(ERROR_INVALID_HANDLE);
458 return NULL;
460 return printer_array[idx - 1];
463 /******************************************************************
464 * WINSPOOL_GetOpenedPrinterRegKey
467 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
469 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
470 DWORD ret;
471 HKEY hkeyPrinters;
473 if(!name) return ERROR_INVALID_HANDLE;
475 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
476 ERROR_SUCCESS)
477 return ret;
479 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
481 ERR("Can't find opened printer %s in registry\n",
482 debugstr_w(name));
483 RegCloseKey(hkeyPrinters);
484 return ERROR_INVALID_PRINTER_NAME; /* ? */
486 RegCloseKey(hkeyPrinters);
487 return ERROR_SUCCESS;
490 /***********************************************************
491 * DEVMODEcpyAtoW
493 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
495 BOOL Formname;
496 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
497 DWORD size;
499 Formname = (dmA->dmSize > off_formname);
500 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
501 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
502 CCHDEVICENAME);
503 if(!Formname) {
504 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
505 dmA->dmSize - CCHDEVICENAME);
506 } else {
507 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
508 off_formname - CCHDEVICENAME);
509 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
510 CCHFORMNAME);
511 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
512 (off_formname + CCHFORMNAME));
514 dmW->dmSize = size;
515 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
516 dmA->dmDriverExtra);
517 return dmW;
520 /***********************************************************
521 * DEVMODEdupWtoA
522 * Creates an ascii copy of supplied devmode on heap
524 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
526 LPDEVMODEA dmA;
527 DWORD size;
528 BOOL Formname;
529 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
531 if(!dmW) return NULL;
532 Formname = (dmW->dmSize > off_formname);
533 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
534 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
535 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
536 CCHDEVICENAME, NULL, NULL);
537 if(!Formname) {
538 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
539 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
540 } else {
541 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
542 off_formname - CCHDEVICENAME * sizeof(WCHAR));
543 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
544 CCHFORMNAME, NULL, NULL);
545 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
546 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
548 dmA->dmSize = size;
549 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
550 dmW->dmDriverExtra);
551 return dmA;
554 /***********************************************************
555 * PRINTER_INFO_2AtoW
556 * Creates a unicode copy of PRINTER_INFO_2A on heap
558 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
560 LPPRINTER_INFO_2W piW;
561 UNICODE_STRING usBuffer;
563 if(!piA) return NULL;
564 piW = HeapAlloc(heap, 0, sizeof(*piW));
565 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
567 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
568 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
569 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
570 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
571 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
572 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
573 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
574 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
575 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
576 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
577 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
578 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
579 return piW;
582 /***********************************************************
583 * FREE_PRINTER_INFO_2W
584 * Free PRINTER_INFO_2W and all strings
586 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
588 if(!piW) return;
590 HeapFree(heap,0,piW->pServerName);
591 HeapFree(heap,0,piW->pPrinterName);
592 HeapFree(heap,0,piW->pShareName);
593 HeapFree(heap,0,piW->pPortName);
594 HeapFree(heap,0,piW->pDriverName);
595 HeapFree(heap,0,piW->pComment);
596 HeapFree(heap,0,piW->pLocation);
597 HeapFree(heap,0,piW->pDevMode);
598 HeapFree(heap,0,piW->pSepFile);
599 HeapFree(heap,0,piW->pPrintProcessor);
600 HeapFree(heap,0,piW->pDatatype);
601 HeapFree(heap,0,piW->pParameters);
602 HeapFree(heap,0,piW);
603 return;
606 /******************************************************************
607 * DeviceCapabilities [WINSPOOL.@]
608 * DeviceCapabilitiesA [WINSPOOL.@]
611 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
612 LPSTR pOutput, LPDEVMODEA lpdm)
614 INT ret;
616 if (!GDI_CallDeviceCapabilities16)
618 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
619 (LPCSTR)104 );
620 if (!GDI_CallDeviceCapabilities16) return -1;
622 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
624 /* If DC_PAPERSIZE map POINT16s to POINTs */
625 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
626 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
627 POINT *pt = (POINT *)pOutput;
628 INT i;
629 memcpy(tmp, pOutput, ret * sizeof(POINT16));
630 for(i = 0; i < ret; i++, pt++)
632 pt->x = tmp[i].x;
633 pt->y = tmp[i].y;
635 HeapFree( GetProcessHeap(), 0, tmp );
637 return ret;
641 /*****************************************************************************
642 * DeviceCapabilitiesW [WINSPOOL.@]
644 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
647 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
648 WORD fwCapability, LPWSTR pOutput,
649 const DEVMODEW *pDevMode)
651 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
652 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
653 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
654 INT ret;
656 if(pOutput && (fwCapability == DC_BINNAMES ||
657 fwCapability == DC_FILEDEPENDENCIES ||
658 fwCapability == DC_PAPERNAMES)) {
659 /* These need A -> W translation */
660 INT size = 0, i;
661 LPSTR pOutputA;
662 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
663 dmA);
664 if(ret == -1)
665 return ret;
666 switch(fwCapability) {
667 case DC_BINNAMES:
668 size = 24;
669 break;
670 case DC_PAPERNAMES:
671 case DC_FILEDEPENDENCIES:
672 size = 64;
673 break;
675 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
676 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
677 dmA);
678 for(i = 0; i < ret; i++)
679 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
680 pOutput + (i * size), size);
681 HeapFree(GetProcessHeap(), 0, pOutputA);
682 } else {
683 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
684 (LPSTR)pOutput, dmA);
686 HeapFree(GetProcessHeap(),0,pPortA);
687 HeapFree(GetProcessHeap(),0,pDeviceA);
688 HeapFree(GetProcessHeap(),0,dmA);
689 return ret;
692 /******************************************************************
693 * DocumentPropertiesA [WINSPOOL.@]
695 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
697 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
698 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
699 LPDEVMODEA pDevModeInput,DWORD fMode )
701 LPSTR lpName = pDeviceName;
702 LONG ret;
704 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
705 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
708 if(!pDeviceName) {
709 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
710 if(!lpNameW) {
711 ERR("no name from hPrinter?\n");
712 return -1;
714 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
717 if (!GDI_CallExtDeviceMode16)
719 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
720 (LPCSTR)102 );
721 if (!GDI_CallExtDeviceMode16) {
722 ERR("No CallExtDeviceMode16?\n");
723 return -1;
726 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
727 pDevModeInput, NULL, fMode);
729 if(!pDeviceName)
730 HeapFree(GetProcessHeap(),0,lpName);
731 return ret;
735 /*****************************************************************************
736 * DocumentPropertiesW (WINSPOOL.@)
738 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
740 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
741 LPWSTR pDeviceName,
742 LPDEVMODEW pDevModeOutput,
743 LPDEVMODEW pDevModeInput, DWORD fMode)
746 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
747 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
748 LPDEVMODEA pDevModeOutputA = NULL;
749 LONG ret;
751 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
752 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
753 fMode);
754 if(pDevModeOutput) {
755 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
756 if(ret < 0) return ret;
757 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
759 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
760 pDevModeInputA, fMode);
761 if(pDevModeOutput) {
762 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
763 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
765 if(fMode == 0 && ret > 0)
766 ret += (CCHDEVICENAME + CCHFORMNAME);
767 HeapFree(GetProcessHeap(),0,pDevModeInputA);
768 HeapFree(GetProcessHeap(),0,pDeviceNameA);
769 return ret;
772 /******************************************************************
773 * OpenPrinterA [WINSPOOL.@]
776 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
777 LPPRINTER_DEFAULTSA pDefault)
779 UNICODE_STRING lpPrinterNameW;
780 UNICODE_STRING usBuffer;
781 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
782 PWSTR pwstrPrinterNameW;
783 BOOL ret;
785 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
787 if(pDefault) {
788 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
789 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
790 DefaultW.DesiredAccess = pDefault->DesiredAccess;
791 pDefaultW = &DefaultW;
793 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
794 if(pDefault) {
795 RtlFreeUnicodeString(&usBuffer);
796 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
798 RtlFreeUnicodeString(&lpPrinterNameW);
799 return ret;
802 /******************************************************************
803 * OpenPrinterW [WINSPOOL.@]
806 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
807 LPPRINTER_DEFAULTSW pDefault)
809 HKEY hkeyPrinters, hkeyPrinter;
811 if (!lpPrinterName) {
812 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
813 SetLastError(ERROR_INVALID_PARAMETER);
814 return FALSE;
817 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
818 pDefault);
820 /* Check Printer exists */
821 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
822 ERROR_SUCCESS) {
823 ERR("Can't create Printers key\n");
824 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
825 return FALSE;
828 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
829 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
830 != ERROR_SUCCESS) {
831 TRACE("Can't find printer %s in registry\n",
832 debugstr_w(lpPrinterName));
833 RegCloseKey(hkeyPrinters);
834 SetLastError(ERROR_INVALID_PRINTER_NAME);
835 return FALSE;
837 RegCloseKey(hkeyPrinter);
838 RegCloseKey(hkeyPrinters);
840 if(!phPrinter) /* This seems to be what win95 does anyway */
841 return TRUE;
843 /* Get the unique handle of the printer*/
844 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
846 if (pDefault != NULL)
847 FIXME("Not handling pDefault\n");
849 return TRUE;
852 /******************************************************************
853 * AddMonitorA [WINSPOOL.@]
856 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
858 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
859 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
860 return FALSE;
863 /******************************************************************
864 * DeletePrinterDriverA [WINSPOOL.@]
867 BOOL WINAPI
868 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
870 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
871 debugstr_a(pDriverName));
872 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
873 return FALSE;
877 /******************************************************************
878 * DeleteMonitorA [WINSPOOL.@]
881 BOOL WINAPI
882 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
884 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
885 debugstr_a(pMonitorName));
886 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
887 return FALSE;
891 /******************************************************************
892 * DeletePortA [WINSPOOL.@]
895 BOOL WINAPI
896 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
898 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
899 debugstr_a(pPortName));
900 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
901 return FALSE;
904 /******************************************************************************
905 * SetPrinterW [WINSPOOL.@]
907 BOOL WINAPI
908 SetPrinterW(
909 HANDLE hPrinter,
910 DWORD Level,
911 LPBYTE pPrinter,
912 DWORD Command) {
914 FIXME("():stub\n");
915 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
916 return FALSE;
919 /******************************************************************************
920 * WritePrinter [WINSPOOL.@]
922 BOOL WINAPI
923 WritePrinter(
924 HANDLE hPrinter,
925 LPVOID pBuf,
926 DWORD cbBuf,
927 LPDWORD pcWritten) {
929 FIXME("():stub\n");
930 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
931 return FALSE;
934 /*****************************************************************************
935 * AddFormA [WINSPOOL.@]
937 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
939 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
940 return 1;
943 /*****************************************************************************
944 * AddFormW [WINSPOOL.@]
946 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
948 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
949 return 1;
952 /*****************************************************************************
953 * AddJobA [WINSPOOL.@]
955 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
956 DWORD cbBuf, LPDWORD pcbNeeded)
958 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
959 pcbNeeded);
960 return 1;
963 /*****************************************************************************
964 * AddJobW [WINSPOOL.@]
966 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
967 LPDWORD pcbNeeded)
969 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
970 pcbNeeded);
971 return 1;
974 /*****************************************************************************
975 * GetPrintProcessorDirectoryA [WINSPOOL.@]
977 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR environ,
978 DWORD level, LPBYTE Info,
979 DWORD cbBuf, LPDWORD needed)
981 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", server, environ, level, Info,
982 cbBuf);
983 return 0;
986 /*****************************************************************************
987 * WINSPOOL_OpenDriverReg [internal]
989 * opens the registry for the printer drivers depending on the given input
990 * variable pEnvironment
992 * RETURNS:
993 * the opened hkey on success
994 * NULL on error
996 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
997 { HKEY retval;
998 LPSTR lpKey, p = NULL;
1000 TRACE("%s\n",
1001 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1003 if(pEnvironment)
1004 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1005 pEnvironment;
1006 else {
1007 OSVERSIONINFOA ver;
1008 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1010 if(!GetVersionExA( &ver))
1011 return 0;
1013 switch (ver.dwPlatformId) {
1014 case VER_PLATFORM_WIN32s:
1015 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1016 return 0;
1018 case VER_PLATFORM_WIN32_NT:
1019 p = "Windows NT x86";
1020 break;
1021 default:
1022 p = "Windows 4.0";
1023 break;
1025 TRACE("set environment to %s\n", p);
1028 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1029 strlen(p) + strlen(Drivers));
1030 sprintf( lpKey, Drivers, p);
1032 TRACE("%s\n", lpKey);
1034 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1035 ERROR_SUCCESS)
1036 retval = 0;
1038 if(pEnvironment && unicode)
1039 HeapFree( GetProcessHeap(), 0, p);
1040 HeapFree( GetProcessHeap(), 0, lpKey);
1042 return retval;
1045 /*****************************************************************************
1046 * AddPrinterW [WINSPOOL.@]
1048 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1050 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1051 LPDEVMODEA dmA;
1052 LPDEVMODEW dmW;
1053 HANDLE retval;
1054 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1055 LONG size;
1057 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1059 if(pName != NULL) {
1060 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1061 SetLastError(ERROR_INVALID_PARAMETER);
1062 return 0;
1064 if(Level != 2) {
1065 ERR("Level = %ld, unsupported!\n", Level);
1066 SetLastError(ERROR_INVALID_LEVEL);
1067 return 0;
1069 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1070 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1071 debugstr_w(pi->pPrinterName)
1073 SetLastError(ERROR_INVALID_LEVEL);
1074 return 0;
1076 if(!pPrinter) {
1077 SetLastError(ERROR_INVALID_PARAMETER);
1078 return 0;
1080 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1081 ERROR_SUCCESS) {
1082 ERR("Can't create Printers key\n");
1083 return 0;
1085 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1086 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1087 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1088 RegCloseKey(hkeyPrinter);
1089 RegCloseKey(hkeyPrinters);
1090 return 0;
1092 RegCloseKey(hkeyPrinter);
1094 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1095 if(!hkeyDrivers) {
1096 ERR("Can't create Drivers key\n");
1097 RegCloseKey(hkeyPrinters);
1098 return 0;
1100 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1101 ERROR_SUCCESS) {
1102 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1103 RegCloseKey(hkeyPrinters);
1104 RegCloseKey(hkeyDrivers);
1105 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1106 return 0;
1108 RegCloseKey(hkeyDriver);
1109 RegCloseKey(hkeyDrivers);
1111 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1112 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1113 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1114 RegCloseKey(hkeyPrinters);
1115 return 0;
1118 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1119 ERROR_SUCCESS) {
1120 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1121 SetLastError(ERROR_INVALID_PRINTER_NAME);
1122 RegCloseKey(hkeyPrinters);
1123 return 0;
1125 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1126 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1127 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1129 /* See if we can load the driver. We may need the devmode structure anyway
1131 * FIXME:
1132 * Note that DocumentPropertiesW will briefly try to open the printer we
1133 * just create to find a DEVMODEA struct (it will use the WINEPS default
1134 * one in case it is not there, so we are ok).
1136 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1138 if(size < 0) {
1139 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1140 size = sizeof(DEVMODEW);
1142 if(pi->pDevMode)
1143 dmW = pi->pDevMode;
1144 else
1146 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1147 ZeroMemory(dmW,size);
1148 dmW->dmSize = size;
1149 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1151 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1152 HeapFree(GetProcessHeap(),0,dmW);
1153 dmW=NULL;
1155 else
1157 /* set devmode to printer name */
1158 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1162 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1163 and we support these drivers. NT writes DEVMODEW so somehow
1164 we'll need to distinguish between these when we support NT
1165 drivers */
1166 if (dmW)
1168 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1169 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1170 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1171 HeapFree(GetProcessHeap(), 0, dmA);
1172 if(!pi->pDevMode)
1173 HeapFree(GetProcessHeap(), 0, dmW);
1175 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1176 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1177 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1178 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1180 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1181 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1182 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1183 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1184 (LPBYTE)&pi->Priority, sizeof(DWORD));
1185 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1186 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1187 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1188 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1189 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1190 (LPBYTE)&pi->Status, sizeof(DWORD));
1191 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1192 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1194 RegCloseKey(hkeyPrinter);
1195 RegCloseKey(hkeyPrinters);
1196 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1197 ERR("OpenPrinter failing\n");
1198 return 0;
1200 return retval;
1203 /*****************************************************************************
1204 * AddPrinterA [WINSPOOL.@]
1206 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1208 UNICODE_STRING pNameW;
1209 PWSTR pwstrNameW;
1210 PRINTER_INFO_2W *piW;
1211 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1212 HANDLE ret;
1214 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1215 if(Level != 2) {
1216 ERR("Level = %ld, unsupported!\n", Level);
1217 SetLastError(ERROR_INVALID_LEVEL);
1218 return 0;
1220 pwstrNameW = asciitounicode(&pNameW,pName);
1221 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1223 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1225 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1226 RtlFreeUnicodeString(&pNameW);
1227 return ret;
1231 /*****************************************************************************
1232 * ClosePrinter [WINSPOOL.@]
1234 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1236 int i = (int)hPrinter;
1238 TRACE("Handle %p\n", hPrinter);
1240 if ((i <= 0) || (i > nb_printers)) return FALSE;
1241 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1242 printer_array[i - 1] = NULL;
1243 return TRUE;
1246 /*****************************************************************************
1247 * DeleteFormA [WINSPOOL.@]
1249 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1251 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1252 return 1;
1255 /*****************************************************************************
1256 * DeleteFormW [WINSPOOL.@]
1258 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1260 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1261 return 1;
1264 /*****************************************************************************
1265 * DeletePrinter [WINSPOOL.@]
1267 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1269 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1270 HKEY hkeyPrinters;
1272 if(!lpNameW) return FALSE;
1273 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1274 ERROR_SUCCESS) {
1275 ERR("Can't open Printers key\n");
1276 return 0;
1279 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1280 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1281 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1282 RegCloseKey(hkeyPrinters);
1283 return 0;
1286 ClosePrinter(hPrinter);
1287 return TRUE;
1290 /*****************************************************************************
1291 * SetPrinterA [WINSPOOL.@]
1293 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1294 DWORD Command)
1296 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1297 return FALSE;
1300 /*****************************************************************************
1301 * SetJobA [WINSPOOL.@]
1303 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1304 LPBYTE pJob, DWORD Command)
1306 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1307 Command);
1308 return FALSE;
1311 /*****************************************************************************
1312 * SetJobW [WINSPOOL.@]
1314 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1315 LPBYTE pJob, DWORD Command)
1317 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1318 Command);
1319 return FALSE;
1322 /*****************************************************************************
1323 * EndDocPrinter [WINSPOOL.@]
1325 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1327 FIXME("(hPrinter=%p): stub\n", hPrinter);
1328 return FALSE;
1331 /*****************************************************************************
1332 * EndPagePrinter [WINSPOOL.@]
1334 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1336 FIXME("(hPrinter=%p): stub\n", hPrinter);
1337 return FALSE;
1340 /*****************************************************************************
1341 * StartDocPrinterA [WINSPOOL.@]
1343 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1345 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1346 return FALSE;
1349 /*****************************************************************************
1350 * StartDocPrinterW [WINSPOOL.@]
1352 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1354 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1355 return FALSE;
1358 /*****************************************************************************
1359 * StartPagePrinter [WINSPOOL.@]
1361 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1363 FIXME("(hPrinter=%p): stub\n", hPrinter);
1364 return FALSE;
1367 /*****************************************************************************
1368 * GetFormA [WINSPOOL.@]
1370 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1371 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1373 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1374 Level,pForm,cbBuf,pcbNeeded);
1375 return FALSE;
1378 /*****************************************************************************
1379 * GetFormW [WINSPOOL.@]
1381 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1382 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1384 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1385 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1386 return FALSE;
1389 /*****************************************************************************
1390 * SetFormA [WINSPOOL.@]
1392 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1393 LPBYTE pForm)
1395 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1396 return FALSE;
1399 /*****************************************************************************
1400 * SetFormW [WINSPOOL.@]
1402 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1403 LPBYTE pForm)
1405 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1406 return FALSE;
1409 /*****************************************************************************
1410 * ReadPrinter [WINSPOOL.@]
1412 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1413 LPDWORD pNoBytesRead)
1415 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1416 return FALSE;
1419 /*****************************************************************************
1420 * ResetPrinterA [WINSPOOL.@]
1422 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1424 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1425 return FALSE;
1428 /*****************************************************************************
1429 * ResetPrinterW [WINSPOOL.@]
1431 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1433 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1434 return FALSE;
1437 /*****************************************************************************
1438 * WINSPOOL_GetDWORDFromReg
1440 * Return DWORD associated with ValueName from hkey.
1442 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1444 DWORD sz = sizeof(DWORD), type, value = 0;
1445 LONG ret;
1447 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1449 if(ret != ERROR_SUCCESS) {
1450 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1451 return 0;
1453 if(type != REG_DWORD) {
1454 ERR("Got type %ld\n", type);
1455 return 0;
1457 return value;
1460 /*****************************************************************************
1461 * WINSPOOL_GetStringFromReg
1463 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1464 * String is stored either as unicode or ascii.
1465 * Bit of a hack here to get the ValueName if we want ascii.
1467 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1468 DWORD buflen, DWORD *needed,
1469 BOOL unicode)
1471 DWORD sz = buflen, type;
1472 LONG ret;
1474 if(unicode)
1475 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1476 else {
1477 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1478 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1479 HeapFree(GetProcessHeap(),0,ValueNameA);
1481 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1482 WARN("Got ret = %ld\n", ret);
1483 *needed = 0;
1484 return FALSE;
1486 *needed = sz;
1487 return TRUE;
1490 /*****************************************************************************
1491 * WINSPOOL_GetDefaultDevMode
1493 * Get a default DevMode values for wineps.
1494 * FIXME - use ppd.
1497 static void WINSPOOL_GetDefaultDevMode(
1498 LPBYTE ptr,
1499 DWORD buflen, DWORD *needed,
1500 BOOL unicode)
1502 DEVMODEA dm;
1504 /* fill default DEVMODE - should be read from ppd... */
1505 ZeroMemory( &dm, sizeof(dm) );
1506 strcpy(dm.dmDeviceName,"wineps");
1507 dm.dmSpecVersion = DM_SPECVERSION;
1508 dm.dmDriverVersion = 1;
1509 dm.dmSize = sizeof(DEVMODEA);
1510 dm.dmDriverExtra = 0;
1511 dm.dmFields =
1512 DM_ORIENTATION | DM_PAPERSIZE |
1513 DM_PAPERLENGTH | DM_PAPERWIDTH |
1514 DM_SCALE |
1515 DM_COPIES |
1516 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1517 DM_YRESOLUTION | DM_TTOPTION;
1519 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1520 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1521 dm.u1.s1.dmPaperLength = 2970;
1522 dm.u1.s1.dmPaperWidth = 2100;
1524 dm.dmScale = 100;
1525 dm.dmCopies = 1;
1526 dm.dmDefaultSource = DMBIN_AUTO;
1527 dm.dmPrintQuality = DMRES_MEDIUM;
1528 /* dm.dmColor */
1529 /* dm.dmDuplex */
1530 dm.dmYResolution = 300; /* 300dpi */
1531 dm.dmTTOption = DMTT_BITMAP;
1532 /* dm.dmCollate */
1533 /* dm.dmFormName */
1534 /* dm.dmLogPixels */
1535 /* dm.dmBitsPerPel */
1536 /* dm.dmPelsWidth */
1537 /* dm.dmPelsHeight */
1538 /* dm.dmDisplayFlags */
1539 /* dm.dmDisplayFrequency */
1540 /* dm.dmICMMethod */
1541 /* dm.dmICMIntent */
1542 /* dm.dmMediaType */
1543 /* dm.dmDitherType */
1544 /* dm.dmReserved1 */
1545 /* dm.dmReserved2 */
1546 /* dm.dmPanningWidth */
1547 /* dm.dmPanningHeight */
1549 if(unicode) {
1550 if(buflen >= sizeof(DEVMODEW)) {
1551 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1552 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1553 HeapFree(GetProcessHeap(),0,pdmW);
1555 *needed = sizeof(DEVMODEW);
1557 else
1559 if(buflen >= sizeof(DEVMODEA)) {
1560 memcpy(ptr, &dm, sizeof(DEVMODEA));
1562 *needed = sizeof(DEVMODEA);
1566 /*****************************************************************************
1567 * WINSPOOL_GetDevModeFromReg
1569 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1570 * DevMode is stored either as unicode or ascii.
1572 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1573 LPBYTE ptr,
1574 DWORD buflen, DWORD *needed,
1575 BOOL unicode)
1577 DWORD sz = buflen, type;
1578 LONG ret;
1580 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1581 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1582 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1583 if (sz < sizeof(DEVMODEA))
1585 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1586 return FALSE;
1588 /* ensures that dmSize is not erratically bogus if registry is invalid */
1589 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1590 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1591 if(unicode) {
1592 sz += (CCHDEVICENAME + CCHFORMNAME);
1593 if(buflen >= sz) {
1594 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1595 memcpy(ptr, dmW, sz);
1596 HeapFree(GetProcessHeap(),0,dmW);
1599 *needed = sz;
1600 return TRUE;
1603 /*********************************************************************
1604 * WINSPOOL_GetPrinter_2
1606 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1607 * The strings are either stored as unicode or ascii.
1609 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1610 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1611 BOOL unicode)
1613 DWORD size, left = cbBuf;
1614 BOOL space = (cbBuf > 0);
1615 LPBYTE ptr = buf;
1617 *pcbNeeded = 0;
1619 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1620 unicode)) {
1621 if(space && size <= left) {
1622 pi2->pPrinterName = (LPWSTR)ptr;
1623 ptr += size;
1624 left -= size;
1625 } else
1626 space = FALSE;
1627 *pcbNeeded += size;
1629 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1630 unicode)) {
1631 if(space && size <= left) {
1632 pi2->pShareName = (LPWSTR)ptr;
1633 ptr += size;
1634 left -= size;
1635 } else
1636 space = FALSE;
1637 *pcbNeeded += size;
1639 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1640 unicode)) {
1641 if(space && size <= left) {
1642 pi2->pPortName = (LPWSTR)ptr;
1643 ptr += size;
1644 left -= size;
1645 } else
1646 space = FALSE;
1647 *pcbNeeded += size;
1649 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1650 &size, unicode)) {
1651 if(space && size <= left) {
1652 pi2->pDriverName = (LPWSTR)ptr;
1653 ptr += size;
1654 left -= size;
1655 } else
1656 space = FALSE;
1657 *pcbNeeded += size;
1659 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1660 unicode)) {
1661 if(space && size <= left) {
1662 pi2->pComment = (LPWSTR)ptr;
1663 ptr += size;
1664 left -= size;
1665 } else
1666 space = FALSE;
1667 *pcbNeeded += size;
1669 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1670 unicode)) {
1671 if(space && size <= left) {
1672 pi2->pLocation = (LPWSTR)ptr;
1673 ptr += size;
1674 left -= size;
1675 } else
1676 space = FALSE;
1677 *pcbNeeded += size;
1679 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1680 &size, unicode)) {
1681 if(space && size <= left) {
1682 pi2->pDevMode = (LPDEVMODEW)ptr;
1683 ptr += size;
1684 left -= size;
1685 } else
1686 space = FALSE;
1687 *pcbNeeded += size;
1689 else
1691 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1692 if(space && size <= left) {
1693 pi2->pDevMode = (LPDEVMODEW)ptr;
1694 ptr += size;
1695 left -= size;
1696 } else
1697 space = FALSE;
1698 *pcbNeeded += size;
1700 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1701 &size, unicode)) {
1702 if(space && size <= left) {
1703 pi2->pSepFile = (LPWSTR)ptr;
1704 ptr += size;
1705 left -= size;
1706 } else
1707 space = FALSE;
1708 *pcbNeeded += size;
1710 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1711 &size, unicode)) {
1712 if(space && size <= left) {
1713 pi2->pPrintProcessor = (LPWSTR)ptr;
1714 ptr += size;
1715 left -= size;
1716 } else
1717 space = FALSE;
1718 *pcbNeeded += size;
1720 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1721 &size, unicode)) {
1722 if(space && size <= left) {
1723 pi2->pDatatype = (LPWSTR)ptr;
1724 ptr += size;
1725 left -= size;
1726 } else
1727 space = FALSE;
1728 *pcbNeeded += size;
1730 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1731 &size, unicode)) {
1732 if(space && size <= left) {
1733 pi2->pParameters = (LPWSTR)ptr;
1734 ptr += size;
1735 left -= size;
1736 } else
1737 space = FALSE;
1738 *pcbNeeded += size;
1740 if(pi2) {
1741 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1742 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1743 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1744 "Default Priority");
1745 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1746 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1749 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1750 memset(pi2, 0, sizeof(*pi2));
1752 return space;
1755 /*********************************************************************
1756 * WINSPOOL_GetPrinter_4
1758 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1760 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1761 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1762 BOOL unicode)
1764 DWORD size, left = cbBuf;
1765 BOOL space = (cbBuf > 0);
1766 LPBYTE ptr = buf;
1768 *pcbNeeded = 0;
1770 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1771 unicode)) {
1772 if(space && size <= left) {
1773 pi4->pPrinterName = (LPWSTR)ptr;
1774 ptr += size;
1775 left -= size;
1776 } else
1777 space = FALSE;
1778 *pcbNeeded += size;
1780 if(pi4) {
1781 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1784 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1785 memset(pi4, 0, sizeof(*pi4));
1787 return space;
1790 /*********************************************************************
1791 * WINSPOOL_GetPrinter_5
1793 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1795 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1796 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1797 BOOL unicode)
1799 DWORD size, left = cbBuf;
1800 BOOL space = (cbBuf > 0);
1801 LPBYTE ptr = buf;
1803 *pcbNeeded = 0;
1805 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1806 unicode)) {
1807 if(space && size <= left) {
1808 pi5->pPrinterName = (LPWSTR)ptr;
1809 ptr += size;
1810 left -= size;
1811 } else
1812 space = FALSE;
1813 *pcbNeeded += size;
1815 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1816 unicode)) {
1817 if(space && size <= left) {
1818 pi5->pPortName = (LPWSTR)ptr;
1819 ptr += size;
1820 left -= size;
1821 } else
1822 space = FALSE;
1823 *pcbNeeded += size;
1825 if(pi5) {
1826 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1827 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1828 "dnsTimeout");
1829 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1830 "txTimeout");
1833 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1834 memset(pi5, 0, sizeof(*pi5));
1836 return space;
1839 /*****************************************************************************
1840 * WINSPOOL_GetPrinter
1842 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1843 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1844 * just a collection of pointers to strings.
1846 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1847 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1849 LPCWSTR name;
1850 DWORD size, needed = 0;
1851 LPBYTE ptr = NULL;
1852 HKEY hkeyPrinter, hkeyPrinters;
1853 BOOL ret;
1855 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1857 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1859 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1860 ERROR_SUCCESS) {
1861 ERR("Can't create Printers key\n");
1862 return FALSE;
1864 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1866 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1867 RegCloseKey(hkeyPrinters);
1868 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1869 return FALSE;
1872 switch(Level) {
1873 case 2:
1875 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1877 size = sizeof(PRINTER_INFO_2W);
1878 if(size <= cbBuf) {
1879 ptr = pPrinter + size;
1880 cbBuf -= size;
1881 memset(pPrinter, 0, size);
1882 } else {
1883 pi2 = NULL;
1884 cbBuf = 0;
1886 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1887 unicode);
1888 needed += size;
1889 break;
1892 case 4:
1894 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1896 size = sizeof(PRINTER_INFO_4W);
1897 if(size <= cbBuf) {
1898 ptr = pPrinter + size;
1899 cbBuf -= size;
1900 memset(pPrinter, 0, size);
1901 } else {
1902 pi4 = NULL;
1903 cbBuf = 0;
1905 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1906 unicode);
1907 needed += size;
1908 break;
1912 case 5:
1914 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1916 size = sizeof(PRINTER_INFO_5W);
1917 if(size <= cbBuf) {
1918 ptr = pPrinter + size;
1919 cbBuf -= size;
1920 memset(pPrinter, 0, size);
1921 } else {
1922 pi5 = NULL;
1923 cbBuf = 0;
1926 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1927 unicode);
1928 needed += size;
1929 break;
1932 default:
1933 FIXME("Unimplemented level %ld\n", Level);
1934 SetLastError(ERROR_INVALID_LEVEL);
1935 RegCloseKey(hkeyPrinters);
1936 RegCloseKey(hkeyPrinter);
1937 return FALSE;
1940 RegCloseKey(hkeyPrinter);
1941 RegCloseKey(hkeyPrinters);
1943 TRACE("returning %d needed = %ld\n", ret, needed);
1944 if(pcbNeeded) *pcbNeeded = needed;
1945 if(!ret)
1946 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1947 return ret;
1950 /*****************************************************************************
1951 * GetPrinterW [WINSPOOL.@]
1953 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1954 DWORD cbBuf, LPDWORD pcbNeeded)
1956 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1957 TRUE);
1960 /*****************************************************************************
1961 * GetPrinterA [WINSPOOL.@]
1963 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1964 DWORD cbBuf, LPDWORD pcbNeeded)
1966 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1967 FALSE);
1970 /*****************************************************************************
1971 * WINSPOOL_EnumPrinters
1973 * Implementation of EnumPrintersA|W
1975 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1976 DWORD dwLevel, LPBYTE lpbPrinters,
1977 DWORD cbBuf, LPDWORD lpdwNeeded,
1978 LPDWORD lpdwReturned, BOOL unicode)
1981 HKEY hkeyPrinters, hkeyPrinter;
1982 WCHAR PrinterName[255];
1983 DWORD needed = 0, number = 0;
1984 DWORD used, i, left;
1985 PBYTE pi, buf;
1987 if(lpbPrinters)
1988 memset(lpbPrinters, 0, cbBuf);
1989 if(lpdwReturned)
1990 *lpdwReturned = 0;
1991 if(lpdwNeeded)
1992 *lpdwNeeded = 0;
1994 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1995 if(dwType == PRINTER_ENUM_DEFAULT)
1996 return TRUE;
1998 if (dwType & PRINTER_ENUM_CONNECTIONS) {
1999 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
2000 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
2001 if(!dwType) return TRUE;
2004 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2005 FIXME("dwType = %08lx\n", dwType);
2006 SetLastError(ERROR_INVALID_FLAGS);
2007 return FALSE;
2010 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2011 ERROR_SUCCESS) {
2012 ERR("Can't create Printers key\n");
2013 return FALSE;
2016 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2017 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2018 RegCloseKey(hkeyPrinters);
2019 ERR("Can't query Printers key\n");
2020 return FALSE;
2022 TRACE("Found %ld printers\n", number);
2024 switch(dwLevel) {
2025 case 1:
2026 RegCloseKey(hkeyPrinters);
2027 if (lpdwReturned)
2028 *lpdwReturned = number;
2029 return TRUE;
2031 case 2:
2032 used = number * sizeof(PRINTER_INFO_2W);
2033 break;
2034 case 4:
2035 used = number * sizeof(PRINTER_INFO_4W);
2036 break;
2037 case 5:
2038 used = number * sizeof(PRINTER_INFO_5W);
2039 break;
2041 default:
2042 SetLastError(ERROR_INVALID_LEVEL);
2043 RegCloseKey(hkeyPrinters);
2044 return FALSE;
2046 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2048 for(i = 0; i < number; i++) {
2049 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2050 ERROR_SUCCESS) {
2051 ERR("Can't enum key number %ld\n", i);
2052 RegCloseKey(hkeyPrinters);
2053 return FALSE;
2055 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2056 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2057 ERROR_SUCCESS) {
2058 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2059 RegCloseKey(hkeyPrinters);
2060 return FALSE;
2063 if(cbBuf > used) {
2064 buf = lpbPrinters + used;
2065 left = cbBuf - used;
2066 } else {
2067 buf = NULL;
2068 left = 0;
2071 switch(dwLevel) {
2072 case 2:
2073 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2074 left, &needed, unicode);
2075 used += needed;
2076 if(pi) pi += sizeof(PRINTER_INFO_2W);
2077 break;
2078 case 4:
2079 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2080 left, &needed, unicode);
2081 used += needed;
2082 if(pi) pi += sizeof(PRINTER_INFO_4W);
2083 break;
2084 case 5:
2085 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2086 left, &needed, unicode);
2087 used += needed;
2088 if(pi) pi += sizeof(PRINTER_INFO_5W);
2089 break;
2090 default:
2091 ERR("Shouldn't be here!\n");
2092 RegCloseKey(hkeyPrinter);
2093 RegCloseKey(hkeyPrinters);
2094 return FALSE;
2096 RegCloseKey(hkeyPrinter);
2098 RegCloseKey(hkeyPrinters);
2100 if(lpdwNeeded)
2101 *lpdwNeeded = used;
2103 if(used > cbBuf) {
2104 if(lpbPrinters)
2105 memset(lpbPrinters, 0, cbBuf);
2106 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2107 return FALSE;
2109 if(lpdwReturned)
2110 *lpdwReturned = number;
2111 SetLastError(ERROR_SUCCESS);
2112 return TRUE;
2116 /******************************************************************
2117 * EnumPrintersW [WINSPOOL.@]
2119 * Enumerates the available printers, print servers and print
2120 * providers, depending on the specified flags, name and level.
2122 * RETURNS:
2124 * If level is set to 1:
2125 * Not implemented yet!
2126 * Returns TRUE with an empty list.
2128 * If level is set to 2:
2129 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2130 * Returns an array of PRINTER_INFO_2 data structures in the
2131 * lpbPrinters buffer. Note that according to MSDN also an
2132 * OpenPrinter should be performed on every remote printer.
2134 * If level is set to 4 (officially WinNT only):
2135 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2136 * Fast: Only the registry is queried to retrieve printer names,
2137 * no connection to the driver is made.
2138 * Returns an array of PRINTER_INFO_4 data structures in the
2139 * lpbPrinters buffer.
2141 * If level is set to 5 (officially WinNT4/Win9x only):
2142 * Fast: Only the registry is queried to retrieve printer names,
2143 * no connection to the driver is made.
2144 * Returns an array of PRINTER_INFO_5 data structures in the
2145 * lpbPrinters buffer.
2147 * If level set to 3 or 6+:
2148 * returns zero (failure!)
2150 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2151 * for information.
2153 * BUGS:
2154 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2155 * - Only levels 2, 4 and 5 are implemented at the moment.
2156 * - 16-bit printer drivers are not enumerated.
2157 * - Returned amount of bytes used/needed does not match the real Windoze
2158 * implementation (as in this implementation, all strings are part
2159 * of the buffer, whereas Win32 keeps them somewhere else)
2160 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2162 * NOTE:
2163 * - In a regular Wine installation, no registry settings for printers
2164 * exist, which makes this function return an empty list.
2166 BOOL WINAPI EnumPrintersW(
2167 DWORD dwType, /* [in] Types of print objects to enumerate */
2168 LPWSTR lpszName, /* [in] name of objects to enumerate */
2169 DWORD dwLevel, /* [in] type of printer info structure */
2170 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2171 DWORD cbBuf, /* [in] max size of buffer in bytes */
2172 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2173 LPDWORD lpdwReturned /* [out] number of entries returned */
2176 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2177 lpdwNeeded, lpdwReturned, TRUE);
2180 /******************************************************************
2181 * EnumPrintersA [WINSPOOL.@]
2184 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2185 DWORD dwLevel, LPBYTE lpbPrinters,
2186 DWORD cbBuf, LPDWORD lpdwNeeded,
2187 LPDWORD lpdwReturned)
2189 BOOL ret;
2190 UNICODE_STRING lpszNameW;
2191 PWSTR pwstrNameW;
2193 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2194 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2195 lpdwNeeded, lpdwReturned, FALSE);
2196 RtlFreeUnicodeString(&lpszNameW);
2197 return ret;
2200 /*****************************************************************************
2201 * WINSPOOL_GetDriverInfoFromReg [internal]
2203 * Enters the information from the registry into the DRIVER_INFO struct
2205 * RETURNS
2206 * zero if the printer driver does not exist in the registry
2207 * (only if Level > 1) otherwise nonzero
2209 static BOOL WINSPOOL_GetDriverInfoFromReg(
2210 HKEY hkeyDrivers,
2211 LPWSTR DriverName,
2212 LPWSTR pEnvironment,
2213 DWORD Level,
2214 LPBYTE ptr, /* DRIVER_INFO */
2215 LPBYTE pDriverStrings, /* strings buffer */
2216 DWORD cbBuf, /* size of string buffer */
2217 LPDWORD pcbNeeded, /* space needed for str. */
2218 BOOL unicode) /* type of strings */
2219 { DWORD dw, size, tmp, type;
2220 HKEY hkeyDriver;
2221 LPBYTE strPtr = pDriverStrings;
2223 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2224 debugstr_w(DriverName), debugstr_w(pEnvironment),
2225 Level, ptr, pDriverStrings, cbBuf, unicode);
2227 if(unicode) {
2228 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2229 if (*pcbNeeded <= cbBuf)
2230 strcpyW((LPWSTR)strPtr, DriverName);
2231 } else {
2232 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2233 NULL, NULL);
2234 if(*pcbNeeded <= cbBuf)
2235 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2236 NULL, NULL);
2238 if(Level == 1) {
2239 if(ptr)
2240 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2241 return TRUE;
2242 } else {
2243 if(ptr)
2244 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2245 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2248 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2249 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2250 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2251 return FALSE;
2254 size = sizeof(dw);
2255 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2256 ERROR_SUCCESS)
2257 WARN("Can't get Version\n");
2258 else if(ptr)
2259 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2261 if(!pEnvironment)
2262 pEnvironment = DefaultEnvironmentW;
2263 if(unicode)
2264 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2265 else
2266 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2267 NULL, NULL);
2268 *pcbNeeded += size;
2269 if(*pcbNeeded <= cbBuf) {
2270 if(unicode)
2271 strcpyW((LPWSTR)strPtr, pEnvironment);
2272 else
2273 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2274 NULL, NULL);
2275 if(ptr)
2276 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2277 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2280 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2281 unicode)) {
2282 *pcbNeeded += size;
2283 if(*pcbNeeded <= cbBuf)
2284 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2285 unicode);
2286 if(ptr)
2287 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2288 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2291 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2292 unicode)) {
2293 *pcbNeeded += size;
2294 if(*pcbNeeded <= cbBuf)
2295 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2296 &tmp, unicode);
2297 if(ptr)
2298 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2299 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2302 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2303 0, &size, unicode)) {
2304 *pcbNeeded += size;
2305 if(*pcbNeeded <= cbBuf)
2306 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2307 size, &tmp, unicode);
2308 if(ptr)
2309 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2310 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2313 if(Level == 2 ) {
2314 RegCloseKey(hkeyDriver);
2315 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2316 return TRUE;
2319 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2320 unicode)) {
2321 *pcbNeeded += size;
2322 if(*pcbNeeded <= cbBuf)
2323 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2324 size, &tmp, unicode);
2325 if(ptr)
2326 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2327 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2330 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2331 &size, unicode)) {
2332 *pcbNeeded += size;
2333 if(*pcbNeeded <= cbBuf)
2334 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2335 size, &tmp, unicode);
2336 if(ptr)
2337 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2338 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2341 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2342 unicode)) {
2343 *pcbNeeded += size;
2344 if(*pcbNeeded <= cbBuf)
2345 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2346 size, &tmp, unicode);
2347 if(ptr)
2348 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2349 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2352 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2353 unicode)) {
2354 *pcbNeeded += size;
2355 if(*pcbNeeded <= cbBuf)
2356 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2357 size, &tmp, unicode);
2358 if(ptr)
2359 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2360 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2363 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2364 RegCloseKey(hkeyDriver);
2365 return TRUE;
2368 /*****************************************************************************
2369 * WINSPOOL_GetPrinterDriver
2371 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2372 DWORD Level, LPBYTE pDriverInfo,
2373 DWORD cbBuf, LPDWORD pcbNeeded,
2374 BOOL unicode)
2376 LPCWSTR name;
2377 WCHAR DriverName[100];
2378 DWORD ret, type, size, needed = 0;
2379 LPBYTE ptr = NULL;
2380 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2382 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2383 Level,pDriverInfo,cbBuf, pcbNeeded);
2385 ZeroMemory(pDriverInfo, cbBuf);
2387 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2389 if(Level < 1 || Level > 3) {
2390 SetLastError(ERROR_INVALID_LEVEL);
2391 return FALSE;
2393 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2394 ERROR_SUCCESS) {
2395 ERR("Can't create Printers key\n");
2396 return FALSE;
2398 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2399 != ERROR_SUCCESS) {
2400 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2401 RegCloseKey(hkeyPrinters);
2402 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2403 return FALSE;
2405 size = sizeof(DriverName);
2406 DriverName[0] = 0;
2407 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2408 (LPBYTE)DriverName, &size);
2409 RegCloseKey(hkeyPrinter);
2410 RegCloseKey(hkeyPrinters);
2411 if(ret != ERROR_SUCCESS) {
2412 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2413 return FALSE;
2416 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2417 if(!hkeyDrivers) {
2418 ERR("Can't create Drivers key\n");
2419 return FALSE;
2422 switch(Level) {
2423 case 1:
2424 size = sizeof(DRIVER_INFO_1W);
2425 break;
2426 case 2:
2427 size = sizeof(DRIVER_INFO_2W);
2428 break;
2429 case 3:
2430 size = sizeof(DRIVER_INFO_3W);
2431 break;
2432 default:
2433 ERR("Invalid level\n");
2434 return FALSE;
2437 if(size <= cbBuf)
2438 ptr = pDriverInfo + size;
2440 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2441 pEnvironment, Level, pDriverInfo,
2442 (cbBuf < size) ? NULL : ptr,
2443 (cbBuf < size) ? 0 : cbBuf - size,
2444 &needed, unicode)) {
2445 RegCloseKey(hkeyDrivers);
2446 return FALSE;
2449 RegCloseKey(hkeyDrivers);
2451 if(pcbNeeded) *pcbNeeded = size + needed;
2452 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2453 if(cbBuf >= needed) return TRUE;
2454 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2455 return FALSE;
2458 /*****************************************************************************
2459 * GetPrinterDriverA [WINSPOOL.@]
2461 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2462 DWORD Level, LPBYTE pDriverInfo,
2463 DWORD cbBuf, LPDWORD pcbNeeded)
2465 BOOL ret;
2466 UNICODE_STRING pEnvW;
2467 PWSTR pwstrEnvW;
2469 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2470 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2471 cbBuf, pcbNeeded, FALSE);
2472 RtlFreeUnicodeString(&pEnvW);
2473 return ret;
2475 /*****************************************************************************
2476 * GetPrinterDriverW [WINSPOOL.@]
2478 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2479 DWORD Level, LPBYTE pDriverInfo,
2480 DWORD cbBuf, LPDWORD pcbNeeded)
2482 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2483 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2486 /*****************************************************************************
2487 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2489 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2490 DWORD Level, LPBYTE pDriverDirectory,
2491 DWORD cbBuf, LPDWORD pcbNeeded)
2493 DWORD needed;
2495 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2496 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2497 if(pName != NULL) {
2498 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2499 SetLastError(ERROR_INVALID_PARAMETER);
2500 return FALSE;
2502 if(pEnvironment != NULL) {
2503 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2504 SetLastError(ERROR_INVALID_ENVIRONMENT);
2505 return FALSE;
2507 if(Level != 1) /* win95 ignores this so we just carry on */
2508 WARN("Level = %ld - assuming 1\n", Level);
2510 /* FIXME should read from registry */
2511 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2512 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2513 * adjust this now
2515 needed++;
2516 needed*=sizeof(WCHAR);
2518 if(pcbNeeded)
2519 *pcbNeeded = needed;
2520 TRACE("required <%08lx>\n", *pcbNeeded);
2521 if(needed > cbBuf) {
2522 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2523 return FALSE;
2525 return TRUE;
2529 /*****************************************************************************
2530 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2532 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2533 DWORD Level, LPBYTE pDriverDirectory,
2534 DWORD cbBuf, LPDWORD pcbNeeded)
2536 UNICODE_STRING nameW, environmentW;
2537 BOOL ret;
2538 DWORD pcbNeededW;
2539 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2540 WCHAR *driverDirectoryW = NULL;
2542 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2544 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2545 else nameW.Buffer = NULL;
2546 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2547 else environmentW.Buffer = NULL;
2549 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2550 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2551 if (ret) {
2552 DWORD needed;
2553 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2554 pDriverDirectory, cbBuf, NULL, NULL);
2555 if(pcbNeeded)
2556 *pcbNeeded = needed;
2557 ret = (needed <= cbBuf) ? TRUE : FALSE;
2558 } else
2559 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2561 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2563 if(driverDirectoryW)
2564 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2565 RtlFreeUnicodeString(&environmentW);
2566 RtlFreeUnicodeString(&nameW);
2568 return ret;
2571 /*****************************************************************************
2572 * AddPrinterDriverA [WINSPOOL.@]
2574 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2576 DRIVER_INFO_3A di3;
2577 HKEY hkeyDrivers, hkeyName;
2579 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2581 if(level != 2 && level != 3) {
2582 SetLastError(ERROR_INVALID_LEVEL);
2583 return FALSE;
2585 if(pName != NULL) {
2586 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2587 SetLastError(ERROR_INVALID_PARAMETER);
2588 return FALSE;
2590 if(!pDriverInfo) {
2591 WARN("pDriverInfo == NULL\n");
2592 SetLastError(ERROR_INVALID_PARAMETER);
2593 return FALSE;
2596 if(level == 3)
2597 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2598 else {
2599 memset(&di3, 0, sizeof(di3));
2600 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2603 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2604 !di3.pDataFile) {
2605 SetLastError(ERROR_INVALID_PARAMETER);
2606 return FALSE;
2608 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2609 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2610 if(!di3.pHelpFile) di3.pHelpFile = "";
2611 if(!di3.pMonitorName) di3.pMonitorName = "";
2613 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2615 if(!hkeyDrivers) {
2616 ERR("Can't create Drivers key\n");
2617 return FALSE;
2620 if(level == 2) { /* apparently can't overwrite with level2 */
2621 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2622 RegCloseKey(hkeyName);
2623 RegCloseKey(hkeyDrivers);
2624 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2625 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2626 return FALSE;
2629 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2630 RegCloseKey(hkeyDrivers);
2631 ERR("Can't create Name key\n");
2632 return FALSE;
2634 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2636 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2637 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2638 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2639 sizeof(DWORD));
2640 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2641 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2642 di3.pDependentFiles, 0);
2643 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2644 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2645 RegCloseKey(hkeyName);
2646 RegCloseKey(hkeyDrivers);
2648 return TRUE;
2650 /*****************************************************************************
2651 * AddPrinterDriverW [WINSPOOL.@]
2653 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2654 LPBYTE pDriverInfo)
2656 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2657 level,pDriverInfo);
2658 return FALSE;
2662 /*****************************************************************************
2663 * PrinterProperties [WINSPOOL.@]
2665 * Displays a dialog to set the properties of the printer.
2667 * RETURNS
2668 * nonzero on success or zero on failure
2670 * BUGS
2671 * implemented as stub only
2673 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2674 HANDLE hPrinter /* [in] handle to printer object */
2676 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2677 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2678 return FALSE;
2681 /*****************************************************************************
2682 * EnumJobsA [WINSPOOL.@]
2685 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2686 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2687 LPDWORD pcReturned)
2689 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2690 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2692 if(pcbNeeded) *pcbNeeded = 0;
2693 if(pcReturned) *pcReturned = 0;
2694 return FALSE;
2698 /*****************************************************************************
2699 * EnumJobsW [WINSPOOL.@]
2702 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2703 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2704 LPDWORD pcReturned)
2706 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2707 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2709 if(pcbNeeded) *pcbNeeded = 0;
2710 if(pcReturned) *pcReturned = 0;
2711 return FALSE;
2714 /*****************************************************************************
2715 * WINSPOOL_EnumPrinterDrivers [internal]
2717 * Delivers information about all printer drivers installed on the
2718 * localhost or a given server
2720 * RETURNS
2721 * nonzero on success or zero on failure. If the buffer for the returned
2722 * information is too small the function will return an error
2724 * BUGS
2725 * - only implemented for localhost, foreign hosts will return an error
2727 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2728 DWORD Level, LPBYTE pDriverInfo,
2729 DWORD cbBuf, LPDWORD pcbNeeded,
2730 LPDWORD pcReturned, BOOL unicode)
2732 { HKEY hkeyDrivers;
2733 DWORD i, needed, number = 0, size = 0;
2734 WCHAR DriverNameW[255];
2735 PBYTE ptr;
2737 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2738 debugstr_w(pName), debugstr_w(pEnvironment),
2739 Level, pDriverInfo, cbBuf, unicode);
2741 /* check for local drivers */
2742 if(pName) {
2743 ERR("remote drivers unsupported! Current remote host is %s\n",
2744 debugstr_w(pName));
2745 return FALSE;
2748 /* check input parameter */
2749 if((Level < 1) || (Level > 3)) {
2750 ERR("unsupported level %ld \n", Level);
2751 return FALSE;
2754 /* initialize return values */
2755 if(pDriverInfo)
2756 memset( pDriverInfo, 0, cbBuf);
2757 *pcbNeeded = 0;
2758 *pcReturned = 0;
2760 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2761 if(!hkeyDrivers) {
2762 ERR("Can't open Drivers key\n");
2763 return FALSE;
2766 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2767 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2768 RegCloseKey(hkeyDrivers);
2769 ERR("Can't query Drivers key\n");
2770 return FALSE;
2772 TRACE("Found %ld Drivers\n", number);
2774 /* get size of single struct
2775 * unicode and ascii structure have the same size
2777 switch (Level) {
2778 case 1:
2779 size = sizeof(DRIVER_INFO_1A);
2780 break;
2781 case 2:
2782 size = sizeof(DRIVER_INFO_2A);
2783 break;
2784 case 3:
2785 size = sizeof(DRIVER_INFO_3A);
2786 break;
2789 /* calculate required buffer size */
2790 *pcbNeeded = size * number;
2792 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2793 i < number;
2794 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2795 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2796 != ERROR_SUCCESS) {
2797 ERR("Can't enum key number %ld\n", i);
2798 RegCloseKey(hkeyDrivers);
2799 return FALSE;
2801 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2802 pEnvironment, Level, ptr,
2803 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2804 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2805 &needed, unicode)) {
2806 RegCloseKey(hkeyDrivers);
2807 return FALSE;
2809 (*pcbNeeded) += needed;
2812 RegCloseKey(hkeyDrivers);
2814 if(cbBuf < *pcbNeeded){
2815 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2816 return FALSE;
2819 return TRUE;
2822 /*****************************************************************************
2823 * EnumPrinterDriversW [WINSPOOL.@]
2825 * see function EnumPrinterDrivers for RETURNS, BUGS
2827 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2828 LPBYTE pDriverInfo, DWORD cbBuf,
2829 LPDWORD pcbNeeded, LPDWORD pcReturned)
2831 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2832 cbBuf, pcbNeeded, pcReturned, TRUE);
2835 /*****************************************************************************
2836 * EnumPrinterDriversA [WINSPOOL.@]
2838 * see function EnumPrinterDrivers for RETURNS, BUGS
2840 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2841 LPBYTE pDriverInfo, DWORD cbBuf,
2842 LPDWORD pcbNeeded, LPDWORD pcReturned)
2843 { BOOL ret;
2844 UNICODE_STRING pNameW, pEnvironmentW;
2845 PWSTR pwstrNameW, pwstrEnvironmentW;
2847 pwstrNameW = asciitounicode(&pNameW, pName);
2848 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
2850 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
2851 Level, pDriverInfo, cbBuf, pcbNeeded,
2852 pcReturned, FALSE);
2853 RtlFreeUnicodeString(&pNameW);
2854 RtlFreeUnicodeString(&pEnvironmentW);
2856 return ret;
2859 static CHAR PortMonitor[] = "Wine Port Monitor";
2860 static CHAR PortDescription[] = "Wine Port";
2862 /******************************************************************************
2863 * EnumPortsA (WINSPOOL.@)
2865 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
2866 LPDWORD bufneeded,LPDWORD bufreturned)
2868 CHAR portname[10];
2869 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
2870 const LPCSTR szSerialPortKey = "Software\\Wine\\Wine\\Config\\serialports";
2871 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
2872 HKEY hkey_serial, hkey_printer;
2874 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
2875 name,level,buffer,bufsize,bufneeded,bufreturned);
2877 switch( level )
2879 case 1:
2880 info_size = sizeof (PORT_INFO_1A);
2881 break;
2882 case 2:
2883 info_size = sizeof (PORT_INFO_2A);
2884 break;
2885 default:
2886 SetLastError(ERROR_INVALID_LEVEL);
2887 return FALSE;
2890 /* see how many exist */
2892 hkey_serial = 0;
2893 hkey_printer = 0;
2894 serial_count = 0;
2895 printer_count = 0;
2896 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szSerialPortKey, &hkey_serial);
2897 if (r == ERROR_SUCCESS)
2899 RegQueryInfoKeyA ( hkey_serial, NULL, NULL, NULL, NULL, NULL, NULL,
2900 &serial_count, NULL, NULL, NULL, NULL);
2903 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
2904 if ( r == ERROR_SUCCESS )
2906 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
2907 &printer_count, NULL, NULL, NULL, NULL);
2909 count = serial_count + printer_count;
2911 /* then fill in the structure info structure once
2912 we know the offset to the first string */
2914 memset( buffer, 0, bufsize );
2915 n = 0;
2916 ofs = info_size*count;
2917 for ( i=0; i<count; i++)
2919 DWORD vallen = sizeof(portname) - 1;
2921 /* get the serial port values, then the printer values */
2922 if ( i < serial_count )
2923 r = RegEnumValueA( hkey_serial, i,
2924 portname, &vallen, NULL, NULL, NULL, 0 );
2925 else
2926 r = RegEnumValueA( hkey_printer, i-serial_count,
2927 portname, &vallen, NULL, NULL, NULL, 0 );
2929 if ( r )
2930 continue;
2932 /* add a colon if necessary, and make it upper case */
2933 CharUpperBuffA(portname,vallen);
2934 if (strcasecmp(portname,"nul")!=0)
2935 if (vallen && (portname[vallen-1] != ':') )
2936 lstrcatA(portname,":");
2938 /* add the port info structure if we can fit it */
2939 if ( info_size*(n+1) < bufsize )
2941 if ( level == 1)
2943 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
2944 info->pName = (LPSTR) &buffer[ofs];
2946 else if ( level == 2)
2948 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
2949 info->pPortName = (LPSTR) &buffer[ofs];
2950 /* FIXME: fill in more stuff here */
2951 info->pMonitorName = PortMonitor;
2952 info->pDescription = PortDescription;
2953 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
2956 /* add the name of the port if we can fit it */
2957 if ( ofs < bufsize )
2958 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
2961 ofs += lstrlenA(portname)+1;
2962 n++;
2965 RegCloseKey(hkey_serial);
2966 RegCloseKey(hkey_printer);
2968 if(bufneeded)
2969 *bufneeded = ofs;
2971 if(bufreturned)
2972 *bufreturned = count;
2974 return TRUE;
2977 /******************************************************************************
2978 * GetDefaultPrinterA (WINSPOOL.@)
2980 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2982 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
2984 char *ptr;
2986 if (*namesize < 1)
2988 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2989 return FALSE;
2992 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
2994 SetLastError (ERROR_FILE_NOT_FOUND);
2995 return FALSE;
2998 if ((ptr = strchr (name, ',')) == NULL)
3000 SetLastError (ERROR_FILE_NOT_FOUND);
3001 return FALSE;
3004 *ptr = '\0';
3005 *namesize = strlen (name) + 1;
3006 return TRUE;
3010 /******************************************************************************
3011 * GetDefaultPrinterW (WINSPOOL.@)
3013 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3015 char *buf;
3016 BOOL ret;
3018 if (*namesize < 1)
3020 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3021 return FALSE;
3024 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
3025 ret = GetDefaultPrinterA (buf, namesize);
3026 if (ret)
3028 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
3029 if (!len)
3031 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3032 ret = FALSE;
3034 else *namesize = len;
3037 HeapFree (GetProcessHeap (), 0, buf);
3038 return ret;
3042 /******************************************************************************
3043 * SetPrinterDataExA (WINSPOOL.@)
3045 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
3046 LPSTR pValueName, DWORD Type,
3047 LPBYTE pData, DWORD cbData)
3049 HKEY hkeyPrinter, hkeySubkey;
3050 DWORD ret;
3052 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3053 debugstr_a(pValueName), Type, pData, cbData);
3055 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3056 != ERROR_SUCCESS)
3057 return ret;
3059 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3060 != ERROR_SUCCESS) {
3061 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3062 RegCloseKey(hkeyPrinter);
3063 return ret;
3065 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3066 RegCloseKey(hkeySubkey);
3067 RegCloseKey(hkeyPrinter);
3068 return ret;
3071 /******************************************************************************
3072 * SetPrinterDataExW (WINSPOOL.@)
3074 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
3075 LPWSTR pValueName, DWORD Type,
3076 LPBYTE pData, DWORD cbData)
3078 HKEY hkeyPrinter, hkeySubkey;
3079 DWORD ret;
3081 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3082 debugstr_w(pValueName), Type, pData, cbData);
3084 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3085 != ERROR_SUCCESS)
3086 return ret;
3088 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3089 != ERROR_SUCCESS) {
3090 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3091 RegCloseKey(hkeyPrinter);
3092 return ret;
3094 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3095 RegCloseKey(hkeySubkey);
3096 RegCloseKey(hkeyPrinter);
3097 return ret;
3100 /******************************************************************************
3101 * SetPrinterDataA (WINSPOOL.@)
3103 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3104 LPBYTE pData, DWORD cbData)
3106 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3107 pData, cbData);
3110 /******************************************************************************
3111 * SetPrinterDataW (WINSPOOL.@)
3113 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3114 LPBYTE pData, DWORD cbData)
3116 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3117 pData, cbData);
3120 /******************************************************************************
3121 * GetPrinterDataExA (WINSPOOL.@)
3123 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
3124 LPSTR pValueName, LPDWORD pType,
3125 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3127 HKEY hkeyPrinter, hkeySubkey;
3128 DWORD ret;
3130 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3131 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3132 pcbNeeded);
3134 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3135 != ERROR_SUCCESS)
3136 return ret;
3138 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3139 != ERROR_SUCCESS) {
3140 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3141 RegCloseKey(hkeyPrinter);
3142 return ret;
3144 *pcbNeeded = nSize;
3145 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3146 RegCloseKey(hkeySubkey);
3147 RegCloseKey(hkeyPrinter);
3148 return ret;
3151 /******************************************************************************
3152 * GetPrinterDataExW (WINSPOOL.@)
3154 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
3155 LPWSTR pValueName, LPDWORD pType,
3156 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3158 HKEY hkeyPrinter, hkeySubkey;
3159 DWORD ret;
3161 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3162 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3163 pcbNeeded);
3165 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3166 != ERROR_SUCCESS)
3167 return ret;
3169 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3170 != ERROR_SUCCESS) {
3171 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3172 RegCloseKey(hkeyPrinter);
3173 return ret;
3175 *pcbNeeded = nSize;
3176 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3177 RegCloseKey(hkeySubkey);
3178 RegCloseKey(hkeyPrinter);
3179 return ret;
3182 /******************************************************************************
3183 * GetPrinterDataA (WINSPOOL.@)
3185 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3186 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3188 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3189 pData, nSize, pcbNeeded);
3192 /******************************************************************************
3193 * GetPrinterDataW (WINSPOOL.@)
3195 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3196 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3198 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3199 pData, nSize, pcbNeeded);
3202 /*******************************************************************************
3203 * EnumPrinterDataExW [WINSPOOL.@]
3205 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3206 LPBYTE pEnumValues, DWORD cbEnumValues,
3207 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3209 HKEY hkPrinter, hkSubKey;
3210 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3211 cbValueNameLen, cbMaxValueLen, cbValueLen,
3212 cbBufSize, dwType;
3213 LPWSTR lpValueName;
3214 HANDLE hHeap;
3215 PBYTE lpValue;
3216 PPRINTER_ENUM_VALUESW ppev;
3218 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3220 if (pKeyName == NULL || *pKeyName == 0)
3221 return ERROR_INVALID_PARAMETER;
3223 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3224 if (ret != ERROR_SUCCESS)
3226 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3227 hPrinter, ret);
3228 return ret;
3231 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3232 if (ret != ERROR_SUCCESS)
3234 r = RegCloseKey (hkPrinter);
3235 if (r != ERROR_SUCCESS)
3236 WARN ("RegCloseKey returned %li\n", r);
3237 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3238 debugstr_w (pKeyName), ret);
3239 return ret;
3242 ret = RegCloseKey (hkPrinter);
3243 if (ret != ERROR_SUCCESS)
3245 ERR ("RegCloseKey returned %li\n", ret);
3246 r = RegCloseKey (hkSubKey);
3247 if (r != ERROR_SUCCESS)
3248 WARN ("RegCloseKey returned %li\n", r);
3249 return ret;
3252 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3253 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3254 if (ret != ERROR_SUCCESS)
3256 r = RegCloseKey (hkSubKey);
3257 if (r != ERROR_SUCCESS)
3258 WARN ("RegCloseKey returned %li\n", r);
3259 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3260 return ret;
3263 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3264 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3266 if (cValues == 0) /* empty key */
3268 r = RegCloseKey (hkSubKey);
3269 if (r != ERROR_SUCCESS)
3270 WARN ("RegCloseKey returned %li\n", r);
3271 *pcbEnumValues = *pnEnumValues = 0;
3272 return ERROR_SUCCESS;
3275 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3277 hHeap = GetProcessHeap ();
3278 if (hHeap == NULL)
3280 ERR ("GetProcessHeap failed\n");
3281 r = RegCloseKey (hkSubKey);
3282 if (r != ERROR_SUCCESS)
3283 WARN ("RegCloseKey returned %li\n", r);
3284 return ERROR_OUTOFMEMORY;
3287 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3288 if (lpValueName == NULL)
3290 ERR ("Failed to allocate %li bytes from process heap\n",
3291 cbMaxValueNameLen * sizeof (WCHAR));
3292 r = RegCloseKey (hkSubKey);
3293 if (r != ERROR_SUCCESS)
3294 WARN ("RegCloseKey returned %li\n", r);
3295 return ERROR_OUTOFMEMORY;
3298 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3299 if (lpValue == NULL)
3301 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3302 if (HeapFree (hHeap, 0, lpValueName) == 0)
3303 WARN ("HeapFree failed with code %li\n", GetLastError ());
3304 r = RegCloseKey (hkSubKey);
3305 if (r != ERROR_SUCCESS)
3306 WARN ("RegCloseKey returned %li\n", r);
3307 return ERROR_OUTOFMEMORY;
3310 TRACE ("pass 1: calculating buffer required for all names and values\n");
3312 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3314 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3316 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3318 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3319 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3320 NULL, NULL, lpValue, &cbValueLen);
3321 if (ret != ERROR_SUCCESS)
3323 if (HeapFree (hHeap, 0, lpValue) == 0)
3324 WARN ("HeapFree failed with code %li\n", GetLastError ());
3325 if (HeapFree (hHeap, 0, lpValueName) == 0)
3326 WARN ("HeapFree failed with code %li\n", GetLastError ());
3327 r = RegCloseKey (hkSubKey);
3328 if (r != ERROR_SUCCESS)
3329 WARN ("RegCloseKey returned %li\n", r);
3330 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3331 return ret;
3334 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3335 debugstr_w (lpValueName), dwIndex,
3336 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3338 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3339 cbBufSize += cbValueLen;
3342 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3344 *pcbEnumValues = cbBufSize;
3345 *pnEnumValues = cValues;
3347 if (cbEnumValues < cbBufSize) /* buffer too small */
3349 if (HeapFree (hHeap, 0, lpValue) == 0)
3350 WARN ("HeapFree failed with code %li\n", GetLastError ());
3351 if (HeapFree (hHeap, 0, lpValueName) == 0)
3352 WARN ("HeapFree failed with code %li\n", GetLastError ());
3353 r = RegCloseKey (hkSubKey);
3354 if (r != ERROR_SUCCESS)
3355 WARN ("RegCloseKey returned %li\n", r);
3356 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3357 return ERROR_MORE_DATA;
3360 TRACE ("pass 2: copying all names and values to buffer\n");
3362 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3363 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3365 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3367 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3368 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3369 NULL, &dwType, lpValue, &cbValueLen);
3370 if (ret != ERROR_SUCCESS)
3372 if (HeapFree (hHeap, 0, lpValue) == 0)
3373 WARN ("HeapFree failed with code %li\n", GetLastError ());
3374 if (HeapFree (hHeap, 0, lpValueName) == 0)
3375 WARN ("HeapFree failed with code %li\n", GetLastError ());
3376 r = RegCloseKey (hkSubKey);
3377 if (r != ERROR_SUCCESS)
3378 WARN ("RegCloseKey returned %li\n", r);
3379 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3380 return ret;
3383 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3384 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3385 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3386 pEnumValues += cbValueNameLen;
3388 /* return # of *bytes* (including trailing \0), not # of chars */
3389 ppev[dwIndex].cbValueName = cbValueNameLen;
3391 ppev[dwIndex].dwType = dwType;
3393 memcpy (pEnumValues, lpValue, cbValueLen);
3394 ppev[dwIndex].pData = pEnumValues;
3395 pEnumValues += cbValueLen;
3397 ppev[dwIndex].cbData = cbValueLen;
3399 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3400 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3403 if (HeapFree (hHeap, 0, lpValue) == 0)
3405 ret = GetLastError ();
3406 ERR ("HeapFree failed with code %li\n", ret);
3407 if (HeapFree (hHeap, 0, lpValueName) == 0)
3408 WARN ("HeapFree failed with code %li\n", GetLastError ());
3409 r = RegCloseKey (hkSubKey);
3410 if (r != ERROR_SUCCESS)
3411 WARN ("RegCloseKey returned %li\n", r);
3412 return ret;
3415 if (HeapFree (hHeap, 0, lpValueName) == 0)
3417 ret = GetLastError ();
3418 ERR ("HeapFree failed with code %li\n", ret);
3419 r = RegCloseKey (hkSubKey);
3420 if (r != ERROR_SUCCESS)
3421 WARN ("RegCloseKey returned %li\n", r);
3422 return ret;
3425 ret = RegCloseKey (hkSubKey);
3426 if (ret != ERROR_SUCCESS)
3428 ERR ("RegCloseKey returned %li\n", ret);
3429 return ret;
3432 return ERROR_SUCCESS;
3435 /*******************************************************************************
3436 * EnumPrinterDataExA [WINSPOOL.@]
3438 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3439 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3440 * what Windows 2000 SP1 does.
3443 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3444 LPBYTE pEnumValues, DWORD cbEnumValues,
3445 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3447 INT len;
3448 LPWSTR pKeyNameW;
3449 DWORD ret, dwIndex, dwBufSize;
3450 HANDLE hHeap;
3451 LPSTR pBuffer;
3453 TRACE ("%p %s\n", hPrinter, pKeyName);
3455 if (pKeyName == NULL || *pKeyName == 0)
3456 return ERROR_INVALID_PARAMETER;
3458 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3459 if (len == 0)
3461 ret = GetLastError ();
3462 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3463 return ret;
3466 hHeap = GetProcessHeap ();
3467 if (hHeap == NULL)
3469 ERR ("GetProcessHeap failed\n");
3470 return ERROR_OUTOFMEMORY;
3473 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3474 if (pKeyNameW == NULL)
3476 ERR ("Failed to allocate %li bytes from process heap\n",
3477 (LONG) len * sizeof (WCHAR));
3478 return ERROR_OUTOFMEMORY;
3481 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3483 ret = GetLastError ();
3484 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3485 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3486 WARN ("HeapFree failed with code %li\n", GetLastError ());
3487 return ret;
3490 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3491 pcbEnumValues, pnEnumValues);
3492 if (ret != ERROR_SUCCESS)
3494 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3495 WARN ("HeapFree failed with code %li\n", GetLastError ());
3496 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3497 return ret;
3500 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3502 ret = GetLastError ();
3503 ERR ("HeapFree failed with code %li\n", ret);
3504 return ret;
3507 if (*pnEnumValues == 0) /* empty key */
3508 return ERROR_SUCCESS;
3510 dwBufSize = 0;
3511 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3513 PPRINTER_ENUM_VALUESW ppev =
3514 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3516 if (dwBufSize < ppev->cbValueName)
3517 dwBufSize = ppev->cbValueName;
3519 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3520 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3521 dwBufSize = ppev->cbData;
3524 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3526 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3527 if (pBuffer == NULL)
3529 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3530 return ERROR_OUTOFMEMORY;
3533 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3535 PPRINTER_ENUM_VALUESW ppev =
3536 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3538 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3539 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3540 NULL);
3541 if (len == 0)
3543 ret = GetLastError ();
3544 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3545 if (HeapFree (hHeap, 0, pBuffer) == 0)
3546 WARN ("HeapFree failed with code %li\n", GetLastError ());
3547 return ret;
3550 memcpy (ppev->pValueName, pBuffer, len);
3552 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3554 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3555 ppev->dwType != REG_MULTI_SZ)
3556 continue;
3558 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3559 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3560 if (len == 0)
3562 ret = GetLastError ();
3563 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3564 if (HeapFree (hHeap, 0, pBuffer) == 0)
3565 WARN ("HeapFree failed with code %li\n", GetLastError ());
3566 return ret;
3569 memcpy (ppev->pData, pBuffer, len);
3571 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3572 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3575 if (HeapFree (hHeap, 0, pBuffer) == 0)
3577 ret = GetLastError ();
3578 ERR ("HeapFree failed with code %li\n", ret);
3579 return ret;
3582 return ERROR_SUCCESS;
3585 /******************************************************************************
3586 * AddPortA (WINSPOOL.@)
3588 BOOL WINAPI AddPortA(LPSTR pName ,HWND hWnd, LPSTR pMonitorName)
3590 FIXME("(%s, %p, %s\n), stub!\n",pName,hWnd,pMonitorName);
3591 return FALSE;
3594 /******************************************************************************
3595 * AddPrinterDriverExW (WINSPOOL.@)
3597 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
3598 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3600 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
3601 Level, pDriverInfo, dwFileCopyFlags);
3602 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3603 return FALSE;
3606 /******************************************************************************
3607 * AddPrinterDriverExA (WINSPOOL.@)
3609 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
3610 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3612 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
3613 Level, pDriverInfo, dwFileCopyFlags);
3614 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3615 return FALSE;
3618 /******************************************************************************
3619 * DeletePrinterDriverExW (WINSPOOL.@)
3621 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
3622 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3624 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
3625 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
3626 return TRUE;
3629 /******************************************************************************
3630 * DeletePrinterDriverExA (WINSPOOL.@)
3632 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
3633 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3635 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
3636 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
3637 return TRUE;
3640 /******************************************************************************
3641 * DeletePrinterDataExW (WINSPOOL.@)
3643 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
3644 LPCWSTR pValueName)
3646 FIXME("%p %s %s\n", hPrinter,
3647 debugstr_w(pKeyName), debugstr_w(pValueName));
3648 return ERROR_INVALID_PARAMETER;
3651 /******************************************************************************
3652 * DeletePrinterDataExA (WINSPOOL.@)
3654 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
3655 LPCSTR pValueName)
3657 FIXME("%p %s %s\n", hPrinter,
3658 debugstr_a(pKeyName), debugstr_a(pValueName));
3659 return ERROR_INVALID_PARAMETER;
3662 /******************************************************************************
3663 * XcvDataW (WINSPOOL.@)
3665 * Notes:
3666 * There doesn't seem to be an A version...
3668 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
3669 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
3670 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
3672 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
3673 pInputData, cbInputData, pOutputData,
3674 cbOutputData, pcbOutputNeeded, pdwStatus);
3675 return FALSE;