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
26 #include "wine/port.h"
34 #ifdef HAVE_CUPS_CUPS_H
35 # include <cups/cups.h>
36 # ifndef SONAME_LIBCUPS
37 # define SONAME_LIBCUPS "libcups.so"
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
43 #include "wine/library.h"
52 #include "wine/windef16.h"
53 #include "wine/unicode.h"
54 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
60 static LPWSTR *printer_array;
61 static int nb_printers;
63 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
64 WORD fwCapability, LPSTR lpszOutput,
66 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
67 LPSTR lpszDevice, LPSTR lpszPort,
68 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
71 static const char Printers[] =
72 "System\\CurrentControlSet\\control\\Print\\Printers\\";
73 static const char Drivers[] =
74 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
76 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
78 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
79 'i','o','n',' ','F','i','l','e',0};
80 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
81 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
82 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
84 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
86 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
87 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
88 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
89 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
90 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
91 static const WCHAR NameW[] = {'N','a','m','e',0};
92 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
93 static const WCHAR PortW[] = {'P','o','r','t',0};
94 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
96 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
98 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
99 'v','e','r','D','a','t','a',0};
100 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
102 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
103 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
104 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
106 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
108 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
109 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
110 DWORD Level, LPBYTE pDriverInfo,
111 DWORD cbBuf, LPDWORD pcbNeeded,
113 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
115 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
116 if passed a NULL string. This returns NULLs to the result.
118 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
122 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
123 return usBufferPtr->Buffer;
125 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
130 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
133 /* If forcing, or no profile string entry for device yet, set the entry
135 * The always change entry if not WINEPS yet is discussable.
138 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
140 !strstr(qbuf,"WINEPS")
142 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
144 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
145 WriteProfileStringA("windows","device",buf);
146 HeapFree(GetProcessHeap(),0,buf);
150 #ifdef HAVE_CUPS_CUPS_H
151 static BOOL CUPS_LoadPrinters(void)
153 typeof(cupsGetDests) *pcupsGetDests = NULL;
154 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
156 BOOL hadprinter = FALSE;
158 PRINTER_INFO_2A pinfo2a;
159 void *cupshandle = NULL;
161 HKEY hkeyPrinter, hkeyPrinters;
163 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
166 TRACE("loaded %s\n", SONAME_LIBCUPS);
169 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
170 if (!p##x) return FALSE;
173 DYNCUPS(cupsGetDests);
176 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
178 ERR("Can't create Printers key\n");
182 nrofdests = pcupsGetDests(&dests);
183 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
184 for (i=0;i<nrofdests;i++) {
185 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
186 sprintf(port,"LPR:%s",dests[i].name);
187 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
188 sprintf(devline,"WINEPS,%s",port);
189 WriteProfileStringA("devices",dests[i].name,devline);
190 HeapFree(GetProcessHeap(),0,devline);
192 TRACE("Printer %d: %s\n", i, dests[i].name);
193 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
194 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
196 TRACE("Printer already exists\n");
197 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
198 RegCloseKey(hkeyPrinter);
200 memset(&pinfo2a,0,sizeof(pinfo2a));
201 pinfo2a.pPrinterName = dests[i].name;
202 pinfo2a.pDatatype = "RAW";
203 pinfo2a.pPrintProcessor = "WinPrint";
204 pinfo2a.pDriverName = "PS Driver";
205 pinfo2a.pComment = "WINEPS Printer using CUPS";
206 pinfo2a.pLocation = "<physical location of printer>";
207 pinfo2a.pPortName = port;
208 pinfo2a.pParameters = "<parameters?>";
209 pinfo2a.pShareName = "<share name?>";
210 pinfo2a.pSepFile = "<sep file?>";
212 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
213 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
214 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
217 HeapFree(GetProcessHeap(),0,port);
220 if (dests[i].is_default)
221 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
223 RegCloseKey(hkeyPrinters);
224 wine_dlclose(cupshandle, NULL, 0);
230 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
231 PRINTER_INFO_2A pinfo2a;
232 char *e,*s,*name,*prettyname,*devname;
233 BOOL ret = FALSE, set_default = FALSE;
234 char *port,*devline,*env_default;
235 HKEY hkeyPrinter, hkeyPrinters;
237 while (isspace(*pent)) pent++;
238 s = strchr(pent,':');
240 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
248 TRACE("name=%s entry=%s\n",name, pent);
250 if(ispunct(*name)) { /* a tc entry, not a real printer */
251 TRACE("skipping tc entry\n");
255 if(strstr(pent,":server")) { /* server only version so skip */
256 TRACE("skipping server entry\n");
260 /* Determine whether this is a postscript printer. */
263 env_default = getenv("PRINTER");
265 /* Get longest name, usually the one at the right for later display. */
266 while((s=strchr(prettyname,'|'))) {
269 while(isspace(*--e)) *e = '\0';
270 TRACE("\t%s\n", debugstr_a(prettyname));
271 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
272 for(prettyname = s+1; isspace(*prettyname); prettyname++)
275 e = prettyname + strlen(prettyname);
276 while(isspace(*--e)) *e = '\0';
277 TRACE("\t%s\n", debugstr_a(prettyname));
278 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
280 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
281 * if it is too long, we use it as comment below. */
282 devname = prettyname;
283 if (strlen(devname)>=CCHDEVICENAME-1)
285 if (strlen(devname)>=CCHDEVICENAME-1) {
290 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
291 sprintf(port,"LPR:%s",name);
293 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
294 sprintf(devline,"WINEPS,%s",port);
295 WriteProfileStringA("devices",devname,devline);
296 HeapFree(GetProcessHeap(),0,devline);
298 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
300 ERR("Can't create Printers key\n");
304 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
305 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
307 TRACE("Printer already exists\n");
308 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
309 RegCloseKey(hkeyPrinter);
311 memset(&pinfo2a,0,sizeof(pinfo2a));
312 pinfo2a.pPrinterName = devname;
313 pinfo2a.pDatatype = "RAW";
314 pinfo2a.pPrintProcessor = "WinPrint";
315 pinfo2a.pDriverName = "PS Driver";
316 pinfo2a.pComment = "WINEPS Printer using LPR";
317 pinfo2a.pLocation = prettyname;
318 pinfo2a.pPortName = port;
319 pinfo2a.pParameters = "<parameters?>";
320 pinfo2a.pShareName = "<share name?>";
321 pinfo2a.pSepFile = "<sep file?>";
323 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
324 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
325 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
328 RegCloseKey(hkeyPrinters);
330 if (isfirst || set_default)
331 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
333 HeapFree(GetProcessHeap(), 0, port);
335 HeapFree(GetProcessHeap(), 0, name);
340 PRINTCAP_LoadPrinters(void) {
341 BOOL hadprinter = FALSE;
345 BOOL had_bash = FALSE;
347 f = fopen("/etc/printcap","r");
351 while(fgets(buf,sizeof(buf),f)) {
354 end=strchr(buf,'\n');
358 while(isspace(*start)) start++;
359 if(*start == '#' || *start == '\0')
362 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
363 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
364 HeapFree(GetProcessHeap(),0,pent);
368 if (end && *--end == '\\') {
375 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
378 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
384 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
385 HeapFree(GetProcessHeap(),0,pent);
391 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
394 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
395 lstrlenW(value) * sizeof(WCHAR));
397 return ERROR_FILE_NOT_FOUND;
400 void WINSPOOL_LoadSystemPrinters(void)
402 HKEY hkey, hkeyPrinters;
405 DWORD needed, num, i;
406 WCHAR PrinterName[256];
409 di3a.cVersion = 0x400;
410 di3a.pName = "PS Driver";
411 di3a.pEnvironment = NULL; /* NULL means auto */
412 di3a.pDriverPath = "wineps16";
413 di3a.pDataFile = "<datafile?>";
414 di3a.pConfigFile = "wineps16";
415 di3a.pHelpFile = "<helpfile?>";
416 di3a.pDependentFiles = "<dependend files?>";
417 di3a.pMonitorName = "<monitor name?>";
418 di3a.pDefaultDataType = "RAW";
420 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
421 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
425 /* This ensures that all printer entries have a valid Name value. If causes
426 problems later if they don't. If one is found to be missed we create one
427 and set it equal to the name of the key */
428 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
429 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
430 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
431 for(i = 0; i < num; i++) {
432 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
433 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
434 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
435 set_reg_szW(hkey, NameW, PrinterName);
442 RegCloseKey(hkeyPrinters);
445 /* We want to avoid calling AddPrinter on printers as much as
446 possible, because on cups printers this will (eventually) lead
447 to a call to cupsGetPPD which takes forever, even with non-cups
448 printers AddPrinter takes a while. So we'll tag all printers that
449 were automatically added last time around, if they still exist
450 we'll leave them be otherwise we'll delete them. */
451 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
453 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
454 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
455 for(i = 0; i < num; i++) {
456 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
457 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
458 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
460 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
468 HeapFree(GetProcessHeap(), 0, pi);
472 #ifdef HAVE_CUPS_CUPS_H
473 done = CUPS_LoadPrinters();
476 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
477 /* Check for [ppd] section in config file before parsing /etc/printcap */
478 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
479 &hkey) == ERROR_SUCCESS) {
481 PRINTCAP_LoadPrinters();
485 /* Now enumerate the list again and delete any printers that a still tagged */
486 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
488 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
489 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
490 for(i = 0; i < num; i++) {
491 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
492 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
493 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
494 DWORD dw, type, size = sizeof(dw);
495 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
496 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
506 HeapFree(GetProcessHeap(), 0, pi);
514 /******************************************************************
515 * WINSPOOL_GetOpenedPrinterEntry
516 * Get the first place empty in the opened printer table
518 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
522 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
524 if (i >= nb_printers)
528 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
529 (nb_printers + 16) * sizeof(*new_array) );
531 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
532 (nb_printers + 16) * sizeof(*new_array) );
534 if (!new_array) return 0;
535 printer_array = new_array;
539 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
541 strcpyW( printer_array[i], name );
542 return (HANDLE)(i + 1);
547 /******************************************************************
548 * WINSPOOL_GetOpenedPrinter
549 * Get the pointer to the opened printer referred by the handle
551 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
553 int idx = (int)printerHandle;
554 if ((idx <= 0) || (idx > nb_printers))
556 SetLastError(ERROR_INVALID_HANDLE);
559 return printer_array[idx - 1];
562 /******************************************************************
563 * WINSPOOL_GetOpenedPrinterRegKey
566 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
568 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
572 if(!name) return ERROR_INVALID_HANDLE;
574 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
578 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
580 ERR("Can't find opened printer %s in registry\n",
582 RegCloseKey(hkeyPrinters);
583 return ERROR_INVALID_PRINTER_NAME; /* ? */
585 RegCloseKey(hkeyPrinters);
586 return ERROR_SUCCESS;
589 /***********************************************************
592 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
595 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
598 Formname = (dmA->dmSize > off_formname);
599 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
600 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
603 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
604 dmA->dmSize - CCHDEVICENAME);
606 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
607 off_formname - CCHDEVICENAME);
608 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
610 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
611 (off_formname + CCHFORMNAME));
614 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
619 /***********************************************************
621 * Creates an ascii copy of supplied devmode on heap
623 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
628 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
630 if(!dmW) return NULL;
631 Formname = (dmW->dmSize > off_formname);
632 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
633 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
634 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
635 CCHDEVICENAME, NULL, NULL);
637 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
638 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
640 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
641 off_formname - CCHDEVICENAME * sizeof(WCHAR));
642 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
643 CCHFORMNAME, NULL, NULL);
644 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
645 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
648 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
653 /***********************************************************
655 * Creates a unicode copy of PRINTER_INFO_2A on heap
657 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
659 LPPRINTER_INFO_2W piW;
660 UNICODE_STRING usBuffer;
662 if(!piA) return NULL;
663 piW = HeapAlloc(heap, 0, sizeof(*piW));
664 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
666 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
667 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
668 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
669 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
670 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
671 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
672 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
673 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
674 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
675 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
676 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
677 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
681 /***********************************************************
682 * FREE_PRINTER_INFO_2W
683 * Free PRINTER_INFO_2W and all strings
685 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
689 HeapFree(heap,0,piW->pServerName);
690 HeapFree(heap,0,piW->pPrinterName);
691 HeapFree(heap,0,piW->pShareName);
692 HeapFree(heap,0,piW->pPortName);
693 HeapFree(heap,0,piW->pDriverName);
694 HeapFree(heap,0,piW->pComment);
695 HeapFree(heap,0,piW->pLocation);
696 HeapFree(heap,0,piW->pDevMode);
697 HeapFree(heap,0,piW->pSepFile);
698 HeapFree(heap,0,piW->pPrintProcessor);
699 HeapFree(heap,0,piW->pDatatype);
700 HeapFree(heap,0,piW->pParameters);
701 HeapFree(heap,0,piW);
705 /******************************************************************
706 * DeviceCapabilities [WINSPOOL.@]
707 * DeviceCapabilitiesA [WINSPOOL.@]
710 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
711 LPSTR pOutput, LPDEVMODEA lpdm)
715 if (!GDI_CallDeviceCapabilities16)
717 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
719 if (!GDI_CallDeviceCapabilities16) return -1;
721 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
723 /* If DC_PAPERSIZE map POINT16s to POINTs */
724 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
725 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
726 POINT *pt = (POINT *)pOutput;
728 memcpy(tmp, pOutput, ret * sizeof(POINT16));
729 for(i = 0; i < ret; i++, pt++)
734 HeapFree( GetProcessHeap(), 0, tmp );
740 /*****************************************************************************
741 * DeviceCapabilitiesW [WINSPOOL.@]
743 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
746 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
747 WORD fwCapability, LPWSTR pOutput,
748 const DEVMODEW *pDevMode)
750 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
751 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
752 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
755 if(pOutput && (fwCapability == DC_BINNAMES ||
756 fwCapability == DC_FILEDEPENDENCIES ||
757 fwCapability == DC_PAPERNAMES)) {
758 /* These need A -> W translation */
761 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
765 switch(fwCapability) {
770 case DC_FILEDEPENDENCIES:
774 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
775 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
777 for(i = 0; i < ret; i++)
778 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
779 pOutput + (i * size), size);
780 HeapFree(GetProcessHeap(), 0, pOutputA);
782 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
783 (LPSTR)pOutput, dmA);
785 HeapFree(GetProcessHeap(),0,pPortA);
786 HeapFree(GetProcessHeap(),0,pDeviceA);
787 HeapFree(GetProcessHeap(),0,dmA);
791 /******************************************************************
792 * DocumentPropertiesA [WINSPOOL.@]
794 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
796 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
797 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
798 LPDEVMODEA pDevModeInput,DWORD fMode )
800 LPSTR lpName = pDeviceName;
803 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
804 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
808 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
810 ERR("no name from hPrinter?\n");
813 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
816 if (!GDI_CallExtDeviceMode16)
818 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
820 if (!GDI_CallExtDeviceMode16) {
821 ERR("No CallExtDeviceMode16?\n");
825 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
826 pDevModeInput, NULL, fMode);
829 HeapFree(GetProcessHeap(),0,lpName);
834 /*****************************************************************************
835 * DocumentPropertiesW (WINSPOOL.@)
837 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
839 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
841 LPDEVMODEW pDevModeOutput,
842 LPDEVMODEW pDevModeInput, DWORD fMode)
845 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
846 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
847 LPDEVMODEA pDevModeOutputA = NULL;
850 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
851 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
854 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
855 if(ret < 0) return ret;
856 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
858 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
859 pDevModeInputA, fMode);
861 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
862 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
864 if(fMode == 0 && ret > 0)
865 ret += (CCHDEVICENAME + CCHFORMNAME);
866 HeapFree(GetProcessHeap(),0,pDevModeInputA);
867 HeapFree(GetProcessHeap(),0,pDeviceNameA);
871 /******************************************************************
872 * OpenPrinterA [WINSPOOL.@]
875 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
876 LPPRINTER_DEFAULTSA pDefault)
878 UNICODE_STRING lpPrinterNameW;
879 UNICODE_STRING usBuffer;
880 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
881 PWSTR pwstrPrinterNameW;
884 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
887 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
888 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
889 DefaultW.DesiredAccess = pDefault->DesiredAccess;
890 pDefaultW = &DefaultW;
892 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
894 RtlFreeUnicodeString(&usBuffer);
895 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
897 RtlFreeUnicodeString(&lpPrinterNameW);
901 /******************************************************************
902 * OpenPrinterW [WINSPOOL.@]
905 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
906 LPPRINTER_DEFAULTSW pDefault)
908 HKEY hkeyPrinters, hkeyPrinter;
910 if (!lpPrinterName) {
911 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
912 SetLastError(ERROR_INVALID_PARAMETER);
916 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
919 /* Check Printer exists */
920 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
922 ERR("Can't create Printers key\n");
923 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
927 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
928 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
930 TRACE("Can't find printer %s in registry\n",
931 debugstr_w(lpPrinterName));
932 RegCloseKey(hkeyPrinters);
933 SetLastError(ERROR_INVALID_PRINTER_NAME);
936 RegCloseKey(hkeyPrinter);
937 RegCloseKey(hkeyPrinters);
939 if(!phPrinter) /* This seems to be what win95 does anyway */
942 /* Get the unique handle of the printer*/
943 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
945 if (pDefault != NULL)
946 FIXME("Not handling pDefault\n");
951 /******************************************************************
952 * AddMonitorA [WINSPOOL.@]
955 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
957 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
958 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
962 /******************************************************************
963 * DeletePrinterDriverA [WINSPOOL.@]
967 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
969 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
970 debugstr_a(pDriverName));
971 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
976 /******************************************************************
977 * DeleteMonitorA [WINSPOOL.@]
981 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
983 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
984 debugstr_a(pMonitorName));
985 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
990 /******************************************************************
991 * DeletePortA [WINSPOOL.@]
995 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
997 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
998 debugstr_a(pPortName));
999 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1003 /******************************************************************************
1004 * SetPrinterW [WINSPOOL.@]
1014 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1018 /******************************************************************************
1019 * WritePrinter [WINSPOOL.@]
1026 LPDWORD pcWritten) {
1029 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1033 /*****************************************************************************
1034 * AddFormA [WINSPOOL.@]
1036 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1038 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1042 /*****************************************************************************
1043 * AddFormW [WINSPOOL.@]
1045 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1047 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1051 /*****************************************************************************
1052 * AddJobA [WINSPOOL.@]
1054 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
1055 DWORD cbBuf, LPDWORD pcbNeeded)
1057 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1062 /*****************************************************************************
1063 * AddJobW [WINSPOOL.@]
1065 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
1068 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1073 /*****************************************************************************
1074 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1076 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR environ,
1077 DWORD level, LPBYTE Info,
1078 DWORD cbBuf, LPDWORD needed)
1080 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", server, environ, level, Info,
1085 /*****************************************************************************
1086 * WINSPOOL_OpenDriverReg [internal]
1088 * opens the registry for the printer drivers depending on the given input
1089 * variable pEnvironment
1092 * the opened hkey on success
1095 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1097 LPSTR lpKey, p = NULL;
1100 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1103 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1107 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1109 if(!GetVersionExA( &ver))
1112 switch (ver.dwPlatformId) {
1113 case VER_PLATFORM_WIN32s:
1114 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1117 case VER_PLATFORM_WIN32_NT:
1118 p = "Windows NT x86";
1124 TRACE("set environment to %s\n", p);
1127 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1128 strlen(p) + strlen(Drivers));
1129 sprintf( lpKey, Drivers, p);
1131 TRACE("%s\n", lpKey);
1133 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1137 if(pEnvironment && unicode)
1138 HeapFree( GetProcessHeap(), 0, p);
1139 HeapFree( GetProcessHeap(), 0, lpKey);
1144 /*****************************************************************************
1145 * AddPrinterW [WINSPOOL.@]
1147 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1149 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1153 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1156 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1159 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1160 SetLastError(ERROR_INVALID_PARAMETER);
1164 ERR("Level = %ld, unsupported!\n", Level);
1165 SetLastError(ERROR_INVALID_LEVEL);
1168 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1169 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1170 debugstr_w(pi->pPrinterName)
1172 SetLastError(ERROR_INVALID_LEVEL);
1176 SetLastError(ERROR_INVALID_PARAMETER);
1179 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1181 ERR("Can't create Printers key\n");
1184 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1185 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1186 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1187 RegCloseKey(hkeyPrinter);
1188 RegCloseKey(hkeyPrinters);
1191 RegCloseKey(hkeyPrinter);
1193 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1195 ERR("Can't create Drivers key\n");
1196 RegCloseKey(hkeyPrinters);
1199 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1201 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1202 RegCloseKey(hkeyPrinters);
1203 RegCloseKey(hkeyDrivers);
1204 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1207 RegCloseKey(hkeyDriver);
1208 RegCloseKey(hkeyDrivers);
1210 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1211 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1212 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1213 RegCloseKey(hkeyPrinters);
1217 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1219 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1220 SetLastError(ERROR_INVALID_PRINTER_NAME);
1221 RegCloseKey(hkeyPrinters);
1224 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1225 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1226 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1228 /* See if we can load the driver. We may need the devmode structure anyway
1231 * Note that DocumentPropertiesW will briefly try to open the printer we
1232 * just create to find a DEVMODEA struct (it will use the WINEPS default
1233 * one in case it is not there, so we are ok).
1235 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1238 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1239 size = sizeof(DEVMODEW);
1245 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1246 ZeroMemory(dmW,size);
1248 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1250 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1251 HeapFree(GetProcessHeap(),0,dmW);
1256 /* set devmode to printer name */
1257 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1261 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1262 and we support these drivers. NT writes DEVMODEW so somehow
1263 we'll need to distinguish between these when we support NT
1267 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1268 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1269 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1270 HeapFree(GetProcessHeap(), 0, dmA);
1272 HeapFree(GetProcessHeap(), 0, dmW);
1274 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1275 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1276 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1277 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1279 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1280 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1281 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1282 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1283 (LPBYTE)&pi->Priority, sizeof(DWORD));
1284 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1285 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1286 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1287 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1288 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1289 (LPBYTE)&pi->Status, sizeof(DWORD));
1290 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1291 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1293 RegCloseKey(hkeyPrinter);
1294 RegCloseKey(hkeyPrinters);
1295 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1296 ERR("OpenPrinter failing\n");
1302 /*****************************************************************************
1303 * AddPrinterA [WINSPOOL.@]
1305 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1307 UNICODE_STRING pNameW;
1309 PRINTER_INFO_2W *piW;
1310 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1313 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1315 ERR("Level = %ld, unsupported!\n", Level);
1316 SetLastError(ERROR_INVALID_LEVEL);
1319 pwstrNameW = asciitounicode(&pNameW,pName);
1320 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1322 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1324 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1325 RtlFreeUnicodeString(&pNameW);
1330 /*****************************************************************************
1331 * ClosePrinter [WINSPOOL.@]
1333 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1335 int i = (int)hPrinter;
1337 TRACE("Handle %p\n", hPrinter);
1339 if ((i <= 0) || (i > nb_printers)) return FALSE;
1340 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1341 printer_array[i - 1] = NULL;
1345 /*****************************************************************************
1346 * DeleteFormA [WINSPOOL.@]
1348 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1350 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1354 /*****************************************************************************
1355 * DeleteFormW [WINSPOOL.@]
1357 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1359 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1363 /*****************************************************************************
1364 * WINSPOOL_SHRegDeleteKey
1366 * Recursively delete subkeys.
1367 * Cut & paste from shlwapi.
1370 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1372 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1373 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1376 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1379 /* Find how many subkeys there are */
1380 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1381 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1385 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1386 /* Name too big: alloc a buffer for it */
1387 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1390 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1393 /* Recursively delete all the subkeys */
1394 for(i = 0; i < dwKeyCount && !dwRet; i++)
1396 dwSize = dwMaxSubkeyLen;
1397 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1399 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1402 if (lpszName != szNameBuf)
1403 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1407 RegCloseKey(hSubKey);
1409 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1414 /*****************************************************************************
1415 * DeletePrinter [WINSPOOL.@]
1417 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1419 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1422 if(!lpNameW) return FALSE;
1423 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1424 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1425 RegCloseKey(hkeyPrinters);
1427 WriteProfileStringW(devicesW, lpNameW, NULL);
1431 /*****************************************************************************
1432 * SetPrinterA [WINSPOOL.@]
1434 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1437 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1441 /*****************************************************************************
1442 * SetJobA [WINSPOOL.@]
1444 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1445 LPBYTE pJob, DWORD Command)
1447 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1452 /*****************************************************************************
1453 * SetJobW [WINSPOOL.@]
1455 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1456 LPBYTE pJob, DWORD Command)
1458 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1463 /*****************************************************************************
1464 * EndDocPrinter [WINSPOOL.@]
1466 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1468 FIXME("(hPrinter=%p): stub\n", hPrinter);
1472 /*****************************************************************************
1473 * EndPagePrinter [WINSPOOL.@]
1475 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1477 FIXME("(hPrinter=%p): stub\n", hPrinter);
1481 /*****************************************************************************
1482 * StartDocPrinterA [WINSPOOL.@]
1484 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1486 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1490 /*****************************************************************************
1491 * StartDocPrinterW [WINSPOOL.@]
1493 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1495 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1499 /*****************************************************************************
1500 * StartPagePrinter [WINSPOOL.@]
1502 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1504 FIXME("(hPrinter=%p): stub\n", hPrinter);
1508 /*****************************************************************************
1509 * GetFormA [WINSPOOL.@]
1511 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1512 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1514 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1515 Level,pForm,cbBuf,pcbNeeded);
1519 /*****************************************************************************
1520 * GetFormW [WINSPOOL.@]
1522 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1523 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1525 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1526 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1530 /*****************************************************************************
1531 * SetFormA [WINSPOOL.@]
1533 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1536 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1540 /*****************************************************************************
1541 * SetFormW [WINSPOOL.@]
1543 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1546 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1550 /*****************************************************************************
1551 * ReadPrinter [WINSPOOL.@]
1553 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1554 LPDWORD pNoBytesRead)
1556 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1560 /*****************************************************************************
1561 * ResetPrinterA [WINSPOOL.@]
1563 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1565 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1569 /*****************************************************************************
1570 * ResetPrinterW [WINSPOOL.@]
1572 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1574 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1578 /*****************************************************************************
1579 * WINSPOOL_GetDWORDFromReg
1581 * Return DWORD associated with ValueName from hkey.
1583 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1585 DWORD sz = sizeof(DWORD), type, value = 0;
1588 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1590 if(ret != ERROR_SUCCESS) {
1591 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1594 if(type != REG_DWORD) {
1595 ERR("Got type %ld\n", type);
1601 /*****************************************************************************
1602 * WINSPOOL_GetStringFromReg
1604 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1605 * String is stored either as unicode or ascii.
1606 * Bit of a hack here to get the ValueName if we want ascii.
1608 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1609 DWORD buflen, DWORD *needed,
1612 DWORD sz = buflen, type;
1616 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1618 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1619 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1620 HeapFree(GetProcessHeap(),0,ValueNameA);
1622 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1623 WARN("Got ret = %ld\n", ret);
1631 /*****************************************************************************
1632 * WINSPOOL_GetDefaultDevMode
1634 * Get a default DevMode values for wineps.
1638 static void WINSPOOL_GetDefaultDevMode(
1640 DWORD buflen, DWORD *needed,
1645 /* fill default DEVMODE - should be read from ppd... */
1646 ZeroMemory( &dm, sizeof(dm) );
1647 strcpy(dm.dmDeviceName,"wineps");
1648 dm.dmSpecVersion = DM_SPECVERSION;
1649 dm.dmDriverVersion = 1;
1650 dm.dmSize = sizeof(DEVMODEA);
1651 dm.dmDriverExtra = 0;
1653 DM_ORIENTATION | DM_PAPERSIZE |
1654 DM_PAPERLENGTH | DM_PAPERWIDTH |
1657 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1658 DM_YRESOLUTION | DM_TTOPTION;
1660 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1661 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1662 dm.u1.s1.dmPaperLength = 2970;
1663 dm.u1.s1.dmPaperWidth = 2100;
1667 dm.dmDefaultSource = DMBIN_AUTO;
1668 dm.dmPrintQuality = DMRES_MEDIUM;
1671 dm.dmYResolution = 300; /* 300dpi */
1672 dm.dmTTOption = DMTT_BITMAP;
1675 /* dm.dmLogPixels */
1676 /* dm.dmBitsPerPel */
1677 /* dm.dmPelsWidth */
1678 /* dm.dmPelsHeight */
1679 /* dm.dmDisplayFlags */
1680 /* dm.dmDisplayFrequency */
1681 /* dm.dmICMMethod */
1682 /* dm.dmICMIntent */
1683 /* dm.dmMediaType */
1684 /* dm.dmDitherType */
1685 /* dm.dmReserved1 */
1686 /* dm.dmReserved2 */
1687 /* dm.dmPanningWidth */
1688 /* dm.dmPanningHeight */
1691 if(buflen >= sizeof(DEVMODEW)) {
1692 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1693 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1694 HeapFree(GetProcessHeap(),0,pdmW);
1696 *needed = sizeof(DEVMODEW);
1700 if(buflen >= sizeof(DEVMODEA)) {
1701 memcpy(ptr, &dm, sizeof(DEVMODEA));
1703 *needed = sizeof(DEVMODEA);
1707 /*****************************************************************************
1708 * WINSPOOL_GetDevModeFromReg
1710 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1711 * DevMode is stored either as unicode or ascii.
1713 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1715 DWORD buflen, DWORD *needed,
1718 DWORD sz = buflen, type;
1721 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1722 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1723 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1724 if (sz < sizeof(DEVMODEA))
1726 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1729 /* ensures that dmSize is not erratically bogus if registry is invalid */
1730 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1731 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1733 sz += (CCHDEVICENAME + CCHFORMNAME);
1735 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1736 memcpy(ptr, dmW, sz);
1737 HeapFree(GetProcessHeap(),0,dmW);
1744 /*********************************************************************
1745 * WINSPOOL_GetPrinter_2
1747 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1748 * The strings are either stored as unicode or ascii.
1750 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1751 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1754 DWORD size, left = cbBuf;
1755 BOOL space = (cbBuf > 0);
1760 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1762 if(space && size <= left) {
1763 pi2->pPrinterName = (LPWSTR)ptr;
1770 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1772 if(space && size <= left) {
1773 pi2->pShareName = (LPWSTR)ptr;
1780 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1782 if(space && size <= left) {
1783 pi2->pPortName = (LPWSTR)ptr;
1790 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1792 if(space && size <= left) {
1793 pi2->pDriverName = (LPWSTR)ptr;
1800 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1802 if(space && size <= left) {
1803 pi2->pComment = (LPWSTR)ptr;
1810 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1812 if(space && size <= left) {
1813 pi2->pLocation = (LPWSTR)ptr;
1820 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1822 if(space && size <= left) {
1823 pi2->pDevMode = (LPDEVMODEW)ptr;
1832 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1833 if(space && size <= left) {
1834 pi2->pDevMode = (LPDEVMODEW)ptr;
1841 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1843 if(space && size <= left) {
1844 pi2->pSepFile = (LPWSTR)ptr;
1851 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1853 if(space && size <= left) {
1854 pi2->pPrintProcessor = (LPWSTR)ptr;
1861 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1863 if(space && size <= left) {
1864 pi2->pDatatype = (LPWSTR)ptr;
1871 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1873 if(space && size <= left) {
1874 pi2->pParameters = (LPWSTR)ptr;
1882 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1883 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1884 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1885 "Default Priority");
1886 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1887 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1890 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1891 memset(pi2, 0, sizeof(*pi2));
1896 /*********************************************************************
1897 * WINSPOOL_GetPrinter_4
1899 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1901 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1902 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1905 DWORD size, left = cbBuf;
1906 BOOL space = (cbBuf > 0);
1911 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1913 if(space && size <= left) {
1914 pi4->pPrinterName = (LPWSTR)ptr;
1922 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1925 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1926 memset(pi4, 0, sizeof(*pi4));
1931 /*********************************************************************
1932 * WINSPOOL_GetPrinter_5
1934 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1936 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1937 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1940 DWORD size, left = cbBuf;
1941 BOOL space = (cbBuf > 0);
1946 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1948 if(space && size <= left) {
1949 pi5->pPrinterName = (LPWSTR)ptr;
1956 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1958 if(space && size <= left) {
1959 pi5->pPortName = (LPWSTR)ptr;
1967 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1968 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1970 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1974 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1975 memset(pi5, 0, sizeof(*pi5));
1980 /*****************************************************************************
1981 * WINSPOOL_GetPrinter
1983 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1984 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1985 * just a collection of pointers to strings.
1987 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1988 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1991 DWORD size, needed = 0;
1993 HKEY hkeyPrinter, hkeyPrinters;
1996 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1998 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2000 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2002 ERR("Can't create Printers key\n");
2005 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2007 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2008 RegCloseKey(hkeyPrinters);
2009 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2016 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2018 size = sizeof(PRINTER_INFO_2W);
2020 ptr = pPrinter + size;
2022 memset(pPrinter, 0, size);
2027 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2035 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2037 size = sizeof(PRINTER_INFO_4W);
2039 ptr = pPrinter + size;
2041 memset(pPrinter, 0, size);
2046 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2055 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2057 size = sizeof(PRINTER_INFO_5W);
2059 ptr = pPrinter + size;
2061 memset(pPrinter, 0, size);
2067 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2074 FIXME("Unimplemented level %ld\n", Level);
2075 SetLastError(ERROR_INVALID_LEVEL);
2076 RegCloseKey(hkeyPrinters);
2077 RegCloseKey(hkeyPrinter);
2081 RegCloseKey(hkeyPrinter);
2082 RegCloseKey(hkeyPrinters);
2084 TRACE("returning %d needed = %ld\n", ret, needed);
2085 if(pcbNeeded) *pcbNeeded = needed;
2087 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2091 /*****************************************************************************
2092 * GetPrinterW [WINSPOOL.@]
2094 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2095 DWORD cbBuf, LPDWORD pcbNeeded)
2097 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2101 /*****************************************************************************
2102 * GetPrinterA [WINSPOOL.@]
2104 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2105 DWORD cbBuf, LPDWORD pcbNeeded)
2107 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2111 /*****************************************************************************
2112 * WINSPOOL_EnumPrinters
2114 * Implementation of EnumPrintersA|W
2116 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2117 DWORD dwLevel, LPBYTE lpbPrinters,
2118 DWORD cbBuf, LPDWORD lpdwNeeded,
2119 LPDWORD lpdwReturned, BOOL unicode)
2122 HKEY hkeyPrinters, hkeyPrinter;
2123 WCHAR PrinterName[255];
2124 DWORD needed = 0, number = 0;
2125 DWORD used, i, left;
2129 memset(lpbPrinters, 0, cbBuf);
2135 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2136 if(dwType == PRINTER_ENUM_DEFAULT)
2139 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2140 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
2141 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
2142 if(!dwType) return TRUE;
2145 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2146 FIXME("dwType = %08lx\n", dwType);
2147 SetLastError(ERROR_INVALID_FLAGS);
2151 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2153 ERR("Can't create Printers key\n");
2157 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2158 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2159 RegCloseKey(hkeyPrinters);
2160 ERR("Can't query Printers key\n");
2163 TRACE("Found %ld printers\n", number);
2167 RegCloseKey(hkeyPrinters);
2169 *lpdwReturned = number;
2173 used = number * sizeof(PRINTER_INFO_2W);
2176 used = number * sizeof(PRINTER_INFO_4W);
2179 used = number * sizeof(PRINTER_INFO_5W);
2183 SetLastError(ERROR_INVALID_LEVEL);
2184 RegCloseKey(hkeyPrinters);
2187 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2189 for(i = 0; i < number; i++) {
2190 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2192 ERR("Can't enum key number %ld\n", i);
2193 RegCloseKey(hkeyPrinters);
2196 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2197 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2199 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2200 RegCloseKey(hkeyPrinters);
2205 buf = lpbPrinters + used;
2206 left = cbBuf - used;
2214 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2215 left, &needed, unicode);
2217 if(pi) pi += sizeof(PRINTER_INFO_2W);
2220 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2221 left, &needed, unicode);
2223 if(pi) pi += sizeof(PRINTER_INFO_4W);
2226 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2227 left, &needed, unicode);
2229 if(pi) pi += sizeof(PRINTER_INFO_5W);
2232 ERR("Shouldn't be here!\n");
2233 RegCloseKey(hkeyPrinter);
2234 RegCloseKey(hkeyPrinters);
2237 RegCloseKey(hkeyPrinter);
2239 RegCloseKey(hkeyPrinters);
2246 memset(lpbPrinters, 0, cbBuf);
2247 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2251 *lpdwReturned = number;
2252 SetLastError(ERROR_SUCCESS);
2257 /******************************************************************
2258 * EnumPrintersW [WINSPOOL.@]
2260 * Enumerates the available printers, print servers and print
2261 * providers, depending on the specified flags, name and level.
2265 * If level is set to 1:
2266 * Not implemented yet!
2267 * Returns TRUE with an empty list.
2269 * If level is set to 2:
2270 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2271 * Returns an array of PRINTER_INFO_2 data structures in the
2272 * lpbPrinters buffer. Note that according to MSDN also an
2273 * OpenPrinter should be performed on every remote printer.
2275 * If level is set to 4 (officially WinNT only):
2276 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2277 * Fast: Only the registry is queried to retrieve printer names,
2278 * no connection to the driver is made.
2279 * Returns an array of PRINTER_INFO_4 data structures in the
2280 * lpbPrinters buffer.
2282 * If level is set to 5 (officially WinNT4/Win9x only):
2283 * Fast: Only the registry is queried to retrieve printer names,
2284 * no connection to the driver is made.
2285 * Returns an array of PRINTER_INFO_5 data structures in the
2286 * lpbPrinters buffer.
2288 * If level set to 3 or 6+:
2289 * returns zero (failure!)
2291 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2295 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2296 * - Only levels 2, 4 and 5 are implemented at the moment.
2297 * - 16-bit printer drivers are not enumerated.
2298 * - Returned amount of bytes used/needed does not match the real Windoze
2299 * implementation (as in this implementation, all strings are part
2300 * of the buffer, whereas Win32 keeps them somewhere else)
2301 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2304 * - In a regular Wine installation, no registry settings for printers
2305 * exist, which makes this function return an empty list.
2307 BOOL WINAPI EnumPrintersW(
2308 DWORD dwType, /* [in] Types of print objects to enumerate */
2309 LPWSTR lpszName, /* [in] name of objects to enumerate */
2310 DWORD dwLevel, /* [in] type of printer info structure */
2311 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2312 DWORD cbBuf, /* [in] max size of buffer in bytes */
2313 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2314 LPDWORD lpdwReturned /* [out] number of entries returned */
2317 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2318 lpdwNeeded, lpdwReturned, TRUE);
2321 /******************************************************************
2322 * EnumPrintersA [WINSPOOL.@]
2325 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2326 DWORD dwLevel, LPBYTE lpbPrinters,
2327 DWORD cbBuf, LPDWORD lpdwNeeded,
2328 LPDWORD lpdwReturned)
2331 UNICODE_STRING lpszNameW;
2334 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2335 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2336 lpdwNeeded, lpdwReturned, FALSE);
2337 RtlFreeUnicodeString(&lpszNameW);
2341 /*****************************************************************************
2342 * WINSPOOL_GetDriverInfoFromReg [internal]
2344 * Enters the information from the registry into the DRIVER_INFO struct
2347 * zero if the printer driver does not exist in the registry
2348 * (only if Level > 1) otherwise nonzero
2350 static BOOL WINSPOOL_GetDriverInfoFromReg(
2353 LPWSTR pEnvironment,
2355 LPBYTE ptr, /* DRIVER_INFO */
2356 LPBYTE pDriverStrings, /* strings buffer */
2357 DWORD cbBuf, /* size of string buffer */
2358 LPDWORD pcbNeeded, /* space needed for str. */
2359 BOOL unicode) /* type of strings */
2360 { DWORD dw, size, tmp, type;
2362 LPBYTE strPtr = pDriverStrings;
2364 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2365 debugstr_w(DriverName), debugstr_w(pEnvironment),
2366 Level, ptr, pDriverStrings, cbBuf, unicode);
2369 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2370 if (*pcbNeeded <= cbBuf)
2371 strcpyW((LPWSTR)strPtr, DriverName);
2373 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2375 if(*pcbNeeded <= cbBuf)
2376 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2381 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2385 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2386 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2389 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2390 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2391 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2396 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2398 WARN("Can't get Version\n");
2400 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2403 pEnvironment = (LPWSTR)DefaultEnvironmentW;
2405 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2407 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2410 if(*pcbNeeded <= cbBuf) {
2412 strcpyW((LPWSTR)strPtr, pEnvironment);
2414 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2417 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2418 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2421 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2424 if(*pcbNeeded <= cbBuf)
2425 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2428 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2429 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2432 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2435 if(*pcbNeeded <= cbBuf)
2436 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2439 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2440 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2443 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2444 0, &size, unicode)) {
2446 if(*pcbNeeded <= cbBuf)
2447 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2448 size, &tmp, unicode);
2450 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2451 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2455 RegCloseKey(hkeyDriver);
2456 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2460 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2463 if(*pcbNeeded <= cbBuf)
2464 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2465 size, &tmp, unicode);
2467 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2468 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2471 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2474 if(*pcbNeeded <= cbBuf)
2475 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2476 size, &tmp, unicode);
2478 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2479 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2482 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2485 if(*pcbNeeded <= cbBuf)
2486 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2487 size, &tmp, unicode);
2489 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2490 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2493 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2496 if(*pcbNeeded <= cbBuf)
2497 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2498 size, &tmp, unicode);
2500 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2501 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2504 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2505 RegCloseKey(hkeyDriver);
2509 /*****************************************************************************
2510 * WINSPOOL_GetPrinterDriver
2512 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2513 DWORD Level, LPBYTE pDriverInfo,
2514 DWORD cbBuf, LPDWORD pcbNeeded,
2518 WCHAR DriverName[100];
2519 DWORD ret, type, size, needed = 0;
2521 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2523 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2524 Level,pDriverInfo,cbBuf, pcbNeeded);
2526 ZeroMemory(pDriverInfo, cbBuf);
2528 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2530 if(Level < 1 || Level > 3) {
2531 SetLastError(ERROR_INVALID_LEVEL);
2534 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2536 ERR("Can't create Printers key\n");
2539 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2541 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2542 RegCloseKey(hkeyPrinters);
2543 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2546 size = sizeof(DriverName);
2548 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2549 (LPBYTE)DriverName, &size);
2550 RegCloseKey(hkeyPrinter);
2551 RegCloseKey(hkeyPrinters);
2552 if(ret != ERROR_SUCCESS) {
2553 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2557 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2559 ERR("Can't create Drivers key\n");
2565 size = sizeof(DRIVER_INFO_1W);
2568 size = sizeof(DRIVER_INFO_2W);
2571 size = sizeof(DRIVER_INFO_3W);
2574 ERR("Invalid level\n");
2579 ptr = pDriverInfo + size;
2581 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2582 pEnvironment, Level, pDriverInfo,
2583 (cbBuf < size) ? NULL : ptr,
2584 (cbBuf < size) ? 0 : cbBuf - size,
2585 &needed, unicode)) {
2586 RegCloseKey(hkeyDrivers);
2590 RegCloseKey(hkeyDrivers);
2592 if(pcbNeeded) *pcbNeeded = size + needed;
2593 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2594 if(cbBuf >= needed) return TRUE;
2595 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2599 /*****************************************************************************
2600 * GetPrinterDriverA [WINSPOOL.@]
2602 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2603 DWORD Level, LPBYTE pDriverInfo,
2604 DWORD cbBuf, LPDWORD pcbNeeded)
2607 UNICODE_STRING pEnvW;
2610 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2611 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2612 cbBuf, pcbNeeded, FALSE);
2613 RtlFreeUnicodeString(&pEnvW);
2616 /*****************************************************************************
2617 * GetPrinterDriverW [WINSPOOL.@]
2619 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2620 DWORD Level, LPBYTE pDriverInfo,
2621 DWORD cbBuf, LPDWORD pcbNeeded)
2623 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2624 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2627 /*****************************************************************************
2628 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2630 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2631 DWORD Level, LPBYTE pDriverDirectory,
2632 DWORD cbBuf, LPDWORD pcbNeeded)
2636 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2637 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2639 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2640 SetLastError(ERROR_INVALID_PARAMETER);
2643 if(pEnvironment != NULL) {
2644 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2645 SetLastError(ERROR_INVALID_ENVIRONMENT);
2648 if(Level != 1) /* win95 ignores this so we just carry on */
2649 WARN("Level = %ld - assuming 1\n", Level);
2651 /* FIXME should read from registry */
2652 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2653 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2657 needed*=sizeof(WCHAR);
2660 *pcbNeeded = needed;
2661 TRACE("required <%08lx>\n", *pcbNeeded);
2662 if(needed > cbBuf) {
2663 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2670 /*****************************************************************************
2671 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2673 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2674 DWORD Level, LPBYTE pDriverDirectory,
2675 DWORD cbBuf, LPDWORD pcbNeeded)
2677 UNICODE_STRING nameW, environmentW;
2680 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2681 WCHAR *driverDirectoryW = NULL;
2683 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2685 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2686 else nameW.Buffer = NULL;
2687 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2688 else environmentW.Buffer = NULL;
2690 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2691 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2694 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2695 pDriverDirectory, cbBuf, NULL, NULL);
2697 *pcbNeeded = needed;
2698 ret = (needed <= cbBuf) ? TRUE : FALSE;
2700 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2702 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2704 if(driverDirectoryW)
2705 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2706 RtlFreeUnicodeString(&environmentW);
2707 RtlFreeUnicodeString(&nameW);
2712 /*****************************************************************************
2713 * AddPrinterDriverA [WINSPOOL.@]
2715 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2718 HKEY hkeyDrivers, hkeyName;
2720 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2722 if(level != 2 && level != 3) {
2723 SetLastError(ERROR_INVALID_LEVEL);
2727 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2728 SetLastError(ERROR_INVALID_PARAMETER);
2732 WARN("pDriverInfo == NULL\n");
2733 SetLastError(ERROR_INVALID_PARAMETER);
2738 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2740 memset(&di3, 0, sizeof(di3));
2741 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2744 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2746 SetLastError(ERROR_INVALID_PARAMETER);
2749 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2750 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2751 if(!di3.pHelpFile) di3.pHelpFile = "";
2752 if(!di3.pMonitorName) di3.pMonitorName = "";
2754 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2757 ERR("Can't create Drivers key\n");
2761 if(level == 2) { /* apparently can't overwrite with level2 */
2762 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2763 RegCloseKey(hkeyName);
2764 RegCloseKey(hkeyDrivers);
2765 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2766 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2770 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2771 RegCloseKey(hkeyDrivers);
2772 ERR("Can't create Name key\n");
2775 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2777 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2778 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2779 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2781 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2782 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2783 di3.pDependentFiles, 0);
2784 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2785 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2786 RegCloseKey(hkeyName);
2787 RegCloseKey(hkeyDrivers);
2791 /*****************************************************************************
2792 * AddPrinterDriverW [WINSPOOL.@]
2794 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2797 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2803 /*****************************************************************************
2804 * PrinterProperties [WINSPOOL.@]
2806 * Displays a dialog to set the properties of the printer.
2809 * nonzero on success or zero on failure
2812 * implemented as stub only
2814 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2815 HANDLE hPrinter /* [in] handle to printer object */
2817 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2818 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2822 /*****************************************************************************
2823 * EnumJobsA [WINSPOOL.@]
2826 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2827 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2830 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2831 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2833 if(pcbNeeded) *pcbNeeded = 0;
2834 if(pcReturned) *pcReturned = 0;
2839 /*****************************************************************************
2840 * EnumJobsW [WINSPOOL.@]
2843 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2844 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2847 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2848 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2850 if(pcbNeeded) *pcbNeeded = 0;
2851 if(pcReturned) *pcReturned = 0;
2855 /*****************************************************************************
2856 * WINSPOOL_EnumPrinterDrivers [internal]
2858 * Delivers information about all printer drivers installed on the
2859 * localhost or a given server
2862 * nonzero on success or zero on failure. If the buffer for the returned
2863 * information is too small the function will return an error
2866 * - only implemented for localhost, foreign hosts will return an error
2868 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2869 DWORD Level, LPBYTE pDriverInfo,
2870 DWORD cbBuf, LPDWORD pcbNeeded,
2871 LPDWORD pcReturned, BOOL unicode)
2874 DWORD i, needed, number = 0, size = 0;
2875 WCHAR DriverNameW[255];
2878 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2879 debugstr_w(pName), debugstr_w(pEnvironment),
2880 Level, pDriverInfo, cbBuf, unicode);
2882 /* check for local drivers */
2884 ERR("remote drivers unsupported! Current remote host is %s\n",
2889 /* check input parameter */
2890 if((Level < 1) || (Level > 3)) {
2891 ERR("unsupported level %ld \n", Level);
2895 /* initialize return values */
2897 memset( pDriverInfo, 0, cbBuf);
2901 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2903 ERR("Can't open Drivers key\n");
2907 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2908 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2909 RegCloseKey(hkeyDrivers);
2910 ERR("Can't query Drivers key\n");
2913 TRACE("Found %ld Drivers\n", number);
2915 /* get size of single struct
2916 * unicode and ascii structure have the same size
2920 size = sizeof(DRIVER_INFO_1A);
2923 size = sizeof(DRIVER_INFO_2A);
2926 size = sizeof(DRIVER_INFO_3A);
2930 /* calculate required buffer size */
2931 *pcbNeeded = size * number;
2933 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2935 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2936 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2938 ERR("Can't enum key number %ld\n", i);
2939 RegCloseKey(hkeyDrivers);
2942 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2943 pEnvironment, Level, ptr,
2944 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2945 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2946 &needed, unicode)) {
2947 RegCloseKey(hkeyDrivers);
2950 (*pcbNeeded) += needed;
2953 RegCloseKey(hkeyDrivers);
2955 if(cbBuf < *pcbNeeded){
2956 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2963 /*****************************************************************************
2964 * EnumPrinterDriversW [WINSPOOL.@]
2966 * see function EnumPrinterDrivers for RETURNS, BUGS
2968 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2969 LPBYTE pDriverInfo, DWORD cbBuf,
2970 LPDWORD pcbNeeded, LPDWORD pcReturned)
2972 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2973 cbBuf, pcbNeeded, pcReturned, TRUE);
2976 /*****************************************************************************
2977 * EnumPrinterDriversA [WINSPOOL.@]
2979 * see function EnumPrinterDrivers for RETURNS, BUGS
2981 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2982 LPBYTE pDriverInfo, DWORD cbBuf,
2983 LPDWORD pcbNeeded, LPDWORD pcReturned)
2985 UNICODE_STRING pNameW, pEnvironmentW;
2986 PWSTR pwstrNameW, pwstrEnvironmentW;
2988 pwstrNameW = asciitounicode(&pNameW, pName);
2989 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
2991 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
2992 Level, pDriverInfo, cbBuf, pcbNeeded,
2994 RtlFreeUnicodeString(&pNameW);
2995 RtlFreeUnicodeString(&pEnvironmentW);
3000 static CHAR PortMonitor[] = "Wine Port Monitor";
3001 static CHAR PortDescription[] = "Wine Port";
3003 /******************************************************************************
3004 * EnumPortsA (WINSPOOL.@)
3006 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3007 LPDWORD bufneeded,LPDWORD bufreturned)
3010 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3011 const LPCSTR szSerialPortKey = "Software\\Wine\\Wine\\Config\\serialports";
3012 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3013 HKEY hkey_serial, hkey_printer;
3015 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3016 name,level,buffer,bufsize,bufneeded,bufreturned);
3021 info_size = sizeof (PORT_INFO_1A);
3024 info_size = sizeof (PORT_INFO_2A);
3027 SetLastError(ERROR_INVALID_LEVEL);
3031 /* see how many exist */
3037 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szSerialPortKey, &hkey_serial);
3038 if (r == ERROR_SUCCESS)
3040 RegQueryInfoKeyA ( hkey_serial, NULL, NULL, NULL, NULL, NULL, NULL,
3041 &serial_count, NULL, NULL, NULL, NULL);
3044 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3045 if ( r == ERROR_SUCCESS )
3047 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3048 &printer_count, NULL, NULL, NULL, NULL);
3050 count = serial_count + printer_count;
3052 /* then fill in the structure info structure once
3053 we know the offset to the first string */
3055 memset( buffer, 0, bufsize );
3057 ofs = info_size*count;
3058 for ( i=0; i<count; i++)
3060 DWORD vallen = sizeof(portname) - 1;
3062 /* get the serial port values, then the printer values */
3063 if ( i < serial_count )
3064 r = RegEnumValueA( hkey_serial, i,
3065 portname, &vallen, NULL, NULL, NULL, 0 );
3067 r = RegEnumValueA( hkey_printer, i-serial_count,
3068 portname, &vallen, NULL, NULL, NULL, 0 );
3073 /* add a colon if necessary, and make it upper case */
3074 CharUpperBuffA(portname,vallen);
3075 if (strcasecmp(portname,"nul")!=0)
3076 if (vallen && (portname[vallen-1] != ':') )
3077 lstrcatA(portname,":");
3079 /* add the port info structure if we can fit it */
3080 if ( info_size*(n+1) < bufsize )
3084 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3085 info->pName = (LPSTR) &buffer[ofs];
3087 else if ( level == 2)
3089 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3090 info->pPortName = (LPSTR) &buffer[ofs];
3091 /* FIXME: fill in more stuff here */
3092 info->pMonitorName = PortMonitor;
3093 info->pDescription = PortDescription;
3094 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3097 /* add the name of the port if we can fit it */
3098 if ( ofs < bufsize )
3099 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3102 ofs += lstrlenA(portname)+1;
3106 RegCloseKey(hkey_serial);
3107 RegCloseKey(hkey_printer);
3113 *bufreturned = count;
3118 /******************************************************************************
3119 * GetDefaultPrinterA (WINSPOOL.@)
3121 * Based on PRINTDLG_GetDefaultPrinterName in dlls/commdlg/printdlg.c
3123 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3129 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3133 if (!GetProfileStringA ("windows", "device", "", name, *namesize))
3135 SetLastError (ERROR_FILE_NOT_FOUND);
3139 if ((ptr = strchr (name, ',')) == NULL)
3141 SetLastError (ERROR_FILE_NOT_FOUND);
3146 *namesize = strlen (name) + 1;
3151 /******************************************************************************
3152 * GetDefaultPrinterW (WINSPOOL.@)
3154 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3161 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3165 buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
3166 ret = GetDefaultPrinterA (buf, namesize);
3169 DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
3172 SetLastError (ERROR_INSUFFICIENT_BUFFER);
3175 else *namesize = len;
3178 HeapFree (GetProcessHeap (), 0, buf);
3183 /******************************************************************************
3184 * SetPrinterDataExA (WINSPOOL.@)
3186 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3187 LPCSTR pValueName, DWORD Type,
3188 LPBYTE pData, DWORD cbData)
3190 HKEY hkeyPrinter, hkeySubkey;
3193 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3194 debugstr_a(pValueName), Type, pData, cbData);
3196 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3200 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3202 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3203 RegCloseKey(hkeyPrinter);
3206 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3207 RegCloseKey(hkeySubkey);
3208 RegCloseKey(hkeyPrinter);
3212 /******************************************************************************
3213 * SetPrinterDataExW (WINSPOOL.@)
3215 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3216 LPCWSTR pValueName, DWORD Type,
3217 LPBYTE pData, DWORD cbData)
3219 HKEY hkeyPrinter, hkeySubkey;
3222 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3223 debugstr_w(pValueName), Type, pData, cbData);
3225 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3229 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3231 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3232 RegCloseKey(hkeyPrinter);
3235 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3236 RegCloseKey(hkeySubkey);
3237 RegCloseKey(hkeyPrinter);
3241 /******************************************************************************
3242 * SetPrinterDataA (WINSPOOL.@)
3244 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3245 LPBYTE pData, DWORD cbData)
3247 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3251 /******************************************************************************
3252 * SetPrinterDataW (WINSPOOL.@)
3254 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3255 LPBYTE pData, DWORD cbData)
3257 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3261 /******************************************************************************
3262 * GetPrinterDataExA (WINSPOOL.@)
3264 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3265 LPCSTR pValueName, LPDWORD pType,
3266 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3268 HKEY hkeyPrinter, hkeySubkey;
3271 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3272 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3275 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3279 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3281 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3282 RegCloseKey(hkeyPrinter);
3286 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3287 RegCloseKey(hkeySubkey);
3288 RegCloseKey(hkeyPrinter);
3292 /******************************************************************************
3293 * GetPrinterDataExW (WINSPOOL.@)
3295 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3296 LPCWSTR pValueName, LPDWORD pType,
3297 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3299 HKEY hkeyPrinter, hkeySubkey;
3302 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3303 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3306 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3310 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3312 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3313 RegCloseKey(hkeyPrinter);
3317 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3318 RegCloseKey(hkeySubkey);
3319 RegCloseKey(hkeyPrinter);
3323 /******************************************************************************
3324 * GetPrinterDataA (WINSPOOL.@)
3326 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3327 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3329 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3330 pData, nSize, pcbNeeded);
3333 /******************************************************************************
3334 * GetPrinterDataW (WINSPOOL.@)
3336 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3337 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3339 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3340 pData, nSize, pcbNeeded);
3343 /*******************************************************************************
3344 * EnumPrinterDataExW [WINSPOOL.@]
3346 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3347 LPBYTE pEnumValues, DWORD cbEnumValues,
3348 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3350 HKEY hkPrinter, hkSubKey;
3351 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3352 cbValueNameLen, cbMaxValueLen, cbValueLen,
3357 PPRINTER_ENUM_VALUESW ppev;
3359 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3361 if (pKeyName == NULL || *pKeyName == 0)
3362 return ERROR_INVALID_PARAMETER;
3364 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3365 if (ret != ERROR_SUCCESS)
3367 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3372 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3373 if (ret != ERROR_SUCCESS)
3375 r = RegCloseKey (hkPrinter);
3376 if (r != ERROR_SUCCESS)
3377 WARN ("RegCloseKey returned %li\n", r);
3378 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3379 debugstr_w (pKeyName), ret);
3383 ret = RegCloseKey (hkPrinter);
3384 if (ret != ERROR_SUCCESS)
3386 ERR ("RegCloseKey returned %li\n", ret);
3387 r = RegCloseKey (hkSubKey);
3388 if (r != ERROR_SUCCESS)
3389 WARN ("RegCloseKey returned %li\n", r);
3393 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3394 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3395 if (ret != ERROR_SUCCESS)
3397 r = RegCloseKey (hkSubKey);
3398 if (r != ERROR_SUCCESS)
3399 WARN ("RegCloseKey returned %li\n", r);
3400 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3404 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3405 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3407 if (cValues == 0) /* empty key */
3409 r = RegCloseKey (hkSubKey);
3410 if (r != ERROR_SUCCESS)
3411 WARN ("RegCloseKey returned %li\n", r);
3412 *pcbEnumValues = *pnEnumValues = 0;
3413 return ERROR_SUCCESS;
3416 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3418 hHeap = GetProcessHeap ();
3421 ERR ("GetProcessHeap failed\n");
3422 r = RegCloseKey (hkSubKey);
3423 if (r != ERROR_SUCCESS)
3424 WARN ("RegCloseKey returned %li\n", r);
3425 return ERROR_OUTOFMEMORY;
3428 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3429 if (lpValueName == NULL)
3431 ERR ("Failed to allocate %li bytes from process heap\n",
3432 cbMaxValueNameLen * sizeof (WCHAR));
3433 r = RegCloseKey (hkSubKey);
3434 if (r != ERROR_SUCCESS)
3435 WARN ("RegCloseKey returned %li\n", r);
3436 return ERROR_OUTOFMEMORY;
3439 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3440 if (lpValue == NULL)
3442 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3443 if (HeapFree (hHeap, 0, lpValueName) == 0)
3444 WARN ("HeapFree failed with code %li\n", GetLastError ());
3445 r = RegCloseKey (hkSubKey);
3446 if (r != ERROR_SUCCESS)
3447 WARN ("RegCloseKey returned %li\n", r);
3448 return ERROR_OUTOFMEMORY;
3451 TRACE ("pass 1: calculating buffer required for all names and values\n");
3453 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3455 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3457 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3459 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3460 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3461 NULL, NULL, lpValue, &cbValueLen);
3462 if (ret != ERROR_SUCCESS)
3464 if (HeapFree (hHeap, 0, lpValue) == 0)
3465 WARN ("HeapFree failed with code %li\n", GetLastError ());
3466 if (HeapFree (hHeap, 0, lpValueName) == 0)
3467 WARN ("HeapFree failed with code %li\n", GetLastError ());
3468 r = RegCloseKey (hkSubKey);
3469 if (r != ERROR_SUCCESS)
3470 WARN ("RegCloseKey returned %li\n", r);
3471 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3475 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3476 debugstr_w (lpValueName), dwIndex,
3477 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3479 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3480 cbBufSize += cbValueLen;
3483 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3485 *pcbEnumValues = cbBufSize;
3486 *pnEnumValues = cValues;
3488 if (cbEnumValues < cbBufSize) /* buffer too small */
3490 if (HeapFree (hHeap, 0, lpValue) == 0)
3491 WARN ("HeapFree failed with code %li\n", GetLastError ());
3492 if (HeapFree (hHeap, 0, lpValueName) == 0)
3493 WARN ("HeapFree failed with code %li\n", GetLastError ());
3494 r = RegCloseKey (hkSubKey);
3495 if (r != ERROR_SUCCESS)
3496 WARN ("RegCloseKey returned %li\n", r);
3497 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3498 return ERROR_MORE_DATA;
3501 TRACE ("pass 2: copying all names and values to buffer\n");
3503 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3504 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3506 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3508 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3509 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3510 NULL, &dwType, lpValue, &cbValueLen);
3511 if (ret != ERROR_SUCCESS)
3513 if (HeapFree (hHeap, 0, lpValue) == 0)
3514 WARN ("HeapFree failed with code %li\n", GetLastError ());
3515 if (HeapFree (hHeap, 0, lpValueName) == 0)
3516 WARN ("HeapFree failed with code %li\n", GetLastError ());
3517 r = RegCloseKey (hkSubKey);
3518 if (r != ERROR_SUCCESS)
3519 WARN ("RegCloseKey returned %li\n", r);
3520 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3524 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3525 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3526 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3527 pEnumValues += cbValueNameLen;
3529 /* return # of *bytes* (including trailing \0), not # of chars */
3530 ppev[dwIndex].cbValueName = cbValueNameLen;
3532 ppev[dwIndex].dwType = dwType;
3534 memcpy (pEnumValues, lpValue, cbValueLen);
3535 ppev[dwIndex].pData = pEnumValues;
3536 pEnumValues += cbValueLen;
3538 ppev[dwIndex].cbData = cbValueLen;
3540 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3541 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3544 if (HeapFree (hHeap, 0, lpValue) == 0)
3546 ret = GetLastError ();
3547 ERR ("HeapFree failed with code %li\n", ret);
3548 if (HeapFree (hHeap, 0, lpValueName) == 0)
3549 WARN ("HeapFree failed with code %li\n", GetLastError ());
3550 r = RegCloseKey (hkSubKey);
3551 if (r != ERROR_SUCCESS)
3552 WARN ("RegCloseKey returned %li\n", r);
3556 if (HeapFree (hHeap, 0, lpValueName) == 0)
3558 ret = GetLastError ();
3559 ERR ("HeapFree failed with code %li\n", ret);
3560 r = RegCloseKey (hkSubKey);
3561 if (r != ERROR_SUCCESS)
3562 WARN ("RegCloseKey returned %li\n", r);
3566 ret = RegCloseKey (hkSubKey);
3567 if (ret != ERROR_SUCCESS)
3569 ERR ("RegCloseKey returned %li\n", ret);
3573 return ERROR_SUCCESS;
3576 /*******************************************************************************
3577 * EnumPrinterDataExA [WINSPOOL.@]
3579 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3580 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3581 * what Windows 2000 SP1 does.
3584 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3585 LPBYTE pEnumValues, DWORD cbEnumValues,
3586 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3590 DWORD ret, dwIndex, dwBufSize;
3594 TRACE ("%p %s\n", hPrinter, pKeyName);
3596 if (pKeyName == NULL || *pKeyName == 0)
3597 return ERROR_INVALID_PARAMETER;
3599 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3602 ret = GetLastError ();
3603 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3607 hHeap = GetProcessHeap ();
3610 ERR ("GetProcessHeap failed\n");
3611 return ERROR_OUTOFMEMORY;
3614 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3615 if (pKeyNameW == NULL)
3617 ERR ("Failed to allocate %li bytes from process heap\n",
3618 (LONG) len * sizeof (WCHAR));
3619 return ERROR_OUTOFMEMORY;
3622 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3624 ret = GetLastError ();
3625 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3626 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3627 WARN ("HeapFree failed with code %li\n", GetLastError ());
3631 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3632 pcbEnumValues, pnEnumValues);
3633 if (ret != ERROR_SUCCESS)
3635 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3636 WARN ("HeapFree failed with code %li\n", GetLastError ());
3637 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3641 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3643 ret = GetLastError ();
3644 ERR ("HeapFree failed with code %li\n", ret);
3648 if (*pnEnumValues == 0) /* empty key */
3649 return ERROR_SUCCESS;
3652 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3654 PPRINTER_ENUM_VALUESW ppev =
3655 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3657 if (dwBufSize < ppev->cbValueName)
3658 dwBufSize = ppev->cbValueName;
3660 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3661 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3662 dwBufSize = ppev->cbData;
3665 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3667 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3668 if (pBuffer == NULL)
3670 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3671 return ERROR_OUTOFMEMORY;
3674 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3676 PPRINTER_ENUM_VALUESW ppev =
3677 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3679 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3680 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3684 ret = GetLastError ();
3685 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3686 if (HeapFree (hHeap, 0, pBuffer) == 0)
3687 WARN ("HeapFree failed with code %li\n", GetLastError ());
3691 memcpy (ppev->pValueName, pBuffer, len);
3693 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3695 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3696 ppev->dwType != REG_MULTI_SZ)
3699 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3700 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3703 ret = GetLastError ();
3704 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3705 if (HeapFree (hHeap, 0, pBuffer) == 0)
3706 WARN ("HeapFree failed with code %li\n", GetLastError ());
3710 memcpy (ppev->pData, pBuffer, len);
3712 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3713 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3716 if (HeapFree (hHeap, 0, pBuffer) == 0)
3718 ret = GetLastError ();
3719 ERR ("HeapFree failed with code %li\n", ret);
3723 return ERROR_SUCCESS;
3726 /******************************************************************************
3727 * AddPortA (WINSPOOL.@)
3729 BOOL WINAPI AddPortA(LPSTR pName ,HWND hWnd, LPSTR pMonitorName)
3731 FIXME("(%s, %p, %s\n), stub!\n",pName,hWnd,pMonitorName);
3735 /******************************************************************************
3736 * AddPrinterDriverExW (WINSPOOL.@)
3738 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
3739 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3741 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
3742 Level, pDriverInfo, dwFileCopyFlags);
3743 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3747 /******************************************************************************
3748 * AddPrinterDriverExA (WINSPOOL.@)
3750 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
3751 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3753 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
3754 Level, pDriverInfo, dwFileCopyFlags);
3755 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3759 /******************************************************************************
3760 * DeletePrinterDriverExW (WINSPOOL.@)
3762 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
3763 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3765 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
3766 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
3770 /******************************************************************************
3771 * DeletePrinterDriverExA (WINSPOOL.@)
3773 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
3774 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3776 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
3777 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
3781 /******************************************************************************
3782 * DeletePrinterDataExW (WINSPOOL.@)
3784 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
3787 FIXME("%p %s %s\n", hPrinter,
3788 debugstr_w(pKeyName), debugstr_w(pValueName));
3789 return ERROR_INVALID_PARAMETER;
3792 /******************************************************************************
3793 * DeletePrinterDataExA (WINSPOOL.@)
3795 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
3798 FIXME("%p %s %s\n", hPrinter,
3799 debugstr_a(pKeyName), debugstr_a(pValueName));
3800 return ERROR_INVALID_PARAMETER;
3803 /******************************************************************************
3804 * XcvDataW (WINSPOOL.@)
3807 * There doesn't seem to be an A version...
3809 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
3810 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
3811 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
3813 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
3814 pInputData, cbInputData, pOutputData,
3815 cbOutputData, pcbOutputNeeded, pdwStatus);