Add a missing return.
[wine.git] / dlls / winspool / info.c
blob5dd9645fb326a7fc23ca9e6caba5c1336c27c9dc
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 devicesW[] = {'d','e','v','i','c','e','s',0};
106 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
108 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
109 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
110 DWORD Level, LPBYTE pDriverInfo,
111 DWORD cbBuf, LPDWORD pcbNeeded,
112 BOOL unicode);
113 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
115 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
116 if passed a NULL string. This returns NULLs to the result.
118 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
120 if ( (src) )
122 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
123 return usBufferPtr->Buffer;
125 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
126 return NULL;
129 static void
130 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
131 char qbuf[200];
133 /* If forcing, or no profile string entry for device yet, set the entry
135 * The always change entry if not WINEPS yet is discussable.
137 if (force ||
138 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
139 !strcmp(qbuf,"*") ||
140 !strstr(qbuf,"WINEPS")
142 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
144 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
145 WriteProfileStringA("windows","device",buf);
146 HeapFree(GetProcessHeap(),0,buf);
150 #ifdef HAVE_CUPS_CUPS_H
151 static BOOL CUPS_LoadPrinters(void)
153 typeof(cupsGetDests) *pcupsGetDests = NULL;
154 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
155 int i, nrofdests;
156 BOOL hadprinter = FALSE;
157 cups_dest_t *dests;
158 PRINTER_INFO_2A pinfo2a;
159 void *cupshandle = NULL;
160 char *port,*devline;
161 HKEY hkeyPrinter, hkeyPrinters;
163 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
164 if (!cupshandle)
165 return FALSE;
166 TRACE("loaded %s\n", SONAME_LIBCUPS);
168 #define DYNCUPS(x) \
169 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
170 if (!p##x) return FALSE;
172 DYNCUPS(cupsGetPPD);
173 DYNCUPS(cupsGetDests);
174 #undef DYNCUPS
176 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
177 ERROR_SUCCESS) {
178 ERR("Can't create Printers key\n");
179 return FALSE;
182 nrofdests = pcupsGetDests(&dests);
183 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
184 for (i=0;i<nrofdests;i++) {
185 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
186 sprintf(port,"LPR:%s",dests[i].name);
187 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
188 sprintf(devline,"WINEPS,%s",port);
189 WriteProfileStringA("devices",dests[i].name,devline);
190 HeapFree(GetProcessHeap(),0,devline);
192 TRACE("Printer %d: %s\n", i, dests[i].name);
193 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
194 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
195 and continue */
196 TRACE("Printer already exists\n");
197 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
198 RegCloseKey(hkeyPrinter);
199 } else {
200 memset(&pinfo2a,0,sizeof(pinfo2a));
201 pinfo2a.pPrinterName = dests[i].name;
202 pinfo2a.pDatatype = "RAW";
203 pinfo2a.pPrintProcessor = "WinPrint";
204 pinfo2a.pDriverName = "PS Driver";
205 pinfo2a.pComment = "WINEPS Printer using CUPS";
206 pinfo2a.pLocation = "<physical location of printer>";
207 pinfo2a.pPortName = port;
208 pinfo2a.pParameters = "<parameters?>";
209 pinfo2a.pShareName = "<share name?>";
210 pinfo2a.pSepFile = "<sep file?>";
212 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
213 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
214 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
217 HeapFree(GetProcessHeap(),0,port);
219 hadprinter = TRUE;
220 if (dests[i].is_default)
221 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
223 RegCloseKey(hkeyPrinters);
224 wine_dlclose(cupshandle, NULL, 0);
225 return hadprinter;
227 #endif
229 static BOOL
230 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
231 PRINTER_INFO_2A pinfo2a;
232 char *e,*s,*name,*prettyname,*devname;
233 BOOL ret = FALSE, set_default = FALSE;
234 char *port,*devline,*env_default;
235 HKEY hkeyPrinter, hkeyPrinters;
237 while (isspace(*pent)) pent++;
238 s = strchr(pent,':');
239 if(s) *s='\0';
240 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
241 strcpy(name,pent);
242 if(s) {
243 *s=':';
244 pent = s;
245 } else
246 pent = "";
248 TRACE("name=%s entry=%s\n",name, pent);
250 if(ispunct(*name)) { /* a tc entry, not a real printer */
251 TRACE("skipping tc entry\n");
252 goto end;
255 if(strstr(pent,":server")) { /* server only version so skip */
256 TRACE("skipping server entry\n");
257 goto end;
260 /* Determine whether this is a postscript printer. */
262 ret = TRUE;
263 env_default = getenv("PRINTER");
264 prettyname = name;
265 /* Get longest name, usually the one at the right for later display. */
266 while((s=strchr(prettyname,'|'))) {
267 *s = '\0';
268 e = s;
269 while(isspace(*--e)) *e = '\0';
270 TRACE("\t%s\n", debugstr_a(prettyname));
271 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
272 for(prettyname = s+1; isspace(*prettyname); prettyname++)
275 e = prettyname + strlen(prettyname);
276 while(isspace(*--e)) *e = '\0';
277 TRACE("\t%s\n", debugstr_a(prettyname));
278 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
280 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
281 * if it is too long, we use it as comment below. */
282 devname = prettyname;
283 if (strlen(devname)>=CCHDEVICENAME-1)
284 devname = name;
285 if (strlen(devname)>=CCHDEVICENAME-1) {
286 ret = FALSE;
287 goto end;
290 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
291 sprintf(port,"LPR:%s",name);
293 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
294 sprintf(devline,"WINEPS,%s",port);
295 WriteProfileStringA("devices",devname,devline);
296 HeapFree(GetProcessHeap(),0,devline);
298 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
299 ERROR_SUCCESS) {
300 ERR("Can't create Printers key\n");
301 ret = FALSE;
302 goto end;
304 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
305 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
306 and continue */
307 TRACE("Printer already exists\n");
308 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
309 RegCloseKey(hkeyPrinter);
310 } else {
311 memset(&pinfo2a,0,sizeof(pinfo2a));
312 pinfo2a.pPrinterName = devname;
313 pinfo2a.pDatatype = "RAW";
314 pinfo2a.pPrintProcessor = "WinPrint";
315 pinfo2a.pDriverName = "PS Driver";
316 pinfo2a.pComment = "WINEPS Printer using LPR";
317 pinfo2a.pLocation = prettyname;
318 pinfo2a.pPortName = port;
319 pinfo2a.pParameters = "<parameters?>";
320 pinfo2a.pShareName = "<share name?>";
321 pinfo2a.pSepFile = "<sep file?>";
323 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
324 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
325 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
328 RegCloseKey(hkeyPrinters);
330 if (isfirst || set_default)
331 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
333 HeapFree(GetProcessHeap(), 0, port);
334 end:
335 HeapFree(GetProcessHeap(), 0, name);
336 return ret;
339 static BOOL
340 PRINTCAP_LoadPrinters(void) {
341 BOOL hadprinter = FALSE;
342 char buf[200];
343 FILE *f;
344 char *pent = NULL;
345 BOOL had_bash = FALSE;
347 f = fopen("/etc/printcap","r");
348 if (!f)
349 return FALSE;
351 while(fgets(buf,sizeof(buf),f)) {
352 char *start, *end;
354 end=strchr(buf,'\n');
355 if (end) *end='\0';
357 start = buf;
358 while(isspace(*start)) start++;
359 if(*start == '#' || *start == '\0')
360 continue;
362 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
363 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
364 HeapFree(GetProcessHeap(),0,pent);
365 pent = NULL;
368 if (end && *--end == '\\') {
369 *end = '\0';
370 had_bash = TRUE;
371 } else
372 had_bash = FALSE;
374 if (pent) {
375 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
376 strcat(pent,start);
377 } else {
378 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
379 strcpy(pent,start);
383 if(pent) {
384 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
385 HeapFree(GetProcessHeap(),0,pent);
387 fclose(f);
388 return hadprinter;
391 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
393 if (value)
394 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
395 lstrlenW(value) * sizeof(WCHAR));
396 else
397 return ERROR_FILE_NOT_FOUND;
400 void WINSPOOL_LoadSystemPrinters(void)
402 HKEY hkey, hkeyPrinters;
403 DRIVER_INFO_3A di3a;
404 HANDLE hprn;
405 DWORD needed, num, i;
406 WCHAR PrinterName[256];
407 BOOL done = FALSE;
409 di3a.cVersion = 0x400;
410 di3a.pName = "PS Driver";
411 di3a.pEnvironment = NULL; /* NULL means auto */
412 di3a.pDriverPath = "wineps16";
413 di3a.pDataFile = "<datafile?>";
414 di3a.pConfigFile = "wineps16";
415 di3a.pHelpFile = "<helpfile?>";
416 di3a.pDependentFiles = "<dependend files?>";
417 di3a.pMonitorName = "<monitor name?>";
418 di3a.pDefaultDataType = "RAW";
420 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
421 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
422 return;
425 /* This ensures that all printer entries have a valid Name value. If causes
426 problems later if they don't. If one is found to be missed we create one
427 and set it equal to the name of the key */
428 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
429 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
430 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
431 for(i = 0; i < num; i++) {
432 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
433 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
434 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
435 set_reg_szW(hkey, NameW, PrinterName);
437 RegCloseKey(hkey);
442 RegCloseKey(hkeyPrinters);
445 /* We want to avoid calling AddPrinter on printers as much as
446 possible, because on cups printers this will (eventually) lead
447 to a call to cupsGetPPD which takes forever, even with non-cups
448 printers AddPrinter takes a while. So we'll tag all printers that
449 were automatically added last time around, if they still exist
450 we'll leave them be otherwise we'll delete them. */
451 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
452 if(needed) {
453 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
454 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
455 for(i = 0; i < num; i++) {
456 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
457 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
458 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
459 DWORD dw = 1;
460 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
461 RegCloseKey(hkey);
463 ClosePrinter(hprn);
468 HeapFree(GetProcessHeap(), 0, pi);
472 #ifdef HAVE_CUPS_CUPS_H
473 done = CUPS_LoadPrinters();
474 #endif
476 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
477 /* Check for [ppd] section in config file before parsing /etc/printcap */
478 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
479 &hkey) == ERROR_SUCCESS) {
480 RegCloseKey(hkey);
481 PRINTCAP_LoadPrinters();
485 /* Now enumerate the list again and delete any printers that a still tagged */
486 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
487 if(needed) {
488 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
489 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
490 for(i = 0; i < num; i++) {
491 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
492 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
493 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
494 DWORD dw, type, size = sizeof(dw);
495 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
496 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
497 DeletePrinter(hprn);
499 RegCloseKey(hkey);
501 ClosePrinter(hprn);
506 HeapFree(GetProcessHeap(), 0, pi);
509 return;
514 /******************************************************************
515 * WINSPOOL_GetOpenedPrinterEntry
516 * Get the first place empty in the opened printer table
518 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
520 int i;
522 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
524 if (i >= nb_printers)
526 LPWSTR *new_array;
527 if (printer_array)
528 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
529 (nb_printers + 16) * sizeof(*new_array) );
530 else
531 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
532 (nb_printers + 16) * sizeof(*new_array) );
534 if (!new_array) return 0;
535 printer_array = new_array;
536 nb_printers += 16;
539 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
541 strcpyW( printer_array[i], name );
542 return (HANDLE)(i + 1);
544 return 0;
547 /******************************************************************
548 * WINSPOOL_GetOpenedPrinter
549 * Get the pointer to the opened printer referred by the handle
551 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
553 int idx = (int)printerHandle;
554 if ((idx <= 0) || (idx > nb_printers))
556 SetLastError(ERROR_INVALID_HANDLE);
557 return NULL;
559 return printer_array[idx - 1];
562 /******************************************************************
563 * WINSPOOL_GetOpenedPrinterRegKey
566 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
568 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
569 DWORD ret;
570 HKEY hkeyPrinters;
572 if(!name) return ERROR_INVALID_HANDLE;
574 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
575 ERROR_SUCCESS)
576 return ret;
578 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
580 ERR("Can't find opened printer %s in registry\n",
581 debugstr_w(name));
582 RegCloseKey(hkeyPrinters);
583 return ERROR_INVALID_PRINTER_NAME; /* ? */
585 RegCloseKey(hkeyPrinters);
586 return ERROR_SUCCESS;
589 /***********************************************************
590 * DEVMODEcpyAtoW
592 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
594 BOOL Formname;
595 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
596 DWORD size;
598 Formname = (dmA->dmSize > off_formname);
599 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
600 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
601 CCHDEVICENAME);
602 if(!Formname) {
603 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
604 dmA->dmSize - CCHDEVICENAME);
605 } else {
606 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
607 off_formname - CCHDEVICENAME);
608 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
609 CCHFORMNAME);
610 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
611 (off_formname + CCHFORMNAME));
613 dmW->dmSize = size;
614 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
615 dmA->dmDriverExtra);
616 return dmW;
619 /***********************************************************
620 * DEVMODEdupWtoA
621 * Creates an ascii copy of supplied devmode on heap
623 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
625 LPDEVMODEA dmA;
626 DWORD size;
627 BOOL Formname;
628 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
630 if(!dmW) return NULL;
631 Formname = (dmW->dmSize > off_formname);
632 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
633 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
634 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
635 CCHDEVICENAME, NULL, NULL);
636 if(!Formname) {
637 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
638 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
639 } else {
640 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
641 off_formname - CCHDEVICENAME * sizeof(WCHAR));
642 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
643 CCHFORMNAME, NULL, NULL);
644 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
645 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
647 dmA->dmSize = size;
648 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
649 dmW->dmDriverExtra);
650 return dmA;
653 /***********************************************************
654 * PRINTER_INFO_2AtoW
655 * Creates a unicode copy of PRINTER_INFO_2A on heap
657 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
659 LPPRINTER_INFO_2W piW;
660 UNICODE_STRING usBuffer;
662 if(!piA) return NULL;
663 piW = HeapAlloc(heap, 0, sizeof(*piW));
664 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
666 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
667 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
668 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
669 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
670 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
671 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
672 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
673 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
674 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
675 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
676 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
677 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
678 return piW;
681 /***********************************************************
682 * FREE_PRINTER_INFO_2W
683 * Free PRINTER_INFO_2W and all strings
685 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
687 if(!piW) return;
689 HeapFree(heap,0,piW->pServerName);
690 HeapFree(heap,0,piW->pPrinterName);
691 HeapFree(heap,0,piW->pShareName);
692 HeapFree(heap,0,piW->pPortName);
693 HeapFree(heap,0,piW->pDriverName);
694 HeapFree(heap,0,piW->pComment);
695 HeapFree(heap,0,piW->pLocation);
696 HeapFree(heap,0,piW->pDevMode);
697 HeapFree(heap,0,piW->pSepFile);
698 HeapFree(heap,0,piW->pPrintProcessor);
699 HeapFree(heap,0,piW->pDatatype);
700 HeapFree(heap,0,piW->pParameters);
701 HeapFree(heap,0,piW);
702 return;
705 /******************************************************************
706 * DeviceCapabilities [WINSPOOL.@]
707 * DeviceCapabilitiesA [WINSPOOL.@]
710 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
711 LPSTR pOutput, LPDEVMODEA lpdm)
713 INT ret;
715 if (!GDI_CallDeviceCapabilities16)
717 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
718 (LPCSTR)104 );
719 if (!GDI_CallDeviceCapabilities16) return -1;
721 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
723 /* If DC_PAPERSIZE map POINT16s to POINTs */
724 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
725 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
726 POINT *pt = (POINT *)pOutput;
727 INT i;
728 memcpy(tmp, pOutput, ret * sizeof(POINT16));
729 for(i = 0; i < ret; i++, pt++)
731 pt->x = tmp[i].x;
732 pt->y = tmp[i].y;
734 HeapFree( GetProcessHeap(), 0, tmp );
736 return ret;
740 /*****************************************************************************
741 * DeviceCapabilitiesW [WINSPOOL.@]
743 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
746 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
747 WORD fwCapability, LPWSTR pOutput,
748 const DEVMODEW *pDevMode)
750 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
751 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
752 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
753 INT ret;
755 if(pOutput && (fwCapability == DC_BINNAMES ||
756 fwCapability == DC_FILEDEPENDENCIES ||
757 fwCapability == DC_PAPERNAMES)) {
758 /* These need A -> W translation */
759 INT size = 0, i;
760 LPSTR pOutputA;
761 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
762 dmA);
763 if(ret == -1)
764 return ret;
765 switch(fwCapability) {
766 case DC_BINNAMES:
767 size = 24;
768 break;
769 case DC_PAPERNAMES:
770 case DC_FILEDEPENDENCIES:
771 size = 64;
772 break;
774 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
775 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
776 dmA);
777 for(i = 0; i < ret; i++)
778 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
779 pOutput + (i * size), size);
780 HeapFree(GetProcessHeap(), 0, pOutputA);
781 } else {
782 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
783 (LPSTR)pOutput, dmA);
785 HeapFree(GetProcessHeap(),0,pPortA);
786 HeapFree(GetProcessHeap(),0,pDeviceA);
787 HeapFree(GetProcessHeap(),0,dmA);
788 return ret;
791 /******************************************************************
792 * DocumentPropertiesA [WINSPOOL.@]
794 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
796 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
797 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
798 LPDEVMODEA pDevModeInput,DWORD fMode )
800 LPSTR lpName = pDeviceName;
801 LONG ret;
803 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
804 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
807 if(!pDeviceName) {
808 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
809 if(!lpNameW) {
810 ERR("no name from hPrinter?\n");
811 return -1;
813 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
816 if (!GDI_CallExtDeviceMode16)
818 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
819 (LPCSTR)102 );
820 if (!GDI_CallExtDeviceMode16) {
821 ERR("No CallExtDeviceMode16?\n");
822 return -1;
825 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
826 pDevModeInput, NULL, fMode);
828 if(!pDeviceName)
829 HeapFree(GetProcessHeap(),0,lpName);
830 return ret;
834 /*****************************************************************************
835 * DocumentPropertiesW (WINSPOOL.@)
837 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
839 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
840 LPWSTR pDeviceName,
841 LPDEVMODEW pDevModeOutput,
842 LPDEVMODEW pDevModeInput, DWORD fMode)
845 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
846 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
847 LPDEVMODEA pDevModeOutputA = NULL;
848 LONG ret;
850 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
851 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
852 fMode);
853 if(pDevModeOutput) {
854 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
855 if(ret < 0) return ret;
856 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
858 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
859 pDevModeInputA, fMode);
860 if(pDevModeOutput) {
861 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
862 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
864 if(fMode == 0 && ret > 0)
865 ret += (CCHDEVICENAME + CCHFORMNAME);
866 HeapFree(GetProcessHeap(),0,pDevModeInputA);
867 HeapFree(GetProcessHeap(),0,pDeviceNameA);
868 return ret;
871 /******************************************************************
872 * OpenPrinterA [WINSPOOL.@]
875 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
876 LPPRINTER_DEFAULTSA pDefault)
878 UNICODE_STRING lpPrinterNameW;
879 UNICODE_STRING usBuffer;
880 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
881 PWSTR pwstrPrinterNameW;
882 BOOL ret;
884 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
886 if(pDefault) {
887 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
888 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
889 DefaultW.DesiredAccess = pDefault->DesiredAccess;
890 pDefaultW = &DefaultW;
892 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
893 if(pDefault) {
894 RtlFreeUnicodeString(&usBuffer);
895 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
897 RtlFreeUnicodeString(&lpPrinterNameW);
898 return ret;
901 /******************************************************************
902 * OpenPrinterW [WINSPOOL.@]
905 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
906 LPPRINTER_DEFAULTSW pDefault)
908 HKEY hkeyPrinters, hkeyPrinter;
910 if (!lpPrinterName) {
911 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
912 SetLastError(ERROR_INVALID_PARAMETER);
913 return FALSE;
916 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
917 pDefault);
919 /* Check Printer exists */
920 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
921 ERROR_SUCCESS) {
922 ERR("Can't create Printers key\n");
923 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
924 return FALSE;
927 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
928 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
929 != ERROR_SUCCESS) {
930 TRACE("Can't find printer %s in registry\n",
931 debugstr_w(lpPrinterName));
932 RegCloseKey(hkeyPrinters);
933 SetLastError(ERROR_INVALID_PRINTER_NAME);
934 return FALSE;
936 RegCloseKey(hkeyPrinter);
937 RegCloseKey(hkeyPrinters);
939 if(!phPrinter) /* This seems to be what win95 does anyway */
940 return TRUE;
942 /* Get the unique handle of the printer*/
943 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
945 if (pDefault != NULL)
946 FIXME("Not handling pDefault\n");
948 return TRUE;
951 /******************************************************************
952 * AddMonitorA [WINSPOOL.@]
955 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
957 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
958 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
959 return FALSE;
962 /******************************************************************
963 * DeletePrinterDriverA [WINSPOOL.@]
966 BOOL WINAPI
967 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
969 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
970 debugstr_a(pDriverName));
971 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
972 return FALSE;
976 /******************************************************************
977 * DeleteMonitorA [WINSPOOL.@]
980 BOOL WINAPI
981 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
983 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
984 debugstr_a(pMonitorName));
985 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
986 return FALSE;
990 /******************************************************************
991 * DeletePortA [WINSPOOL.@]
994 BOOL WINAPI
995 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
997 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
998 debugstr_a(pPortName));
999 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1000 return FALSE;
1003 /******************************************************************************
1004 * SetPrinterW [WINSPOOL.@]
1006 BOOL WINAPI
1007 SetPrinterW(
1008 HANDLE hPrinter,
1009 DWORD Level,
1010 LPBYTE pPrinter,
1011 DWORD Command) {
1013 FIXME("():stub\n");
1014 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1015 return FALSE;
1018 /******************************************************************************
1019 * WritePrinter [WINSPOOL.@]
1021 BOOL WINAPI
1022 WritePrinter(
1023 HANDLE hPrinter,
1024 LPVOID pBuf,
1025 DWORD cbBuf,
1026 LPDWORD pcWritten) {
1028 FIXME("():stub\n");
1029 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1030 return FALSE;
1033 /*****************************************************************************
1034 * AddFormA [WINSPOOL.@]
1036 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1038 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1039 return 1;
1042 /*****************************************************************************
1043 * AddFormW [WINSPOOL.@]
1045 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1047 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1048 return 1;
1051 /*****************************************************************************
1052 * AddJobA [WINSPOOL.@]
1054 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
1055 DWORD cbBuf, LPDWORD pcbNeeded)
1057 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1058 pcbNeeded);
1059 return 1;
1062 /*****************************************************************************
1063 * AddJobW [WINSPOOL.@]
1065 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
1066 LPDWORD pcbNeeded)
1068 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1069 pcbNeeded);
1070 return 1;
1073 /*****************************************************************************
1074 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1076 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1077 DWORD level, LPBYTE Info,
1078 DWORD cbBuf, LPDWORD needed)
1080 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", server, env, level, Info, cbBuf);
1081 return 0;
1084 /*****************************************************************************
1085 * WINSPOOL_OpenDriverReg [internal]
1087 * opens the registry for the printer drivers depending on the given input
1088 * variable pEnvironment
1090 * RETURNS:
1091 * the opened hkey on success
1092 * NULL on error
1094 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1095 { HKEY retval;
1096 LPSTR lpKey, p = NULL;
1098 TRACE("%s\n",
1099 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1101 if(pEnvironment)
1102 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1103 pEnvironment;
1104 else {
1105 OSVERSIONINFOA ver;
1106 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1108 if(!GetVersionExA( &ver))
1109 return 0;
1111 switch (ver.dwPlatformId) {
1112 case VER_PLATFORM_WIN32s:
1113 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1114 return 0;
1116 case VER_PLATFORM_WIN32_NT:
1117 p = "Windows NT x86";
1118 break;
1119 default:
1120 p = "Windows 4.0";
1121 break;
1123 TRACE("set environment to %s\n", p);
1126 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1127 strlen(p) + strlen(Drivers));
1128 sprintf( lpKey, Drivers, p);
1130 TRACE("%s\n", lpKey);
1132 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1133 ERROR_SUCCESS)
1134 retval = 0;
1136 if(pEnvironment && unicode)
1137 HeapFree( GetProcessHeap(), 0, p);
1138 HeapFree( GetProcessHeap(), 0, lpKey);
1140 return retval;
1143 /*****************************************************************************
1144 * AddPrinterW [WINSPOOL.@]
1146 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1148 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1149 LPDEVMODEA dmA;
1150 LPDEVMODEW dmW;
1151 HANDLE retval;
1152 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1153 LONG size;
1155 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1157 if(pName != NULL) {
1158 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1159 SetLastError(ERROR_INVALID_PARAMETER);
1160 return 0;
1162 if(Level != 2) {
1163 ERR("Level = %ld, unsupported!\n", Level);
1164 SetLastError(ERROR_INVALID_LEVEL);
1165 return 0;
1167 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1168 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1169 debugstr_w(pi->pPrinterName)
1171 SetLastError(ERROR_INVALID_LEVEL);
1172 return 0;
1174 if(!pPrinter) {
1175 SetLastError(ERROR_INVALID_PARAMETER);
1176 return 0;
1178 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1179 ERROR_SUCCESS) {
1180 ERR("Can't create Printers key\n");
1181 return 0;
1183 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1184 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1185 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1186 RegCloseKey(hkeyPrinter);
1187 RegCloseKey(hkeyPrinters);
1188 return 0;
1190 RegCloseKey(hkeyPrinter);
1192 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1193 if(!hkeyDrivers) {
1194 ERR("Can't create Drivers key\n");
1195 RegCloseKey(hkeyPrinters);
1196 return 0;
1198 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1199 ERROR_SUCCESS) {
1200 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1201 RegCloseKey(hkeyPrinters);
1202 RegCloseKey(hkeyDrivers);
1203 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1204 return 0;
1206 RegCloseKey(hkeyDriver);
1207 RegCloseKey(hkeyDrivers);
1209 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1210 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1211 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1212 RegCloseKey(hkeyPrinters);
1213 return 0;
1216 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1217 ERROR_SUCCESS) {
1218 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1219 SetLastError(ERROR_INVALID_PRINTER_NAME);
1220 RegCloseKey(hkeyPrinters);
1221 return 0;
1223 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1224 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1225 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1227 /* See if we can load the driver. We may need the devmode structure anyway
1229 * FIXME:
1230 * Note that DocumentPropertiesW will briefly try to open the printer we
1231 * just create to find a DEVMODEA struct (it will use the WINEPS default
1232 * one in case it is not there, so we are ok).
1234 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1236 if(size < 0) {
1237 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1238 size = sizeof(DEVMODEW);
1240 if(pi->pDevMode)
1241 dmW = pi->pDevMode;
1242 else
1244 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1245 ZeroMemory(dmW,size);
1246 dmW->dmSize = size;
1247 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1249 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1250 HeapFree(GetProcessHeap(),0,dmW);
1251 dmW=NULL;
1253 else
1255 /* set devmode to printer name */
1256 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1260 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1261 and we support these drivers. NT writes DEVMODEW so somehow
1262 we'll need to distinguish between these when we support NT
1263 drivers */
1264 if (dmW)
1266 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1267 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1268 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1269 HeapFree(GetProcessHeap(), 0, dmA);
1270 if(!pi->pDevMode)
1271 HeapFree(GetProcessHeap(), 0, dmW);
1273 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1274 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1275 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1276 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1278 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1279 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1280 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1281 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1282 (LPBYTE)&pi->Priority, sizeof(DWORD));
1283 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1284 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1285 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1286 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1287 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1288 (LPBYTE)&pi->Status, sizeof(DWORD));
1289 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1290 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1292 RegCloseKey(hkeyPrinter);
1293 RegCloseKey(hkeyPrinters);
1294 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1295 ERR("OpenPrinter failing\n");
1296 return 0;
1298 return retval;
1301 /*****************************************************************************
1302 * AddPrinterA [WINSPOOL.@]
1304 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1306 UNICODE_STRING pNameW;
1307 PWSTR pwstrNameW;
1308 PRINTER_INFO_2W *piW;
1309 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1310 HANDLE ret;
1312 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1313 if(Level != 2) {
1314 ERR("Level = %ld, unsupported!\n", Level);
1315 SetLastError(ERROR_INVALID_LEVEL);
1316 return 0;
1318 pwstrNameW = asciitounicode(&pNameW,pName);
1319 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1321 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1323 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1324 RtlFreeUnicodeString(&pNameW);
1325 return ret;
1329 /*****************************************************************************
1330 * ClosePrinter [WINSPOOL.@]
1332 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1334 int i = (int)hPrinter;
1336 TRACE("Handle %p\n", hPrinter);
1338 if ((i <= 0) || (i > nb_printers)) return FALSE;
1339 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1340 printer_array[i - 1] = NULL;
1341 return TRUE;
1344 /*****************************************************************************
1345 * DeleteFormA [WINSPOOL.@]
1347 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1349 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1350 return 1;
1353 /*****************************************************************************
1354 * DeleteFormW [WINSPOOL.@]
1356 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1358 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1359 return 1;
1362 /*****************************************************************************
1363 * WINSPOOL_SHRegDeleteKey
1365 * Recursively delete subkeys.
1366 * Cut & paste from shlwapi.
1369 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1371 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1372 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1373 HKEY hSubKey = 0;
1375 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1376 if(!dwRet)
1378 /* Find how many subkeys there are */
1379 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1380 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1381 if(!dwRet)
1383 dwMaxSubkeyLen++;
1384 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1385 /* Name too big: alloc a buffer for it */
1386 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1388 if(!lpszName)
1389 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1390 else
1392 /* Recursively delete all the subkeys */
1393 for(i = 0; i < dwKeyCount && !dwRet; i++)
1395 dwSize = dwMaxSubkeyLen;
1396 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1397 if(!dwRet)
1398 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1401 if (lpszName != szNameBuf)
1402 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1406 RegCloseKey(hSubKey);
1407 if(!dwRet)
1408 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1410 return dwRet;
1413 /*****************************************************************************
1414 * DeletePrinter [WINSPOOL.@]
1416 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1418 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1419 HKEY hkeyPrinters;
1421 if(!lpNameW) return FALSE;
1422 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1423 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1424 RegCloseKey(hkeyPrinters);
1426 WriteProfileStringW(devicesW, lpNameW, NULL);
1427 return TRUE;
1430 /*****************************************************************************
1431 * SetPrinterA [WINSPOOL.@]
1433 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1434 DWORD Command)
1436 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1437 return FALSE;
1440 /*****************************************************************************
1441 * SetJobA [WINSPOOL.@]
1443 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1444 LPBYTE pJob, DWORD Command)
1446 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1447 Command);
1448 return FALSE;
1451 /*****************************************************************************
1452 * SetJobW [WINSPOOL.@]
1454 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1455 LPBYTE pJob, DWORD Command)
1457 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1458 Command);
1459 return FALSE;
1462 /*****************************************************************************
1463 * EndDocPrinter [WINSPOOL.@]
1465 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1467 FIXME("(hPrinter=%p): stub\n", hPrinter);
1468 return FALSE;
1471 /*****************************************************************************
1472 * EndPagePrinter [WINSPOOL.@]
1474 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1476 FIXME("(hPrinter=%p): stub\n", hPrinter);
1477 return FALSE;
1480 /*****************************************************************************
1481 * StartDocPrinterA [WINSPOOL.@]
1483 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1485 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1486 return FALSE;
1489 /*****************************************************************************
1490 * StartDocPrinterW [WINSPOOL.@]
1492 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1494 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1495 return FALSE;
1498 /*****************************************************************************
1499 * StartPagePrinter [WINSPOOL.@]
1501 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1503 FIXME("(hPrinter=%p): stub\n", hPrinter);
1504 return FALSE;
1507 /*****************************************************************************
1508 * GetFormA [WINSPOOL.@]
1510 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1511 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1513 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1514 Level,pForm,cbBuf,pcbNeeded);
1515 return FALSE;
1518 /*****************************************************************************
1519 * GetFormW [WINSPOOL.@]
1521 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1522 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1524 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1525 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1526 return FALSE;
1529 /*****************************************************************************
1530 * SetFormA [WINSPOOL.@]
1532 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1533 LPBYTE pForm)
1535 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1536 return FALSE;
1539 /*****************************************************************************
1540 * SetFormW [WINSPOOL.@]
1542 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1543 LPBYTE pForm)
1545 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1546 return FALSE;
1549 /*****************************************************************************
1550 * ReadPrinter [WINSPOOL.@]
1552 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1553 LPDWORD pNoBytesRead)
1555 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1556 return FALSE;
1559 /*****************************************************************************
1560 * ResetPrinterA [WINSPOOL.@]
1562 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1564 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1565 return FALSE;
1568 /*****************************************************************************
1569 * ResetPrinterW [WINSPOOL.@]
1571 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1573 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1574 return FALSE;
1577 /*****************************************************************************
1578 * WINSPOOL_GetDWORDFromReg
1580 * Return DWORD associated with ValueName from hkey.
1582 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1584 DWORD sz = sizeof(DWORD), type, value = 0;
1585 LONG ret;
1587 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1589 if(ret != ERROR_SUCCESS) {
1590 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1591 return 0;
1593 if(type != REG_DWORD) {
1594 ERR("Got type %ld\n", type);
1595 return 0;
1597 return value;
1600 /*****************************************************************************
1601 * WINSPOOL_GetStringFromReg
1603 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1604 * String is stored either as unicode or ascii.
1605 * Bit of a hack here to get the ValueName if we want ascii.
1607 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1608 DWORD buflen, DWORD *needed,
1609 BOOL unicode)
1611 DWORD sz = buflen, type;
1612 LONG ret;
1614 if(unicode)
1615 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1616 else {
1617 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1618 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1619 HeapFree(GetProcessHeap(),0,ValueNameA);
1621 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1622 WARN("Got ret = %ld\n", ret);
1623 *needed = 0;
1624 return FALSE;
1626 *needed = sz;
1627 return TRUE;
1630 /*****************************************************************************
1631 * WINSPOOL_GetDefaultDevMode
1633 * Get a default DevMode values for wineps.
1634 * FIXME - use ppd.
1637 static void WINSPOOL_GetDefaultDevMode(
1638 LPBYTE ptr,
1639 DWORD buflen, DWORD *needed,
1640 BOOL unicode)
1642 DEVMODEA dm;
1644 /* fill default DEVMODE - should be read from ppd... */
1645 ZeroMemory( &dm, sizeof(dm) );
1646 strcpy(dm.dmDeviceName,"wineps");
1647 dm.dmSpecVersion = DM_SPECVERSION;
1648 dm.dmDriverVersion = 1;
1649 dm.dmSize = sizeof(DEVMODEA);
1650 dm.dmDriverExtra = 0;
1651 dm.dmFields =
1652 DM_ORIENTATION | DM_PAPERSIZE |
1653 DM_PAPERLENGTH | DM_PAPERWIDTH |
1654 DM_SCALE |
1655 DM_COPIES |
1656 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1657 DM_YRESOLUTION | DM_TTOPTION;
1659 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1660 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1661 dm.u1.s1.dmPaperLength = 2970;
1662 dm.u1.s1.dmPaperWidth = 2100;
1664 dm.dmScale = 100;
1665 dm.dmCopies = 1;
1666 dm.dmDefaultSource = DMBIN_AUTO;
1667 dm.dmPrintQuality = DMRES_MEDIUM;
1668 /* dm.dmColor */
1669 /* dm.dmDuplex */
1670 dm.dmYResolution = 300; /* 300dpi */
1671 dm.dmTTOption = DMTT_BITMAP;
1672 /* dm.dmCollate */
1673 /* dm.dmFormName */
1674 /* dm.dmLogPixels */
1675 /* dm.dmBitsPerPel */
1676 /* dm.dmPelsWidth */
1677 /* dm.dmPelsHeight */
1678 /* dm.dmDisplayFlags */
1679 /* dm.dmDisplayFrequency */
1680 /* dm.dmICMMethod */
1681 /* dm.dmICMIntent */
1682 /* dm.dmMediaType */
1683 /* dm.dmDitherType */
1684 /* dm.dmReserved1 */
1685 /* dm.dmReserved2 */
1686 /* dm.dmPanningWidth */
1687 /* dm.dmPanningHeight */
1689 if(unicode) {
1690 if(buflen >= sizeof(DEVMODEW)) {
1691 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1692 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1693 HeapFree(GetProcessHeap(),0,pdmW);
1695 *needed = sizeof(DEVMODEW);
1697 else
1699 if(buflen >= sizeof(DEVMODEA)) {
1700 memcpy(ptr, &dm, sizeof(DEVMODEA));
1702 *needed = sizeof(DEVMODEA);
1706 /*****************************************************************************
1707 * WINSPOOL_GetDevModeFromReg
1709 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1710 * DevMode is stored either as unicode or ascii.
1712 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1713 LPBYTE ptr,
1714 DWORD buflen, DWORD *needed,
1715 BOOL unicode)
1717 DWORD sz = buflen, type;
1718 LONG ret;
1720 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1721 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1722 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1723 if (sz < sizeof(DEVMODEA))
1725 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1726 return FALSE;
1728 /* ensures that dmSize is not erratically bogus if registry is invalid */
1729 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1730 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1731 if(unicode) {
1732 sz += (CCHDEVICENAME + CCHFORMNAME);
1733 if(buflen >= sz) {
1734 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1735 memcpy(ptr, dmW, sz);
1736 HeapFree(GetProcessHeap(),0,dmW);
1739 *needed = sz;
1740 return TRUE;
1743 /*********************************************************************
1744 * WINSPOOL_GetPrinter_2
1746 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1747 * The strings are either stored as unicode or ascii.
1749 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1750 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1751 BOOL unicode)
1753 DWORD size, left = cbBuf;
1754 BOOL space = (cbBuf > 0);
1755 LPBYTE ptr = buf;
1757 *pcbNeeded = 0;
1759 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1760 unicode)) {
1761 if(space && size <= left) {
1762 pi2->pPrinterName = (LPWSTR)ptr;
1763 ptr += size;
1764 left -= size;
1765 } else
1766 space = FALSE;
1767 *pcbNeeded += size;
1769 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1770 unicode)) {
1771 if(space && size <= left) {
1772 pi2->pShareName = (LPWSTR)ptr;
1773 ptr += size;
1774 left -= size;
1775 } else
1776 space = FALSE;
1777 *pcbNeeded += size;
1779 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1780 unicode)) {
1781 if(space && size <= left) {
1782 pi2->pPortName = (LPWSTR)ptr;
1783 ptr += size;
1784 left -= size;
1785 } else
1786 space = FALSE;
1787 *pcbNeeded += size;
1789 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1790 &size, unicode)) {
1791 if(space && size <= left) {
1792 pi2->pDriverName = (LPWSTR)ptr;
1793 ptr += size;
1794 left -= size;
1795 } else
1796 space = FALSE;
1797 *pcbNeeded += size;
1799 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1800 unicode)) {
1801 if(space && size <= left) {
1802 pi2->pComment = (LPWSTR)ptr;
1803 ptr += size;
1804 left -= size;
1805 } else
1806 space = FALSE;
1807 *pcbNeeded += size;
1809 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1810 unicode)) {
1811 if(space && size <= left) {
1812 pi2->pLocation = (LPWSTR)ptr;
1813 ptr += size;
1814 left -= size;
1815 } else
1816 space = FALSE;
1817 *pcbNeeded += size;
1819 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1820 &size, unicode)) {
1821 if(space && size <= left) {
1822 pi2->pDevMode = (LPDEVMODEW)ptr;
1823 ptr += size;
1824 left -= size;
1825 } else
1826 space = FALSE;
1827 *pcbNeeded += size;
1829 else
1831 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1832 if(space && size <= left) {
1833 pi2->pDevMode = (LPDEVMODEW)ptr;
1834 ptr += size;
1835 left -= size;
1836 } else
1837 space = FALSE;
1838 *pcbNeeded += size;
1840 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1841 &size, unicode)) {
1842 if(space && size <= left) {
1843 pi2->pSepFile = (LPWSTR)ptr;
1844 ptr += size;
1845 left -= size;
1846 } else
1847 space = FALSE;
1848 *pcbNeeded += size;
1850 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1851 &size, unicode)) {
1852 if(space && size <= left) {
1853 pi2->pPrintProcessor = (LPWSTR)ptr;
1854 ptr += size;
1855 left -= size;
1856 } else
1857 space = FALSE;
1858 *pcbNeeded += size;
1860 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1861 &size, unicode)) {
1862 if(space && size <= left) {
1863 pi2->pDatatype = (LPWSTR)ptr;
1864 ptr += size;
1865 left -= size;
1866 } else
1867 space = FALSE;
1868 *pcbNeeded += size;
1870 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1871 &size, unicode)) {
1872 if(space && size <= left) {
1873 pi2->pParameters = (LPWSTR)ptr;
1874 ptr += size;
1875 left -= size;
1876 } else
1877 space = FALSE;
1878 *pcbNeeded += size;
1880 if(pi2) {
1881 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1882 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1883 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1884 "Default Priority");
1885 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1886 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1889 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1890 memset(pi2, 0, sizeof(*pi2));
1892 return space;
1895 /*********************************************************************
1896 * WINSPOOL_GetPrinter_4
1898 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1900 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1901 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1902 BOOL unicode)
1904 DWORD size, left = cbBuf;
1905 BOOL space = (cbBuf > 0);
1906 LPBYTE ptr = buf;
1908 *pcbNeeded = 0;
1910 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1911 unicode)) {
1912 if(space && size <= left) {
1913 pi4->pPrinterName = (LPWSTR)ptr;
1914 ptr += size;
1915 left -= size;
1916 } else
1917 space = FALSE;
1918 *pcbNeeded += size;
1920 if(pi4) {
1921 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1924 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1925 memset(pi4, 0, sizeof(*pi4));
1927 return space;
1930 /*********************************************************************
1931 * WINSPOOL_GetPrinter_5
1933 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1935 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1936 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1937 BOOL unicode)
1939 DWORD size, left = cbBuf;
1940 BOOL space = (cbBuf > 0);
1941 LPBYTE ptr = buf;
1943 *pcbNeeded = 0;
1945 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1946 unicode)) {
1947 if(space && size <= left) {
1948 pi5->pPrinterName = (LPWSTR)ptr;
1949 ptr += size;
1950 left -= size;
1951 } else
1952 space = FALSE;
1953 *pcbNeeded += size;
1955 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1956 unicode)) {
1957 if(space && size <= left) {
1958 pi5->pPortName = (LPWSTR)ptr;
1959 ptr += size;
1960 left -= size;
1961 } else
1962 space = FALSE;
1963 *pcbNeeded += size;
1965 if(pi5) {
1966 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1967 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1968 "dnsTimeout");
1969 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1970 "txTimeout");
1973 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1974 memset(pi5, 0, sizeof(*pi5));
1976 return space;
1979 /*****************************************************************************
1980 * WINSPOOL_GetPrinter
1982 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1983 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1984 * just a collection of pointers to strings.
1986 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1987 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1989 LPCWSTR name;
1990 DWORD size, needed = 0;
1991 LPBYTE ptr = NULL;
1992 HKEY hkeyPrinter, hkeyPrinters;
1993 BOOL ret;
1995 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1997 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1999 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2000 ERROR_SUCCESS) {
2001 ERR("Can't create Printers key\n");
2002 return FALSE;
2004 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2006 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2007 RegCloseKey(hkeyPrinters);
2008 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2009 return FALSE;
2012 switch(Level) {
2013 case 2:
2015 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2017 size = sizeof(PRINTER_INFO_2W);
2018 if(size <= cbBuf) {
2019 ptr = pPrinter + size;
2020 cbBuf -= size;
2021 memset(pPrinter, 0, size);
2022 } else {
2023 pi2 = NULL;
2024 cbBuf = 0;
2026 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2027 unicode);
2028 needed += size;
2029 break;
2032 case 4:
2034 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2036 size = sizeof(PRINTER_INFO_4W);
2037 if(size <= cbBuf) {
2038 ptr = pPrinter + size;
2039 cbBuf -= size;
2040 memset(pPrinter, 0, size);
2041 } else {
2042 pi4 = NULL;
2043 cbBuf = 0;
2045 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2046 unicode);
2047 needed += size;
2048 break;
2052 case 5:
2054 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2056 size = sizeof(PRINTER_INFO_5W);
2057 if(size <= cbBuf) {
2058 ptr = pPrinter + size;
2059 cbBuf -= size;
2060 memset(pPrinter, 0, size);
2061 } else {
2062 pi5 = NULL;
2063 cbBuf = 0;
2066 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2067 unicode);
2068 needed += size;
2069 break;
2072 default:
2073 FIXME("Unimplemented level %ld\n", Level);
2074 SetLastError(ERROR_INVALID_LEVEL);
2075 RegCloseKey(hkeyPrinters);
2076 RegCloseKey(hkeyPrinter);
2077 return FALSE;
2080 RegCloseKey(hkeyPrinter);
2081 RegCloseKey(hkeyPrinters);
2083 TRACE("returning %d needed = %ld\n", ret, needed);
2084 if(pcbNeeded) *pcbNeeded = needed;
2085 if(!ret)
2086 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2087 return ret;
2090 /*****************************************************************************
2091 * GetPrinterW [WINSPOOL.@]
2093 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2094 DWORD cbBuf, LPDWORD pcbNeeded)
2096 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2097 TRUE);
2100 /*****************************************************************************
2101 * GetPrinterA [WINSPOOL.@]
2103 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2104 DWORD cbBuf, LPDWORD pcbNeeded)
2106 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2107 FALSE);
2110 /*****************************************************************************
2111 * WINSPOOL_EnumPrinters
2113 * Implementation of EnumPrintersA|W
2115 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2116 DWORD dwLevel, LPBYTE lpbPrinters,
2117 DWORD cbBuf, LPDWORD lpdwNeeded,
2118 LPDWORD lpdwReturned, BOOL unicode)
2121 HKEY hkeyPrinters, hkeyPrinter;
2122 WCHAR PrinterName[255];
2123 DWORD needed = 0, number = 0;
2124 DWORD used, i, left;
2125 PBYTE pi, buf;
2127 if(lpbPrinters)
2128 memset(lpbPrinters, 0, cbBuf);
2129 if(lpdwReturned)
2130 *lpdwReturned = 0;
2131 if(lpdwNeeded)
2132 *lpdwNeeded = 0;
2134 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2135 if(dwType == PRINTER_ENUM_DEFAULT)
2136 return TRUE;
2138 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2139 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2140 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2141 if(!dwType) return TRUE;
2144 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2145 FIXME("dwType = %08lx\n", dwType);
2146 SetLastError(ERROR_INVALID_FLAGS);
2147 return FALSE;
2150 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2151 ERROR_SUCCESS) {
2152 ERR("Can't create Printers key\n");
2153 return FALSE;
2156 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2157 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2158 RegCloseKey(hkeyPrinters);
2159 ERR("Can't query Printers key\n");
2160 return FALSE;
2162 TRACE("Found %ld printers\n", number);
2164 switch(dwLevel) {
2165 case 1:
2166 RegCloseKey(hkeyPrinters);
2167 if (lpdwReturned)
2168 *lpdwReturned = number;
2169 return TRUE;
2171 case 2:
2172 used = number * sizeof(PRINTER_INFO_2W);
2173 break;
2174 case 4:
2175 used = number * sizeof(PRINTER_INFO_4W);
2176 break;
2177 case 5:
2178 used = number * sizeof(PRINTER_INFO_5W);
2179 break;
2181 default:
2182 SetLastError(ERROR_INVALID_LEVEL);
2183 RegCloseKey(hkeyPrinters);
2184 return FALSE;
2186 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2188 for(i = 0; i < number; i++) {
2189 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2190 ERROR_SUCCESS) {
2191 ERR("Can't enum key number %ld\n", i);
2192 RegCloseKey(hkeyPrinters);
2193 return FALSE;
2195 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2196 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2197 ERROR_SUCCESS) {
2198 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2199 RegCloseKey(hkeyPrinters);
2200 return FALSE;
2203 if(cbBuf > used) {
2204 buf = lpbPrinters + used;
2205 left = cbBuf - used;
2206 } else {
2207 buf = NULL;
2208 left = 0;
2211 switch(dwLevel) {
2212 case 2:
2213 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2214 left, &needed, unicode);
2215 used += needed;
2216 if(pi) pi += sizeof(PRINTER_INFO_2W);
2217 break;
2218 case 4:
2219 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2220 left, &needed, unicode);
2221 used += needed;
2222 if(pi) pi += sizeof(PRINTER_INFO_4W);
2223 break;
2224 case 5:
2225 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2226 left, &needed, unicode);
2227 used += needed;
2228 if(pi) pi += sizeof(PRINTER_INFO_5W);
2229 break;
2230 default:
2231 ERR("Shouldn't be here!\n");
2232 RegCloseKey(hkeyPrinter);
2233 RegCloseKey(hkeyPrinters);
2234 return FALSE;
2236 RegCloseKey(hkeyPrinter);
2238 RegCloseKey(hkeyPrinters);
2240 if(lpdwNeeded)
2241 *lpdwNeeded = used;
2243 if(used > cbBuf) {
2244 if(lpbPrinters)
2245 memset(lpbPrinters, 0, cbBuf);
2246 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2247 return FALSE;
2249 if(lpdwReturned)
2250 *lpdwReturned = number;
2251 SetLastError(ERROR_SUCCESS);
2252 return TRUE;
2256 /******************************************************************
2257 * EnumPrintersW [WINSPOOL.@]
2259 * Enumerates the available printers, print servers and print
2260 * providers, depending on the specified flags, name and level.
2262 * RETURNS:
2264 * If level is set to 1:
2265 * Not implemented yet!
2266 * Returns TRUE with an empty list.
2268 * If level is set to 2:
2269 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2270 * Returns an array of PRINTER_INFO_2 data structures in the
2271 * lpbPrinters buffer. Note that according to MSDN also an
2272 * OpenPrinter should be performed on every remote printer.
2274 * If level is set to 4 (officially WinNT only):
2275 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2276 * Fast: Only the registry is queried to retrieve printer names,
2277 * no connection to the driver is made.
2278 * Returns an array of PRINTER_INFO_4 data structures in the
2279 * lpbPrinters buffer.
2281 * If level is set to 5 (officially WinNT4/Win9x only):
2282 * Fast: Only the registry is queried to retrieve printer names,
2283 * no connection to the driver is made.
2284 * Returns an array of PRINTER_INFO_5 data structures in the
2285 * lpbPrinters buffer.
2287 * If level set to 3 or 6+:
2288 * returns zero (failure!)
2290 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2291 * for information.
2293 * BUGS:
2294 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2295 * - Only levels 2, 4 and 5 are implemented at the moment.
2296 * - 16-bit printer drivers are not enumerated.
2297 * - Returned amount of bytes used/needed does not match the real Windoze
2298 * implementation (as in this implementation, all strings are part
2299 * of the buffer, whereas Win32 keeps them somewhere else)
2300 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2302 * NOTE:
2303 * - In a regular Wine installation, no registry settings for printers
2304 * exist, which makes this function return an empty list.
2306 BOOL WINAPI EnumPrintersW(
2307 DWORD dwType, /* [in] Types of print objects to enumerate */
2308 LPWSTR lpszName, /* [in] name of objects to enumerate */
2309 DWORD dwLevel, /* [in] type of printer info structure */
2310 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2311 DWORD cbBuf, /* [in] max size of buffer in bytes */
2312 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2313 LPDWORD lpdwReturned /* [out] number of entries returned */
2316 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2317 lpdwNeeded, lpdwReturned, TRUE);
2320 /******************************************************************
2321 * EnumPrintersA [WINSPOOL.@]
2324 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2325 DWORD dwLevel, LPBYTE lpbPrinters,
2326 DWORD cbBuf, LPDWORD lpdwNeeded,
2327 LPDWORD lpdwReturned)
2329 BOOL ret;
2330 UNICODE_STRING lpszNameW;
2331 PWSTR pwstrNameW;
2333 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2334 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2335 lpdwNeeded, lpdwReturned, FALSE);
2336 RtlFreeUnicodeString(&lpszNameW);
2337 return ret;
2340 /*****************************************************************************
2341 * WINSPOOL_GetDriverInfoFromReg [internal]
2343 * Enters the information from the registry into the DRIVER_INFO struct
2345 * RETURNS
2346 * zero if the printer driver does not exist in the registry
2347 * (only if Level > 1) otherwise nonzero
2349 static BOOL WINSPOOL_GetDriverInfoFromReg(
2350 HKEY hkeyDrivers,
2351 LPWSTR DriverName,
2352 LPWSTR pEnvironment,
2353 DWORD Level,
2354 LPBYTE ptr, /* DRIVER_INFO */
2355 LPBYTE pDriverStrings, /* strings buffer */
2356 DWORD cbBuf, /* size of string buffer */
2357 LPDWORD pcbNeeded, /* space needed for str. */
2358 BOOL unicode) /* type of strings */
2359 { DWORD dw, size, tmp, type;
2360 HKEY hkeyDriver;
2361 LPBYTE strPtr = pDriverStrings;
2363 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2364 debugstr_w(DriverName), debugstr_w(pEnvironment),
2365 Level, ptr, pDriverStrings, cbBuf, unicode);
2367 if(unicode) {
2368 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2369 if (*pcbNeeded <= cbBuf)
2370 strcpyW((LPWSTR)strPtr, DriverName);
2371 } else {
2372 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2373 NULL, NULL);
2374 if(*pcbNeeded <= cbBuf)
2375 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2376 NULL, NULL);
2378 if(Level == 1) {
2379 if(ptr)
2380 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2381 return TRUE;
2382 } else {
2383 if(ptr)
2384 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2385 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2388 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2389 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2390 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2391 return FALSE;
2394 size = sizeof(dw);
2395 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2396 ERROR_SUCCESS)
2397 WARN("Can't get Version\n");
2398 else if(ptr)
2399 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2401 if(!pEnvironment)
2402 pEnvironment = (LPWSTR)DefaultEnvironmentW;
2403 if(unicode)
2404 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2405 else
2406 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2407 NULL, NULL);
2408 *pcbNeeded += size;
2409 if(*pcbNeeded <= cbBuf) {
2410 if(unicode)
2411 strcpyW((LPWSTR)strPtr, pEnvironment);
2412 else
2413 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2414 NULL, NULL);
2415 if(ptr)
2416 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2417 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2420 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2421 unicode)) {
2422 *pcbNeeded += size;
2423 if(*pcbNeeded <= cbBuf)
2424 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2425 unicode);
2426 if(ptr)
2427 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2428 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2431 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2432 unicode)) {
2433 *pcbNeeded += size;
2434 if(*pcbNeeded <= cbBuf)
2435 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2436 &tmp, unicode);
2437 if(ptr)
2438 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2439 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2442 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2443 0, &size, unicode)) {
2444 *pcbNeeded += size;
2445 if(*pcbNeeded <= cbBuf)
2446 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2447 size, &tmp, unicode);
2448 if(ptr)
2449 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2450 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2453 if(Level == 2 ) {
2454 RegCloseKey(hkeyDriver);
2455 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2456 return TRUE;
2459 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2460 unicode)) {
2461 *pcbNeeded += size;
2462 if(*pcbNeeded <= cbBuf)
2463 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2464 size, &tmp, unicode);
2465 if(ptr)
2466 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2467 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2470 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2471 &size, unicode)) {
2472 *pcbNeeded += size;
2473 if(*pcbNeeded <= cbBuf)
2474 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2475 size, &tmp, unicode);
2476 if(ptr)
2477 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2478 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2481 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2482 unicode)) {
2483 *pcbNeeded += size;
2484 if(*pcbNeeded <= cbBuf)
2485 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2486 size, &tmp, unicode);
2487 if(ptr)
2488 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2489 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2492 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2493 unicode)) {
2494 *pcbNeeded += size;
2495 if(*pcbNeeded <= cbBuf)
2496 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2497 size, &tmp, unicode);
2498 if(ptr)
2499 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2500 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2503 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2504 RegCloseKey(hkeyDriver);
2505 return TRUE;
2508 /*****************************************************************************
2509 * WINSPOOL_GetPrinterDriver
2511 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2512 DWORD Level, LPBYTE pDriverInfo,
2513 DWORD cbBuf, LPDWORD pcbNeeded,
2514 BOOL unicode)
2516 LPCWSTR name;
2517 WCHAR DriverName[100];
2518 DWORD ret, type, size, needed = 0;
2519 LPBYTE ptr = NULL;
2520 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2522 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2523 Level,pDriverInfo,cbBuf, pcbNeeded);
2525 ZeroMemory(pDriverInfo, cbBuf);
2527 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2529 if(Level < 1 || Level > 3) {
2530 SetLastError(ERROR_INVALID_LEVEL);
2531 return FALSE;
2533 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2534 ERROR_SUCCESS) {
2535 ERR("Can't create Printers key\n");
2536 return FALSE;
2538 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2539 != ERROR_SUCCESS) {
2540 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2541 RegCloseKey(hkeyPrinters);
2542 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2543 return FALSE;
2545 size = sizeof(DriverName);
2546 DriverName[0] = 0;
2547 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2548 (LPBYTE)DriverName, &size);
2549 RegCloseKey(hkeyPrinter);
2550 RegCloseKey(hkeyPrinters);
2551 if(ret != ERROR_SUCCESS) {
2552 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2553 return FALSE;
2556 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2557 if(!hkeyDrivers) {
2558 ERR("Can't create Drivers key\n");
2559 return FALSE;
2562 switch(Level) {
2563 case 1:
2564 size = sizeof(DRIVER_INFO_1W);
2565 break;
2566 case 2:
2567 size = sizeof(DRIVER_INFO_2W);
2568 break;
2569 case 3:
2570 size = sizeof(DRIVER_INFO_3W);
2571 break;
2572 default:
2573 ERR("Invalid level\n");
2574 return FALSE;
2577 if(size <= cbBuf)
2578 ptr = pDriverInfo + size;
2580 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2581 pEnvironment, Level, pDriverInfo,
2582 (cbBuf < size) ? NULL : ptr,
2583 (cbBuf < size) ? 0 : cbBuf - size,
2584 &needed, unicode)) {
2585 RegCloseKey(hkeyDrivers);
2586 return FALSE;
2589 RegCloseKey(hkeyDrivers);
2591 if(pcbNeeded) *pcbNeeded = size + needed;
2592 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2593 if(cbBuf >= needed) return TRUE;
2594 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2595 return FALSE;
2598 /*****************************************************************************
2599 * GetPrinterDriverA [WINSPOOL.@]
2601 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2602 DWORD Level, LPBYTE pDriverInfo,
2603 DWORD cbBuf, LPDWORD pcbNeeded)
2605 BOOL ret;
2606 UNICODE_STRING pEnvW;
2607 PWSTR pwstrEnvW;
2609 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2610 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2611 cbBuf, pcbNeeded, FALSE);
2612 RtlFreeUnicodeString(&pEnvW);
2613 return ret;
2615 /*****************************************************************************
2616 * GetPrinterDriverW [WINSPOOL.@]
2618 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2619 DWORD Level, LPBYTE pDriverInfo,
2620 DWORD cbBuf, LPDWORD pcbNeeded)
2622 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2623 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2626 /*****************************************************************************
2627 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2629 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2630 DWORD Level, LPBYTE pDriverDirectory,
2631 DWORD cbBuf, LPDWORD pcbNeeded)
2633 DWORD needed;
2635 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2636 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2637 if(pName != NULL) {
2638 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2639 SetLastError(ERROR_INVALID_PARAMETER);
2640 return FALSE;
2642 if(pEnvironment != NULL) {
2643 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2644 SetLastError(ERROR_INVALID_ENVIRONMENT);
2645 return FALSE;
2647 if(Level != 1) /* win95 ignores this so we just carry on */
2648 WARN("Level = %ld - assuming 1\n", Level);
2650 /* FIXME should read from registry */
2651 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2652 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2653 * adjust this now
2655 needed++;
2656 needed*=sizeof(WCHAR);
2658 if(pcbNeeded)
2659 *pcbNeeded = needed;
2660 TRACE("required <%08lx>\n", *pcbNeeded);
2661 if(needed > cbBuf) {
2662 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2663 return FALSE;
2665 return TRUE;
2669 /*****************************************************************************
2670 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2672 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2673 DWORD Level, LPBYTE pDriverDirectory,
2674 DWORD cbBuf, LPDWORD pcbNeeded)
2676 UNICODE_STRING nameW, environmentW;
2677 BOOL ret;
2678 DWORD pcbNeededW;
2679 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2680 WCHAR *driverDirectoryW = NULL;
2682 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2684 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2685 else nameW.Buffer = NULL;
2686 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2687 else environmentW.Buffer = NULL;
2689 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2690 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2691 if (ret) {
2692 DWORD needed;
2693 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2694 pDriverDirectory, cbBuf, NULL, NULL);
2695 if(pcbNeeded)
2696 *pcbNeeded = needed;
2697 ret = (needed <= cbBuf) ? TRUE : FALSE;
2698 } else
2699 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2701 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2703 if(driverDirectoryW)
2704 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2705 RtlFreeUnicodeString(&environmentW);
2706 RtlFreeUnicodeString(&nameW);
2708 return ret;
2711 /*****************************************************************************
2712 * AddPrinterDriverA [WINSPOOL.@]
2714 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2716 DRIVER_INFO_3A di3;
2717 HKEY hkeyDrivers, hkeyName;
2719 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2721 if(level != 2 && level != 3) {
2722 SetLastError(ERROR_INVALID_LEVEL);
2723 return FALSE;
2725 if(pName != NULL) {
2726 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2727 SetLastError(ERROR_INVALID_PARAMETER);
2728 return FALSE;
2730 if(!pDriverInfo) {
2731 WARN("pDriverInfo == NULL\n");
2732 SetLastError(ERROR_INVALID_PARAMETER);
2733 return FALSE;
2736 if(level == 3)
2737 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2738 else {
2739 memset(&di3, 0, sizeof(di3));
2740 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2743 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2744 !di3.pDataFile) {
2745 SetLastError(ERROR_INVALID_PARAMETER);
2746 return FALSE;
2748 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2749 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2750 if(!di3.pHelpFile) di3.pHelpFile = "";
2751 if(!di3.pMonitorName) di3.pMonitorName = "";
2753 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2755 if(!hkeyDrivers) {
2756 ERR("Can't create Drivers key\n");
2757 return FALSE;
2760 if(level == 2) { /* apparently can't overwrite with level2 */
2761 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2762 RegCloseKey(hkeyName);
2763 RegCloseKey(hkeyDrivers);
2764 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2765 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2766 return FALSE;
2769 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2770 RegCloseKey(hkeyDrivers);
2771 ERR("Can't create Name key\n");
2772 return FALSE;
2774 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2776 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2777 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2778 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2779 sizeof(DWORD));
2780 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2781 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2782 di3.pDependentFiles, 0);
2783 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2784 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2785 RegCloseKey(hkeyName);
2786 RegCloseKey(hkeyDrivers);
2788 return TRUE;
2790 /*****************************************************************************
2791 * AddPrinterDriverW [WINSPOOL.@]
2793 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2794 LPBYTE pDriverInfo)
2796 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2797 level,pDriverInfo);
2798 return FALSE;
2802 /*****************************************************************************
2803 * PrinterProperties [WINSPOOL.@]
2805 * Displays a dialog to set the properties of the printer.
2807 * RETURNS
2808 * nonzero on success or zero on failure
2810 * BUGS
2811 * implemented as stub only
2813 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2814 HANDLE hPrinter /* [in] handle to printer object */
2816 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2817 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2818 return FALSE;
2821 /*****************************************************************************
2822 * EnumJobsA [WINSPOOL.@]
2825 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2826 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2827 LPDWORD pcReturned)
2829 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2830 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2832 if(pcbNeeded) *pcbNeeded = 0;
2833 if(pcReturned) *pcReturned = 0;
2834 return FALSE;
2838 /*****************************************************************************
2839 * EnumJobsW [WINSPOOL.@]
2842 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2843 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2844 LPDWORD pcReturned)
2846 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2847 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2849 if(pcbNeeded) *pcbNeeded = 0;
2850 if(pcReturned) *pcReturned = 0;
2851 return FALSE;
2854 /*****************************************************************************
2855 * WINSPOOL_EnumPrinterDrivers [internal]
2857 * Delivers information about all printer drivers installed on the
2858 * localhost or a given server
2860 * RETURNS
2861 * nonzero on success or zero on failure. If the buffer for the returned
2862 * information is too small the function will return an error
2864 * BUGS
2865 * - only implemented for localhost, foreign hosts will return an error
2867 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2868 DWORD Level, LPBYTE pDriverInfo,
2869 DWORD cbBuf, LPDWORD pcbNeeded,
2870 LPDWORD pcReturned, BOOL unicode)
2872 { HKEY hkeyDrivers;
2873 DWORD i, needed, number = 0, size = 0;
2874 WCHAR DriverNameW[255];
2875 PBYTE ptr;
2877 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2878 debugstr_w(pName), debugstr_w(pEnvironment),
2879 Level, pDriverInfo, cbBuf, unicode);
2881 /* check for local drivers */
2882 if(pName) {
2883 ERR("remote drivers unsupported! Current remote host is %s\n",
2884 debugstr_w(pName));
2885 return FALSE;
2888 /* check input parameter */
2889 if((Level < 1) || (Level > 3)) {
2890 ERR("unsupported level %ld \n", Level);
2891 return FALSE;
2894 /* initialize return values */
2895 if(pDriverInfo)
2896 memset( pDriverInfo, 0, cbBuf);
2897 *pcbNeeded = 0;
2898 *pcReturned = 0;
2900 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2901 if(!hkeyDrivers) {
2902 ERR("Can't open Drivers key\n");
2903 return FALSE;
2906 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2907 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2908 RegCloseKey(hkeyDrivers);
2909 ERR("Can't query Drivers key\n");
2910 return FALSE;
2912 TRACE("Found %ld Drivers\n", number);
2914 /* get size of single struct
2915 * unicode and ascii structure have the same size
2917 switch (Level) {
2918 case 1:
2919 size = sizeof(DRIVER_INFO_1A);
2920 break;
2921 case 2:
2922 size = sizeof(DRIVER_INFO_2A);
2923 break;
2924 case 3:
2925 size = sizeof(DRIVER_INFO_3A);
2926 break;
2929 /* calculate required buffer size */
2930 *pcbNeeded = size * number;
2932 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2933 i < number;
2934 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2935 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2936 != ERROR_SUCCESS) {
2937 ERR("Can't enum key number %ld\n", i);
2938 RegCloseKey(hkeyDrivers);
2939 return FALSE;
2941 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2942 pEnvironment, Level, ptr,
2943 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2944 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2945 &needed, unicode)) {
2946 RegCloseKey(hkeyDrivers);
2947 return FALSE;
2949 (*pcbNeeded) += needed;
2952 RegCloseKey(hkeyDrivers);
2954 if(cbBuf < *pcbNeeded){
2955 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2956 return FALSE;
2959 return TRUE;
2962 /*****************************************************************************
2963 * EnumPrinterDriversW [WINSPOOL.@]
2965 * see function EnumPrinterDrivers for RETURNS, BUGS
2967 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2968 LPBYTE pDriverInfo, DWORD cbBuf,
2969 LPDWORD pcbNeeded, LPDWORD pcReturned)
2971 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2972 cbBuf, pcbNeeded, pcReturned, TRUE);
2975 /*****************************************************************************
2976 * EnumPrinterDriversA [WINSPOOL.@]
2978 * see function EnumPrinterDrivers for RETURNS, BUGS
2980 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2981 LPBYTE pDriverInfo, DWORD cbBuf,
2982 LPDWORD pcbNeeded, LPDWORD pcReturned)
2983 { BOOL ret;
2984 UNICODE_STRING pNameW, pEnvironmentW;
2985 PWSTR pwstrNameW, pwstrEnvironmentW;
2987 pwstrNameW = asciitounicode(&pNameW, pName);
2988 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
2990 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
2991 Level, pDriverInfo, cbBuf, pcbNeeded,
2992 pcReturned, FALSE);
2993 RtlFreeUnicodeString(&pNameW);
2994 RtlFreeUnicodeString(&pEnvironmentW);
2996 return ret;
2999 static CHAR PortMonitor[] = "Wine Port Monitor";
3000 static CHAR PortDescription[] = "Wine Port";
3002 /******************************************************************************
3003 * EnumPortsA (WINSPOOL.@)
3005 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3006 LPDWORD bufneeded,LPDWORD bufreturned)
3008 CHAR portname[10];
3009 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3010 const LPCSTR szSerialPortKey = "Software\\Wine\\Wine\\Config\\serialports";
3011 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3012 HKEY hkey_serial, hkey_printer;
3014 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3015 name,level,buffer,bufsize,bufneeded,bufreturned);
3017 switch( level )
3019 case 1:
3020 info_size = sizeof (PORT_INFO_1A);
3021 break;
3022 case 2:
3023 info_size = sizeof (PORT_INFO_2A);
3024 break;
3025 default:
3026 SetLastError(ERROR_INVALID_LEVEL);
3027 return FALSE;
3030 /* see how many exist */
3032 hkey_serial = 0;
3033 hkey_printer = 0;
3034 serial_count = 0;
3035 printer_count = 0;
3036 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szSerialPortKey, &hkey_serial);
3037 if (r == ERROR_SUCCESS)
3039 RegQueryInfoKeyA ( hkey_serial, NULL, NULL, NULL, NULL, NULL, NULL,
3040 &serial_count, NULL, NULL, NULL, NULL);
3043 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3044 if ( r == ERROR_SUCCESS )
3046 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3047 &printer_count, NULL, NULL, NULL, NULL);
3049 count = serial_count + printer_count;
3051 /* then fill in the structure info structure once
3052 we know the offset to the first string */
3054 memset( buffer, 0, bufsize );
3055 n = 0;
3056 ofs = info_size*count;
3057 for ( i=0; i<count; i++)
3059 DWORD vallen = sizeof(portname) - 1;
3061 /* get the serial port values, then the printer values */
3062 if ( i < serial_count )
3063 r = RegEnumValueA( hkey_serial, i,
3064 portname, &vallen, NULL, NULL, NULL, 0 );
3065 else
3066 r = RegEnumValueA( hkey_printer, i-serial_count,
3067 portname, &vallen, NULL, NULL, NULL, 0 );
3069 if ( r )
3070 continue;
3072 /* add a colon if necessary, and make it upper case */
3073 CharUpperBuffA(portname,vallen);
3074 if (strcasecmp(portname,"nul")!=0)
3075 if (vallen && (portname[vallen-1] != ':') )
3076 lstrcatA(portname,":");
3078 /* add the port info structure if we can fit it */
3079 if ( info_size*(n+1) < bufsize )
3081 if ( level == 1)
3083 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3084 info->pName = (LPSTR) &buffer[ofs];
3086 else if ( level == 2)
3088 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3089 info->pPortName = (LPSTR) &buffer[ofs];
3090 /* FIXME: fill in more stuff here */
3091 info->pMonitorName = PortMonitor;
3092 info->pDescription = PortDescription;
3093 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3096 /* add the name of the port if we can fit it */
3097 if ( ofs < bufsize )
3098 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3101 ofs += lstrlenA(portname)+1;
3102 n++;
3105 RegCloseKey(hkey_serial);
3106 RegCloseKey(hkey_printer);
3108 if(bufneeded)
3109 *bufneeded = ofs;
3111 if(bufreturned)
3112 *bufreturned = count;
3114 return TRUE;
3117 /******************************************************************************
3118 * GetDefaultPrinterA (WINSPOOL.@)
3120 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3122 char *ptr;
3124 if (*namesize < 1)
3126 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3127 return FALSE;
3130 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
3132 SetLastError (ERROR_FILE_NOT_FOUND);
3133 return FALSE;
3136 if ((ptr = strchr (name, ',')) == NULL)
3138 SetLastError (ERROR_FILE_NOT_FOUND);
3139 return FALSE;
3142 *ptr = '\0';
3143 *namesize = strlen (name) + 1;
3144 return TRUE;
3148 /******************************************************************************
3149 * GetDefaultPrinterW (WINSPOOL.@)
3151 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3153 char *buf;
3154 BOOL ret;
3156 if (*namesize < 1)
3158 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3159 return FALSE;
3162 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
3163 ret = GetDefaultPrinterA (buf, namesize);
3164 if (ret)
3166 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
3167 if (!len)
3169 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3170 ret = FALSE;
3172 else *namesize = len;
3175 HeapFree (GetProcessHeap (), 0, buf);
3176 return ret;
3180 /******************************************************************************
3181 * SetPrinterDataExA (WINSPOOL.@)
3183 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3184 LPCSTR pValueName, DWORD Type,
3185 LPBYTE pData, DWORD cbData)
3187 HKEY hkeyPrinter, hkeySubkey;
3188 DWORD ret;
3190 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3191 debugstr_a(pValueName), Type, pData, cbData);
3193 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3194 != ERROR_SUCCESS)
3195 return ret;
3197 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3198 != ERROR_SUCCESS) {
3199 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3200 RegCloseKey(hkeyPrinter);
3201 return ret;
3203 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3204 RegCloseKey(hkeySubkey);
3205 RegCloseKey(hkeyPrinter);
3206 return ret;
3209 /******************************************************************************
3210 * SetPrinterDataExW (WINSPOOL.@)
3212 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3213 LPCWSTR pValueName, DWORD Type,
3214 LPBYTE pData, DWORD cbData)
3216 HKEY hkeyPrinter, hkeySubkey;
3217 DWORD ret;
3219 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3220 debugstr_w(pValueName), Type, pData, cbData);
3222 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3223 != ERROR_SUCCESS)
3224 return ret;
3226 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3227 != ERROR_SUCCESS) {
3228 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3229 RegCloseKey(hkeyPrinter);
3230 return ret;
3232 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3233 RegCloseKey(hkeySubkey);
3234 RegCloseKey(hkeyPrinter);
3235 return ret;
3238 /******************************************************************************
3239 * SetPrinterDataA (WINSPOOL.@)
3241 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3242 LPBYTE pData, DWORD cbData)
3244 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3245 pData, cbData);
3248 /******************************************************************************
3249 * SetPrinterDataW (WINSPOOL.@)
3251 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3252 LPBYTE pData, DWORD cbData)
3254 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3255 pData, cbData);
3258 /******************************************************************************
3259 * GetPrinterDataExA (WINSPOOL.@)
3261 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3262 LPCSTR pValueName, LPDWORD pType,
3263 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3265 HKEY hkeyPrinter, hkeySubkey;
3266 DWORD ret;
3268 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3269 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3270 pcbNeeded);
3272 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3273 != ERROR_SUCCESS)
3274 return ret;
3276 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3277 != ERROR_SUCCESS) {
3278 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3279 RegCloseKey(hkeyPrinter);
3280 return ret;
3282 *pcbNeeded = nSize;
3283 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3284 RegCloseKey(hkeySubkey);
3285 RegCloseKey(hkeyPrinter);
3286 return ret;
3289 /******************************************************************************
3290 * GetPrinterDataExW (WINSPOOL.@)
3292 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3293 LPCWSTR pValueName, LPDWORD pType,
3294 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3296 HKEY hkeyPrinter, hkeySubkey;
3297 DWORD ret;
3299 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3300 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3301 pcbNeeded);
3303 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3304 != ERROR_SUCCESS)
3305 return ret;
3307 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3308 != ERROR_SUCCESS) {
3309 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3310 RegCloseKey(hkeyPrinter);
3311 return ret;
3313 *pcbNeeded = nSize;
3314 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3315 RegCloseKey(hkeySubkey);
3316 RegCloseKey(hkeyPrinter);
3317 return ret;
3320 /******************************************************************************
3321 * GetPrinterDataA (WINSPOOL.@)
3323 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3324 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3326 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3327 pData, nSize, pcbNeeded);
3330 /******************************************************************************
3331 * GetPrinterDataW (WINSPOOL.@)
3333 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3334 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3336 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3337 pData, nSize, pcbNeeded);
3340 /*******************************************************************************
3341 * EnumPrinterDataExW [WINSPOOL.@]
3343 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3344 LPBYTE pEnumValues, DWORD cbEnumValues,
3345 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3347 HKEY hkPrinter, hkSubKey;
3348 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3349 cbValueNameLen, cbMaxValueLen, cbValueLen,
3350 cbBufSize, dwType;
3351 LPWSTR lpValueName;
3352 HANDLE hHeap;
3353 PBYTE lpValue;
3354 PPRINTER_ENUM_VALUESW ppev;
3356 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3358 if (pKeyName == NULL || *pKeyName == 0)
3359 return ERROR_INVALID_PARAMETER;
3361 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3362 if (ret != ERROR_SUCCESS)
3364 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3365 hPrinter, ret);
3366 return ret;
3369 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3370 if (ret != ERROR_SUCCESS)
3372 r = RegCloseKey (hkPrinter);
3373 if (r != ERROR_SUCCESS)
3374 WARN ("RegCloseKey returned %li\n", r);
3375 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3376 debugstr_w (pKeyName), ret);
3377 return ret;
3380 ret = RegCloseKey (hkPrinter);
3381 if (ret != ERROR_SUCCESS)
3383 ERR ("RegCloseKey returned %li\n", ret);
3384 r = RegCloseKey (hkSubKey);
3385 if (r != ERROR_SUCCESS)
3386 WARN ("RegCloseKey returned %li\n", r);
3387 return ret;
3390 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3391 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3392 if (ret != ERROR_SUCCESS)
3394 r = RegCloseKey (hkSubKey);
3395 if (r != ERROR_SUCCESS)
3396 WARN ("RegCloseKey returned %li\n", r);
3397 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3398 return ret;
3401 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3402 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3404 if (cValues == 0) /* empty key */
3406 r = RegCloseKey (hkSubKey);
3407 if (r != ERROR_SUCCESS)
3408 WARN ("RegCloseKey returned %li\n", r);
3409 *pcbEnumValues = *pnEnumValues = 0;
3410 return ERROR_SUCCESS;
3413 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3415 hHeap = GetProcessHeap ();
3416 if (hHeap == NULL)
3418 ERR ("GetProcessHeap failed\n");
3419 r = RegCloseKey (hkSubKey);
3420 if (r != ERROR_SUCCESS)
3421 WARN ("RegCloseKey returned %li\n", r);
3422 return ERROR_OUTOFMEMORY;
3425 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3426 if (lpValueName == NULL)
3428 ERR ("Failed to allocate %li bytes from process heap\n",
3429 cbMaxValueNameLen * sizeof (WCHAR));
3430 r = RegCloseKey (hkSubKey);
3431 if (r != ERROR_SUCCESS)
3432 WARN ("RegCloseKey returned %li\n", r);
3433 return ERROR_OUTOFMEMORY;
3436 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3437 if (lpValue == NULL)
3439 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3440 if (HeapFree (hHeap, 0, lpValueName) == 0)
3441 WARN ("HeapFree failed with code %li\n", GetLastError ());
3442 r = RegCloseKey (hkSubKey);
3443 if (r != ERROR_SUCCESS)
3444 WARN ("RegCloseKey returned %li\n", r);
3445 return ERROR_OUTOFMEMORY;
3448 TRACE ("pass 1: calculating buffer required for all names and values\n");
3450 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3452 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3454 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3456 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3457 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3458 NULL, NULL, lpValue, &cbValueLen);
3459 if (ret != ERROR_SUCCESS)
3461 if (HeapFree (hHeap, 0, lpValue) == 0)
3462 WARN ("HeapFree failed with code %li\n", GetLastError ());
3463 if (HeapFree (hHeap, 0, lpValueName) == 0)
3464 WARN ("HeapFree failed with code %li\n", GetLastError ());
3465 r = RegCloseKey (hkSubKey);
3466 if (r != ERROR_SUCCESS)
3467 WARN ("RegCloseKey returned %li\n", r);
3468 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3469 return ret;
3472 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3473 debugstr_w (lpValueName), dwIndex,
3474 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3476 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3477 cbBufSize += cbValueLen;
3480 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3482 *pcbEnumValues = cbBufSize;
3483 *pnEnumValues = cValues;
3485 if (cbEnumValues < cbBufSize) /* buffer too small */
3487 if (HeapFree (hHeap, 0, lpValue) == 0)
3488 WARN ("HeapFree failed with code %li\n", GetLastError ());
3489 if (HeapFree (hHeap, 0, lpValueName) == 0)
3490 WARN ("HeapFree failed with code %li\n", GetLastError ());
3491 r = RegCloseKey (hkSubKey);
3492 if (r != ERROR_SUCCESS)
3493 WARN ("RegCloseKey returned %li\n", r);
3494 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3495 return ERROR_MORE_DATA;
3498 TRACE ("pass 2: copying all names and values to buffer\n");
3500 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3501 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3503 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3505 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3506 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3507 NULL, &dwType, lpValue, &cbValueLen);
3508 if (ret != ERROR_SUCCESS)
3510 if (HeapFree (hHeap, 0, lpValue) == 0)
3511 WARN ("HeapFree failed with code %li\n", GetLastError ());
3512 if (HeapFree (hHeap, 0, lpValueName) == 0)
3513 WARN ("HeapFree failed with code %li\n", GetLastError ());
3514 r = RegCloseKey (hkSubKey);
3515 if (r != ERROR_SUCCESS)
3516 WARN ("RegCloseKey returned %li\n", r);
3517 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3518 return ret;
3521 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3522 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3523 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3524 pEnumValues += cbValueNameLen;
3526 /* return # of *bytes* (including trailing \0), not # of chars */
3527 ppev[dwIndex].cbValueName = cbValueNameLen;
3529 ppev[dwIndex].dwType = dwType;
3531 memcpy (pEnumValues, lpValue, cbValueLen);
3532 ppev[dwIndex].pData = pEnumValues;
3533 pEnumValues += cbValueLen;
3535 ppev[dwIndex].cbData = cbValueLen;
3537 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3538 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3541 if (HeapFree (hHeap, 0, lpValue) == 0)
3543 ret = GetLastError ();
3544 ERR ("HeapFree failed with code %li\n", ret);
3545 if (HeapFree (hHeap, 0, lpValueName) == 0)
3546 WARN ("HeapFree failed with code %li\n", GetLastError ());
3547 r = RegCloseKey (hkSubKey);
3548 if (r != ERROR_SUCCESS)
3549 WARN ("RegCloseKey returned %li\n", r);
3550 return ret;
3553 if (HeapFree (hHeap, 0, lpValueName) == 0)
3555 ret = GetLastError ();
3556 ERR ("HeapFree failed with code %li\n", ret);
3557 r = RegCloseKey (hkSubKey);
3558 if (r != ERROR_SUCCESS)
3559 WARN ("RegCloseKey returned %li\n", r);
3560 return ret;
3563 ret = RegCloseKey (hkSubKey);
3564 if (ret != ERROR_SUCCESS)
3566 ERR ("RegCloseKey returned %li\n", ret);
3567 return ret;
3570 return ERROR_SUCCESS;
3573 /*******************************************************************************
3574 * EnumPrinterDataExA [WINSPOOL.@]
3576 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3577 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3578 * what Windows 2000 SP1 does.
3581 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3582 LPBYTE pEnumValues, DWORD cbEnumValues,
3583 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3585 INT len;
3586 LPWSTR pKeyNameW;
3587 DWORD ret, dwIndex, dwBufSize;
3588 HANDLE hHeap;
3589 LPSTR pBuffer;
3591 TRACE ("%p %s\n", hPrinter, pKeyName);
3593 if (pKeyName == NULL || *pKeyName == 0)
3594 return ERROR_INVALID_PARAMETER;
3596 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3597 if (len == 0)
3599 ret = GetLastError ();
3600 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3601 return ret;
3604 hHeap = GetProcessHeap ();
3605 if (hHeap == NULL)
3607 ERR ("GetProcessHeap failed\n");
3608 return ERROR_OUTOFMEMORY;
3611 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3612 if (pKeyNameW == NULL)
3614 ERR ("Failed to allocate %li bytes from process heap\n",
3615 (LONG) len * sizeof (WCHAR));
3616 return ERROR_OUTOFMEMORY;
3619 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3621 ret = GetLastError ();
3622 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3623 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3624 WARN ("HeapFree failed with code %li\n", GetLastError ());
3625 return ret;
3628 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3629 pcbEnumValues, pnEnumValues);
3630 if (ret != ERROR_SUCCESS)
3632 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3633 WARN ("HeapFree failed with code %li\n", GetLastError ());
3634 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3635 return ret;
3638 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3640 ret = GetLastError ();
3641 ERR ("HeapFree failed with code %li\n", ret);
3642 return ret;
3645 if (*pnEnumValues == 0) /* empty key */
3646 return ERROR_SUCCESS;
3648 dwBufSize = 0;
3649 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3651 PPRINTER_ENUM_VALUESW ppev =
3652 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3654 if (dwBufSize < ppev->cbValueName)
3655 dwBufSize = ppev->cbValueName;
3657 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3658 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3659 dwBufSize = ppev->cbData;
3662 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3664 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3665 if (pBuffer == NULL)
3667 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3668 return ERROR_OUTOFMEMORY;
3671 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3673 PPRINTER_ENUM_VALUESW ppev =
3674 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3676 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3677 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3678 NULL);
3679 if (len == 0)
3681 ret = GetLastError ();
3682 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3683 if (HeapFree (hHeap, 0, pBuffer) == 0)
3684 WARN ("HeapFree failed with code %li\n", GetLastError ());
3685 return ret;
3688 memcpy (ppev->pValueName, pBuffer, len);
3690 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3692 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3693 ppev->dwType != REG_MULTI_SZ)
3694 continue;
3696 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3697 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3698 if (len == 0)
3700 ret = GetLastError ();
3701 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3702 if (HeapFree (hHeap, 0, pBuffer) == 0)
3703 WARN ("HeapFree failed with code %li\n", GetLastError ());
3704 return ret;
3707 memcpy (ppev->pData, pBuffer, len);
3709 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3710 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3713 if (HeapFree (hHeap, 0, pBuffer) == 0)
3715 ret = GetLastError ();
3716 ERR ("HeapFree failed with code %li\n", ret);
3717 return ret;
3720 return ERROR_SUCCESS;
3723 /******************************************************************************
3724 * AddPortA (WINSPOOL.@)
3726 BOOL WINAPI AddPortA(LPSTR pName ,HWND hWnd, LPSTR pMonitorName)
3728 FIXME("(%s, %p, %s\n), stub!\n",pName,hWnd,pMonitorName);
3729 return FALSE;
3732 /******************************************************************************
3733 * AddPrinterDriverExW (WINSPOOL.@)
3735 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
3736 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3738 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
3739 Level, pDriverInfo, dwFileCopyFlags);
3740 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3741 return FALSE;
3744 /******************************************************************************
3745 * AddPrinterDriverExA (WINSPOOL.@)
3747 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
3748 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3750 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
3751 Level, pDriverInfo, dwFileCopyFlags);
3752 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3753 return FALSE;
3756 /******************************************************************************
3757 * DeletePrinterDriverExW (WINSPOOL.@)
3759 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
3760 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3762 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
3763 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
3764 return TRUE;
3767 /******************************************************************************
3768 * DeletePrinterDriverExA (WINSPOOL.@)
3770 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
3771 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3773 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
3774 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
3775 return TRUE;
3778 /******************************************************************************
3779 * DeletePrinterDataExW (WINSPOOL.@)
3781 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
3782 LPCWSTR pValueName)
3784 FIXME("%p %s %s\n", hPrinter,
3785 debugstr_w(pKeyName), debugstr_w(pValueName));
3786 return ERROR_INVALID_PARAMETER;
3789 /******************************************************************************
3790 * DeletePrinterDataExA (WINSPOOL.@)
3792 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
3793 LPCSTR pValueName)
3795 FIXME("%p %s %s\n", hPrinter,
3796 debugstr_a(pKeyName), debugstr_a(pValueName));
3797 return ERROR_INVALID_PARAMETER;
3800 /******************************************************************************
3801 * XcvDataW (WINSPOOL.@)
3803 * Notes:
3804 * There doesn't seem to be an A version...
3806 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
3807 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
3808 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
3810 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
3811 pInputData, cbInputData, pOutputData,
3812 cbOutputData, pcbOutputNeeded, pdwStatus);
3813 return FALSE;