Store print dlg structure in a property instead of DWL_USER.
[wine/multimedia.git] / dlls / winspool / info.c
blob320b81ec2a06eefc57aebc0d59e12e13338b7fb7
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"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stddef.h>
32 #ifdef HAVE_CUPS
33 # include <cups/cups.h>
34 #endif
35 #include "winspool.h"
36 #include "winbase.h"
37 #include "winerror.h"
38 #include "winreg.h"
39 #include "wine/windef16.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42 #include "heap.h"
43 #include "winnls.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
47 static LPWSTR *printer_array;
48 static int nb_printers;
50 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
51 WORD fwCapability, LPSTR lpszOutput,
52 LPDEVMODEA lpdm );
53 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
54 LPSTR lpszDevice, LPSTR lpszPort,
55 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
56 DWORD fwMode );
58 static char Printers[] =
59 "System\\CurrentControlSet\\control\\Print\\Printers\\";
60 static char Drivers[] =
61 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
63 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
65 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
66 'i','o','n',' ','F','i','l','e',0};
67 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
68 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
69 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
70 'M','o','d','e',0};
71 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
72 'i','l','e','s',0};
73 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
74 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
75 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
76 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
77 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
78 static WCHAR NameW[] = {'N','a','m','e',0};
79 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
80 static WCHAR PortW[] = {'P','o','r','t',0};
81 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
82 's','s','o','r',0};
83 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
84 'v','e','r',0};
85 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
86 'v','e','r','D','a','t','a',0};
87 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
88 'i','l','e',0};
89 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
90 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
92 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
93 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
94 DWORD Level, LPBYTE pDriverInfo,
95 DWORD cbBuf, LPDWORD pcbNeeded,
96 BOOL unicode);
97 static void
98 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
99 char qbuf[200];
101 /* If forcing, or no profile string entry for device yet, set the entry
103 * The always change entry if not WINEPS yet is discussable.
105 if (force ||
106 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
107 !strcmp(qbuf,"*") ||
108 !strstr(qbuf,"WINEPS")
110 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
112 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
113 WriteProfileStringA("windows","device",buf);
114 HeapFree(GetProcessHeap(),0,buf);
118 #ifdef HAVE_CUPS
119 BOOL
120 CUPS_LoadPrinters(void) {
121 char **printers;
122 int i,nrofdests,hadprinter = FALSE;
123 PRINTER_INFO_2A pinfo2a;
124 const char* def = cupsGetDefault();
126 nrofdests = cupsGetPrinters(&printers);
128 for (i=0;i<nrofdests;i++) {
129 const char *ppd = cupsGetPPD(printers[i]);
130 char *port,*devline;
132 if (!ppd) {
133 WARN("No ppd file for %s.\n",printers[i]);
134 continue;
136 unlink(ppd);
138 hadprinter = TRUE;
140 if (!strcmp(def,printers[i]))
141 WINSPOOL_SetDefaultPrinter(printers[i],printers[i],FALSE);
142 memset(&pinfo2a,0,sizeof(pinfo2a));
143 pinfo2a.pPrinterName = printers[i];
144 pinfo2a.pDatatype = "RAW";
145 pinfo2a.pPrintProcessor = "WinPrint";
146 pinfo2a.pDriverName = "PS Driver";
147 pinfo2a.pComment = "WINEPS Printer using CUPS";
148 pinfo2a.pLocation = "<physical location of printer>";
149 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(printers[i])+1);
150 sprintf(port,"LPR:%s",printers[i]);
151 pinfo2a.pPortName = port;
152 pinfo2a.pParameters = "<parameters?>";
153 pinfo2a.pShareName = "<share name?>";
154 pinfo2a.pSepFile = "<sep file?>";
156 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
157 sprintf(devline,"WINEPS,%s",port);
158 WriteProfileStringA("devices",printers[i],devline);
159 HeapFree(GetProcessHeap(),0,devline);
161 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
162 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
163 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",printers[i],GetLastError());
165 HeapFree(GetProcessHeap(),0,port);
167 return hadprinter;
169 #endif
171 static BOOL
172 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
173 PRINTER_INFO_2A pinfo2a;
174 char *s,*name,*prettyname,*devname;
175 BOOL isps = FALSE;
176 char *port,*devline;
178 while (isspace(*pent)) pent++;
179 s = strchr(pent,':');
180 if (!s) return FALSE;
181 *s='\0';
182 name = pent;
183 pent = s+1;
184 TRACE("%s\n",name);
186 /* Determine whether this is a postscript printer. */
188 /* 1. Check if name or aliases contain trigger phrases like 'ps' */
189 if (strstr(name,"ps") ||
190 strstr(name,"pd") || /* postscript double page */
191 strstr(name,"postscript") ||
192 strstr(name,"PostScript")
194 TRACE("%s has 'ps' style name, assuming postscript.\n",name);
195 isps = TRUE;
197 /* 2. Check if this is a remote printer. These usually are postscript
198 * capable
200 if (strstr(pent,":rm")) {
201 isps = TRUE;
202 TRACE("%s is remote, assuming postscript.\n",name);
204 /* 3. Check if we have an input filter program. If we have one, it
205 * most likely is one capable of converting postscript.
206 * (Could probably check for occurrence of 'gs' or 'ghostscript'
207 * in the if file itself.)
209 if (strstr(pent,":if=/")) {
210 isps = TRUE;
211 TRACE("%s has inputfilter program, assuming postscript.\n",name);
214 /* If it is not a postscript printer, we cannot use it. */
215 if (!isps)
216 return FALSE;
218 prettyname = name;
219 /* Get longest name, usually the one at the right for later display. */
220 while ((s=strchr(prettyname,'|'))) prettyname = s+1;
221 s=strchr(name,'|');if (s) *s='\0';
223 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
224 * if it is too long, we use it as comment below. */
225 devname = prettyname;
226 if (strlen(devname)>=CCHDEVICENAME-1)
227 devname = name;
228 if (strlen(devname)>=CCHDEVICENAME-1)
229 return FALSE;
231 if (isfirst) /* set first entry as default */
232 WINSPOOL_SetDefaultPrinter(devname,name,FALSE);
234 memset(&pinfo2a,0,sizeof(pinfo2a));
235 pinfo2a.pPrinterName = devname;
236 pinfo2a.pDatatype = "RAW";
237 pinfo2a.pPrintProcessor = "WinPrint";
238 pinfo2a.pDriverName = "PS Driver";
239 pinfo2a.pComment = "WINEPS Printer using LPR";
240 pinfo2a.pLocation = prettyname;
241 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
242 sprintf(port,"LPR:%s",name);
243 pinfo2a.pPortName = port;
244 pinfo2a.pParameters = "<parameters?>";
245 pinfo2a.pShareName = "<share name?>";
246 pinfo2a.pSepFile = "<sep file?>";
248 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
249 sprintf(devline,"WINEPS,%s",port);
250 WriteProfileStringA("devices",devname,devline);
251 HeapFree(GetProcessHeap(),0,devline);
253 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
254 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
255 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
257 HeapFree(GetProcessHeap(),0,port);
258 return TRUE;
261 static BOOL
262 PRINTCAP_LoadPrinters(void) {
263 BOOL hadprinter = FALSE, isfirst = TRUE;
264 char buf[200];
265 FILE *f;
267 f = fopen("/etc/printcap","r");
268 if (!f)
269 return FALSE;
271 while (fgets(buf,sizeof(buf),f)) {
272 char *pent = NULL;
273 do {
274 char *s;
275 s=strchr(buf,'\n'); if (s) *s='\0';
276 if ((buf[0]=='#') || (buf[0]=='\0'))
277 continue;
279 if (pent) {
280 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
281 strcat(pent,buf);
282 } else {
283 pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
284 strcpy(pent,buf);
287 if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
288 pent[strlen(pent)-1] = '\0';
289 else
290 break;
291 } while (fgets(buf,sizeof(buf),f));
292 if (pent)
293 hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
294 isfirst = FALSE;
295 if (pent) HeapFree(GetProcessHeap(),0,pent);
296 pent = NULL;
297 if (feof(f)) break;
299 fclose(f);
300 return hadprinter;
303 static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
305 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
306 lstrlenW(value) * sizeof(WCHAR));
309 void
310 WINSPOOL_LoadSystemPrinters() {
311 HKEY hkPPD;
312 DRIVER_INFO_3A di3a;
313 di3a.cVersion = 0x400;
314 di3a.pName = "PS Driver";
315 di3a.pEnvironment = NULL; /* NULL means auto */
316 di3a.pDriverPath = "wineps.drv";
317 di3a.pDataFile = "<datafile?>";
318 di3a.pConfigFile = "wineps.drv";
319 di3a.pHelpFile = "<helpfile?>";
320 di3a.pDependentFiles = "<dependend files?>";
321 di3a.pMonitorName = "<monitor name?>";
322 di3a.pDefaultDataType = "RAW";
324 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
325 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
326 return;
328 #ifdef HAVE_CUPS
329 /* If we have any CUPS based printers, skip looking for printcap printers */
330 if (CUPS_LoadPrinters())
331 return;
332 #endif
334 /* Check for [ppd] section in config file before parsing /etc/printcap */
336 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
337 &hkPPD) == ERROR_SUCCESS)
339 RegCloseKey(hkPPD);
340 PRINTCAP_LoadPrinters();
345 /******************************************************************
346 * WINSPOOL_GetOpenedPrinterEntry
347 * Get the first place empty in the opened printer table
349 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
351 int i;
353 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
355 if (i >= nb_printers)
357 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
358 (nb_printers + 16) * sizeof(*new_array) );
359 if (!new_array) return 0;
360 printer_array = new_array;
361 nb_printers += 16;
364 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
366 strcpyW( printer_array[i], name );
367 return (HANDLE)(i + 1);
369 return 0;
372 /******************************************************************
373 * WINSPOOL_GetOpenedPrinter
374 * Get the pointer to the opened printer referred by the handle
376 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
378 int idx = (int)printerHandle;
379 if ((idx <= 0) || (idx > nb_printers))
381 SetLastError(ERROR_INVALID_HANDLE);
382 return NULL;
384 return printer_array[idx - 1];
387 /******************************************************************
388 * WINSPOOL_GetOpenedPrinterRegKey
391 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
393 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
394 DWORD ret;
395 HKEY hkeyPrinters;
397 if(!name) return ERROR_INVALID_HANDLE;
399 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
400 ERROR_SUCCESS)
401 return ret;
403 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
405 ERR("Can't find opened printer %s in registry\n",
406 debugstr_w(name));
407 RegCloseKey(hkeyPrinters);
408 return ERROR_INVALID_PRINTER_NAME; /* ? */
410 RegCloseKey(hkeyPrinters);
411 return ERROR_SUCCESS;
414 /***********************************************************
415 * DEVMODEcpyAtoW
417 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
419 BOOL Formname;
420 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
421 DWORD size;
423 Formname = (dmA->dmSize > off_formname);
424 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
425 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
426 CCHDEVICENAME);
427 if(!Formname) {
428 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
429 dmA->dmSize - CCHDEVICENAME);
430 } else {
431 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
432 off_formname - CCHDEVICENAME);
433 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
434 CCHFORMNAME);
435 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
436 (off_formname + CCHFORMNAME));
438 dmW->dmSize = size;
439 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
440 dmA->dmDriverExtra);
441 return dmW;
444 /***********************************************************
445 * DEVMODEdupAtoW
446 * Creates a unicode copy of supplied devmode on heap
448 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
450 LPDEVMODEW dmW;
451 DWORD size;
452 BOOL Formname;
453 ptrdiff_t off_formname;
455 TRACE("\n");
456 if(!dmA) return NULL;
458 off_formname = (char *)dmA->dmFormName - (char *)dmA;
459 Formname = (dmA->dmSize > off_formname);
460 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
461 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
462 return DEVMODEcpyAtoW(dmW, dmA);
465 /***********************************************************
466 * DEVMODEdupWtoA
467 * Creates an ascii copy of supplied devmode on heap
469 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
471 LPDEVMODEA dmA;
472 DWORD size;
473 BOOL Formname;
474 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
476 if(!dmW) return NULL;
477 Formname = (dmW->dmSize > off_formname);
478 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
479 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
480 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
481 CCHDEVICENAME, NULL, NULL);
482 if(!Formname) {
483 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
484 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
485 } else {
486 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
487 off_formname - CCHDEVICENAME * sizeof(WCHAR));
488 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
489 CCHFORMNAME, NULL, NULL);
490 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
491 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
493 dmA->dmSize = size;
494 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
495 dmW->dmDriverExtra);
496 return dmA;
499 /***********************************************************
500 * PRINTER_INFO_2AtoW
501 * Creates a unicode copy of PRINTER_INFO_2A on heap
503 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
505 LPPRINTER_INFO_2W piW;
506 if(!piA) return NULL;
507 piW = HeapAlloc(heap, 0, sizeof(*piW));
508 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
509 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
510 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
511 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
512 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
513 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
514 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
515 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
516 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
517 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
518 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
519 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
520 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
521 return piW;
524 /***********************************************************
525 * FREE_PRINTER_INFO_2W
526 * Free PRINTER_INFO_2W and all strings
528 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
530 if(!piW) return;
532 HeapFree(heap,0,piW->pServerName);
533 HeapFree(heap,0,piW->pPrinterName);
534 HeapFree(heap,0,piW->pShareName);
535 HeapFree(heap,0,piW->pPortName);
536 HeapFree(heap,0,piW->pDriverName);
537 HeapFree(heap,0,piW->pComment);
538 HeapFree(heap,0,piW->pLocation);
539 HeapFree(heap,0,piW->pDevMode);
540 HeapFree(heap,0,piW->pSepFile);
541 HeapFree(heap,0,piW->pPrintProcessor);
542 HeapFree(heap,0,piW->pDatatype);
543 HeapFree(heap,0,piW->pParameters);
544 HeapFree(heap,0,piW);
545 return;
548 /******************************************************************
549 * DeviceCapabilities [WINSPOOL.@]
550 * DeviceCapabilitiesA [WINSPOOL.@]
553 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
554 LPSTR pOutput, LPDEVMODEA lpdm)
556 INT ret;
558 if (!GDI_CallDeviceCapabilities16)
560 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
561 (LPCSTR)104 );
562 if (!GDI_CallDeviceCapabilities16) return -1;
564 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
566 /* If DC_PAPERSIZE map POINT16s to POINTs */
567 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
568 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
569 POINT *pt = (POINT *)pOutput;
570 INT i;
571 memcpy(tmp, pOutput, ret * sizeof(POINT16));
572 for(i = 0; i < ret; i++, pt++)
574 pt->x = tmp[i].x;
575 pt->y = tmp[i].y;
577 HeapFree( GetProcessHeap(), 0, tmp );
579 return ret;
583 /*****************************************************************************
584 * DeviceCapabilitiesW [WINSPOOL.@]
586 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
589 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
590 WORD fwCapability, LPWSTR pOutput,
591 const DEVMODEW *pDevMode)
593 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
594 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
595 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
596 INT ret;
598 if(pOutput && (fwCapability == DC_BINNAMES ||
599 fwCapability == DC_FILEDEPENDENCIES ||
600 fwCapability == DC_PAPERNAMES)) {
601 /* These need A -> W translation */
602 INT size = 0, i;
603 LPSTR pOutputA;
604 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
605 dmA);
606 if(ret == -1)
607 return ret;
608 switch(fwCapability) {
609 case DC_BINNAMES:
610 size = 24;
611 break;
612 case DC_PAPERNAMES:
613 case DC_FILEDEPENDENCIES:
614 size = 64;
615 break;
617 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
618 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
619 dmA);
620 for(i = 0; i < ret; i++)
621 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
622 pOutput + (i * size), size);
623 HeapFree(GetProcessHeap(), 0, pOutputA);
624 } else {
625 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
626 (LPSTR)pOutput, dmA);
628 HeapFree(GetProcessHeap(),0,pPortA);
629 HeapFree(GetProcessHeap(),0,pDeviceA);
630 HeapFree(GetProcessHeap(),0,dmA);
631 return ret;
634 /******************************************************************
635 * DocumentPropertiesA [WINSPOOL.@]
638 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
639 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
640 LPDEVMODEA pDevModeInput,DWORD fMode )
642 LPSTR lpName = pDeviceName;
643 LONG ret;
645 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
646 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
649 if(!pDeviceName) {
650 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
651 if(!lpNameW) {
652 ERR("no name from hPrinter?\n");
653 return -1;
655 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
658 if (!GDI_CallExtDeviceMode16)
660 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
661 (LPCSTR)102 );
662 if (!GDI_CallExtDeviceMode16) {
663 ERR("No CallExtDeviceMode16?\n");
664 return -1;
667 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
668 pDevModeInput, NULL, fMode);
670 if(!pDeviceName)
671 HeapFree(GetProcessHeap(),0,lpName);
672 return ret;
676 /*****************************************************************************
677 * DocumentPropertiesW (WINSPOOL.@)
679 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
680 LPWSTR pDeviceName,
681 LPDEVMODEW pDevModeOutput,
682 LPDEVMODEW pDevModeInput, DWORD fMode)
685 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
686 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
687 LPDEVMODEA pDevModeOutputA = NULL;
688 LONG ret;
690 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
691 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
692 fMode);
693 if(pDevModeOutput) {
694 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
695 if(ret < 0) return ret;
696 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
698 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
699 pDevModeInputA, fMode);
700 if(pDevModeOutput) {
701 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
702 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
704 if(fMode == 0 && ret > 0)
705 ret += (CCHDEVICENAME + CCHFORMNAME);
706 HeapFree(GetProcessHeap(),0,pDevModeInputA);
707 HeapFree(GetProcessHeap(),0,pDeviceNameA);
708 return ret;
711 /******************************************************************
712 * OpenPrinterA [WINSPOOL.@]
715 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
716 LPPRINTER_DEFAULTSA pDefault)
718 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
719 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
720 BOOL ret;
722 if(pDefault) {
723 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
724 pDefault->pDatatype);
725 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
726 pDefault->pDevMode);
727 DefaultW.DesiredAccess = pDefault->DesiredAccess;
728 pDefaultW = &DefaultW;
730 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
731 if(pDefault) {
732 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
733 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
735 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
736 return ret;
739 /******************************************************************
740 * OpenPrinterW [WINSPOOL.@]
743 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
744 LPPRINTER_DEFAULTSW pDefault)
746 HKEY hkeyPrinters, hkeyPrinter;
748 if (!lpPrinterName) {
749 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
750 SetLastError(ERROR_INVALID_PARAMETER);
751 return FALSE;
754 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
755 pDefault);
757 /* Check Printer exists */
758 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
759 ERROR_SUCCESS) {
760 ERR("Can't create Printers key\n");
761 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
762 return FALSE;
765 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
766 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
767 != ERROR_SUCCESS) {
768 TRACE("Can't find printer %s in registry\n",
769 debugstr_w(lpPrinterName));
770 RegCloseKey(hkeyPrinters);
771 SetLastError(ERROR_INVALID_PRINTER_NAME);
772 return FALSE;
774 RegCloseKey(hkeyPrinter);
775 RegCloseKey(hkeyPrinters);
777 if(!phPrinter) /* This seems to be what win95 does anyway */
778 return TRUE;
780 /* Get the unique handle of the printer*/
781 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
783 if (pDefault != NULL)
784 FIXME("Not handling pDefault\n");
786 return TRUE;
789 /******************************************************************
790 * AddMonitorA [WINSPOOL.@]
793 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
795 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
796 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
797 return FALSE;
800 /******************************************************************
801 * DeletePrinterDriverA [WINSPOOL.@]
804 BOOL WINAPI
805 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
807 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
808 debugstr_a(pDriverName));
809 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
810 return FALSE;
814 /******************************************************************
815 * DeleteMonitorA [WINSPOOL.@]
818 BOOL WINAPI
819 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
821 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
822 debugstr_a(pMonitorName));
823 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
824 return FALSE;
828 /******************************************************************
829 * DeletePortA [WINSPOOL.@]
832 BOOL WINAPI
833 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
835 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
836 debugstr_a(pPortName));
837 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
838 return FALSE;
841 /******************************************************************************
842 * SetPrinterW [WINSPOOL.@]
844 BOOL WINAPI
845 SetPrinterW(
846 HANDLE hPrinter,
847 DWORD Level,
848 LPBYTE pPrinter,
849 DWORD Command) {
851 FIXME("():stub\n");
852 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
853 return FALSE;
856 /******************************************************************************
857 * WritePrinter [WINSPOOL.@]
859 BOOL WINAPI
860 WritePrinter(
861 HANDLE hPrinter,
862 LPVOID pBuf,
863 DWORD cbBuf,
864 LPDWORD pcWritten) {
866 FIXME("():stub\n");
867 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
868 return FALSE;
871 /*****************************************************************************
872 * AddFormA [WINSPOOL.@]
874 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
876 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
877 return 1;
880 /*****************************************************************************
881 * AddFormW [WINSPOOL.@]
883 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
885 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
886 return 1;
889 /*****************************************************************************
890 * AddJobA [WINSPOOL.@]
892 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
893 DWORD cbBuf, LPDWORD pcbNeeded)
895 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
896 pcbNeeded);
897 return 1;
900 /*****************************************************************************
901 * AddJobW [WINSPOOL.@]
903 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
904 LPDWORD pcbNeeded)
906 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
907 pcbNeeded);
908 return 1;
911 /*****************************************************************************
912 * WINSPOOL_OpenDriverReg [internal]
914 * opens the registry for the printer drivers depending on the given input
915 * variable pEnvironment
917 * RETURNS:
918 * the opened hkey on success
919 * NULL on error
921 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
922 { HKEY retval;
923 LPSTR lpKey, p = NULL;
925 TRACE("%s\n",
926 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
928 if(pEnvironment)
929 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
930 pEnvironment;
931 else {
932 OSVERSIONINFOA ver;
933 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
935 if(!GetVersionExA( &ver))
936 return 0;
938 switch (ver.dwPlatformId) {
939 case VER_PLATFORM_WIN32s:
940 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
941 return 0;
943 case VER_PLATFORM_WIN32_NT:
944 p = "Windows NT x86";
945 break;
946 default:
947 p = "Windows 4.0";
948 break;
950 TRACE("set environment to %s\n", p);
953 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
954 strlen(p) + strlen(Drivers));
955 sprintf( lpKey, Drivers, p);
957 TRACE("%s\n", lpKey);
959 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
960 ERROR_SUCCESS)
961 retval = 0;
963 if(pEnvironment && unicode)
964 HeapFree( GetProcessHeap(), 0, p);
965 HeapFree( GetProcessHeap(), 0, lpKey);
967 return retval;
970 /*****************************************************************************
971 * AddPrinterW [WINSPOOL.@]
973 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
975 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
976 LPDEVMODEA dmA;
977 LPDEVMODEW dmW;
978 HANDLE retval;
979 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
980 LONG size;
982 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
984 if(pName != NULL) {
985 ERR("pName = %s - unsupported\n", debugstr_w(pName));
986 SetLastError(ERROR_INVALID_PARAMETER);
987 return 0;
989 if(Level != 2) {
990 ERR("Level = %ld, unsupported!\n", Level);
991 SetLastError(ERROR_INVALID_LEVEL);
992 return 0;
994 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
995 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
996 debugstr_w(pi->pPrinterName)
998 SetLastError(ERROR_INVALID_LEVEL);
999 return 0;
1001 if(!pPrinter) {
1002 SetLastError(ERROR_INVALID_PARAMETER);
1003 return 0;
1005 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1006 ERROR_SUCCESS) {
1007 ERR("Can't create Printers key\n");
1008 return 0;
1010 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1011 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1012 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1013 RegCloseKey(hkeyPrinter);
1014 RegCloseKey(hkeyPrinters);
1015 return 0;
1017 RegCloseKey(hkeyPrinter);
1019 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1020 if(!hkeyDrivers) {
1021 ERR("Can't create Drivers key\n");
1022 RegCloseKey(hkeyPrinters);
1023 return 0;
1025 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1026 ERROR_SUCCESS) {
1027 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1028 RegCloseKey(hkeyPrinters);
1029 RegCloseKey(hkeyDrivers);
1030 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1031 return 0;
1033 RegCloseKey(hkeyDriver);
1034 RegCloseKey(hkeyDrivers);
1036 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1037 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1038 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1039 RegCloseKey(hkeyPrinters);
1040 return 0;
1043 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1044 ERROR_SUCCESS) {
1045 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1046 SetLastError(ERROR_INVALID_PRINTER_NAME);
1047 RegCloseKey(hkeyPrinters);
1048 return 0;
1050 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1051 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1052 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1054 /* See if we can load the driver. We may need the devmode structure anyway
1056 * FIXME:
1057 * Note that DocumentPropertiesW will briefly try to open the printer we
1058 * just create to find a DEVMODEA struct (it will use the WINEPS default
1059 * one in case it is not there, so we are ok).
1061 size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
1062 if(size < 0) {
1063 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1064 size = sizeof(DEVMODEW);
1066 if(pi->pDevMode)
1067 dmW = pi->pDevMode;
1068 else {
1069 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1070 dmW->dmSize = size;
1071 if (0>DocumentPropertiesW(0,-1,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
1072 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1073 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1074 return 0;
1076 /* set devmode to printer name */
1077 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1080 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1081 and we support these drivers. NT writes DEVMODEW so somehow
1082 we'll need to distinguish between these when we support NT
1083 drivers */
1084 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1085 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
1086 dmA->dmSize + dmA->dmDriverExtra);
1087 HeapFree(GetProcessHeap(), 0, dmA);
1088 if(!pi->pDevMode)
1089 HeapFree(GetProcessHeap(), 0, dmW);
1090 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1091 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1092 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1093 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1095 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1096 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1097 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1098 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1099 (LPBYTE)&pi->Priority, sizeof(DWORD));
1100 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1101 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1102 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1103 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1104 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1105 (LPBYTE)&pi->Status, sizeof(DWORD));
1106 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1107 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1109 RegCloseKey(hkeyPrinter);
1110 RegCloseKey(hkeyPrinters);
1111 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1112 ERR("OpenPrinter failing\n");
1113 return 0;
1115 return retval;
1118 /*****************************************************************************
1119 * AddPrinterA [WINSPOOL.@]
1121 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1123 WCHAR *pNameW;
1124 PRINTER_INFO_2W *piW;
1125 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1126 HANDLE ret;
1128 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1129 if(Level != 2) {
1130 ERR("Level = %ld, unsupported!\n", Level);
1131 SetLastError(ERROR_INVALID_LEVEL);
1132 return 0;
1134 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
1135 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1137 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
1139 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1140 HeapFree(GetProcessHeap(),0,pNameW);
1141 return ret;
1145 /*****************************************************************************
1146 * ClosePrinter [WINSPOOL.@]
1148 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1150 int i = (int)hPrinter;
1152 TRACE("Handle %d\n", hPrinter);
1154 if ((i <= 0) || (i > nb_printers)) return FALSE;
1155 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1156 printer_array[i - 1] = NULL;
1157 return TRUE;
1160 /*****************************************************************************
1161 * DeleteFormA [WINSPOOL.@]
1163 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1165 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
1166 return 1;
1169 /*****************************************************************************
1170 * DeleteFormW [WINSPOOL.@]
1172 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1174 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
1175 return 1;
1178 /*****************************************************************************
1179 * DeletePrinter [WINSPOOL.@]
1181 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1183 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1184 HKEY hkeyPrinters;
1186 if(!lpNameW) return FALSE;
1187 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1188 ERROR_SUCCESS) {
1189 ERR("Can't open Printers key\n");
1190 return 0;
1193 /* This should use a recursive delete see Q142491 or SHDeleteKey */
1194 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
1195 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
1196 RegCloseKey(hkeyPrinters);
1197 return 0;
1200 ClosePrinter(hPrinter);
1201 return TRUE;
1204 /*****************************************************************************
1205 * SetPrinterA [WINSPOOL.@]
1207 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1208 DWORD Command)
1210 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1211 return FALSE;
1214 /*****************************************************************************
1215 * SetJobA [WINSPOOL.@]
1217 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1218 LPBYTE pJob, DWORD Command)
1220 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1221 Command);
1222 return FALSE;
1225 /*****************************************************************************
1226 * SetJobW [WINSPOOL.@]
1228 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1229 LPBYTE pJob, DWORD Command)
1231 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1232 Command);
1233 return FALSE;
1236 /*****************************************************************************
1237 * GetFormA [WINSPOOL.@]
1239 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1240 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1242 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1243 Level,pForm,cbBuf,pcbNeeded);
1244 return FALSE;
1247 /*****************************************************************************
1248 * GetFormW [WINSPOOL.@]
1250 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1251 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1253 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1254 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1255 return FALSE;
1258 /*****************************************************************************
1259 * SetFormA [WINSPOOL.@]
1261 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1262 LPBYTE pForm)
1264 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1265 return FALSE;
1268 /*****************************************************************************
1269 * SetFormW [WINSPOOL.@]
1271 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1272 LPBYTE pForm)
1274 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1275 return FALSE;
1278 /*****************************************************************************
1279 * ReadPrinter [WINSPOOL.@]
1281 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1282 LPDWORD pNoBytesRead)
1284 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1285 return FALSE;
1288 /*****************************************************************************
1289 * ResetPrinterA [WINSPOOL.@]
1291 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1293 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1294 return FALSE;
1297 /*****************************************************************************
1298 * ResetPrinterW [WINSPOOL.@]
1300 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1302 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1303 return FALSE;
1306 /*****************************************************************************
1307 * WINSPOOL_GetDWORDFromReg
1309 * Return DWORD associated with ValueName from hkey.
1311 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1313 DWORD sz = sizeof(DWORD), type, value = 0;
1314 LONG ret;
1316 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1318 if(ret != ERROR_SUCCESS) {
1319 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1320 return 0;
1322 if(type != REG_DWORD) {
1323 ERR("Got type %ld\n", type);
1324 return 0;
1326 return value;
1329 /*****************************************************************************
1330 * WINSPOOL_GetStringFromReg
1332 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1333 * String is stored either as unicode or ascii.
1334 * Bit of a hack here to get the ValueName if we want ascii.
1336 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1337 DWORD buflen, DWORD *needed,
1338 BOOL unicode)
1340 DWORD sz = buflen, type;
1341 LONG ret;
1343 if(unicode)
1344 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1345 else {
1346 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1347 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1348 HeapFree(GetProcessHeap(),0,ValueNameA);
1350 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1351 WARN("Got ret = %ld\n", ret);
1352 *needed = 0;
1353 return FALSE;
1355 *needed = sz;
1356 return TRUE;
1359 /*****************************************************************************
1360 * WINSPOOL_GetDefaultDevMode
1362 * Get a default DevMode values for wineps.
1363 * FIXME - use ppd.
1366 static void WINSPOOL_GetDefaultDevMode(
1367 LPBYTE ptr,
1368 DWORD buflen, DWORD *needed,
1369 BOOL unicode)
1371 DEVMODEA dm;
1373 /* fill default DEVMODE - should be read from ppd... */
1374 ZeroMemory( &dm, sizeof(dm) );
1375 strcpy(dm.dmDeviceName,"wineps");
1376 dm.dmSpecVersion = DM_SPECVERSION;
1377 dm.dmDriverVersion = 1;
1378 dm.dmSize = sizeof(DEVMODEA);
1379 dm.dmDriverExtra = 0;
1380 dm.dmFields =
1381 DM_ORIENTATION | DM_PAPERSIZE |
1382 DM_PAPERLENGTH | DM_PAPERWIDTH |
1383 DM_SCALE |
1384 DM_COPIES |
1385 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1386 DM_YRESOLUTION | DM_TTOPTION;
1388 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1389 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1390 dm.u1.s1.dmPaperLength = 2970;
1391 dm.u1.s1.dmPaperWidth = 2100;
1393 dm.dmScale = 100;
1394 dm.dmCopies = 1;
1395 dm.dmDefaultSource = DMBIN_AUTO;
1396 dm.dmPrintQuality = DMRES_MEDIUM;
1397 /* dm.dmColor */
1398 /* dm.dmDuplex */
1399 dm.dmYResolution = 300; /* 300dpi */
1400 dm.dmTTOption = DMTT_BITMAP;
1401 /* dm.dmCollate */
1402 /* dm.dmFormName */
1403 /* dm.dmLogPixels */
1404 /* dm.dmBitsPerPel */
1405 /* dm.dmPelsWidth */
1406 /* dm.dmPelsHeight */
1407 /* dm.dmDisplayFlags */
1408 /* dm.dmDisplayFrequency */
1409 /* dm.dmICMMethod */
1410 /* dm.dmICMIntent */
1411 /* dm.dmMediaType */
1412 /* dm.dmDitherType */
1413 /* dm.dmReserved1 */
1414 /* dm.dmReserved2 */
1415 /* dm.dmPanningWidth */
1416 /* dm.dmPanningHeight */
1418 if(unicode) {
1419 if(buflen >= sizeof(DEVMODEW)) {
1420 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
1421 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1422 HeapFree(GetProcessHeap(),0,pdmW);
1424 *needed = sizeof(DEVMODEW);
1426 else
1428 if(buflen >= sizeof(DEVMODEA)) {
1429 memcpy(ptr, &dm, sizeof(DEVMODEA));
1431 *needed = sizeof(DEVMODEA);
1435 /*****************************************************************************
1436 * WINSPOOL_GetDevModeFromReg
1438 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1439 * DevMode is stored either as unicode or ascii.
1441 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1442 LPBYTE ptr,
1443 DWORD buflen, DWORD *needed,
1444 BOOL unicode)
1446 DWORD sz = buflen, type;
1447 LONG ret;
1449 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1450 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1451 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1452 if (sz < sizeof(DEVMODEA))
1454 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1455 return FALSE;
1457 /* ensures that dmSize is not erratically bogus if registry is invalid */
1458 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1459 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1460 if(unicode) {
1461 sz += (CCHDEVICENAME + CCHFORMNAME);
1462 if(buflen >= sz) {
1463 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1464 memcpy(ptr, dmW, sz);
1465 HeapFree(GetProcessHeap(),0,dmW);
1468 *needed = sz;
1469 return TRUE;
1472 /*********************************************************************
1473 * WINSPOOL_GetPrinter_2
1475 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1476 * The strings are either stored as unicode or ascii.
1478 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1479 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1480 BOOL unicode)
1482 DWORD size, left = cbBuf;
1483 BOOL space = (cbBuf > 0);
1484 LPBYTE ptr = buf;
1486 *pcbNeeded = 0;
1488 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1489 unicode)) {
1490 if(space && size <= left) {
1491 pi2->pPrinterName = (LPWSTR)ptr;
1492 ptr += size;
1493 left -= size;
1494 } else
1495 space = FALSE;
1496 *pcbNeeded += size;
1498 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1499 unicode)) {
1500 if(space && size <= left) {
1501 pi2->pShareName = (LPWSTR)ptr;
1502 ptr += size;
1503 left -= size;
1504 } else
1505 space = FALSE;
1506 *pcbNeeded += size;
1508 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1509 unicode)) {
1510 if(space && size <= left) {
1511 pi2->pPortName = (LPWSTR)ptr;
1512 ptr += size;
1513 left -= size;
1514 } else
1515 space = FALSE;
1516 *pcbNeeded += size;
1518 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1519 &size, unicode)) {
1520 if(space && size <= left) {
1521 pi2->pDriverName = (LPWSTR)ptr;
1522 ptr += size;
1523 left -= size;
1524 } else
1525 space = FALSE;
1526 *pcbNeeded += size;
1528 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1529 unicode)) {
1530 if(space && size <= left) {
1531 pi2->pComment = (LPWSTR)ptr;
1532 ptr += size;
1533 left -= size;
1534 } else
1535 space = FALSE;
1536 *pcbNeeded += size;
1538 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1539 unicode)) {
1540 if(space && size <= left) {
1541 pi2->pLocation = (LPWSTR)ptr;
1542 ptr += size;
1543 left -= size;
1544 } else
1545 space = FALSE;
1546 *pcbNeeded += size;
1548 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1549 &size, unicode)) {
1550 if(space && size <= left) {
1551 pi2->pDevMode = (LPDEVMODEW)ptr;
1552 ptr += size;
1553 left -= size;
1554 } else
1555 space = FALSE;
1556 *pcbNeeded += size;
1558 else
1560 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
1561 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
1562 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1563 if(space && size <= left) {
1564 pi2->pDevMode = (LPDEVMODEW)ptr;
1565 ptr += size;
1566 left -= size;
1567 } else
1568 space = FALSE;
1569 *pcbNeeded += size;
1571 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1572 &size, unicode)) {
1573 if(space && size <= left) {
1574 pi2->pSepFile = (LPWSTR)ptr;
1575 ptr += size;
1576 left -= size;
1577 } else
1578 space = FALSE;
1579 *pcbNeeded += size;
1581 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1582 &size, unicode)) {
1583 if(space && size <= left) {
1584 pi2->pPrintProcessor = (LPWSTR)ptr;
1585 ptr += size;
1586 left -= size;
1587 } else
1588 space = FALSE;
1589 *pcbNeeded += size;
1591 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1592 &size, unicode)) {
1593 if(space && size <= left) {
1594 pi2->pDatatype = (LPWSTR)ptr;
1595 ptr += size;
1596 left -= size;
1597 } else
1598 space = FALSE;
1599 *pcbNeeded += size;
1601 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1602 &size, unicode)) {
1603 if(space && size <= left) {
1604 pi2->pParameters = (LPWSTR)ptr;
1605 ptr += size;
1606 left -= size;
1607 } else
1608 space = FALSE;
1609 *pcbNeeded += size;
1611 if(pi2) {
1612 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1613 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1614 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1615 "Default Priority");
1616 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1617 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1620 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1621 memset(pi2, 0, sizeof(*pi2));
1623 return space;
1626 /*********************************************************************
1627 * WINSPOOL_GetPrinter_4
1629 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1631 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1632 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1633 BOOL unicode)
1635 DWORD size, left = cbBuf;
1636 BOOL space = (cbBuf > 0);
1637 LPBYTE ptr = buf;
1639 *pcbNeeded = 0;
1641 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1642 unicode)) {
1643 if(space && size <= left) {
1644 pi4->pPrinterName = (LPWSTR)ptr;
1645 ptr += size;
1646 left -= size;
1647 } else
1648 space = FALSE;
1649 *pcbNeeded += size;
1651 if(pi4) {
1652 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1655 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1656 memset(pi4, 0, sizeof(*pi4));
1658 return space;
1661 /*********************************************************************
1662 * WINSPOOL_GetPrinter_5
1664 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1666 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1667 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1668 BOOL unicode)
1670 DWORD size, left = cbBuf;
1671 BOOL space = (cbBuf > 0);
1672 LPBYTE ptr = buf;
1674 *pcbNeeded = 0;
1676 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1677 unicode)) {
1678 if(space && size <= left) {
1679 pi5->pPrinterName = (LPWSTR)ptr;
1680 ptr += size;
1681 left -= size;
1682 } else
1683 space = FALSE;
1684 *pcbNeeded += size;
1686 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1687 unicode)) {
1688 if(space && size <= left) {
1689 pi5->pPortName = (LPWSTR)ptr;
1690 ptr += size;
1691 left -= size;
1692 } else
1693 space = FALSE;
1694 *pcbNeeded += size;
1696 if(pi5) {
1697 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1698 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1699 "dnsTimeout");
1700 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1701 "txTimeout");
1704 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1705 memset(pi5, 0, sizeof(*pi5));
1707 return space;
1710 /*****************************************************************************
1711 * WINSPOOL_GetPrinter
1713 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1714 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1715 * just a collection of pointers to strings.
1717 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1718 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1720 LPCWSTR name;
1721 DWORD size, needed = 0;
1722 LPBYTE ptr = NULL;
1723 HKEY hkeyPrinter, hkeyPrinters;
1724 BOOL ret;
1726 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1728 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1730 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1731 ERROR_SUCCESS) {
1732 ERR("Can't create Printers key\n");
1733 return FALSE;
1735 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1737 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1738 RegCloseKey(hkeyPrinters);
1739 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1740 return FALSE;
1743 switch(Level) {
1744 case 2:
1746 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1748 size = sizeof(PRINTER_INFO_2W);
1749 if(size <= cbBuf) {
1750 ptr = pPrinter + size;
1751 cbBuf -= size;
1752 memset(pPrinter, 0, size);
1753 } else {
1754 pi2 = NULL;
1755 cbBuf = 0;
1757 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1758 unicode);
1759 needed += size;
1760 break;
1763 case 4:
1765 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1767 size = sizeof(PRINTER_INFO_4W);
1768 if(size <= cbBuf) {
1769 ptr = pPrinter + size;
1770 cbBuf -= size;
1771 memset(pPrinter, 0, size);
1772 } else {
1773 pi4 = NULL;
1774 cbBuf = 0;
1776 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1777 unicode);
1778 needed += size;
1779 break;
1783 case 5:
1785 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1787 size = sizeof(PRINTER_INFO_5W);
1788 if(size <= cbBuf) {
1789 ptr = pPrinter + size;
1790 cbBuf -= size;
1791 memset(pPrinter, 0, size);
1792 } else {
1793 pi5 = NULL;
1794 cbBuf = 0;
1797 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1798 unicode);
1799 needed += size;
1800 break;
1803 default:
1804 FIXME("Unimplemented level %ld\n", Level);
1805 SetLastError(ERROR_INVALID_LEVEL);
1806 RegCloseKey(hkeyPrinters);
1807 RegCloseKey(hkeyPrinter);
1808 return FALSE;
1811 RegCloseKey(hkeyPrinter);
1812 RegCloseKey(hkeyPrinters);
1814 TRACE("returing %d needed = %ld\n", ret, needed);
1815 if(pcbNeeded) *pcbNeeded = needed;
1816 if(!ret)
1817 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1818 return ret;
1821 /*****************************************************************************
1822 * GetPrinterW [WINSPOOL.@]
1824 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1825 DWORD cbBuf, LPDWORD pcbNeeded)
1827 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1828 TRUE);
1831 /*****************************************************************************
1832 * GetPrinterA [WINSPOOL.@]
1834 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1835 DWORD cbBuf, LPDWORD pcbNeeded)
1837 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1838 FALSE);
1841 /*****************************************************************************
1842 * WINSPOOL_EnumPrinters
1844 * Implementation of EnumPrintersA|W
1846 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1847 DWORD dwLevel, LPBYTE lpbPrinters,
1848 DWORD cbBuf, LPDWORD lpdwNeeded,
1849 LPDWORD lpdwReturned, BOOL unicode)
1852 HKEY hkeyPrinters, hkeyPrinter;
1853 WCHAR PrinterName[255];
1854 DWORD needed = 0, number = 0;
1855 DWORD used, i, left;
1856 PBYTE pi, buf;
1858 if(lpbPrinters)
1859 memset(lpbPrinters, 0, cbBuf);
1860 if(lpdwReturned)
1861 *lpdwReturned = 0;
1862 if(lpdwNeeded)
1863 *lpdwNeeded = 0;
1865 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1866 if(dwType == PRINTER_ENUM_DEFAULT)
1867 return TRUE;
1869 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1870 FIXME("dwType = %08lx\n", dwType);
1871 SetLastError(ERROR_INVALID_FLAGS);
1872 return FALSE;
1875 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1876 ERROR_SUCCESS) {
1877 ERR("Can't create Printers key\n");
1878 return FALSE;
1881 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1882 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1883 RegCloseKey(hkeyPrinters);
1884 ERR("Can't query Printers key\n");
1885 return FALSE;
1887 TRACE("Found %ld printers\n", number);
1889 switch(dwLevel) {
1890 case 1:
1891 RegCloseKey(hkeyPrinters);
1892 if (lpdwReturned)
1893 *lpdwReturned = number;
1894 return TRUE;
1896 case 2:
1897 used = number * sizeof(PRINTER_INFO_2W);
1898 break;
1899 case 4:
1900 used = number * sizeof(PRINTER_INFO_4W);
1901 break;
1902 case 5:
1903 used = number * sizeof(PRINTER_INFO_5W);
1904 break;
1906 default:
1907 SetLastError(ERROR_INVALID_LEVEL);
1908 RegCloseKey(hkeyPrinters);
1909 return FALSE;
1911 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1913 for(i = 0; i < number; i++) {
1914 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1915 ERROR_SUCCESS) {
1916 ERR("Can't enum key number %ld\n", i);
1917 RegCloseKey(hkeyPrinters);
1918 return FALSE;
1920 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1921 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1922 ERROR_SUCCESS) {
1923 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1924 RegCloseKey(hkeyPrinters);
1925 return FALSE;
1928 if(cbBuf > used) {
1929 buf = lpbPrinters + used;
1930 left = cbBuf - used;
1931 } else {
1932 buf = NULL;
1933 left = 0;
1936 switch(dwLevel) {
1937 case 2:
1938 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1939 left, &needed, unicode);
1940 used += needed;
1941 if(pi) pi += sizeof(PRINTER_INFO_2W);
1942 break;
1943 case 4:
1944 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1945 left, &needed, unicode);
1946 used += needed;
1947 if(pi) pi += sizeof(PRINTER_INFO_4W);
1948 break;
1949 case 5:
1950 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1951 left, &needed, unicode);
1952 used += needed;
1953 if(pi) pi += sizeof(PRINTER_INFO_5W);
1954 break;
1955 default:
1956 ERR("Shouldn't be here!\n");
1957 RegCloseKey(hkeyPrinter);
1958 RegCloseKey(hkeyPrinters);
1959 return FALSE;
1961 RegCloseKey(hkeyPrinter);
1963 RegCloseKey(hkeyPrinters);
1965 if(lpdwNeeded)
1966 *lpdwNeeded = used;
1968 if(used > cbBuf) {
1969 if(lpbPrinters)
1970 memset(lpbPrinters, 0, cbBuf);
1971 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1972 return FALSE;
1974 if(lpdwReturned)
1975 *lpdwReturned = number;
1976 SetLastError(ERROR_SUCCESS);
1977 return TRUE;
1981 /******************************************************************
1982 * EnumPrintersW [WINSPOOL.@]
1984 * Enumerates the available printers, print servers and print
1985 * providers, depending on the specified flags, name and level.
1987 * RETURNS:
1989 * If level is set to 1:
1990 * Not implemented yet!
1991 * Returns TRUE with an empty list.
1993 * If level is set to 2:
1994 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1995 * Returns an array of PRINTER_INFO_2 data structures in the
1996 * lpbPrinters buffer. Note that according to MSDN also an
1997 * OpenPrinter should be performed on every remote printer.
1999 * If level is set to 4 (officially WinNT only):
2000 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2001 * Fast: Only the registry is queried to retrieve printer names,
2002 * no connection to the driver is made.
2003 * Returns an array of PRINTER_INFO_4 data structures in the
2004 * lpbPrinters buffer.
2006 * If level is set to 5 (officially WinNT4/Win9x only):
2007 * Fast: Only the registry is queried to retrieve printer names,
2008 * no connection to the driver is made.
2009 * Returns an array of PRINTER_INFO_5 data structures in the
2010 * lpbPrinters buffer.
2012 * If level set to 3 or 6+:
2013 * returns zero (failure!)
2015 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2016 * for information.
2018 * BUGS:
2019 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2020 * - Only levels 2, 4 and 5 are implemented at the moment.
2021 * - 16-bit printer drivers are not enumerated.
2022 * - Returned amount of bytes used/needed does not match the real Windoze
2023 * implementation (as in this implementation, all strings are part
2024 * of the buffer, whereas Win32 keeps them somewhere else)
2025 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2027 * NOTE:
2028 * - In a regular Wine installation, no registry settings for printers
2029 * exist, which makes this function return an empty list.
2031 BOOL WINAPI EnumPrintersW(
2032 DWORD dwType, /* [in] Types of print objects to enumerate */
2033 LPWSTR lpszName, /* [in] name of objects to enumerate */
2034 DWORD dwLevel, /* [in] type of printer info structure */
2035 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2036 DWORD cbBuf, /* [in] max size of buffer in bytes */
2037 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2038 LPDWORD lpdwReturned /* [out] number of entries returned */
2041 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2042 lpdwNeeded, lpdwReturned, TRUE);
2045 /******************************************************************
2046 * EnumPrintersA [WINSPOOL.@]
2049 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2050 DWORD dwLevel, LPBYTE lpbPrinters,
2051 DWORD cbBuf, LPDWORD lpdwNeeded,
2052 LPDWORD lpdwReturned)
2054 BOOL ret;
2055 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
2057 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
2058 lpdwNeeded, lpdwReturned, FALSE);
2059 HeapFree(GetProcessHeap(),0,lpszNameW);
2060 return ret;
2063 /*****************************************************************************
2064 * WINSPOOL_GetDriverInfoFromReg [internal]
2066 * Enters the information from the registry into the DRIVER_INFO struct
2068 * RETURNS
2069 * zero if the printer driver does not exist in the registry
2070 * (only if Level > 1) otherwise nonzero
2072 static BOOL WINSPOOL_GetDriverInfoFromReg(
2073 HKEY hkeyDrivers,
2074 LPWSTR DriverName,
2075 LPWSTR pEnvironment,
2076 DWORD Level,
2077 LPBYTE ptr, /* DRIVER_INFO */
2078 LPBYTE pDriverStrings, /* strings buffer */
2079 DWORD cbBuf, /* size of string buffer */
2080 LPDWORD pcbNeeded, /* space needed for str. */
2081 BOOL unicode) /* type of strings */
2082 { DWORD dw, size, tmp, type;
2083 HKEY hkeyDriver;
2084 LPBYTE strPtr = pDriverStrings;
2086 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2087 debugstr_w(DriverName), debugstr_w(pEnvironment),
2088 Level, ptr, pDriverStrings, cbBuf, unicode);
2090 if(unicode) {
2091 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2092 if (*pcbNeeded <= cbBuf)
2093 strcpyW((LPWSTR)strPtr, DriverName);
2094 } else {
2095 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2096 NULL, NULL);
2097 if(*pcbNeeded <= cbBuf)
2098 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2099 NULL, NULL);
2101 if(Level == 1) {
2102 if(ptr)
2103 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2104 return TRUE;
2105 } else {
2106 if(ptr)
2107 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2108 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2111 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2112 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2113 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2114 return FALSE;
2117 size = sizeof(dw);
2118 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2119 ERROR_SUCCESS)
2120 WARN("Can't get Version\n");
2121 else if(ptr)
2122 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2124 if(!pEnvironment)
2125 pEnvironment = DefaultEnvironmentW;
2126 if(unicode)
2127 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2128 else
2129 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2130 NULL, NULL);
2131 *pcbNeeded += size;
2132 if(*pcbNeeded <= cbBuf) {
2133 if(unicode)
2134 strcpyW((LPWSTR)strPtr, pEnvironment);
2135 else
2136 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2137 NULL, NULL);
2138 if(ptr)
2139 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2140 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2143 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2144 unicode)) {
2145 *pcbNeeded += size;
2146 if(*pcbNeeded <= cbBuf)
2147 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2148 unicode);
2149 if(ptr)
2150 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2151 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2154 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2155 unicode)) {
2156 *pcbNeeded += size;
2157 if(*pcbNeeded <= cbBuf)
2158 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2159 &tmp, unicode);
2160 if(ptr)
2161 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2162 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2165 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2166 0, &size, unicode)) {
2167 *pcbNeeded += size;
2168 if(*pcbNeeded <= cbBuf)
2169 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2170 size, &tmp, unicode);
2171 if(ptr)
2172 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2173 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2176 if(Level == 2 ) {
2177 RegCloseKey(hkeyDriver);
2178 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2179 return TRUE;
2182 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2183 unicode)) {
2184 *pcbNeeded += size;
2185 if(*pcbNeeded <= cbBuf)
2186 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2187 size, &tmp, unicode);
2188 if(ptr)
2189 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2190 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2193 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2194 &size, unicode)) {
2195 *pcbNeeded += size;
2196 if(*pcbNeeded <= cbBuf)
2197 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2198 size, &tmp, unicode);
2199 if(ptr)
2200 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2201 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2204 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2205 unicode)) {
2206 *pcbNeeded += size;
2207 if(*pcbNeeded <= cbBuf)
2208 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2209 size, &tmp, unicode);
2210 if(ptr)
2211 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2212 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2215 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2216 unicode)) {
2217 *pcbNeeded += size;
2218 if(*pcbNeeded <= cbBuf)
2219 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2220 size, &tmp, unicode);
2221 if(ptr)
2222 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2223 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2226 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2227 RegCloseKey(hkeyDriver);
2228 return TRUE;
2231 /*****************************************************************************
2232 * WINSPOOL_GetPrinterDriver
2234 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2235 DWORD Level, LPBYTE pDriverInfo,
2236 DWORD cbBuf, LPDWORD pcbNeeded,
2237 BOOL unicode)
2239 LPCWSTR name;
2240 WCHAR DriverName[100];
2241 DWORD ret, type, size, needed = 0;
2242 LPBYTE ptr = NULL;
2243 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2245 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2246 Level,pDriverInfo,cbBuf, pcbNeeded);
2248 ZeroMemory(pDriverInfo, cbBuf);
2250 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2252 if(Level < 1 || Level > 3) {
2253 SetLastError(ERROR_INVALID_LEVEL);
2254 return FALSE;
2256 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2257 ERROR_SUCCESS) {
2258 ERR("Can't create Printers key\n");
2259 return FALSE;
2261 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2262 != ERROR_SUCCESS) {
2263 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2264 RegCloseKey(hkeyPrinters);
2265 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2266 return FALSE;
2268 size = sizeof(DriverName);
2269 DriverName[0] = 0;
2270 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2271 (LPBYTE)DriverName, &size);
2272 RegCloseKey(hkeyPrinter);
2273 RegCloseKey(hkeyPrinters);
2274 if(ret != ERROR_SUCCESS) {
2275 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2276 return FALSE;
2279 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2280 if(!hkeyDrivers) {
2281 ERR("Can't create Drivers key\n");
2282 return FALSE;
2285 switch(Level) {
2286 case 1:
2287 size = sizeof(DRIVER_INFO_1W);
2288 break;
2289 case 2:
2290 size = sizeof(DRIVER_INFO_2W);
2291 break;
2292 case 3:
2293 size = sizeof(DRIVER_INFO_3W);
2294 break;
2295 default:
2296 ERR("Invalid level\n");
2297 return FALSE;
2300 if(size <= cbBuf)
2301 ptr = pDriverInfo + size;
2303 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2304 pEnvironment, Level, pDriverInfo,
2305 (cbBuf < size) ? NULL : ptr,
2306 (cbBuf < size) ? 0 : cbBuf - size,
2307 &needed, unicode)) {
2308 RegCloseKey(hkeyDrivers);
2309 return FALSE;
2312 RegCloseKey(hkeyDrivers);
2314 if(pcbNeeded) *pcbNeeded = size + needed;
2315 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2316 if(cbBuf >= needed) return TRUE;
2317 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2318 return FALSE;
2321 /*****************************************************************************
2322 * GetPrinterDriverA [WINSPOOL.@]
2324 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2325 DWORD Level, LPBYTE pDriverInfo,
2326 DWORD cbBuf, LPDWORD pcbNeeded)
2328 BOOL ret;
2329 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2330 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2331 cbBuf, pcbNeeded, FALSE);
2332 HeapFree(GetProcessHeap(),0,pEnvW);
2333 return ret;
2335 /*****************************************************************************
2336 * GetPrinterDriverW [WINSPOOL.@]
2338 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2339 DWORD Level, LPBYTE pDriverInfo,
2340 DWORD cbBuf, LPDWORD pcbNeeded)
2342 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2343 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2346 /*****************************************************************************
2347 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2349 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2350 DWORD Level, LPBYTE pDriverDirectory,
2351 DWORD cbBuf, LPDWORD pcbNeeded)
2353 DWORD needed;
2355 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2356 pDriverDirectory, cbBuf, pcbNeeded);
2357 if(pName != NULL) {
2358 FIXME("pName = `%s' - unsupported\n", pName);
2359 SetLastError(ERROR_INVALID_PARAMETER);
2360 return FALSE;
2362 if(pEnvironment != NULL) {
2363 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2364 SetLastError(ERROR_INVALID_ENVIRONMENT);
2365 return FALSE;
2367 if(Level != 1) /* win95 ignores this so we just carry on */
2368 WARN("Level = %ld - assuming 1\n", Level);
2370 /* FIXME should read from registry */
2371 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2372 needed++;
2373 if(pcbNeeded)
2374 *pcbNeeded = needed;
2375 if(needed > cbBuf) {
2376 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2377 return FALSE;
2379 return TRUE;
2383 /*****************************************************************************
2384 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2386 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2387 DWORD Level, LPBYTE pDriverDirectory,
2388 DWORD cbBuf, LPDWORD pcbNeeded)
2390 LPSTR pNameA = NULL, pEnvironmentA = NULL;
2391 BOOL ret;
2393 if(pName)
2394 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2395 if(pEnvironment)
2396 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2397 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2398 pDriverDirectory, cbBuf, pcbNeeded );
2399 if(pNameA)
2400 HeapFree( GetProcessHeap(), 0, pNameA );
2401 if(pEnvironmentA)
2402 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2404 return ret;
2407 /*****************************************************************************
2408 * AddPrinterDriverA [WINSPOOL.@]
2410 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2412 DRIVER_INFO_3A di3;
2413 HKEY hkeyDrivers, hkeyName;
2415 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2417 if(level != 2 && level != 3) {
2418 SetLastError(ERROR_INVALID_LEVEL);
2419 return FALSE;
2421 if(pName != NULL) {
2422 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2423 SetLastError(ERROR_INVALID_PARAMETER);
2424 return FALSE;
2426 if(!pDriverInfo) {
2427 WARN("pDriverInfo == NULL\n");
2428 SetLastError(ERROR_INVALID_PARAMETER);
2429 return FALSE;
2432 if(level == 3)
2433 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2434 else {
2435 memset(&di3, 0, sizeof(di3));
2436 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2439 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2440 !di3.pDataFile) {
2441 SetLastError(ERROR_INVALID_PARAMETER);
2442 return FALSE;
2444 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2445 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2446 if(!di3.pHelpFile) di3.pHelpFile = "";
2447 if(!di3.pMonitorName) di3.pMonitorName = "";
2449 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2451 if(!hkeyDrivers) {
2452 ERR("Can't create Drivers key\n");
2453 return FALSE;
2456 if(level == 2) { /* apparently can't overwrite with level2 */
2457 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2458 RegCloseKey(hkeyName);
2459 RegCloseKey(hkeyDrivers);
2460 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2461 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2462 return FALSE;
2465 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2466 RegCloseKey(hkeyDrivers);
2467 ERR("Can't create Name key\n");
2468 return FALSE;
2470 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2472 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2473 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2474 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2475 sizeof(DWORD));
2476 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2477 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2478 di3.pDependentFiles, 0);
2479 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2480 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2481 RegCloseKey(hkeyName);
2482 RegCloseKey(hkeyDrivers);
2484 return TRUE;
2486 /*****************************************************************************
2487 * AddPrinterDriverW [WINSPOOL.@]
2489 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2490 LPBYTE pDriverInfo)
2492 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2493 level,pDriverInfo);
2494 return FALSE;
2498 /*****************************************************************************
2499 * PrinterProperties [WINSPOOL.@]
2501 * Displays a dialog to set the properties of the printer.
2503 * RETURNS
2504 * nonzero on success or zero on failure
2506 * BUGS
2507 * implemented as stub only
2509 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2510 HANDLE hPrinter /* [in] handle to printer object */
2512 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2513 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2514 return FALSE;
2517 /*****************************************************************************
2518 * EnumJobsA [WINSPOOL.@]
2521 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2522 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2523 LPDWORD pcReturned)
2525 FIXME("stub\n");
2526 if(pcbNeeded) *pcbNeeded = 0;
2527 if(pcReturned) *pcReturned = 0;
2528 return TRUE;
2532 /*****************************************************************************
2533 * EnumJobsW [WINSPOOL.@]
2536 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2537 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2538 LPDWORD pcReturned)
2540 FIXME("stub\n");
2541 if(pcbNeeded) *pcbNeeded = 0;
2542 if(pcReturned) *pcReturned = 0;
2543 return TRUE;
2546 /*****************************************************************************
2547 * WINSPOOL_EnumPrinterDrivers [internal]
2549 * Delivers information about all printer drivers installed on the
2550 * localhost or a given server
2552 * RETURNS
2553 * nonzero on success or zero on failure. If the buffer for the returned
2554 * information is too small the function will return an error
2556 * BUGS
2557 * - only implemented for localhost, foreign hosts will return an error
2559 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2560 DWORD Level, LPBYTE pDriverInfo,
2561 DWORD cbBuf, LPDWORD pcbNeeded,
2562 LPDWORD pcReturned, BOOL unicode)
2564 { HKEY hkeyDrivers;
2565 DWORD i, needed, number = 0, size = 0;
2566 WCHAR DriverNameW[255];
2567 PBYTE ptr;
2569 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2570 debugstr_w(pName), debugstr_w(pEnvironment),
2571 Level, pDriverInfo, cbBuf, unicode);
2573 /* check for local drivers */
2574 if(pName) {
2575 ERR("remote drivers unsupported! Current remote host is %s\n",
2576 debugstr_w(pName));
2577 return FALSE;
2580 /* check input parameter */
2581 if((Level < 1) || (Level > 3)) {
2582 ERR("unsupported level %ld \n", Level);
2583 return FALSE;
2586 /* initialize return values */
2587 if(pDriverInfo)
2588 memset( pDriverInfo, 0, cbBuf);
2589 *pcbNeeded = 0;
2590 *pcReturned = 0;
2592 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2593 if(!hkeyDrivers) {
2594 ERR("Can't open Drivers key\n");
2595 return FALSE;
2598 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2599 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2600 RegCloseKey(hkeyDrivers);
2601 ERR("Can't query Drivers key\n");
2602 return FALSE;
2604 TRACE("Found %ld Drivers\n", number);
2606 /* get size of single struct
2607 * unicode and ascii structure have the same size
2609 switch (Level) {
2610 case 1:
2611 size = sizeof(DRIVER_INFO_1A);
2612 break;
2613 case 2:
2614 size = sizeof(DRIVER_INFO_2A);
2615 break;
2616 case 3:
2617 size = sizeof(DRIVER_INFO_3A);
2618 break;
2621 /* calculate required buffer size */
2622 *pcbNeeded = size * number;
2624 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2625 i < number;
2626 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2627 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2628 != ERROR_SUCCESS) {
2629 ERR("Can't enum key number %ld\n", i);
2630 RegCloseKey(hkeyDrivers);
2631 return FALSE;
2633 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2634 pEnvironment, Level, ptr,
2635 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2636 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2637 &needed, unicode)) {
2638 RegCloseKey(hkeyDrivers);
2639 return FALSE;
2641 (*pcbNeeded) += needed;
2644 RegCloseKey(hkeyDrivers);
2646 if(cbBuf < *pcbNeeded){
2647 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2648 return FALSE;
2651 return TRUE;
2654 /*****************************************************************************
2655 * EnumPrinterDriversW [WINSPOOL.@]
2657 * see function EnumPrinterDrivers for RETURNS, BUGS
2659 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2660 LPBYTE pDriverInfo, DWORD cbBuf,
2661 LPDWORD pcbNeeded, LPDWORD pcReturned)
2663 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2664 cbBuf, pcbNeeded, pcReturned, TRUE);
2667 /*****************************************************************************
2668 * EnumPrinterDriversA [WINSPOOL.@]
2670 * see function EnumPrinterDrivers for RETURNS, BUGS
2672 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2673 LPBYTE pDriverInfo, DWORD cbBuf,
2674 LPDWORD pcbNeeded, LPDWORD pcReturned)
2675 { BOOL ret;
2676 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2678 if(pName)
2679 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2680 if(pEnvironment)
2681 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2683 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2684 cbBuf, pcbNeeded, pcReturned, FALSE);
2685 if(pNameW)
2686 HeapFree(GetProcessHeap(), 0, pNameW);
2687 if(pEnvironmentW)
2688 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2690 return ret;
2694 /******************************************************************************
2695 * EnumPortsA (WINSPOOL.@)
2697 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2698 LPDWORD bufneeded,LPDWORD bufreturned)
2700 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2701 return FALSE;
2704 /******************************************************************************
2705 * GetDefaultPrinterA (WINSPOOL.@)
2707 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
2709 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
2711 char *ptr;
2713 if (*namesize < 1)
2715 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2716 return FALSE;
2719 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
2721 SetLastError (ERROR_FILE_NOT_FOUND);
2722 return FALSE;
2725 if ((ptr = strchr (name, ',')) == NULL)
2727 SetLastError (ERROR_FILE_NOT_FOUND);
2728 return FALSE;
2731 *ptr = '\0';
2732 *namesize = strlen (name) + 1;
2733 return TRUE;
2737 /******************************************************************************
2738 * GetDefaultPrinterW (WINSPOOL.@)
2740 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
2742 char *buf;
2743 BOOL ret;
2745 if (*namesize < 1)
2747 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2748 return FALSE;
2751 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
2752 ret = GetDefaultPrinterA (buf, namesize);
2753 if (ret)
2755 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
2756 if (!len)
2758 SetLastError (ERROR_INSUFFICIENT_BUFFER);
2759 ret = FALSE;
2761 else *namesize = len;
2764 HeapFree (GetProcessHeap (), 0, buf);
2765 return ret;
2769 /******************************************************************************
2770 * SetPrinterDataExA (WINSPOOL.@)
2772 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2773 LPSTR pValueName, DWORD Type,
2774 LPBYTE pData, DWORD cbData)
2776 HKEY hkeyPrinter, hkeySubkey;
2777 DWORD ret;
2779 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2780 debugstr_a(pValueName), Type, pData, cbData);
2782 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2783 != ERROR_SUCCESS)
2784 return ret;
2786 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2787 != ERROR_SUCCESS) {
2788 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2789 RegCloseKey(hkeyPrinter);
2790 return ret;
2792 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2793 RegCloseKey(hkeySubkey);
2794 RegCloseKey(hkeyPrinter);
2795 return ret;
2798 /******************************************************************************
2799 * SetPrinterDataExW (WINSPOOL.@)
2801 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2802 LPWSTR pValueName, DWORD Type,
2803 LPBYTE pData, DWORD cbData)
2805 HKEY hkeyPrinter, hkeySubkey;
2806 DWORD ret;
2808 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2809 debugstr_w(pValueName), Type, pData, cbData);
2811 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2812 != ERROR_SUCCESS)
2813 return ret;
2815 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2816 != ERROR_SUCCESS) {
2817 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2818 RegCloseKey(hkeyPrinter);
2819 return ret;
2821 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2822 RegCloseKey(hkeySubkey);
2823 RegCloseKey(hkeyPrinter);
2824 return ret;
2827 /******************************************************************************
2828 * SetPrinterDataA (WINSPOOL.@)
2830 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2831 LPBYTE pData, DWORD cbData)
2833 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2834 pData, cbData);
2837 /******************************************************************************
2838 * SetPrinterDataW (WINSPOOL.@)
2840 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2841 LPBYTE pData, DWORD cbData)
2843 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2844 pData, cbData);
2847 /******************************************************************************
2848 * GetPrinterDataExA (WINSPOOL.@)
2850 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2851 LPSTR pValueName, LPDWORD pType,
2852 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2854 HKEY hkeyPrinter, hkeySubkey;
2855 DWORD ret;
2857 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2858 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2859 pcbNeeded);
2861 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2862 != ERROR_SUCCESS)
2863 return ret;
2865 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2866 != ERROR_SUCCESS) {
2867 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2868 RegCloseKey(hkeyPrinter);
2869 return ret;
2871 *pcbNeeded = nSize;
2872 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2873 RegCloseKey(hkeySubkey);
2874 RegCloseKey(hkeyPrinter);
2875 return ret;
2878 /******************************************************************************
2879 * GetPrinterDataExW (WINSPOOL.@)
2881 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2882 LPWSTR pValueName, LPDWORD pType,
2883 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2885 HKEY hkeyPrinter, hkeySubkey;
2886 DWORD ret;
2888 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2889 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2890 pcbNeeded);
2892 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2893 != ERROR_SUCCESS)
2894 return ret;
2896 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2897 != ERROR_SUCCESS) {
2898 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2899 RegCloseKey(hkeyPrinter);
2900 return ret;
2902 *pcbNeeded = nSize;
2903 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2904 RegCloseKey(hkeySubkey);
2905 RegCloseKey(hkeyPrinter);
2906 return ret;
2909 /******************************************************************************
2910 * GetPrinterDataA (WINSPOOL.@)
2912 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
2913 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2915 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
2916 pData, nSize, pcbNeeded);
2919 /******************************************************************************
2920 * GetPrinterDataW (WINSPOOL.@)
2922 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
2923 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2925 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
2926 pData, nSize, pcbNeeded);
2929 /*******************************************************************************
2930 * EnumPrinterDataExW [WINSPOOL.@]
2932 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
2933 LPBYTE pEnumValues, DWORD cbEnumValues,
2934 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2936 HKEY hkPrinter, hkSubKey;
2937 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
2938 cbValueNameLen, cbMaxValueLen, cbValueLen,
2939 cbBufSize, dwType;
2940 LPWSTR lpValueName;
2941 HANDLE hHeap;
2942 PBYTE lpValue;
2943 PPRINTER_ENUM_VALUESW ppev;
2945 TRACE ("%08x %s\n", hPrinter, debugstr_w (pKeyName));
2947 if (pKeyName == NULL || *pKeyName == 0)
2948 return ERROR_INVALID_PARAMETER;
2950 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
2951 if (ret != ERROR_SUCCESS)
2953 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%08x) returned %li\n",
2954 hPrinter, ret);
2955 return ret;
2958 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
2959 if (ret != ERROR_SUCCESS)
2961 r = RegCloseKey (hkPrinter);
2962 if (r != ERROR_SUCCESS)
2963 WARN ("RegCloseKey returned %li\n", r);
2964 TRACE ("RegOpenKeyExW (%08x, %s) returned %li\n", hPrinter,
2965 debugstr_w (pKeyName), ret);
2966 return ret;
2969 ret = RegCloseKey (hkPrinter);
2970 if (ret != ERROR_SUCCESS)
2972 ERR ("RegCloseKey returned %li\n", ret);
2973 r = RegCloseKey (hkSubKey);
2974 if (r != ERROR_SUCCESS)
2975 WARN ("RegCloseKey returned %li\n", r);
2976 return ret;
2979 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
2980 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
2981 if (ret != ERROR_SUCCESS)
2983 r = RegCloseKey (hkSubKey);
2984 if (r != ERROR_SUCCESS)
2985 WARN ("RegCloseKey returned %li\n", r);
2986 TRACE ("RegQueryInfoKeyW (%08x) returned %li\n", hkSubKey, ret);
2987 return ret;
2990 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
2991 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
2993 if (cValues == 0) /* empty key */
2995 r = RegCloseKey (hkSubKey);
2996 if (r != ERROR_SUCCESS)
2997 WARN ("RegCloseKey returned %li\n", r);
2998 *pcbEnumValues = *pnEnumValues = 0;
2999 return ERROR_SUCCESS;
3002 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3004 hHeap = GetProcessHeap ();
3005 if (hHeap == (HANDLE) NULL)
3007 ERR ("GetProcessHeap failed\n");
3008 r = RegCloseKey (hkSubKey);
3009 if (r != ERROR_SUCCESS)
3010 WARN ("RegCloseKey returned %li\n", r);
3011 return ERROR_OUTOFMEMORY;
3014 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3015 if (lpValueName == NULL)
3017 ERR ("Failed to allocate %li bytes from process heap\n",
3018 cbMaxValueNameLen * sizeof (WCHAR));
3019 r = RegCloseKey (hkSubKey);
3020 if (r != ERROR_SUCCESS)
3021 WARN ("RegCloseKey returned %li\n", r);
3022 return ERROR_OUTOFMEMORY;
3025 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3026 if (lpValue == NULL)
3028 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3029 if (HeapFree (hHeap, 0, lpValueName) == 0)
3030 WARN ("HeapFree failed with code %li\n", GetLastError ());
3031 r = RegCloseKey (hkSubKey);
3032 if (r != ERROR_SUCCESS)
3033 WARN ("RegCloseKey returned %li\n", r);
3034 return ERROR_OUTOFMEMORY;
3037 TRACE ("pass 1: calculating buffer required for all names and values\n");
3039 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3041 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3043 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3045 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3046 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3047 NULL, NULL, lpValue, &cbValueLen);
3048 if (ret != ERROR_SUCCESS)
3050 if (HeapFree (hHeap, 0, lpValue) == 0)
3051 WARN ("HeapFree failed with code %li\n", GetLastError ());
3052 if (HeapFree (hHeap, 0, lpValueName) == 0)
3053 WARN ("HeapFree failed with code %li\n", GetLastError ());
3054 r = RegCloseKey (hkSubKey);
3055 if (r != ERROR_SUCCESS)
3056 WARN ("RegCloseKey returned %li\n", r);
3057 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3058 return ret;
3061 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3062 debugstr_w (lpValueName), dwIndex,
3063 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3065 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3066 cbBufSize += cbValueLen;
3069 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3071 *pcbEnumValues = cbBufSize;
3072 *pnEnumValues = cValues;
3074 if (cbEnumValues < cbBufSize) /* buffer too small */
3076 if (HeapFree (hHeap, 0, lpValue) == 0)
3077 WARN ("HeapFree failed with code %li\n", GetLastError ());
3078 if (HeapFree (hHeap, 0, lpValueName) == 0)
3079 WARN ("HeapFree failed with code %li\n", GetLastError ());
3080 r = RegCloseKey (hkSubKey);
3081 if (r != ERROR_SUCCESS)
3082 WARN ("RegCloseKey returned %li\n", r);
3083 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3084 return ERROR_MORE_DATA;
3087 TRACE ("pass 2: copying all names and values to buffer\n");
3089 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3090 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3092 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3094 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3095 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3096 NULL, &dwType, lpValue, &cbValueLen);
3097 if (ret != ERROR_SUCCESS)
3099 if (HeapFree (hHeap, 0, lpValue) == 0)
3100 WARN ("HeapFree failed with code %li\n", GetLastError ());
3101 if (HeapFree (hHeap, 0, lpValueName) == 0)
3102 WARN ("HeapFree failed with code %li\n", GetLastError ());
3103 r = RegCloseKey (hkSubKey);
3104 if (r != ERROR_SUCCESS)
3105 WARN ("RegCloseKey returned %li\n", r);
3106 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3107 return ret;
3110 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3111 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3112 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3113 pEnumValues += cbValueNameLen;
3115 /* return # of *bytes* (including trailing \0), not # of chars */
3116 ppev[dwIndex].cbValueName = cbValueNameLen;
3118 ppev[dwIndex].dwType = dwType;
3120 memcpy (pEnumValues, lpValue, cbValueLen);
3121 ppev[dwIndex].pData = pEnumValues;
3122 pEnumValues += cbValueLen;
3124 ppev[dwIndex].cbData = cbValueLen;
3126 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3127 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3130 if (HeapFree (hHeap, 0, lpValue) == 0)
3132 ret = GetLastError ();
3133 ERR ("HeapFree failed with code %li\n", ret);
3134 if (HeapFree (hHeap, 0, lpValueName) == 0)
3135 WARN ("HeapFree failed with code %li\n", GetLastError ());
3136 r = RegCloseKey (hkSubKey);
3137 if (r != ERROR_SUCCESS)
3138 WARN ("RegCloseKey returned %li\n", r);
3139 return ret;
3142 if (HeapFree (hHeap, 0, lpValueName) == 0)
3144 ret = GetLastError ();
3145 ERR ("HeapFree failed with code %li\n", ret);
3146 r = RegCloseKey (hkSubKey);
3147 if (r != ERROR_SUCCESS)
3148 WARN ("RegCloseKey returned %li\n", r);
3149 return ret;
3152 ret = RegCloseKey (hkSubKey);
3153 if (ret != ERROR_SUCCESS)
3155 ERR ("RegCloseKey returned %li\n", ret);
3156 return ret;
3159 return ERROR_SUCCESS;
3162 /*******************************************************************************
3163 * EnumPrinterDataExA [WINSPOOL.@]
3165 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3166 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3167 * what Windows 2000 SP1 does.
3170 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3171 LPBYTE pEnumValues, DWORD cbEnumValues,
3172 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3174 INT len;
3175 LPWSTR pKeyNameW;
3176 DWORD ret, dwIndex, dwBufSize;
3177 HANDLE hHeap;
3178 LPSTR pBuffer;
3180 TRACE ("%08x %s\n", hPrinter, pKeyName);
3182 if (pKeyName == NULL || *pKeyName == 0)
3183 return ERROR_INVALID_PARAMETER;
3185 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3186 if (len == 0)
3188 ret = GetLastError ();
3189 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3190 return ret;
3193 hHeap = GetProcessHeap ();
3194 if (hHeap == (HANDLE) NULL)
3196 ERR ("GetProcessHeap failed\n");
3197 return ERROR_OUTOFMEMORY;
3200 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3201 if (pKeyNameW == NULL)
3203 ERR ("Failed to allocate %li bytes from process heap\n",
3204 (LONG) len * sizeof (WCHAR));
3205 return ERROR_OUTOFMEMORY;
3208 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3210 ret = GetLastError ();
3211 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3212 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3213 WARN ("HeapFree failed with code %li\n", GetLastError ());
3214 return ret;
3217 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3218 pcbEnumValues, pnEnumValues);
3219 if (ret != ERROR_SUCCESS)
3221 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3222 WARN ("HeapFree failed with code %li\n", GetLastError ());
3223 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3224 return ret;
3227 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3229 ret = GetLastError ();
3230 ERR ("HeapFree failed with code %li\n", ret);
3231 return ret;
3234 if (*pnEnumValues == 0) /* empty key */
3235 return ERROR_SUCCESS;
3237 dwBufSize = 0;
3238 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3240 PPRINTER_ENUM_VALUESW ppev =
3241 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3243 if (dwBufSize < ppev->cbValueName)
3244 dwBufSize = ppev->cbValueName;
3246 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3247 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3248 dwBufSize = ppev->cbData;
3251 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3253 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3254 if (pBuffer == NULL)
3256 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3257 return ERROR_OUTOFMEMORY;
3260 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3262 PPRINTER_ENUM_VALUESW ppev =
3263 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3265 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3266 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3267 NULL);
3268 if (len == 0)
3270 ret = GetLastError ();
3271 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3272 if (HeapFree (hHeap, 0, pBuffer) == 0)
3273 WARN ("HeapFree failed with code %li\n", GetLastError ());
3274 return ret;
3277 memcpy (ppev->pValueName, pBuffer, len);
3279 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3281 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3282 ppev->dwType != REG_MULTI_SZ)
3283 continue;
3285 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3286 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3287 if (len == 0)
3289 ret = GetLastError ();
3290 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3291 if (HeapFree (hHeap, 0, pBuffer) == 0)
3292 WARN ("HeapFree failed with code %li\n", GetLastError ());
3293 return ret;
3296 memcpy (ppev->pData, pBuffer, len);
3298 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3299 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3302 if (HeapFree (hHeap, 0, pBuffer) == 0)
3304 ret = GetLastError ();
3305 ERR ("HeapFree failed with code %li\n", ret);
3306 return ret;
3309 return ERROR_SUCCESS;