Fixed buffer overflow.
[wine/multimedia.git] / dlls / winspool / info.c
blob0aad44151949e11ed174ae79fe28f3ebaa6f45fe
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 const char Printers[] =
72 "System\\CurrentControlSet\\control\\Print\\Printers\\";
73 static const char Drivers[] =
74 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
76 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
78 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
79 'i','o','n',' ','F','i','l','e',0};
80 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
81 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
82 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
83 'M','o','d','e',0};
84 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
85 'i','l','e','s',0};
86 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
87 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
88 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
89 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
90 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
91 static const WCHAR NameW[] = {'N','a','m','e',0};
92 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
93 static const WCHAR PortW[] = {'P','o','r','t',0};
94 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
95 's','s','o','r',0};
96 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
97 'v','e','r',0};
98 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
99 'v','e','r','D','a','t','a',0};
100 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
101 'i','l','e',0};
102 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
103 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
104 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
105 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
106 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
107 static const WCHAR emptyStringW[] = {0};
109 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
111 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
112 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
113 DWORD Level, LPBYTE pDriverInfo,
114 DWORD cbBuf, LPDWORD pcbNeeded,
115 BOOL unicode);
116 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
118 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
119 if passed a NULL string. This returns NULLs to the result.
121 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
123 if ( (src) )
125 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
126 return usBufferPtr->Buffer;
128 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
129 return NULL;
132 static void
133 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
134 char qbuf[200];
136 /* If forcing, or no profile string entry for device yet, set the entry
138 * The always change entry if not WINEPS yet is discussable.
140 if (force ||
141 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
142 !strcmp(qbuf,"*") ||
143 !strstr(qbuf,"WINEPS")
145 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
147 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
148 WriteProfileStringA("windows","device",buf);
149 HeapFree(GetProcessHeap(),0,buf);
153 #ifdef HAVE_CUPS_CUPS_H
154 static BOOL CUPS_LoadPrinters(void)
156 typeof(cupsGetDests) *pcupsGetDests = NULL;
157 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
158 int i, nrofdests;
159 BOOL hadprinter = FALSE;
160 cups_dest_t *dests;
161 PRINTER_INFO_2A pinfo2a;
162 void *cupshandle = NULL;
163 char *port,*devline;
164 HKEY hkeyPrinter, hkeyPrinters;
166 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
167 if (!cupshandle)
168 return FALSE;
169 TRACE("loaded %s\n", SONAME_LIBCUPS);
171 #define DYNCUPS(x) \
172 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
173 if (!p##x) return FALSE;
175 DYNCUPS(cupsGetPPD);
176 DYNCUPS(cupsGetDests);
177 #undef DYNCUPS
179 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
180 ERROR_SUCCESS) {
181 ERR("Can't create Printers key\n");
182 return FALSE;
185 nrofdests = pcupsGetDests(&dests);
186 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
187 for (i=0;i<nrofdests;i++) {
188 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
189 sprintf(port,"LPR:%s",dests[i].name);
190 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
191 sprintf(devline,"WINEPS,%s",port);
192 WriteProfileStringA("devices",dests[i].name,devline);
193 HeapFree(GetProcessHeap(),0,devline);
195 TRACE("Printer %d: %s\n", i, dests[i].name);
196 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
197 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
198 and continue */
199 TRACE("Printer already exists\n");
200 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
201 RegCloseKey(hkeyPrinter);
202 } else {
203 memset(&pinfo2a,0,sizeof(pinfo2a));
204 pinfo2a.pPrinterName = dests[i].name;
205 pinfo2a.pDatatype = "RAW";
206 pinfo2a.pPrintProcessor = "WinPrint";
207 pinfo2a.pDriverName = "PS Driver";
208 pinfo2a.pComment = "WINEPS Printer using CUPS";
209 pinfo2a.pLocation = "<physical location of printer>";
210 pinfo2a.pPortName = port;
211 pinfo2a.pParameters = "<parameters?>";
212 pinfo2a.pShareName = "<share name?>";
213 pinfo2a.pSepFile = "<sep file?>";
215 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
216 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
217 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
220 HeapFree(GetProcessHeap(),0,port);
222 hadprinter = TRUE;
223 if (dests[i].is_default)
224 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
226 RegCloseKey(hkeyPrinters);
227 wine_dlclose(cupshandle, NULL, 0);
228 return hadprinter;
230 #endif
232 static BOOL
233 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
234 PRINTER_INFO_2A pinfo2a;
235 char *e,*s,*name,*prettyname,*devname;
236 BOOL ret = FALSE, set_default = FALSE;
237 char *port,*devline,*env_default;
238 HKEY hkeyPrinter, hkeyPrinters;
240 while (isspace(*pent)) pent++;
241 s = strchr(pent,':');
242 if(s) *s='\0';
243 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
244 strcpy(name,pent);
245 if(s) {
246 *s=':';
247 pent = s;
248 } else
249 pent = "";
251 TRACE("name=%s entry=%s\n",name, pent);
253 if(ispunct(*name)) { /* a tc entry, not a real printer */
254 TRACE("skipping tc entry\n");
255 goto end;
258 if(strstr(pent,":server")) { /* server only version so skip */
259 TRACE("skipping server entry\n");
260 goto end;
263 /* Determine whether this is a postscript printer. */
265 ret = TRUE;
266 env_default = getenv("PRINTER");
267 prettyname = name;
268 /* Get longest name, usually the one at the right for later display. */
269 while((s=strchr(prettyname,'|'))) {
270 *s = '\0';
271 e = s;
272 while(isspace(*--e)) *e = '\0';
273 TRACE("\t%s\n", debugstr_a(prettyname));
274 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
275 for(prettyname = s+1; isspace(*prettyname); prettyname++)
278 e = prettyname + strlen(prettyname);
279 while(isspace(*--e)) *e = '\0';
280 TRACE("\t%s\n", debugstr_a(prettyname));
281 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
283 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
284 * if it is too long, we use it as comment below. */
285 devname = prettyname;
286 if (strlen(devname)>=CCHDEVICENAME-1)
287 devname = name;
288 if (strlen(devname)>=CCHDEVICENAME-1) {
289 ret = FALSE;
290 goto end;
293 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
294 sprintf(port,"LPR:%s",name);
296 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
297 sprintf(devline,"WINEPS,%s",port);
298 WriteProfileStringA("devices",devname,devline);
299 HeapFree(GetProcessHeap(),0,devline);
301 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
302 ERROR_SUCCESS) {
303 ERR("Can't create Printers key\n");
304 ret = FALSE;
305 goto end;
307 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
308 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
309 and continue */
310 TRACE("Printer already exists\n");
311 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
312 RegCloseKey(hkeyPrinter);
313 } else {
314 memset(&pinfo2a,0,sizeof(pinfo2a));
315 pinfo2a.pPrinterName = devname;
316 pinfo2a.pDatatype = "RAW";
317 pinfo2a.pPrintProcessor = "WinPrint";
318 pinfo2a.pDriverName = "PS Driver";
319 pinfo2a.pComment = "WINEPS Printer using LPR";
320 pinfo2a.pLocation = prettyname;
321 pinfo2a.pPortName = port;
322 pinfo2a.pParameters = "<parameters?>";
323 pinfo2a.pShareName = "<share name?>";
324 pinfo2a.pSepFile = "<sep file?>";
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());
331 RegCloseKey(hkeyPrinters);
333 if (isfirst || set_default)
334 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
336 HeapFree(GetProcessHeap(), 0, port);
337 end:
338 HeapFree(GetProcessHeap(), 0, name);
339 return ret;
342 static BOOL
343 PRINTCAP_LoadPrinters(void) {
344 BOOL hadprinter = FALSE;
345 char buf[200];
346 FILE *f;
347 char *pent = NULL;
348 BOOL had_bash = FALSE;
350 f = fopen("/etc/printcap","r");
351 if (!f)
352 return FALSE;
354 while(fgets(buf,sizeof(buf),f)) {
355 char *start, *end;
357 end=strchr(buf,'\n');
358 if (end) *end='\0';
360 start = buf;
361 while(isspace(*start)) start++;
362 if(*start == '#' || *start == '\0')
363 continue;
365 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
366 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
367 HeapFree(GetProcessHeap(),0,pent);
368 pent = NULL;
371 if (end && *--end == '\\') {
372 *end = '\0';
373 had_bash = TRUE;
374 } else
375 had_bash = FALSE;
377 if (pent) {
378 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
379 strcat(pent,start);
380 } else {
381 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
382 strcpy(pent,start);
386 if(pent) {
387 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
388 HeapFree(GetProcessHeap(),0,pent);
390 fclose(f);
391 return hadprinter;
394 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
396 if (value)
397 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
398 lstrlenW(value) * sizeof(WCHAR));
399 else
400 return ERROR_FILE_NOT_FOUND;
403 void WINSPOOL_LoadSystemPrinters(void)
405 HKEY hkey, hkeyPrinters;
406 DRIVER_INFO_3A di3a;
407 HANDLE hprn;
408 DWORD needed, num, i;
409 WCHAR PrinterName[256];
410 BOOL done = FALSE;
412 di3a.cVersion = 0x400;
413 di3a.pName = "PS Driver";
414 di3a.pEnvironment = NULL; /* NULL means auto */
415 di3a.pDriverPath = "wineps16";
416 di3a.pDataFile = "<datafile?>";
417 di3a.pConfigFile = "wineps16";
418 di3a.pHelpFile = "<helpfile?>";
419 di3a.pDependentFiles = "<dependend files?>";
420 di3a.pMonitorName = "<monitor name?>";
421 di3a.pDefaultDataType = "RAW";
423 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
424 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
425 return;
428 /* This ensures that all printer entries have a valid Name value. If causes
429 problems later if they don't. If one is found to be missed we create one
430 and set it equal to the name of the key */
431 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
432 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
433 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
434 for(i = 0; i < num; i++) {
435 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
436 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
437 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
438 set_reg_szW(hkey, NameW, PrinterName);
440 RegCloseKey(hkey);
445 RegCloseKey(hkeyPrinters);
448 /* We want to avoid calling AddPrinter on printers as much as
449 possible, because on cups printers this will (eventually) lead
450 to a call to cupsGetPPD which takes forever, even with non-cups
451 printers AddPrinter takes a while. So we'll tag all printers that
452 were automatically added last time around, if they still exist
453 we'll leave them be otherwise we'll delete them. */
454 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
455 if(needed) {
456 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
457 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
458 for(i = 0; i < num; i++) {
459 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
460 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
461 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
462 DWORD dw = 1;
463 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
464 RegCloseKey(hkey);
466 ClosePrinter(hprn);
471 HeapFree(GetProcessHeap(), 0, pi);
475 #ifdef HAVE_CUPS_CUPS_H
476 done = CUPS_LoadPrinters();
477 #endif
479 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
480 /* Check for [ppd] section in config file before parsing /etc/printcap */
481 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
482 &hkey) == ERROR_SUCCESS) {
483 RegCloseKey(hkey);
484 PRINTCAP_LoadPrinters();
488 /* Now enumerate the list again and delete any printers that a still tagged */
489 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
490 if(needed) {
491 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
492 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
493 for(i = 0; i < num; i++) {
494 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
495 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
496 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
497 DWORD dw, type, size = sizeof(dw);
498 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
499 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
500 DeletePrinter(hprn);
502 RegCloseKey(hkey);
504 ClosePrinter(hprn);
509 HeapFree(GetProcessHeap(), 0, pi);
512 return;
517 /******************************************************************
518 * WINSPOOL_GetOpenedPrinterEntry
519 * Get the first place empty in the opened printer table
521 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
523 int i;
525 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
527 if (i >= nb_printers)
529 LPWSTR *new_array;
530 if (printer_array)
531 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
532 (nb_printers + 16) * sizeof(*new_array) );
533 else
534 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
535 (nb_printers + 16) * sizeof(*new_array) );
537 if (!new_array) return 0;
538 printer_array = new_array;
539 nb_printers += 16;
542 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
544 strcpyW( printer_array[i], name );
545 return (HANDLE)(i + 1);
547 return 0;
550 /******************************************************************
551 * WINSPOOL_GetOpenedPrinter
552 * Get the pointer to the opened printer referred by the handle
554 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
556 int idx = (int)printerHandle;
557 if ((idx <= 0) || (idx > nb_printers))
559 SetLastError(ERROR_INVALID_HANDLE);
560 return NULL;
562 return printer_array[idx - 1];
565 /******************************************************************
566 * WINSPOOL_GetOpenedPrinterRegKey
569 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
571 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
572 DWORD ret;
573 HKEY hkeyPrinters;
575 if(!name) return ERROR_INVALID_HANDLE;
577 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
578 ERROR_SUCCESS)
579 return ret;
581 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
583 ERR("Can't find opened printer %s in registry\n",
584 debugstr_w(name));
585 RegCloseKey(hkeyPrinters);
586 return ERROR_INVALID_PRINTER_NAME; /* ? */
588 RegCloseKey(hkeyPrinters);
589 return ERROR_SUCCESS;
592 /***********************************************************
593 * DEVMODEcpyAtoW
595 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
597 BOOL Formname;
598 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
599 DWORD size;
601 Formname = (dmA->dmSize > off_formname);
602 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
603 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
604 CCHDEVICENAME);
605 if(!Formname) {
606 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
607 dmA->dmSize - CCHDEVICENAME);
608 } else {
609 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
610 off_formname - CCHDEVICENAME);
611 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
612 CCHFORMNAME);
613 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
614 (off_formname + CCHFORMNAME));
616 dmW->dmSize = size;
617 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
618 dmA->dmDriverExtra);
619 return dmW;
622 /***********************************************************
623 * DEVMODEdupWtoA
624 * Creates an ascii copy of supplied devmode on heap
626 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
628 LPDEVMODEA dmA;
629 DWORD size;
630 BOOL Formname;
631 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
633 if(!dmW) return NULL;
634 Formname = (dmW->dmSize > off_formname);
635 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
636 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
637 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
638 CCHDEVICENAME, NULL, NULL);
639 if(!Formname) {
640 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
641 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
642 } else {
643 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
644 off_formname - CCHDEVICENAME * sizeof(WCHAR));
645 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
646 CCHFORMNAME, NULL, NULL);
647 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
648 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
650 dmA->dmSize = size;
651 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
652 dmW->dmDriverExtra);
653 return dmA;
656 /***********************************************************
657 * PRINTER_INFO_2AtoW
658 * Creates a unicode copy of PRINTER_INFO_2A on heap
660 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
662 LPPRINTER_INFO_2W piW;
663 UNICODE_STRING usBuffer;
665 if(!piA) return NULL;
666 piW = HeapAlloc(heap, 0, sizeof(*piW));
667 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
669 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
670 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
671 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
672 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
673 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
674 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
675 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
676 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
677 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
678 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
679 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
680 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
681 return piW;
684 /***********************************************************
685 * FREE_PRINTER_INFO_2W
686 * Free PRINTER_INFO_2W and all strings
688 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
690 if(!piW) return;
692 HeapFree(heap,0,piW->pServerName);
693 HeapFree(heap,0,piW->pPrinterName);
694 HeapFree(heap,0,piW->pShareName);
695 HeapFree(heap,0,piW->pPortName);
696 HeapFree(heap,0,piW->pDriverName);
697 HeapFree(heap,0,piW->pComment);
698 HeapFree(heap,0,piW->pLocation);
699 HeapFree(heap,0,piW->pDevMode);
700 HeapFree(heap,0,piW->pSepFile);
701 HeapFree(heap,0,piW->pPrintProcessor);
702 HeapFree(heap,0,piW->pDatatype);
703 HeapFree(heap,0,piW->pParameters);
704 HeapFree(heap,0,piW);
705 return;
708 /******************************************************************
709 * DeviceCapabilities [WINSPOOL.@]
710 * DeviceCapabilitiesA [WINSPOOL.@]
713 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
714 LPSTR pOutput, LPDEVMODEA lpdm)
716 INT ret;
718 if (!GDI_CallDeviceCapabilities16)
720 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
721 (LPCSTR)104 );
722 if (!GDI_CallDeviceCapabilities16) return -1;
724 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
726 /* If DC_PAPERSIZE map POINT16s to POINTs */
727 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
728 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
729 POINT *pt = (POINT *)pOutput;
730 INT i;
731 memcpy(tmp, pOutput, ret * sizeof(POINT16));
732 for(i = 0; i < ret; i++, pt++)
734 pt->x = tmp[i].x;
735 pt->y = tmp[i].y;
737 HeapFree( GetProcessHeap(), 0, tmp );
739 return ret;
743 /*****************************************************************************
744 * DeviceCapabilitiesW [WINSPOOL.@]
746 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
749 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
750 WORD fwCapability, LPWSTR pOutput,
751 const DEVMODEW *pDevMode)
753 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
754 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
755 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
756 INT ret;
758 if(pOutput && (fwCapability == DC_BINNAMES ||
759 fwCapability == DC_FILEDEPENDENCIES ||
760 fwCapability == DC_PAPERNAMES)) {
761 /* These need A -> W translation */
762 INT size = 0, i;
763 LPSTR pOutputA;
764 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
765 dmA);
766 if(ret == -1)
767 return ret;
768 switch(fwCapability) {
769 case DC_BINNAMES:
770 size = 24;
771 break;
772 case DC_PAPERNAMES:
773 case DC_FILEDEPENDENCIES:
774 size = 64;
775 break;
777 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
778 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
779 dmA);
780 for(i = 0; i < ret; i++)
781 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
782 pOutput + (i * size), size);
783 HeapFree(GetProcessHeap(), 0, pOutputA);
784 } else {
785 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
786 (LPSTR)pOutput, dmA);
788 HeapFree(GetProcessHeap(),0,pPortA);
789 HeapFree(GetProcessHeap(),0,pDeviceA);
790 HeapFree(GetProcessHeap(),0,dmA);
791 return ret;
794 /******************************************************************
795 * DocumentPropertiesA [WINSPOOL.@]
797 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
799 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
800 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
801 LPDEVMODEA pDevModeInput,DWORD fMode )
803 LPSTR lpName = pDeviceName;
804 LONG ret;
806 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
807 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
810 if(!pDeviceName) {
811 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
812 if(!lpNameW) {
813 ERR("no name from hPrinter?\n");
814 return -1;
816 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
819 if (!GDI_CallExtDeviceMode16)
821 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
822 (LPCSTR)102 );
823 if (!GDI_CallExtDeviceMode16) {
824 ERR("No CallExtDeviceMode16?\n");
825 return -1;
828 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
829 pDevModeInput, NULL, fMode);
831 if(!pDeviceName)
832 HeapFree(GetProcessHeap(),0,lpName);
833 return ret;
837 /*****************************************************************************
838 * DocumentPropertiesW (WINSPOOL.@)
840 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
842 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
843 LPWSTR pDeviceName,
844 LPDEVMODEW pDevModeOutput,
845 LPDEVMODEW pDevModeInput, DWORD fMode)
848 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
849 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
850 LPDEVMODEA pDevModeOutputA = NULL;
851 LONG ret;
853 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
854 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
855 fMode);
856 if(pDevModeOutput) {
857 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
858 if(ret < 0) return ret;
859 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
861 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
862 pDevModeInputA, fMode);
863 if(pDevModeOutput) {
864 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
865 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
867 if(fMode == 0 && ret > 0)
868 ret += (CCHDEVICENAME + CCHFORMNAME);
869 HeapFree(GetProcessHeap(),0,pDevModeInputA);
870 HeapFree(GetProcessHeap(),0,pDeviceNameA);
871 return ret;
874 /******************************************************************
875 * OpenPrinterA [WINSPOOL.@]
878 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
879 LPPRINTER_DEFAULTSA pDefault)
881 UNICODE_STRING lpPrinterNameW;
882 UNICODE_STRING usBuffer;
883 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
884 PWSTR pwstrPrinterNameW;
885 BOOL ret;
887 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
889 if(pDefault) {
890 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
891 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
892 DefaultW.DesiredAccess = pDefault->DesiredAccess;
893 pDefaultW = &DefaultW;
895 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
896 if(pDefault) {
897 RtlFreeUnicodeString(&usBuffer);
898 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
900 RtlFreeUnicodeString(&lpPrinterNameW);
901 return ret;
904 /******************************************************************
905 * OpenPrinterW [WINSPOOL.@]
908 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
909 LPPRINTER_DEFAULTSW pDefault)
911 HKEY hkeyPrinters, hkeyPrinter;
913 if (!lpPrinterName) {
914 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
915 SetLastError(ERROR_INVALID_PARAMETER);
916 return FALSE;
919 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
920 pDefault);
922 /* Check Printer exists */
923 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
924 ERROR_SUCCESS) {
925 ERR("Can't create Printers key\n");
926 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
927 return FALSE;
930 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
931 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
932 != ERROR_SUCCESS) {
933 TRACE("Can't find printer %s in registry\n",
934 debugstr_w(lpPrinterName));
935 RegCloseKey(hkeyPrinters);
936 SetLastError(ERROR_INVALID_PRINTER_NAME);
937 return FALSE;
939 RegCloseKey(hkeyPrinter);
940 RegCloseKey(hkeyPrinters);
942 if(!phPrinter) /* This seems to be what win95 does anyway */
943 return TRUE;
945 /* Get the unique handle of the printer*/
946 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
948 if (pDefault != NULL)
949 FIXME("Not handling pDefault\n");
951 return TRUE;
954 /******************************************************************
955 * AddMonitorA [WINSPOOL.@]
958 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
960 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
961 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
962 return FALSE;
965 /******************************************************************
966 * DeletePrinterDriverA [WINSPOOL.@]
969 BOOL WINAPI
970 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
972 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
973 debugstr_a(pDriverName));
974 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
975 return FALSE;
979 /******************************************************************
980 * DeleteMonitorA [WINSPOOL.@]
983 BOOL WINAPI
984 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
986 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
987 debugstr_a(pMonitorName));
988 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
989 return FALSE;
993 /******************************************************************
994 * DeletePortA [WINSPOOL.@]
997 BOOL WINAPI
998 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1000 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1001 debugstr_a(pPortName));
1002 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1003 return FALSE;
1006 /******************************************************************************
1007 * SetPrinterW [WINSPOOL.@]
1009 BOOL WINAPI
1010 SetPrinterW(
1011 HANDLE hPrinter,
1012 DWORD Level,
1013 LPBYTE pPrinter,
1014 DWORD Command) {
1016 FIXME("():stub\n");
1017 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1018 return FALSE;
1021 /******************************************************************************
1022 * WritePrinter [WINSPOOL.@]
1024 BOOL WINAPI
1025 WritePrinter(
1026 HANDLE hPrinter,
1027 LPVOID pBuf,
1028 DWORD cbBuf,
1029 LPDWORD pcWritten) {
1031 FIXME("():stub\n");
1032 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1033 return FALSE;
1036 /*****************************************************************************
1037 * AddFormA [WINSPOOL.@]
1039 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1041 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1042 return 1;
1045 /*****************************************************************************
1046 * AddFormW [WINSPOOL.@]
1048 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1050 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1051 return 1;
1054 /*****************************************************************************
1055 * AddJobA [WINSPOOL.@]
1057 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
1058 DWORD cbBuf, LPDWORD pcbNeeded)
1060 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1061 pcbNeeded);
1062 return 1;
1065 /*****************************************************************************
1066 * AddJobW [WINSPOOL.@]
1068 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
1069 LPDWORD pcbNeeded)
1071 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1072 pcbNeeded);
1073 return 1;
1076 /*****************************************************************************
1077 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1079 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1080 DWORD level, LPBYTE Info,
1081 DWORD cbBuf, LPDWORD needed)
1083 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", server, env, level, Info, cbBuf);
1084 return 0;
1087 /*****************************************************************************
1088 * WINSPOOL_OpenDriverReg [internal]
1090 * opens the registry for the printer drivers depending on the given input
1091 * variable pEnvironment
1093 * RETURNS:
1094 * the opened hkey on success
1095 * NULL on error
1097 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1098 { HKEY retval;
1099 LPSTR lpKey, p = NULL;
1101 TRACE("%s\n",
1102 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1104 if(pEnvironment)
1105 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1106 pEnvironment;
1107 else {
1108 OSVERSIONINFOA ver;
1109 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1111 if(!GetVersionExA( &ver))
1112 return 0;
1114 switch (ver.dwPlatformId) {
1115 case VER_PLATFORM_WIN32s:
1116 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1117 return 0;
1119 case VER_PLATFORM_WIN32_NT:
1120 p = "Windows NT x86";
1121 break;
1122 default:
1123 p = "Windows 4.0";
1124 break;
1126 TRACE("set environment to %s\n", p);
1129 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1130 strlen(p) + strlen(Drivers));
1131 sprintf( lpKey, Drivers, p);
1133 TRACE("%s\n", lpKey);
1135 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1136 ERROR_SUCCESS)
1137 retval = 0;
1139 if(pEnvironment && unicode)
1140 HeapFree( GetProcessHeap(), 0, p);
1141 HeapFree( GetProcessHeap(), 0, lpKey);
1143 return retval;
1146 /*****************************************************************************
1147 * AddPrinterW [WINSPOOL.@]
1149 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1151 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1152 LPDEVMODEA dmA;
1153 LPDEVMODEW dmW;
1154 HANDLE retval;
1155 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1156 LONG size;
1158 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1160 if(pName != NULL) {
1161 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1162 SetLastError(ERROR_INVALID_PARAMETER);
1163 return 0;
1165 if(Level != 2) {
1166 ERR("Level = %ld, unsupported!\n", Level);
1167 SetLastError(ERROR_INVALID_LEVEL);
1168 return 0;
1170 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1171 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1172 debugstr_w(pi->pPrinterName)
1174 SetLastError(ERROR_INVALID_LEVEL);
1175 return 0;
1177 if(!pPrinter) {
1178 SetLastError(ERROR_INVALID_PARAMETER);
1179 return 0;
1181 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1182 ERROR_SUCCESS) {
1183 ERR("Can't create Printers key\n");
1184 return 0;
1186 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1187 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1188 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1189 RegCloseKey(hkeyPrinter);
1190 RegCloseKey(hkeyPrinters);
1191 return 0;
1193 RegCloseKey(hkeyPrinter);
1195 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1196 if(!hkeyDrivers) {
1197 ERR("Can't create Drivers key\n");
1198 RegCloseKey(hkeyPrinters);
1199 return 0;
1201 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1202 ERROR_SUCCESS) {
1203 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1204 RegCloseKey(hkeyPrinters);
1205 RegCloseKey(hkeyDrivers);
1206 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1207 return 0;
1209 RegCloseKey(hkeyDriver);
1210 RegCloseKey(hkeyDrivers);
1212 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1213 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1214 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1215 RegCloseKey(hkeyPrinters);
1216 return 0;
1219 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1220 ERROR_SUCCESS) {
1221 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1222 SetLastError(ERROR_INVALID_PRINTER_NAME);
1223 RegCloseKey(hkeyPrinters);
1224 return 0;
1226 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1227 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1228 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1230 /* See if we can load the driver. We may need the devmode structure anyway
1232 * FIXME:
1233 * Note that DocumentPropertiesW will briefly try to open the printer we
1234 * just create to find a DEVMODEA struct (it will use the WINEPS default
1235 * one in case it is not there, so we are ok).
1237 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1239 if(size < 0) {
1240 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1241 size = sizeof(DEVMODEW);
1243 if(pi->pDevMode)
1244 dmW = pi->pDevMode;
1245 else
1247 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1248 ZeroMemory(dmW,size);
1249 dmW->dmSize = size;
1250 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1252 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1253 HeapFree(GetProcessHeap(),0,dmW);
1254 dmW=NULL;
1256 else
1258 /* set devmode to printer name */
1259 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1263 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1264 and we support these drivers. NT writes DEVMODEW so somehow
1265 we'll need to distinguish between these when we support NT
1266 drivers */
1267 if (dmW)
1269 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1270 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1271 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1272 HeapFree(GetProcessHeap(), 0, dmA);
1273 if(!pi->pDevMode)
1274 HeapFree(GetProcessHeap(), 0, dmW);
1276 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1277 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1278 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1279 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1281 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1282 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1283 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1284 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1285 (LPBYTE)&pi->Priority, sizeof(DWORD));
1286 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1287 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1288 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1289 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1290 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1291 (LPBYTE)&pi->Status, sizeof(DWORD));
1292 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1293 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1295 RegCloseKey(hkeyPrinter);
1296 RegCloseKey(hkeyPrinters);
1297 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1298 ERR("OpenPrinter failing\n");
1299 return 0;
1301 return retval;
1304 /*****************************************************************************
1305 * AddPrinterA [WINSPOOL.@]
1307 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1309 UNICODE_STRING pNameW;
1310 PWSTR pwstrNameW;
1311 PRINTER_INFO_2W *piW;
1312 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1313 HANDLE ret;
1315 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1316 if(Level != 2) {
1317 ERR("Level = %ld, unsupported!\n", Level);
1318 SetLastError(ERROR_INVALID_LEVEL);
1319 return 0;
1321 pwstrNameW = asciitounicode(&pNameW,pName);
1322 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1324 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1326 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1327 RtlFreeUnicodeString(&pNameW);
1328 return ret;
1332 /*****************************************************************************
1333 * ClosePrinter [WINSPOOL.@]
1335 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1337 int i = (int)hPrinter;
1339 TRACE("Handle %p\n", hPrinter);
1341 if ((i <= 0) || (i > nb_printers)) return FALSE;
1342 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1343 printer_array[i - 1] = NULL;
1344 return TRUE;
1347 /*****************************************************************************
1348 * DeleteFormA [WINSPOOL.@]
1350 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1352 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1353 return 1;
1356 /*****************************************************************************
1357 * DeleteFormW [WINSPOOL.@]
1359 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1361 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1362 return 1;
1365 /*****************************************************************************
1366 * WINSPOOL_SHRegDeleteKey
1368 * Recursively delete subkeys.
1369 * Cut & paste from shlwapi.
1372 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1374 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1375 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1376 HKEY hSubKey = 0;
1378 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1379 if(!dwRet)
1381 /* Find how many subkeys there are */
1382 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1383 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1384 if(!dwRet)
1386 dwMaxSubkeyLen++;
1387 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1388 /* Name too big: alloc a buffer for it */
1389 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1391 if(!lpszName)
1392 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1393 else
1395 /* Recursively delete all the subkeys */
1396 for(i = 0; i < dwKeyCount && !dwRet; i++)
1398 dwSize = dwMaxSubkeyLen;
1399 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1400 if(!dwRet)
1401 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1404 if (lpszName != szNameBuf)
1405 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1409 RegCloseKey(hSubKey);
1410 if(!dwRet)
1411 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1413 return dwRet;
1416 /*****************************************************************************
1417 * DeletePrinter [WINSPOOL.@]
1419 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1421 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1422 HKEY hkeyPrinters;
1424 if(!lpNameW) return FALSE;
1425 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1426 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1427 RegCloseKey(hkeyPrinters);
1429 WriteProfileStringW(devicesW, lpNameW, NULL);
1430 return TRUE;
1433 /*****************************************************************************
1434 * SetPrinterA [WINSPOOL.@]
1436 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1437 DWORD Command)
1439 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1440 return FALSE;
1443 /*****************************************************************************
1444 * SetJobA [WINSPOOL.@]
1446 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1447 LPBYTE pJob, DWORD Command)
1449 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1450 Command);
1451 return FALSE;
1454 /*****************************************************************************
1455 * SetJobW [WINSPOOL.@]
1457 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1458 LPBYTE pJob, DWORD Command)
1460 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1461 Command);
1462 return FALSE;
1465 /*****************************************************************************
1466 * EndDocPrinter [WINSPOOL.@]
1468 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1470 FIXME("(hPrinter=%p): stub\n", hPrinter);
1471 return FALSE;
1474 /*****************************************************************************
1475 * EndPagePrinter [WINSPOOL.@]
1477 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1479 FIXME("(hPrinter=%p): stub\n", hPrinter);
1480 return FALSE;
1483 /*****************************************************************************
1484 * StartDocPrinterA [WINSPOOL.@]
1486 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1488 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1489 return FALSE;
1492 /*****************************************************************************
1493 * StartDocPrinterW [WINSPOOL.@]
1495 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1497 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1498 return FALSE;
1501 /*****************************************************************************
1502 * StartPagePrinter [WINSPOOL.@]
1504 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1506 FIXME("(hPrinter=%p): stub\n", hPrinter);
1507 return FALSE;
1510 /*****************************************************************************
1511 * GetFormA [WINSPOOL.@]
1513 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1514 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1516 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1517 Level,pForm,cbBuf,pcbNeeded);
1518 return FALSE;
1521 /*****************************************************************************
1522 * GetFormW [WINSPOOL.@]
1524 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1525 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1527 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1528 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1529 return FALSE;
1532 /*****************************************************************************
1533 * SetFormA [WINSPOOL.@]
1535 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1536 LPBYTE pForm)
1538 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1539 return FALSE;
1542 /*****************************************************************************
1543 * SetFormW [WINSPOOL.@]
1545 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1546 LPBYTE pForm)
1548 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1549 return FALSE;
1552 /*****************************************************************************
1553 * ReadPrinter [WINSPOOL.@]
1555 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1556 LPDWORD pNoBytesRead)
1558 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1559 return FALSE;
1562 /*****************************************************************************
1563 * ResetPrinterA [WINSPOOL.@]
1565 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1567 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1568 return FALSE;
1571 /*****************************************************************************
1572 * ResetPrinterW [WINSPOOL.@]
1574 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1576 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1577 return FALSE;
1580 /*****************************************************************************
1581 * WINSPOOL_GetDWORDFromReg
1583 * Return DWORD associated with ValueName from hkey.
1585 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1587 DWORD sz = sizeof(DWORD), type, value = 0;
1588 LONG ret;
1590 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1592 if(ret != ERROR_SUCCESS) {
1593 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1594 return 0;
1596 if(type != REG_DWORD) {
1597 ERR("Got type %ld\n", type);
1598 return 0;
1600 return value;
1603 /*****************************************************************************
1604 * WINSPOOL_GetStringFromReg
1606 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1607 * String is stored either as unicode or ascii.
1608 * Bit of a hack here to get the ValueName if we want ascii.
1610 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1611 DWORD buflen, DWORD *needed,
1612 BOOL unicode)
1614 DWORD sz = buflen, type;
1615 LONG ret;
1617 if(unicode)
1618 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1619 else {
1620 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1621 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1622 HeapFree(GetProcessHeap(),0,ValueNameA);
1624 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1625 WARN("Got ret = %ld\n", ret);
1626 *needed = 0;
1627 return FALSE;
1629 *needed = sz;
1630 return TRUE;
1633 /*****************************************************************************
1634 * WINSPOOL_GetDefaultDevMode
1636 * Get a default DevMode values for wineps.
1637 * FIXME - use ppd.
1640 static void WINSPOOL_GetDefaultDevMode(
1641 LPBYTE ptr,
1642 DWORD buflen, DWORD *needed,
1643 BOOL unicode)
1645 DEVMODEA dm;
1647 /* fill default DEVMODE - should be read from ppd... */
1648 ZeroMemory( &dm, sizeof(dm) );
1649 strcpy(dm.dmDeviceName,"wineps");
1650 dm.dmSpecVersion = DM_SPECVERSION;
1651 dm.dmDriverVersion = 1;
1652 dm.dmSize = sizeof(DEVMODEA);
1653 dm.dmDriverExtra = 0;
1654 dm.dmFields =
1655 DM_ORIENTATION | DM_PAPERSIZE |
1656 DM_PAPERLENGTH | DM_PAPERWIDTH |
1657 DM_SCALE |
1658 DM_COPIES |
1659 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1660 DM_YRESOLUTION | DM_TTOPTION;
1662 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1663 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1664 dm.u1.s1.dmPaperLength = 2970;
1665 dm.u1.s1.dmPaperWidth = 2100;
1667 dm.dmScale = 100;
1668 dm.dmCopies = 1;
1669 dm.dmDefaultSource = DMBIN_AUTO;
1670 dm.dmPrintQuality = DMRES_MEDIUM;
1671 /* dm.dmColor */
1672 /* dm.dmDuplex */
1673 dm.dmYResolution = 300; /* 300dpi */
1674 dm.dmTTOption = DMTT_BITMAP;
1675 /* dm.dmCollate */
1676 /* dm.dmFormName */
1677 /* dm.dmLogPixels */
1678 /* dm.dmBitsPerPel */
1679 /* dm.dmPelsWidth */
1680 /* dm.dmPelsHeight */
1681 /* dm.dmDisplayFlags */
1682 /* dm.dmDisplayFrequency */
1683 /* dm.dmICMMethod */
1684 /* dm.dmICMIntent */
1685 /* dm.dmMediaType */
1686 /* dm.dmDitherType */
1687 /* dm.dmReserved1 */
1688 /* dm.dmReserved2 */
1689 /* dm.dmPanningWidth */
1690 /* dm.dmPanningHeight */
1692 if(unicode) {
1693 if(buflen >= sizeof(DEVMODEW)) {
1694 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1695 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1696 HeapFree(GetProcessHeap(),0,pdmW);
1698 *needed = sizeof(DEVMODEW);
1700 else
1702 if(buflen >= sizeof(DEVMODEA)) {
1703 memcpy(ptr, &dm, sizeof(DEVMODEA));
1705 *needed = sizeof(DEVMODEA);
1709 /*****************************************************************************
1710 * WINSPOOL_GetDevModeFromReg
1712 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1713 * DevMode is stored either as unicode or ascii.
1715 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1716 LPBYTE ptr,
1717 DWORD buflen, DWORD *needed,
1718 BOOL unicode)
1720 DWORD sz = buflen, type;
1721 LONG ret;
1723 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1724 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1725 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1726 if (sz < sizeof(DEVMODEA))
1728 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1729 return FALSE;
1731 /* ensures that dmSize is not erratically bogus if registry is invalid */
1732 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1733 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1734 if(unicode) {
1735 sz += (CCHDEVICENAME + CCHFORMNAME);
1736 if(buflen >= sz) {
1737 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1738 memcpy(ptr, dmW, sz);
1739 HeapFree(GetProcessHeap(),0,dmW);
1742 *needed = sz;
1743 return TRUE;
1746 /*********************************************************************
1747 * WINSPOOL_GetPrinter_2
1749 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1750 * The strings are either stored as unicode or ascii.
1752 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1753 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1754 BOOL unicode)
1756 DWORD size, left = cbBuf;
1757 BOOL space = (cbBuf > 0);
1758 LPBYTE ptr = buf;
1760 *pcbNeeded = 0;
1762 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1763 unicode)) {
1764 if(space && size <= left) {
1765 pi2->pPrinterName = (LPWSTR)ptr;
1766 ptr += size;
1767 left -= size;
1768 } else
1769 space = FALSE;
1770 *pcbNeeded += size;
1772 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1773 unicode)) {
1774 if(space && size <= left) {
1775 pi2->pShareName = (LPWSTR)ptr;
1776 ptr += size;
1777 left -= size;
1778 } else
1779 space = FALSE;
1780 *pcbNeeded += size;
1782 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1783 unicode)) {
1784 if(space && size <= left) {
1785 pi2->pPortName = (LPWSTR)ptr;
1786 ptr += size;
1787 left -= size;
1788 } else
1789 space = FALSE;
1790 *pcbNeeded += size;
1792 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1793 &size, unicode)) {
1794 if(space && size <= left) {
1795 pi2->pDriverName = (LPWSTR)ptr;
1796 ptr += size;
1797 left -= size;
1798 } else
1799 space = FALSE;
1800 *pcbNeeded += size;
1802 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1803 unicode)) {
1804 if(space && size <= left) {
1805 pi2->pComment = (LPWSTR)ptr;
1806 ptr += size;
1807 left -= size;
1808 } else
1809 space = FALSE;
1810 *pcbNeeded += size;
1812 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1813 unicode)) {
1814 if(space && size <= left) {
1815 pi2->pLocation = (LPWSTR)ptr;
1816 ptr += size;
1817 left -= size;
1818 } else
1819 space = FALSE;
1820 *pcbNeeded += size;
1822 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1823 &size, unicode)) {
1824 if(space && size <= left) {
1825 pi2->pDevMode = (LPDEVMODEW)ptr;
1826 ptr += size;
1827 left -= size;
1828 } else
1829 space = FALSE;
1830 *pcbNeeded += size;
1832 else
1834 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1835 if(space && size <= left) {
1836 pi2->pDevMode = (LPDEVMODEW)ptr;
1837 ptr += size;
1838 left -= size;
1839 } else
1840 space = FALSE;
1841 *pcbNeeded += size;
1843 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1844 &size, unicode)) {
1845 if(space && size <= left) {
1846 pi2->pSepFile = (LPWSTR)ptr;
1847 ptr += size;
1848 left -= size;
1849 } else
1850 space = FALSE;
1851 *pcbNeeded += size;
1853 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1854 &size, unicode)) {
1855 if(space && size <= left) {
1856 pi2->pPrintProcessor = (LPWSTR)ptr;
1857 ptr += size;
1858 left -= size;
1859 } else
1860 space = FALSE;
1861 *pcbNeeded += size;
1863 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1864 &size, unicode)) {
1865 if(space && size <= left) {
1866 pi2->pDatatype = (LPWSTR)ptr;
1867 ptr += size;
1868 left -= size;
1869 } else
1870 space = FALSE;
1871 *pcbNeeded += size;
1873 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1874 &size, unicode)) {
1875 if(space && size <= left) {
1876 pi2->pParameters = (LPWSTR)ptr;
1877 ptr += size;
1878 left -= size;
1879 } else
1880 space = FALSE;
1881 *pcbNeeded += size;
1883 if(pi2) {
1884 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1885 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1886 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1887 "Default Priority");
1888 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1889 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1892 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1893 memset(pi2, 0, sizeof(*pi2));
1895 return space;
1898 /*********************************************************************
1899 * WINSPOOL_GetPrinter_4
1901 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1903 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1904 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1905 BOOL unicode)
1907 DWORD size, left = cbBuf;
1908 BOOL space = (cbBuf > 0);
1909 LPBYTE ptr = buf;
1911 *pcbNeeded = 0;
1913 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1914 unicode)) {
1915 if(space && size <= left) {
1916 pi4->pPrinterName = (LPWSTR)ptr;
1917 ptr += size;
1918 left -= size;
1919 } else
1920 space = FALSE;
1921 *pcbNeeded += size;
1923 if(pi4) {
1924 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1927 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1928 memset(pi4, 0, sizeof(*pi4));
1930 return space;
1933 /*********************************************************************
1934 * WINSPOOL_GetPrinter_5
1936 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1938 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1939 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1940 BOOL unicode)
1942 DWORD size, left = cbBuf;
1943 BOOL space = (cbBuf > 0);
1944 LPBYTE ptr = buf;
1946 *pcbNeeded = 0;
1948 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1949 unicode)) {
1950 if(space && size <= left) {
1951 pi5->pPrinterName = (LPWSTR)ptr;
1952 ptr += size;
1953 left -= size;
1954 } else
1955 space = FALSE;
1956 *pcbNeeded += size;
1958 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1959 unicode)) {
1960 if(space && size <= left) {
1961 pi5->pPortName = (LPWSTR)ptr;
1962 ptr += size;
1963 left -= size;
1964 } else
1965 space = FALSE;
1966 *pcbNeeded += size;
1968 if(pi5) {
1969 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1970 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1971 "dnsTimeout");
1972 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1973 "txTimeout");
1976 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1977 memset(pi5, 0, sizeof(*pi5));
1979 return space;
1982 /*****************************************************************************
1983 * WINSPOOL_GetPrinter
1985 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1986 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1987 * just a collection of pointers to strings.
1989 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1990 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1992 LPCWSTR name;
1993 DWORD size, needed = 0;
1994 LPBYTE ptr = NULL;
1995 HKEY hkeyPrinter, hkeyPrinters;
1996 BOOL ret;
1998 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2000 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2002 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2003 ERROR_SUCCESS) {
2004 ERR("Can't create Printers key\n");
2005 return FALSE;
2007 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2009 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2010 RegCloseKey(hkeyPrinters);
2011 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2012 return FALSE;
2015 switch(Level) {
2016 case 2:
2018 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2020 size = sizeof(PRINTER_INFO_2W);
2021 if(size <= cbBuf) {
2022 ptr = pPrinter + size;
2023 cbBuf -= size;
2024 memset(pPrinter, 0, size);
2025 } else {
2026 pi2 = NULL;
2027 cbBuf = 0;
2029 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2030 unicode);
2031 needed += size;
2032 break;
2035 case 4:
2037 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2039 size = sizeof(PRINTER_INFO_4W);
2040 if(size <= cbBuf) {
2041 ptr = pPrinter + size;
2042 cbBuf -= size;
2043 memset(pPrinter, 0, size);
2044 } else {
2045 pi4 = NULL;
2046 cbBuf = 0;
2048 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2049 unicode);
2050 needed += size;
2051 break;
2055 case 5:
2057 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2059 size = sizeof(PRINTER_INFO_5W);
2060 if(size <= cbBuf) {
2061 ptr = pPrinter + size;
2062 cbBuf -= size;
2063 memset(pPrinter, 0, size);
2064 } else {
2065 pi5 = NULL;
2066 cbBuf = 0;
2069 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2070 unicode);
2071 needed += size;
2072 break;
2075 default:
2076 FIXME("Unimplemented level %ld\n", Level);
2077 SetLastError(ERROR_INVALID_LEVEL);
2078 RegCloseKey(hkeyPrinters);
2079 RegCloseKey(hkeyPrinter);
2080 return FALSE;
2083 RegCloseKey(hkeyPrinter);
2084 RegCloseKey(hkeyPrinters);
2086 TRACE("returning %d needed = %ld\n", ret, needed);
2087 if(pcbNeeded) *pcbNeeded = needed;
2088 if(!ret)
2089 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2090 return ret;
2093 /*****************************************************************************
2094 * GetPrinterW [WINSPOOL.@]
2096 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2097 DWORD cbBuf, LPDWORD pcbNeeded)
2099 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2100 TRUE);
2103 /*****************************************************************************
2104 * GetPrinterA [WINSPOOL.@]
2106 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2107 DWORD cbBuf, LPDWORD pcbNeeded)
2109 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2110 FALSE);
2113 /*****************************************************************************
2114 * WINSPOOL_EnumPrinters
2116 * Implementation of EnumPrintersA|W
2118 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2119 DWORD dwLevel, LPBYTE lpbPrinters,
2120 DWORD cbBuf, LPDWORD lpdwNeeded,
2121 LPDWORD lpdwReturned, BOOL unicode)
2124 HKEY hkeyPrinters, hkeyPrinter;
2125 WCHAR PrinterName[255];
2126 DWORD needed = 0, number = 0;
2127 DWORD used, i, left;
2128 PBYTE pi, buf;
2130 if(lpbPrinters)
2131 memset(lpbPrinters, 0, cbBuf);
2132 if(lpdwReturned)
2133 *lpdwReturned = 0;
2134 if(lpdwNeeded)
2135 *lpdwNeeded = 0;
2137 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2138 if(dwType == PRINTER_ENUM_DEFAULT)
2139 return TRUE;
2141 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2142 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2143 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2144 if(!dwType) return TRUE;
2147 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2148 FIXME("dwType = %08lx\n", dwType);
2149 SetLastError(ERROR_INVALID_FLAGS);
2150 return FALSE;
2153 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2154 ERROR_SUCCESS) {
2155 ERR("Can't create Printers key\n");
2156 return FALSE;
2159 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2160 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2161 RegCloseKey(hkeyPrinters);
2162 ERR("Can't query Printers key\n");
2163 return FALSE;
2165 TRACE("Found %ld printers\n", number);
2167 switch(dwLevel) {
2168 case 1:
2169 RegCloseKey(hkeyPrinters);
2170 if (lpdwReturned)
2171 *lpdwReturned = number;
2172 return TRUE;
2174 case 2:
2175 used = number * sizeof(PRINTER_INFO_2W);
2176 break;
2177 case 4:
2178 used = number * sizeof(PRINTER_INFO_4W);
2179 break;
2180 case 5:
2181 used = number * sizeof(PRINTER_INFO_5W);
2182 break;
2184 default:
2185 SetLastError(ERROR_INVALID_LEVEL);
2186 RegCloseKey(hkeyPrinters);
2187 return FALSE;
2189 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2191 for(i = 0; i < number; i++) {
2192 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2193 ERROR_SUCCESS) {
2194 ERR("Can't enum key number %ld\n", i);
2195 RegCloseKey(hkeyPrinters);
2196 return FALSE;
2198 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2199 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2200 ERROR_SUCCESS) {
2201 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2202 RegCloseKey(hkeyPrinters);
2203 return FALSE;
2206 if(cbBuf > used) {
2207 buf = lpbPrinters + used;
2208 left = cbBuf - used;
2209 } else {
2210 buf = NULL;
2211 left = 0;
2214 switch(dwLevel) {
2215 case 2:
2216 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2217 left, &needed, unicode);
2218 used += needed;
2219 if(pi) pi += sizeof(PRINTER_INFO_2W);
2220 break;
2221 case 4:
2222 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2223 left, &needed, unicode);
2224 used += needed;
2225 if(pi) pi += sizeof(PRINTER_INFO_4W);
2226 break;
2227 case 5:
2228 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2229 left, &needed, unicode);
2230 used += needed;
2231 if(pi) pi += sizeof(PRINTER_INFO_5W);
2232 break;
2233 default:
2234 ERR("Shouldn't be here!\n");
2235 RegCloseKey(hkeyPrinter);
2236 RegCloseKey(hkeyPrinters);
2237 return FALSE;
2239 RegCloseKey(hkeyPrinter);
2241 RegCloseKey(hkeyPrinters);
2243 if(lpdwNeeded)
2244 *lpdwNeeded = used;
2246 if(used > cbBuf) {
2247 if(lpbPrinters)
2248 memset(lpbPrinters, 0, cbBuf);
2249 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2250 return FALSE;
2252 if(lpdwReturned)
2253 *lpdwReturned = number;
2254 SetLastError(ERROR_SUCCESS);
2255 return TRUE;
2259 /******************************************************************
2260 * EnumPrintersW [WINSPOOL.@]
2262 * Enumerates the available printers, print servers and print
2263 * providers, depending on the specified flags, name and level.
2265 * RETURNS:
2267 * If level is set to 1:
2268 * Not implemented yet!
2269 * Returns TRUE with an empty list.
2271 * If level is set to 2:
2272 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2273 * Returns an array of PRINTER_INFO_2 data structures in the
2274 * lpbPrinters buffer. Note that according to MSDN also an
2275 * OpenPrinter should be performed on every remote printer.
2277 * If level is set to 4 (officially WinNT only):
2278 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2279 * Fast: Only the registry is queried to retrieve printer names,
2280 * no connection to the driver is made.
2281 * Returns an array of PRINTER_INFO_4 data structures in the
2282 * lpbPrinters buffer.
2284 * If level is set to 5 (officially WinNT4/Win9x only):
2285 * Fast: Only the registry is queried to retrieve printer names,
2286 * no connection to the driver is made.
2287 * Returns an array of PRINTER_INFO_5 data structures in the
2288 * lpbPrinters buffer.
2290 * If level set to 3 or 6+:
2291 * returns zero (failure!)
2293 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2294 * for information.
2296 * BUGS:
2297 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2298 * - Only levels 2, 4 and 5 are implemented at the moment.
2299 * - 16-bit printer drivers are not enumerated.
2300 * - Returned amount of bytes used/needed does not match the real Windoze
2301 * implementation (as in this implementation, all strings are part
2302 * of the buffer, whereas Win32 keeps them somewhere else)
2303 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2305 * NOTE:
2306 * - In a regular Wine installation, no registry settings for printers
2307 * exist, which makes this function return an empty list.
2309 BOOL WINAPI EnumPrintersW(
2310 DWORD dwType, /* [in] Types of print objects to enumerate */
2311 LPWSTR lpszName, /* [in] name of objects to enumerate */
2312 DWORD dwLevel, /* [in] type of printer info structure */
2313 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2314 DWORD cbBuf, /* [in] max size of buffer in bytes */
2315 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2316 LPDWORD lpdwReturned /* [out] number of entries returned */
2319 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2320 lpdwNeeded, lpdwReturned, TRUE);
2323 /******************************************************************
2324 * EnumPrintersA [WINSPOOL.@]
2327 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2328 DWORD dwLevel, LPBYTE lpbPrinters,
2329 DWORD cbBuf, LPDWORD lpdwNeeded,
2330 LPDWORD lpdwReturned)
2332 BOOL ret;
2333 UNICODE_STRING lpszNameW;
2334 PWSTR pwstrNameW;
2336 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2337 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2338 lpdwNeeded, lpdwReturned, FALSE);
2339 RtlFreeUnicodeString(&lpszNameW);
2340 return ret;
2343 /*****************************************************************************
2344 * WINSPOOL_GetDriverInfoFromReg [internal]
2346 * Enters the information from the registry into the DRIVER_INFO struct
2348 * RETURNS
2349 * zero if the printer driver does not exist in the registry
2350 * (only if Level > 1) otherwise nonzero
2352 static BOOL WINSPOOL_GetDriverInfoFromReg(
2353 HKEY hkeyDrivers,
2354 LPWSTR DriverName,
2355 LPWSTR pEnvironment,
2356 DWORD Level,
2357 LPBYTE ptr, /* DRIVER_INFO */
2358 LPBYTE pDriverStrings, /* strings buffer */
2359 DWORD cbBuf, /* size of string buffer */
2360 LPDWORD pcbNeeded, /* space needed for str. */
2361 BOOL unicode) /* type of strings */
2362 { DWORD dw, size, tmp, type;
2363 HKEY hkeyDriver;
2364 LPBYTE strPtr = pDriverStrings;
2366 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2367 debugstr_w(DriverName), debugstr_w(pEnvironment),
2368 Level, ptr, pDriverStrings, cbBuf, unicode);
2370 if(unicode) {
2371 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2372 if (*pcbNeeded <= cbBuf)
2373 strcpyW((LPWSTR)strPtr, DriverName);
2374 } else {
2375 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2376 NULL, NULL);
2377 if(*pcbNeeded <= cbBuf)
2378 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2379 NULL, NULL);
2381 if(Level == 1) {
2382 if(ptr)
2383 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2384 return TRUE;
2385 } else {
2386 if(ptr)
2387 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2388 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2391 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2392 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2393 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2394 return FALSE;
2397 size = sizeof(dw);
2398 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2399 ERROR_SUCCESS)
2400 WARN("Can't get Version\n");
2401 else if(ptr)
2402 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2404 if(!pEnvironment)
2405 pEnvironment = (LPWSTR)DefaultEnvironmentW;
2406 if(unicode)
2407 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2408 else
2409 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2410 NULL, NULL);
2411 *pcbNeeded += size;
2412 if(*pcbNeeded <= cbBuf) {
2413 if(unicode)
2414 strcpyW((LPWSTR)strPtr, pEnvironment);
2415 else
2416 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2417 NULL, NULL);
2418 if(ptr)
2419 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2420 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2423 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2424 unicode)) {
2425 *pcbNeeded += size;
2426 if(*pcbNeeded <= cbBuf)
2427 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2428 unicode);
2429 if(ptr)
2430 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2431 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2434 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2435 unicode)) {
2436 *pcbNeeded += size;
2437 if(*pcbNeeded <= cbBuf)
2438 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2439 &tmp, unicode);
2440 if(ptr)
2441 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2442 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2445 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2446 0, &size, unicode)) {
2447 *pcbNeeded += size;
2448 if(*pcbNeeded <= cbBuf)
2449 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2450 size, &tmp, unicode);
2451 if(ptr)
2452 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2453 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2456 if(Level == 2 ) {
2457 RegCloseKey(hkeyDriver);
2458 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2459 return TRUE;
2462 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2463 unicode)) {
2464 *pcbNeeded += size;
2465 if(*pcbNeeded <= cbBuf)
2466 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2467 size, &tmp, unicode);
2468 if(ptr)
2469 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2470 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2473 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2474 &size, unicode)) {
2475 *pcbNeeded += size;
2476 if(*pcbNeeded <= cbBuf)
2477 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2478 size, &tmp, unicode);
2479 if(ptr)
2480 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2481 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2484 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2485 unicode)) {
2486 *pcbNeeded += size;
2487 if(*pcbNeeded <= cbBuf)
2488 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2489 size, &tmp, unicode);
2490 if(ptr)
2491 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2492 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2495 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2496 unicode)) {
2497 *pcbNeeded += size;
2498 if(*pcbNeeded <= cbBuf)
2499 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2500 size, &tmp, unicode);
2501 if(ptr)
2502 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2503 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2506 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2507 RegCloseKey(hkeyDriver);
2508 return TRUE;
2511 /*****************************************************************************
2512 * WINSPOOL_GetPrinterDriver
2514 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2515 DWORD Level, LPBYTE pDriverInfo,
2516 DWORD cbBuf, LPDWORD pcbNeeded,
2517 BOOL unicode)
2519 LPCWSTR name;
2520 WCHAR DriverName[100];
2521 DWORD ret, type, size, needed = 0;
2522 LPBYTE ptr = NULL;
2523 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2525 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2526 Level,pDriverInfo,cbBuf, pcbNeeded);
2528 ZeroMemory(pDriverInfo, cbBuf);
2530 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2532 if(Level < 1 || Level > 3) {
2533 SetLastError(ERROR_INVALID_LEVEL);
2534 return FALSE;
2536 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2537 ERROR_SUCCESS) {
2538 ERR("Can't create Printers key\n");
2539 return FALSE;
2541 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2542 != ERROR_SUCCESS) {
2543 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2544 RegCloseKey(hkeyPrinters);
2545 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2546 return FALSE;
2548 size = sizeof(DriverName);
2549 DriverName[0] = 0;
2550 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2551 (LPBYTE)DriverName, &size);
2552 RegCloseKey(hkeyPrinter);
2553 RegCloseKey(hkeyPrinters);
2554 if(ret != ERROR_SUCCESS) {
2555 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2556 return FALSE;
2559 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2560 if(!hkeyDrivers) {
2561 ERR("Can't create Drivers key\n");
2562 return FALSE;
2565 switch(Level) {
2566 case 1:
2567 size = sizeof(DRIVER_INFO_1W);
2568 break;
2569 case 2:
2570 size = sizeof(DRIVER_INFO_2W);
2571 break;
2572 case 3:
2573 size = sizeof(DRIVER_INFO_3W);
2574 break;
2575 default:
2576 ERR("Invalid level\n");
2577 return FALSE;
2580 if(size <= cbBuf)
2581 ptr = pDriverInfo + size;
2583 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2584 pEnvironment, Level, pDriverInfo,
2585 (cbBuf < size) ? NULL : ptr,
2586 (cbBuf < size) ? 0 : cbBuf - size,
2587 &needed, unicode)) {
2588 RegCloseKey(hkeyDrivers);
2589 return FALSE;
2592 RegCloseKey(hkeyDrivers);
2594 if(pcbNeeded) *pcbNeeded = size + needed;
2595 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2596 if(cbBuf >= needed) return TRUE;
2597 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2598 return FALSE;
2601 /*****************************************************************************
2602 * GetPrinterDriverA [WINSPOOL.@]
2604 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2605 DWORD Level, LPBYTE pDriverInfo,
2606 DWORD cbBuf, LPDWORD pcbNeeded)
2608 BOOL ret;
2609 UNICODE_STRING pEnvW;
2610 PWSTR pwstrEnvW;
2612 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2613 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2614 cbBuf, pcbNeeded, FALSE);
2615 RtlFreeUnicodeString(&pEnvW);
2616 return ret;
2618 /*****************************************************************************
2619 * GetPrinterDriverW [WINSPOOL.@]
2621 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2622 DWORD Level, LPBYTE pDriverInfo,
2623 DWORD cbBuf, LPDWORD pcbNeeded)
2625 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2626 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2629 /*****************************************************************************
2630 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2632 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2633 DWORD Level, LPBYTE pDriverDirectory,
2634 DWORD cbBuf, LPDWORD pcbNeeded)
2636 DWORD needed;
2638 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2639 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2640 if(pName != NULL) {
2641 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2642 SetLastError(ERROR_INVALID_PARAMETER);
2643 return FALSE;
2645 if(pEnvironment != NULL) {
2646 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2647 SetLastError(ERROR_INVALID_ENVIRONMENT);
2648 return FALSE;
2650 if(Level != 1) /* win95 ignores this so we just carry on */
2651 WARN("Level = %ld - assuming 1\n", Level);
2653 /* FIXME should read from registry */
2654 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2655 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2656 * adjust this now
2658 needed++;
2659 needed*=sizeof(WCHAR);
2661 if(pcbNeeded)
2662 *pcbNeeded = needed;
2663 TRACE("required <%08lx>\n", *pcbNeeded);
2664 if(needed > cbBuf) {
2665 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2666 return FALSE;
2668 return TRUE;
2672 /*****************************************************************************
2673 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2675 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2676 DWORD Level, LPBYTE pDriverDirectory,
2677 DWORD cbBuf, LPDWORD pcbNeeded)
2679 UNICODE_STRING nameW, environmentW;
2680 BOOL ret;
2681 DWORD pcbNeededW;
2682 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2683 WCHAR *driverDirectoryW = NULL;
2685 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2687 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2688 else nameW.Buffer = NULL;
2689 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2690 else environmentW.Buffer = NULL;
2692 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2693 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2694 if (ret) {
2695 DWORD needed;
2696 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2697 pDriverDirectory, cbBuf, NULL, NULL);
2698 if(pcbNeeded)
2699 *pcbNeeded = needed;
2700 ret = (needed <= cbBuf) ? TRUE : FALSE;
2701 } else
2702 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2704 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2706 if(driverDirectoryW)
2707 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2708 RtlFreeUnicodeString(&environmentW);
2709 RtlFreeUnicodeString(&nameW);
2711 return ret;
2714 /*****************************************************************************
2715 * AddPrinterDriverA [WINSPOOL.@]
2717 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2719 DRIVER_INFO_3A di3;
2720 HKEY hkeyDrivers, hkeyName;
2722 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2724 if(level != 2 && level != 3) {
2725 SetLastError(ERROR_INVALID_LEVEL);
2726 return FALSE;
2728 if(pName != NULL) {
2729 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2730 SetLastError(ERROR_INVALID_PARAMETER);
2731 return FALSE;
2733 if(!pDriverInfo) {
2734 WARN("pDriverInfo == NULL\n");
2735 SetLastError(ERROR_INVALID_PARAMETER);
2736 return FALSE;
2739 if(level == 3)
2740 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2741 else {
2742 memset(&di3, 0, sizeof(di3));
2743 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2746 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2747 !di3.pDataFile) {
2748 SetLastError(ERROR_INVALID_PARAMETER);
2749 return FALSE;
2751 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2752 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2753 if(!di3.pHelpFile) di3.pHelpFile = "";
2754 if(!di3.pMonitorName) di3.pMonitorName = "";
2756 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2758 if(!hkeyDrivers) {
2759 ERR("Can't create Drivers key\n");
2760 return FALSE;
2763 if(level == 2) { /* apparently can't overwrite with level2 */
2764 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2765 RegCloseKey(hkeyName);
2766 RegCloseKey(hkeyDrivers);
2767 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2768 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2769 return FALSE;
2772 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2773 RegCloseKey(hkeyDrivers);
2774 ERR("Can't create Name key\n");
2775 return FALSE;
2777 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2779 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2780 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2781 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2782 sizeof(DWORD));
2783 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2784 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2785 di3.pDependentFiles, 0);
2786 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2787 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2788 RegCloseKey(hkeyName);
2789 RegCloseKey(hkeyDrivers);
2791 return TRUE;
2793 /*****************************************************************************
2794 * AddPrinterDriverW [WINSPOOL.@]
2796 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2797 LPBYTE pDriverInfo)
2799 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2800 level,pDriverInfo);
2801 return FALSE;
2805 /*****************************************************************************
2806 * PrinterProperties [WINSPOOL.@]
2808 * Displays a dialog to set the properties of the printer.
2810 * RETURNS
2811 * nonzero on success or zero on failure
2813 * BUGS
2814 * implemented as stub only
2816 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2817 HANDLE hPrinter /* [in] handle to printer object */
2819 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2820 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2821 return FALSE;
2824 /*****************************************************************************
2825 * EnumJobsA [WINSPOOL.@]
2828 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2829 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2830 LPDWORD pcReturned)
2832 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2833 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2835 if(pcbNeeded) *pcbNeeded = 0;
2836 if(pcReturned) *pcReturned = 0;
2837 return FALSE;
2841 /*****************************************************************************
2842 * EnumJobsW [WINSPOOL.@]
2845 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2846 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2847 LPDWORD pcReturned)
2849 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2850 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2852 if(pcbNeeded) *pcbNeeded = 0;
2853 if(pcReturned) *pcReturned = 0;
2854 return FALSE;
2857 /*****************************************************************************
2858 * WINSPOOL_EnumPrinterDrivers [internal]
2860 * Delivers information about all printer drivers installed on the
2861 * localhost or a given server
2863 * RETURNS
2864 * nonzero on success or zero on failure. If the buffer for the returned
2865 * information is too small the function will return an error
2867 * BUGS
2868 * - only implemented for localhost, foreign hosts will return an error
2870 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2871 DWORD Level, LPBYTE pDriverInfo,
2872 DWORD cbBuf, LPDWORD pcbNeeded,
2873 LPDWORD pcReturned, BOOL unicode)
2875 { HKEY hkeyDrivers;
2876 DWORD i, needed, number = 0, size = 0;
2877 WCHAR DriverNameW[255];
2878 PBYTE ptr;
2880 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2881 debugstr_w(pName), debugstr_w(pEnvironment),
2882 Level, pDriverInfo, cbBuf, unicode);
2884 /* check for local drivers */
2885 if(pName) {
2886 ERR("remote drivers unsupported! Current remote host is %s\n",
2887 debugstr_w(pName));
2888 return FALSE;
2891 /* check input parameter */
2892 if((Level < 1) || (Level > 3)) {
2893 ERR("unsupported level %ld \n", Level);
2894 return FALSE;
2897 /* initialize return values */
2898 if(pDriverInfo)
2899 memset( pDriverInfo, 0, cbBuf);
2900 *pcbNeeded = 0;
2901 *pcReturned = 0;
2903 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2904 if(!hkeyDrivers) {
2905 ERR("Can't open Drivers key\n");
2906 return FALSE;
2909 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2910 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2911 RegCloseKey(hkeyDrivers);
2912 ERR("Can't query Drivers key\n");
2913 return FALSE;
2915 TRACE("Found %ld Drivers\n", number);
2917 /* get size of single struct
2918 * unicode and ascii structure have the same size
2920 switch (Level) {
2921 case 1:
2922 size = sizeof(DRIVER_INFO_1A);
2923 break;
2924 case 2:
2925 size = sizeof(DRIVER_INFO_2A);
2926 break;
2927 case 3:
2928 size = sizeof(DRIVER_INFO_3A);
2929 break;
2932 /* calculate required buffer size */
2933 *pcbNeeded = size * number;
2935 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2936 i < number;
2937 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2938 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2939 != ERROR_SUCCESS) {
2940 ERR("Can't enum key number %ld\n", i);
2941 RegCloseKey(hkeyDrivers);
2942 return FALSE;
2944 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2945 pEnvironment, Level, ptr,
2946 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2947 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2948 &needed, unicode)) {
2949 RegCloseKey(hkeyDrivers);
2950 return FALSE;
2952 (*pcbNeeded) += needed;
2955 RegCloseKey(hkeyDrivers);
2957 if(cbBuf < *pcbNeeded){
2958 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2959 return FALSE;
2962 return TRUE;
2965 /*****************************************************************************
2966 * EnumPrinterDriversW [WINSPOOL.@]
2968 * see function EnumPrinterDrivers for RETURNS, BUGS
2970 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2971 LPBYTE pDriverInfo, DWORD cbBuf,
2972 LPDWORD pcbNeeded, LPDWORD pcReturned)
2974 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2975 cbBuf, pcbNeeded, pcReturned, TRUE);
2978 /*****************************************************************************
2979 * EnumPrinterDriversA [WINSPOOL.@]
2981 * see function EnumPrinterDrivers for RETURNS, BUGS
2983 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2984 LPBYTE pDriverInfo, DWORD cbBuf,
2985 LPDWORD pcbNeeded, LPDWORD pcReturned)
2986 { BOOL ret;
2987 UNICODE_STRING pNameW, pEnvironmentW;
2988 PWSTR pwstrNameW, pwstrEnvironmentW;
2990 pwstrNameW = asciitounicode(&pNameW, pName);
2991 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
2993 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
2994 Level, pDriverInfo, cbBuf, pcbNeeded,
2995 pcReturned, FALSE);
2996 RtlFreeUnicodeString(&pNameW);
2997 RtlFreeUnicodeString(&pEnvironmentW);
2999 return ret;
3002 static CHAR PortMonitor[] = "Wine Port Monitor";
3003 static CHAR PortDescription[] = "Wine Port";
3005 /******************************************************************************
3006 * EnumPortsA (WINSPOOL.@)
3008 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3009 LPDWORD bufneeded,LPDWORD bufreturned)
3011 CHAR portname[10];
3012 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3013 const LPCSTR szSerialPortKey = "Software\\Wine\\Wine\\Config\\serialports";
3014 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3015 HKEY hkey_serial, hkey_printer;
3017 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3018 name,level,buffer,bufsize,bufneeded,bufreturned);
3020 switch( level )
3022 case 1:
3023 info_size = sizeof (PORT_INFO_1A);
3024 break;
3025 case 2:
3026 info_size = sizeof (PORT_INFO_2A);
3027 break;
3028 default:
3029 SetLastError(ERROR_INVALID_LEVEL);
3030 return FALSE;
3033 /* see how many exist */
3035 hkey_serial = 0;
3036 hkey_printer = 0;
3037 serial_count = 0;
3038 printer_count = 0;
3039 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szSerialPortKey, &hkey_serial);
3040 if (r == ERROR_SUCCESS)
3042 RegQueryInfoKeyA ( hkey_serial, NULL, NULL, NULL, NULL, NULL, NULL,
3043 &serial_count, NULL, NULL, NULL, NULL);
3046 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3047 if ( r == ERROR_SUCCESS )
3049 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3050 &printer_count, NULL, NULL, NULL, NULL);
3052 count = serial_count + printer_count;
3054 /* then fill in the structure info structure once
3055 we know the offset to the first string */
3057 memset( buffer, 0, bufsize );
3058 n = 0;
3059 ofs = info_size*count;
3060 for ( i=0; i<count; i++)
3062 DWORD vallen = sizeof(portname) - 1;
3064 /* get the serial port values, then the printer values */
3065 if ( i < serial_count )
3066 r = RegEnumValueA( hkey_serial, i,
3067 portname, &vallen, NULL, NULL, NULL, 0 );
3068 else
3069 r = RegEnumValueA( hkey_printer, i-serial_count,
3070 portname, &vallen, NULL, NULL, NULL, 0 );
3072 if ( r )
3073 continue;
3075 /* add a colon if necessary, and make it upper case */
3076 CharUpperBuffA(portname,vallen);
3077 if (strcasecmp(portname,"nul")!=0)
3078 if (vallen && (portname[vallen-1] != ':') )
3079 lstrcatA(portname,":");
3081 /* add the port info structure if we can fit it */
3082 if ( info_size*(n+1) < bufsize )
3084 if ( level == 1)
3086 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3087 info->pName = (LPSTR) &buffer[ofs];
3089 else if ( level == 2)
3091 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3092 info->pPortName = (LPSTR) &buffer[ofs];
3093 /* FIXME: fill in more stuff here */
3094 info->pMonitorName = PortMonitor;
3095 info->pDescription = PortDescription;
3096 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3099 /* add the name of the port if we can fit it */
3100 if ( ofs < bufsize )
3101 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3104 ofs += lstrlenA(portname)+1;
3105 n++;
3108 RegCloseKey(hkey_serial);
3109 RegCloseKey(hkey_printer);
3111 if(bufneeded)
3112 *bufneeded = ofs;
3114 if(bufreturned)
3115 *bufreturned = count;
3117 return TRUE;
3121 /******************************************************************************
3122 * GetDefaultPrinterW (WINSPOOL.@)
3124 * FIXME
3125 * This function must read the value from data 'device' of key
3126 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3128 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3130 BOOL retval = TRUE;
3131 DWORD insize, len;
3132 WCHAR *buffer, *ptr;
3134 if (!namesize)
3136 SetLastError(ERROR_INVALID_PARAMETER);
3137 return FALSE;
3140 /* make the buffer big enough for the stuff from the profile/registry,
3141 * the content must fit into the local buffer to compute the correct
3142 * size even if the extern buffer is to small or not given.
3143 * (20 for ,driver,port) */
3144 insize = *namesize;
3145 len = max(100, (insize + 20));
3146 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3148 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3150 SetLastError (ERROR_FILE_NOT_FOUND);
3151 retval = FALSE;
3152 goto end;
3154 TRACE("%s\n", debugstr_w(buffer));
3156 if ((ptr = strchrW(buffer, ',')) == NULL)
3158 SetLastError(ERROR_INVALID_NAME);
3159 retval = FALSE;
3160 goto end;
3163 *ptr = 0;
3164 *namesize = strlenW(buffer) + 1;
3165 if(!name || (*namesize > insize))
3167 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3168 retval = FALSE;
3169 goto end;
3171 strcpyW(name, buffer);
3173 end:
3174 if(buffer) HeapFree( GetProcessHeap(), 0, buffer);
3175 return retval;
3179 /******************************************************************************
3180 * GetDefaultPrinterA (WINSPOOL.@)
3182 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3184 BOOL retval = TRUE;
3185 DWORD insize = 0;
3186 WCHAR *bufferW = NULL;
3188 if (!namesize)
3190 SetLastError(ERROR_INVALID_PARAMETER);
3191 return FALSE;
3194 if(name && *namesize) {
3195 insize = *namesize;
3196 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3199 if(!GetDefaultPrinterW( bufferW, namesize)) {
3200 retval = FALSE;
3201 goto end;
3204 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3205 NULL, NULL);
3206 if (!*namesize)
3208 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3209 retval = FALSE;
3211 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3213 end:
3214 if(bufferW) HeapFree( GetProcessHeap(), 0, bufferW);
3215 return retval;
3219 /******************************************************************************
3220 * SetPrinterDataExA (WINSPOOL.@)
3222 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3223 LPCSTR pValueName, DWORD Type,
3224 LPBYTE pData, DWORD cbData)
3226 HKEY hkeyPrinter, hkeySubkey;
3227 DWORD ret;
3229 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3230 debugstr_a(pValueName), Type, pData, cbData);
3232 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3233 != ERROR_SUCCESS)
3234 return ret;
3236 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3237 != ERROR_SUCCESS) {
3238 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3239 RegCloseKey(hkeyPrinter);
3240 return ret;
3242 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3243 RegCloseKey(hkeySubkey);
3244 RegCloseKey(hkeyPrinter);
3245 return ret;
3248 /******************************************************************************
3249 * SetPrinterDataExW (WINSPOOL.@)
3251 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3252 LPCWSTR pValueName, DWORD Type,
3253 LPBYTE pData, DWORD cbData)
3255 HKEY hkeyPrinter, hkeySubkey;
3256 DWORD ret;
3258 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3259 debugstr_w(pValueName), Type, pData, cbData);
3261 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3262 != ERROR_SUCCESS)
3263 return ret;
3265 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3266 != ERROR_SUCCESS) {
3267 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3268 RegCloseKey(hkeyPrinter);
3269 return ret;
3271 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3272 RegCloseKey(hkeySubkey);
3273 RegCloseKey(hkeyPrinter);
3274 return ret;
3277 /******************************************************************************
3278 * SetPrinterDataA (WINSPOOL.@)
3280 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3281 LPBYTE pData, DWORD cbData)
3283 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3284 pData, cbData);
3287 /******************************************************************************
3288 * SetPrinterDataW (WINSPOOL.@)
3290 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3291 LPBYTE pData, DWORD cbData)
3293 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3294 pData, cbData);
3297 /******************************************************************************
3298 * GetPrinterDataExA (WINSPOOL.@)
3300 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3301 LPCSTR pValueName, LPDWORD pType,
3302 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3304 HKEY hkeyPrinter, hkeySubkey;
3305 DWORD ret;
3307 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3308 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3309 pcbNeeded);
3311 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3312 != ERROR_SUCCESS)
3313 return ret;
3315 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3316 != ERROR_SUCCESS) {
3317 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3318 RegCloseKey(hkeyPrinter);
3319 return ret;
3321 *pcbNeeded = nSize;
3322 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3323 RegCloseKey(hkeySubkey);
3324 RegCloseKey(hkeyPrinter);
3325 return ret;
3328 /******************************************************************************
3329 * GetPrinterDataExW (WINSPOOL.@)
3331 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3332 LPCWSTR pValueName, LPDWORD pType,
3333 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3335 HKEY hkeyPrinter, hkeySubkey;
3336 DWORD ret;
3338 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3339 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3340 pcbNeeded);
3342 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3343 != ERROR_SUCCESS)
3344 return ret;
3346 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3347 != ERROR_SUCCESS) {
3348 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3349 RegCloseKey(hkeyPrinter);
3350 return ret;
3352 *pcbNeeded = nSize;
3353 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3354 RegCloseKey(hkeySubkey);
3355 RegCloseKey(hkeyPrinter);
3356 return ret;
3359 /******************************************************************************
3360 * GetPrinterDataA (WINSPOOL.@)
3362 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3363 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3365 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3366 pData, nSize, pcbNeeded);
3369 /******************************************************************************
3370 * GetPrinterDataW (WINSPOOL.@)
3372 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3373 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3375 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3376 pData, nSize, pcbNeeded);
3379 /*******************************************************************************
3380 * EnumPrinterDataExW [WINSPOOL.@]
3382 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3383 LPBYTE pEnumValues, DWORD cbEnumValues,
3384 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3386 HKEY hkPrinter, hkSubKey;
3387 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3388 cbValueNameLen, cbMaxValueLen, cbValueLen,
3389 cbBufSize, dwType;
3390 LPWSTR lpValueName;
3391 HANDLE hHeap;
3392 PBYTE lpValue;
3393 PPRINTER_ENUM_VALUESW ppev;
3395 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3397 if (pKeyName == NULL || *pKeyName == 0)
3398 return ERROR_INVALID_PARAMETER;
3400 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3401 if (ret != ERROR_SUCCESS)
3403 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3404 hPrinter, ret);
3405 return ret;
3408 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3409 if (ret != ERROR_SUCCESS)
3411 r = RegCloseKey (hkPrinter);
3412 if (r != ERROR_SUCCESS)
3413 WARN ("RegCloseKey returned %li\n", r);
3414 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3415 debugstr_w (pKeyName), ret);
3416 return ret;
3419 ret = RegCloseKey (hkPrinter);
3420 if (ret != ERROR_SUCCESS)
3422 ERR ("RegCloseKey returned %li\n", ret);
3423 r = RegCloseKey (hkSubKey);
3424 if (r != ERROR_SUCCESS)
3425 WARN ("RegCloseKey returned %li\n", r);
3426 return ret;
3429 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3430 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3431 if (ret != ERROR_SUCCESS)
3433 r = RegCloseKey (hkSubKey);
3434 if (r != ERROR_SUCCESS)
3435 WARN ("RegCloseKey returned %li\n", r);
3436 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3437 return ret;
3440 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3441 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3443 if (cValues == 0) /* empty key */
3445 r = RegCloseKey (hkSubKey);
3446 if (r != ERROR_SUCCESS)
3447 WARN ("RegCloseKey returned %li\n", r);
3448 *pcbEnumValues = *pnEnumValues = 0;
3449 return ERROR_SUCCESS;
3452 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3454 hHeap = GetProcessHeap ();
3455 if (hHeap == NULL)
3457 ERR ("GetProcessHeap failed\n");
3458 r = RegCloseKey (hkSubKey);
3459 if (r != ERROR_SUCCESS)
3460 WARN ("RegCloseKey returned %li\n", r);
3461 return ERROR_OUTOFMEMORY;
3464 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3465 if (lpValueName == NULL)
3467 ERR ("Failed to allocate %li bytes from process heap\n",
3468 cbMaxValueNameLen * sizeof (WCHAR));
3469 r = RegCloseKey (hkSubKey);
3470 if (r != ERROR_SUCCESS)
3471 WARN ("RegCloseKey returned %li\n", r);
3472 return ERROR_OUTOFMEMORY;
3475 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3476 if (lpValue == NULL)
3478 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3479 if (HeapFree (hHeap, 0, lpValueName) == 0)
3480 WARN ("HeapFree failed with code %li\n", GetLastError ());
3481 r = RegCloseKey (hkSubKey);
3482 if (r != ERROR_SUCCESS)
3483 WARN ("RegCloseKey returned %li\n", r);
3484 return ERROR_OUTOFMEMORY;
3487 TRACE ("pass 1: calculating buffer required for all names and values\n");
3489 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3491 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3493 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3495 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3496 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3497 NULL, NULL, lpValue, &cbValueLen);
3498 if (ret != ERROR_SUCCESS)
3500 if (HeapFree (hHeap, 0, lpValue) == 0)
3501 WARN ("HeapFree failed with code %li\n", GetLastError ());
3502 if (HeapFree (hHeap, 0, lpValueName) == 0)
3503 WARN ("HeapFree failed with code %li\n", GetLastError ());
3504 r = RegCloseKey (hkSubKey);
3505 if (r != ERROR_SUCCESS)
3506 WARN ("RegCloseKey returned %li\n", r);
3507 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3508 return ret;
3511 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3512 debugstr_w (lpValueName), dwIndex,
3513 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3515 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3516 cbBufSize += cbValueLen;
3519 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3521 *pcbEnumValues = cbBufSize;
3522 *pnEnumValues = cValues;
3524 if (cbEnumValues < cbBufSize) /* buffer too small */
3526 if (HeapFree (hHeap, 0, lpValue) == 0)
3527 WARN ("HeapFree failed with code %li\n", GetLastError ());
3528 if (HeapFree (hHeap, 0, lpValueName) == 0)
3529 WARN ("HeapFree failed with code %li\n", GetLastError ());
3530 r = RegCloseKey (hkSubKey);
3531 if (r != ERROR_SUCCESS)
3532 WARN ("RegCloseKey returned %li\n", r);
3533 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3534 return ERROR_MORE_DATA;
3537 TRACE ("pass 2: copying all names and values to buffer\n");
3539 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3540 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3542 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3544 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3545 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3546 NULL, &dwType, lpValue, &cbValueLen);
3547 if (ret != ERROR_SUCCESS)
3549 if (HeapFree (hHeap, 0, lpValue) == 0)
3550 WARN ("HeapFree failed with code %li\n", GetLastError ());
3551 if (HeapFree (hHeap, 0, lpValueName) == 0)
3552 WARN ("HeapFree failed with code %li\n", GetLastError ());
3553 r = RegCloseKey (hkSubKey);
3554 if (r != ERROR_SUCCESS)
3555 WARN ("RegCloseKey returned %li\n", r);
3556 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3557 return ret;
3560 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3561 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3562 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3563 pEnumValues += cbValueNameLen;
3565 /* return # of *bytes* (including trailing \0), not # of chars */
3566 ppev[dwIndex].cbValueName = cbValueNameLen;
3568 ppev[dwIndex].dwType = dwType;
3570 memcpy (pEnumValues, lpValue, cbValueLen);
3571 ppev[dwIndex].pData = pEnumValues;
3572 pEnumValues += cbValueLen;
3574 ppev[dwIndex].cbData = cbValueLen;
3576 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3577 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3580 if (HeapFree (hHeap, 0, lpValue) == 0)
3582 ret = GetLastError ();
3583 ERR ("HeapFree failed with code %li\n", ret);
3584 if (HeapFree (hHeap, 0, lpValueName) == 0)
3585 WARN ("HeapFree failed with code %li\n", GetLastError ());
3586 r = RegCloseKey (hkSubKey);
3587 if (r != ERROR_SUCCESS)
3588 WARN ("RegCloseKey returned %li\n", r);
3589 return ret;
3592 if (HeapFree (hHeap, 0, lpValueName) == 0)
3594 ret = GetLastError ();
3595 ERR ("HeapFree failed with code %li\n", ret);
3596 r = RegCloseKey (hkSubKey);
3597 if (r != ERROR_SUCCESS)
3598 WARN ("RegCloseKey returned %li\n", r);
3599 return ret;
3602 ret = RegCloseKey (hkSubKey);
3603 if (ret != ERROR_SUCCESS)
3605 ERR ("RegCloseKey returned %li\n", ret);
3606 return ret;
3609 return ERROR_SUCCESS;
3612 /*******************************************************************************
3613 * EnumPrinterDataExA [WINSPOOL.@]
3615 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3616 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3617 * what Windows 2000 SP1 does.
3620 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3621 LPBYTE pEnumValues, DWORD cbEnumValues,
3622 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3624 INT len;
3625 LPWSTR pKeyNameW;
3626 DWORD ret, dwIndex, dwBufSize;
3627 HANDLE hHeap;
3628 LPSTR pBuffer;
3630 TRACE ("%p %s\n", hPrinter, pKeyName);
3632 if (pKeyName == NULL || *pKeyName == 0)
3633 return ERROR_INVALID_PARAMETER;
3635 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3636 if (len == 0)
3638 ret = GetLastError ();
3639 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3640 return ret;
3643 hHeap = GetProcessHeap ();
3644 if (hHeap == NULL)
3646 ERR ("GetProcessHeap failed\n");
3647 return ERROR_OUTOFMEMORY;
3650 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3651 if (pKeyNameW == NULL)
3653 ERR ("Failed to allocate %li bytes from process heap\n",
3654 (LONG) len * sizeof (WCHAR));
3655 return ERROR_OUTOFMEMORY;
3658 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3660 ret = GetLastError ();
3661 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3662 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3663 WARN ("HeapFree failed with code %li\n", GetLastError ());
3664 return ret;
3667 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3668 pcbEnumValues, pnEnumValues);
3669 if (ret != ERROR_SUCCESS)
3671 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3672 WARN ("HeapFree failed with code %li\n", GetLastError ());
3673 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3674 return ret;
3677 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3679 ret = GetLastError ();
3680 ERR ("HeapFree failed with code %li\n", ret);
3681 return ret;
3684 if (*pnEnumValues == 0) /* empty key */
3685 return ERROR_SUCCESS;
3687 dwBufSize = 0;
3688 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3690 PPRINTER_ENUM_VALUESW ppev =
3691 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3693 if (dwBufSize < ppev->cbValueName)
3694 dwBufSize = ppev->cbValueName;
3696 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3697 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3698 dwBufSize = ppev->cbData;
3701 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3703 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3704 if (pBuffer == NULL)
3706 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3707 return ERROR_OUTOFMEMORY;
3710 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3712 PPRINTER_ENUM_VALUESW ppev =
3713 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3715 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3716 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3717 NULL);
3718 if (len == 0)
3720 ret = GetLastError ();
3721 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3722 if (HeapFree (hHeap, 0, pBuffer) == 0)
3723 WARN ("HeapFree failed with code %li\n", GetLastError ());
3724 return ret;
3727 memcpy (ppev->pValueName, pBuffer, len);
3729 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3731 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3732 ppev->dwType != REG_MULTI_SZ)
3733 continue;
3735 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3736 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3737 if (len == 0)
3739 ret = GetLastError ();
3740 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3741 if (HeapFree (hHeap, 0, pBuffer) == 0)
3742 WARN ("HeapFree failed with code %li\n", GetLastError ());
3743 return ret;
3746 memcpy (ppev->pData, pBuffer, len);
3748 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3749 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3752 if (HeapFree (hHeap, 0, pBuffer) == 0)
3754 ret = GetLastError ();
3755 ERR ("HeapFree failed with code %li\n", ret);
3756 return ret;
3759 return ERROR_SUCCESS;
3762 /******************************************************************************
3763 * AddPortA (WINSPOOL.@)
3765 BOOL WINAPI AddPortA(LPSTR pName ,HWND hWnd, LPSTR pMonitorName)
3767 FIXME("(%s, %p, %s\n), stub!\n",pName,hWnd,pMonitorName);
3768 return FALSE;
3771 /******************************************************************************
3772 * AddPrinterDriverExW (WINSPOOL.@)
3774 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
3775 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3777 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
3778 Level, pDriverInfo, dwFileCopyFlags);
3779 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3780 return FALSE;
3783 /******************************************************************************
3784 * AddPrinterDriverExA (WINSPOOL.@)
3786 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
3787 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3789 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
3790 Level, pDriverInfo, dwFileCopyFlags);
3791 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3792 return FALSE;
3795 /******************************************************************************
3796 * DeletePrinterDriverExW (WINSPOOL.@)
3798 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
3799 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3801 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
3802 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
3803 return TRUE;
3806 /******************************************************************************
3807 * DeletePrinterDriverExA (WINSPOOL.@)
3809 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
3810 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3812 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
3813 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
3814 return TRUE;
3817 /******************************************************************************
3818 * DeletePrinterDataExW (WINSPOOL.@)
3820 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
3821 LPCWSTR pValueName)
3823 FIXME("%p %s %s\n", hPrinter,
3824 debugstr_w(pKeyName), debugstr_w(pValueName));
3825 return ERROR_INVALID_PARAMETER;
3828 /******************************************************************************
3829 * DeletePrinterDataExA (WINSPOOL.@)
3831 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
3832 LPCSTR pValueName)
3834 FIXME("%p %s %s\n", hPrinter,
3835 debugstr_a(pKeyName), debugstr_a(pValueName));
3836 return ERROR_INVALID_PARAMETER;
3839 /*****************************************************************************
3840 * EnumMonitorsA [WINSPOOL.@]
3843 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
3844 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
3846 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
3847 cbBuf, pcbNeeded, pcReturned);
3848 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3849 return 0;
3852 /*****************************************************************************
3853 * EnumMonitorsW [WINSPOOL.@]
3856 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
3857 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
3859 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
3860 cbBuf, pcbNeeded, pcReturned);
3861 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3862 return 0;
3865 /******************************************************************************
3866 * XcvDataW (WINSPOOL.@)
3868 * Notes:
3869 * There doesn't seem to be an A version...
3871 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
3872 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
3873 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
3875 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
3876 pInputData, cbInputData, pOutputData,
3877 cbOutputData, pcbOutputNeeded, pdwStatus);
3878 return FALSE;