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 deviceW[] = {'d','e','v','i','c','e',0};
105 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
106 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
107 static const WCHAR emptyStringW[] = {0};
109 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
111 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
112 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
113 DWORD Level, LPBYTE pDriverInfo,
114 DWORD cbBuf, LPDWORD pcbNeeded,
116 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
118 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
119 if passed a NULL string. This returns NULLs to the result.
121 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
125 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
126 return usBufferPtr->Buffer;
128 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
133 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
136 /* If forcing, or no profile string entry for device yet, set the entry
138 * The always change entry if not WINEPS yet is discussable.
141 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
143 !strstr(qbuf,"WINEPS")
145 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
147 sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
148 WriteProfileStringA("windows","device",buf);
149 HeapFree(GetProcessHeap(),0,buf);
153 #ifdef HAVE_CUPS_CUPS_H
154 static BOOL CUPS_LoadPrinters(void)
156 typeof(cupsGetDests) *pcupsGetDests = NULL;
157 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
159 BOOL hadprinter = FALSE;
161 PRINTER_INFO_2A pinfo2a;
162 void *cupshandle = NULL;
164 HKEY hkeyPrinter, hkeyPrinters;
166 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
169 TRACE("loaded %s\n", SONAME_LIBCUPS);
172 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
173 if (!p##x) return FALSE;
176 DYNCUPS(cupsGetDests);
179 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
181 ERR("Can't create Printers key\n");
185 nrofdests = pcupsGetDests(&dests);
186 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
187 for (i=0;i<nrofdests;i++) {
188 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
189 sprintf(port,"LPR:%s",dests[i].name);
190 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
191 sprintf(devline,"WINEPS,%s",port);
192 WriteProfileStringA("devices",dests[i].name,devline);
193 HeapFree(GetProcessHeap(),0,devline);
195 TRACE("Printer %d: %s\n", i, dests[i].name);
196 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
197 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
199 TRACE("Printer already exists\n");
200 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
201 RegCloseKey(hkeyPrinter);
203 memset(&pinfo2a,0,sizeof(pinfo2a));
204 pinfo2a.pPrinterName = dests[i].name;
205 pinfo2a.pDatatype = "RAW";
206 pinfo2a.pPrintProcessor = "WinPrint";
207 pinfo2a.pDriverName = "PS Driver";
208 pinfo2a.pComment = "WINEPS Printer using CUPS";
209 pinfo2a.pLocation = "<physical location of printer>";
210 pinfo2a.pPortName = port;
211 pinfo2a.pParameters = "<parameters?>";
212 pinfo2a.pShareName = "<share name?>";
213 pinfo2a.pSepFile = "<sep file?>";
215 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
216 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
217 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
220 HeapFree(GetProcessHeap(),0,port);
223 if (dests[i].is_default)
224 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
226 RegCloseKey(hkeyPrinters);
227 wine_dlclose(cupshandle, NULL, 0);
233 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
234 PRINTER_INFO_2A pinfo2a;
235 char *e,*s,*name,*prettyname,*devname;
236 BOOL ret = FALSE, set_default = FALSE;
237 char *port,*devline,*env_default;
238 HKEY hkeyPrinter, hkeyPrinters;
240 while (isspace(*pent)) pent++;
241 s = strchr(pent,':');
243 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
251 TRACE("name=%s entry=%s\n",name, pent);
253 if(ispunct(*name)) { /* a tc entry, not a real printer */
254 TRACE("skipping tc entry\n");
258 if(strstr(pent,":server")) { /* server only version so skip */
259 TRACE("skipping server entry\n");
263 /* Determine whether this is a postscript printer. */
266 env_default = getenv("PRINTER");
268 /* Get longest name, usually the one at the right for later display. */
269 while((s=strchr(prettyname,'|'))) {
272 while(isspace(*--e)) *e = '\0';
273 TRACE("\t%s\n", debugstr_a(prettyname));
274 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
275 for(prettyname = s+1; isspace(*prettyname); prettyname++)
278 e = prettyname + strlen(prettyname);
279 while(isspace(*--e)) *e = '\0';
280 TRACE("\t%s\n", debugstr_a(prettyname));
281 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
283 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
284 * if it is too long, we use it as comment below. */
285 devname = prettyname;
286 if (strlen(devname)>=CCHDEVICENAME-1)
288 if (strlen(devname)>=CCHDEVICENAME-1) {
293 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
294 sprintf(port,"LPR:%s",name);
296 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
297 sprintf(devline,"WINEPS,%s",port);
298 WriteProfileStringA("devices",devname,devline);
299 HeapFree(GetProcessHeap(),0,devline);
301 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
303 ERR("Can't create Printers key\n");
307 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
308 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
310 TRACE("Printer already exists\n");
311 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
312 RegCloseKey(hkeyPrinter);
314 memset(&pinfo2a,0,sizeof(pinfo2a));
315 pinfo2a.pPrinterName = devname;
316 pinfo2a.pDatatype = "RAW";
317 pinfo2a.pPrintProcessor = "WinPrint";
318 pinfo2a.pDriverName = "PS Driver";
319 pinfo2a.pComment = "WINEPS Printer using LPR";
320 pinfo2a.pLocation = prettyname;
321 pinfo2a.pPortName = port;
322 pinfo2a.pParameters = "<parameters?>";
323 pinfo2a.pShareName = "<share name?>";
324 pinfo2a.pSepFile = "<sep file?>";
326 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
327 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
328 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
331 RegCloseKey(hkeyPrinters);
333 if (isfirst || set_default)
334 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
336 HeapFree(GetProcessHeap(), 0, port);
338 HeapFree(GetProcessHeap(), 0, name);
343 PRINTCAP_LoadPrinters(void) {
344 BOOL hadprinter = FALSE;
348 BOOL had_bash = FALSE;
350 f = fopen("/etc/printcap","r");
354 while(fgets(buf,sizeof(buf),f)) {
357 end=strchr(buf,'\n');
361 while(isspace(*start)) start++;
362 if(*start == '#' || *start == '\0')
365 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
366 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
367 HeapFree(GetProcessHeap(),0,pent);
371 if (end && *--end == '\\') {
378 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
381 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
387 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
388 HeapFree(GetProcessHeap(),0,pent);
394 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
397 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
398 lstrlenW(value) * sizeof(WCHAR));
400 return ERROR_FILE_NOT_FOUND;
403 void WINSPOOL_LoadSystemPrinters(void)
405 HKEY hkey, hkeyPrinters;
408 DWORD needed, num, i;
409 WCHAR PrinterName[256];
412 di3a.cVersion = 0x400;
413 di3a.pName = "PS Driver";
414 di3a.pEnvironment = NULL; /* NULL means auto */
415 di3a.pDriverPath = "wineps16";
416 di3a.pDataFile = "<datafile?>";
417 di3a.pConfigFile = "wineps16";
418 di3a.pHelpFile = "<helpfile?>";
419 di3a.pDependentFiles = "<dependend files?>";
420 di3a.pMonitorName = "<monitor name?>";
421 di3a.pDefaultDataType = "RAW";
423 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
424 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
428 /* This ensures that all printer entries have a valid Name value. If causes
429 problems later if they don't. If one is found to be missed we create one
430 and set it equal to the name of the key */
431 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
432 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
433 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
434 for(i = 0; i < num; i++) {
435 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
436 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
437 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
438 set_reg_szW(hkey, NameW, PrinterName);
445 RegCloseKey(hkeyPrinters);
448 /* We want to avoid calling AddPrinter on printers as much as
449 possible, because on cups printers this will (eventually) lead
450 to a call to cupsGetPPD which takes forever, even with non-cups
451 printers AddPrinter takes a while. So we'll tag all printers that
452 were automatically added last time around, if they still exist
453 we'll leave them be otherwise we'll delete them. */
454 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
456 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
457 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
458 for(i = 0; i < num; i++) {
459 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
460 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
461 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
463 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
471 HeapFree(GetProcessHeap(), 0, pi);
475 #ifdef HAVE_CUPS_CUPS_H
476 done = CUPS_LoadPrinters();
479 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
480 /* Check for [ppd] section in config file before parsing /etc/printcap */
481 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
482 &hkey) == ERROR_SUCCESS) {
484 PRINTCAP_LoadPrinters();
488 /* Now enumerate the list again and delete any printers that a still tagged */
489 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
491 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
492 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
493 for(i = 0; i < num; i++) {
494 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
495 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
496 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
497 DWORD dw, type, size = sizeof(dw);
498 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
499 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
509 HeapFree(GetProcessHeap(), 0, pi);
517 /******************************************************************
518 * WINSPOOL_GetOpenedPrinterEntry
519 * Get the first place empty in the opened printer table
521 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
525 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
527 if (i >= nb_printers)
531 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
532 (nb_printers + 16) * sizeof(*new_array) );
534 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
535 (nb_printers + 16) * sizeof(*new_array) );
537 if (!new_array) return 0;
538 printer_array = new_array;
542 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
544 strcpyW( printer_array[i], name );
545 return (HANDLE)(i + 1);
550 /******************************************************************
551 * WINSPOOL_GetOpenedPrinter
552 * Get the pointer to the opened printer referred by the handle
554 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
556 int idx = (int)printerHandle;
557 if ((idx <= 0) || (idx > nb_printers))
559 SetLastError(ERROR_INVALID_HANDLE);
562 return printer_array[idx - 1];
565 /******************************************************************
566 * WINSPOOL_GetOpenedPrinterRegKey
569 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
571 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
575 if(!name) return ERROR_INVALID_HANDLE;
577 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
581 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
583 ERR("Can't find opened printer %s in registry\n",
585 RegCloseKey(hkeyPrinters);
586 return ERROR_INVALID_PRINTER_NAME; /* ? */
588 RegCloseKey(hkeyPrinters);
589 return ERROR_SUCCESS;
592 /***********************************************************
595 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
598 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
601 Formname = (dmA->dmSize > off_formname);
602 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
603 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
606 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
607 dmA->dmSize - CCHDEVICENAME);
609 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
610 off_formname - CCHDEVICENAME);
611 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
613 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
614 (off_formname + CCHFORMNAME));
617 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
622 /***********************************************************
624 * Creates an ascii copy of supplied devmode on heap
626 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
631 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
633 if(!dmW) return NULL;
634 Formname = (dmW->dmSize > off_formname);
635 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
636 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
637 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
638 CCHDEVICENAME, NULL, NULL);
640 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
641 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
643 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
644 off_formname - CCHDEVICENAME * sizeof(WCHAR));
645 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
646 CCHFORMNAME, NULL, NULL);
647 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
648 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
651 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
656 /***********************************************************
658 * Creates a unicode copy of PRINTER_INFO_2A on heap
660 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
662 LPPRINTER_INFO_2W piW;
663 UNICODE_STRING usBuffer;
665 if(!piA) return NULL;
666 piW = HeapAlloc(heap, 0, sizeof(*piW));
667 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
669 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
670 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
671 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
672 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
673 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
674 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
675 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
676 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
677 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
678 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
679 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
680 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
684 /***********************************************************
685 * FREE_PRINTER_INFO_2W
686 * Free PRINTER_INFO_2W and all strings
688 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
692 HeapFree(heap,0,piW->pServerName);
693 HeapFree(heap,0,piW->pPrinterName);
694 HeapFree(heap,0,piW->pShareName);
695 HeapFree(heap,0,piW->pPortName);
696 HeapFree(heap,0,piW->pDriverName);
697 HeapFree(heap,0,piW->pComment);
698 HeapFree(heap,0,piW->pLocation);
699 HeapFree(heap,0,piW->pDevMode);
700 HeapFree(heap,0,piW->pSepFile);
701 HeapFree(heap,0,piW->pPrintProcessor);
702 HeapFree(heap,0,piW->pDatatype);
703 HeapFree(heap,0,piW->pParameters);
704 HeapFree(heap,0,piW);
708 /******************************************************************
709 * DeviceCapabilities [WINSPOOL.@]
710 * DeviceCapabilitiesA [WINSPOOL.@]
713 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
714 LPSTR pOutput, LPDEVMODEA lpdm)
718 if (!GDI_CallDeviceCapabilities16)
720 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
722 if (!GDI_CallDeviceCapabilities16) return -1;
724 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
726 /* If DC_PAPERSIZE map POINT16s to POINTs */
727 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
728 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
729 POINT *pt = (POINT *)pOutput;
731 memcpy(tmp, pOutput, ret * sizeof(POINT16));
732 for(i = 0; i < ret; i++, pt++)
737 HeapFree( GetProcessHeap(), 0, tmp );
743 /*****************************************************************************
744 * DeviceCapabilitiesW [WINSPOOL.@]
746 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
749 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
750 WORD fwCapability, LPWSTR pOutput,
751 const DEVMODEW *pDevMode)
753 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
754 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
755 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
758 if(pOutput && (fwCapability == DC_BINNAMES ||
759 fwCapability == DC_FILEDEPENDENCIES ||
760 fwCapability == DC_PAPERNAMES)) {
761 /* These need A -> W translation */
764 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
768 switch(fwCapability) {
773 case DC_FILEDEPENDENCIES:
777 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
778 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
780 for(i = 0; i < ret; i++)
781 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
782 pOutput + (i * size), size);
783 HeapFree(GetProcessHeap(), 0, pOutputA);
785 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
786 (LPSTR)pOutput, dmA);
788 HeapFree(GetProcessHeap(),0,pPortA);
789 HeapFree(GetProcessHeap(),0,pDeviceA);
790 HeapFree(GetProcessHeap(),0,dmA);
794 /******************************************************************
795 * DocumentPropertiesA [WINSPOOL.@]
797 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
799 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
800 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
801 LPDEVMODEA pDevModeInput,DWORD fMode )
803 LPSTR lpName = pDeviceName;
806 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
807 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
811 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
813 ERR("no name from hPrinter?\n");
816 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
819 if (!GDI_CallExtDeviceMode16)
821 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
823 if (!GDI_CallExtDeviceMode16) {
824 ERR("No CallExtDeviceMode16?\n");
828 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
829 pDevModeInput, NULL, fMode);
832 HeapFree(GetProcessHeap(),0,lpName);
837 /*****************************************************************************
838 * DocumentPropertiesW (WINSPOOL.@)
840 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
842 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
844 LPDEVMODEW pDevModeOutput,
845 LPDEVMODEW pDevModeInput, DWORD fMode)
848 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
849 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
850 LPDEVMODEA pDevModeOutputA = NULL;
853 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
854 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
857 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
858 if(ret < 0) return ret;
859 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
861 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
862 pDevModeInputA, fMode);
864 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
865 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
867 if(fMode == 0 && ret > 0)
868 ret += (CCHDEVICENAME + CCHFORMNAME);
869 HeapFree(GetProcessHeap(),0,pDevModeInputA);
870 HeapFree(GetProcessHeap(),0,pDeviceNameA);
874 /******************************************************************
875 * OpenPrinterA [WINSPOOL.@]
878 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
879 LPPRINTER_DEFAULTSA pDefault)
881 UNICODE_STRING lpPrinterNameW;
882 UNICODE_STRING usBuffer;
883 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
884 PWSTR pwstrPrinterNameW;
887 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
890 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
891 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
892 DefaultW.DesiredAccess = pDefault->DesiredAccess;
893 pDefaultW = &DefaultW;
895 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
897 RtlFreeUnicodeString(&usBuffer);
898 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
900 RtlFreeUnicodeString(&lpPrinterNameW);
904 /******************************************************************
905 * OpenPrinterW [WINSPOOL.@]
908 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
909 LPPRINTER_DEFAULTSW pDefault)
911 HKEY hkeyPrinters, hkeyPrinter;
913 if (!lpPrinterName) {
914 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
915 SetLastError(ERROR_INVALID_PARAMETER);
919 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
922 /* Check Printer exists */
923 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
925 ERR("Can't create Printers key\n");
926 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
930 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
931 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
933 TRACE("Can't find printer %s in registry\n",
934 debugstr_w(lpPrinterName));
935 RegCloseKey(hkeyPrinters);
936 SetLastError(ERROR_INVALID_PRINTER_NAME);
939 RegCloseKey(hkeyPrinter);
940 RegCloseKey(hkeyPrinters);
942 if(!phPrinter) /* This seems to be what win95 does anyway */
945 /* Get the unique handle of the printer*/
946 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
948 if (pDefault != NULL)
949 FIXME("Not handling pDefault\n");
954 /******************************************************************
955 * AddMonitorA [WINSPOOL.@]
958 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
960 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
961 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
965 /******************************************************************
966 * DeletePrinterDriverA [WINSPOOL.@]
970 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
972 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
973 debugstr_a(pDriverName));
974 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
979 /******************************************************************
980 * DeleteMonitorA [WINSPOOL.@]
984 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
986 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
987 debugstr_a(pMonitorName));
988 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
993 /******************************************************************
994 * DeletePortA [WINSPOOL.@]
998 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1000 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1001 debugstr_a(pPortName));
1002 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1006 /******************************************************************************
1007 * SetPrinterW [WINSPOOL.@]
1017 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1021 /******************************************************************************
1022 * WritePrinter [WINSPOOL.@]
1029 LPDWORD pcWritten) {
1032 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1036 /*****************************************************************************
1037 * AddFormA [WINSPOOL.@]
1039 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1041 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1045 /*****************************************************************************
1046 * AddFormW [WINSPOOL.@]
1048 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1050 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1054 /*****************************************************************************
1055 * AddJobA [WINSPOOL.@]
1057 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
1058 DWORD cbBuf, LPDWORD pcbNeeded)
1060 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1065 /*****************************************************************************
1066 * AddJobW [WINSPOOL.@]
1068 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
1071 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1076 /*****************************************************************************
1077 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1079 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1080 DWORD level, LPBYTE Info,
1081 DWORD cbBuf, LPDWORD needed)
1083 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", server, env, level, Info, cbBuf);
1087 /*****************************************************************************
1088 * WINSPOOL_OpenDriverReg [internal]
1090 * opens the registry for the printer drivers depending on the given input
1091 * variable pEnvironment
1094 * the opened hkey on success
1097 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1099 LPSTR lpKey, p = NULL;
1102 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1105 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1109 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1111 if(!GetVersionExA( &ver))
1114 switch (ver.dwPlatformId) {
1115 case VER_PLATFORM_WIN32s:
1116 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1119 case VER_PLATFORM_WIN32_NT:
1120 p = "Windows NT x86";
1126 TRACE("set environment to %s\n", p);
1129 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1130 strlen(p) + strlen(Drivers));
1131 sprintf( lpKey, Drivers, p);
1133 TRACE("%s\n", lpKey);
1135 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1139 if(pEnvironment && unicode)
1140 HeapFree( GetProcessHeap(), 0, p);
1141 HeapFree( GetProcessHeap(), 0, lpKey);
1146 /*****************************************************************************
1147 * AddPrinterW [WINSPOOL.@]
1149 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1151 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1155 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1158 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1161 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1162 SetLastError(ERROR_INVALID_PARAMETER);
1166 ERR("Level = %ld, unsupported!\n", Level);
1167 SetLastError(ERROR_INVALID_LEVEL);
1170 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1171 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1172 debugstr_w(pi->pPrinterName)
1174 SetLastError(ERROR_INVALID_LEVEL);
1178 SetLastError(ERROR_INVALID_PARAMETER);
1181 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1183 ERR("Can't create Printers key\n");
1186 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1187 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1188 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1189 RegCloseKey(hkeyPrinter);
1190 RegCloseKey(hkeyPrinters);
1193 RegCloseKey(hkeyPrinter);
1195 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1197 ERR("Can't create Drivers key\n");
1198 RegCloseKey(hkeyPrinters);
1201 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1203 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1204 RegCloseKey(hkeyPrinters);
1205 RegCloseKey(hkeyDrivers);
1206 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1209 RegCloseKey(hkeyDriver);
1210 RegCloseKey(hkeyDrivers);
1212 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1213 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1214 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1215 RegCloseKey(hkeyPrinters);
1219 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1221 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1222 SetLastError(ERROR_INVALID_PRINTER_NAME);
1223 RegCloseKey(hkeyPrinters);
1226 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1227 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1228 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1230 /* See if we can load the driver. We may need the devmode structure anyway
1233 * Note that DocumentPropertiesW will briefly try to open the printer we
1234 * just create to find a DEVMODEA struct (it will use the WINEPS default
1235 * one in case it is not there, so we are ok).
1237 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1240 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1241 size = sizeof(DEVMODEW);
1247 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1248 ZeroMemory(dmW,size);
1250 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1252 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1253 HeapFree(GetProcessHeap(),0,dmW);
1258 /* set devmode to printer name */
1259 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1263 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1264 and we support these drivers. NT writes DEVMODEW so somehow
1265 we'll need to distinguish between these when we support NT
1269 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1270 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1271 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1272 HeapFree(GetProcessHeap(), 0, dmA);
1274 HeapFree(GetProcessHeap(), 0, dmW);
1276 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1277 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1278 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1279 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1281 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1282 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1283 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1284 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1285 (LPBYTE)&pi->Priority, sizeof(DWORD));
1286 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1287 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1288 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1289 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1290 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1291 (LPBYTE)&pi->Status, sizeof(DWORD));
1292 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1293 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1295 RegCloseKey(hkeyPrinter);
1296 RegCloseKey(hkeyPrinters);
1297 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1298 ERR("OpenPrinter failing\n");
1304 /*****************************************************************************
1305 * AddPrinterA [WINSPOOL.@]
1307 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1309 UNICODE_STRING pNameW;
1311 PRINTER_INFO_2W *piW;
1312 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1315 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1317 ERR("Level = %ld, unsupported!\n", Level);
1318 SetLastError(ERROR_INVALID_LEVEL);
1321 pwstrNameW = asciitounicode(&pNameW,pName);
1322 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1324 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1326 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1327 RtlFreeUnicodeString(&pNameW);
1332 /*****************************************************************************
1333 * ClosePrinter [WINSPOOL.@]
1335 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1337 int i = (int)hPrinter;
1339 TRACE("Handle %p\n", hPrinter);
1341 if ((i <= 0) || (i > nb_printers)) return FALSE;
1342 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1343 printer_array[i - 1] = NULL;
1347 /*****************************************************************************
1348 * DeleteFormA [WINSPOOL.@]
1350 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1352 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1356 /*****************************************************************************
1357 * DeleteFormW [WINSPOOL.@]
1359 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1361 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1365 /*****************************************************************************
1366 * WINSPOOL_SHRegDeleteKey
1368 * Recursively delete subkeys.
1369 * Cut & paste from shlwapi.
1372 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1374 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1375 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1378 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1381 /* Find how many subkeys there are */
1382 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1383 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1387 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1388 /* Name too big: alloc a buffer for it */
1389 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1392 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1395 /* Recursively delete all the subkeys */
1396 for(i = 0; i < dwKeyCount && !dwRet; i++)
1398 dwSize = dwMaxSubkeyLen;
1399 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1401 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1404 if (lpszName != szNameBuf)
1405 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1409 RegCloseKey(hSubKey);
1411 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1416 /*****************************************************************************
1417 * DeletePrinter [WINSPOOL.@]
1419 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1421 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1424 if(!lpNameW) return FALSE;
1425 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1426 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1427 RegCloseKey(hkeyPrinters);
1429 WriteProfileStringW(devicesW, lpNameW, NULL);
1433 /*****************************************************************************
1434 * SetPrinterA [WINSPOOL.@]
1436 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1439 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1443 /*****************************************************************************
1444 * SetJobA [WINSPOOL.@]
1446 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1447 LPBYTE pJob, DWORD Command)
1449 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1454 /*****************************************************************************
1455 * SetJobW [WINSPOOL.@]
1457 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1458 LPBYTE pJob, DWORD Command)
1460 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1465 /*****************************************************************************
1466 * EndDocPrinter [WINSPOOL.@]
1468 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1470 FIXME("(hPrinter=%p): stub\n", hPrinter);
1474 /*****************************************************************************
1475 * EndPagePrinter [WINSPOOL.@]
1477 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1479 FIXME("(hPrinter=%p): stub\n", hPrinter);
1483 /*****************************************************************************
1484 * StartDocPrinterA [WINSPOOL.@]
1486 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1488 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1492 /*****************************************************************************
1493 * StartDocPrinterW [WINSPOOL.@]
1495 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1497 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1501 /*****************************************************************************
1502 * StartPagePrinter [WINSPOOL.@]
1504 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1506 FIXME("(hPrinter=%p): stub\n", hPrinter);
1510 /*****************************************************************************
1511 * GetFormA [WINSPOOL.@]
1513 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1514 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1516 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1517 Level,pForm,cbBuf,pcbNeeded);
1521 /*****************************************************************************
1522 * GetFormW [WINSPOOL.@]
1524 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1525 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1527 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1528 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1532 /*****************************************************************************
1533 * SetFormA [WINSPOOL.@]
1535 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1538 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1542 /*****************************************************************************
1543 * SetFormW [WINSPOOL.@]
1545 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1548 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1552 /*****************************************************************************
1553 * ReadPrinter [WINSPOOL.@]
1555 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1556 LPDWORD pNoBytesRead)
1558 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1562 /*****************************************************************************
1563 * ResetPrinterA [WINSPOOL.@]
1565 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1567 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1571 /*****************************************************************************
1572 * ResetPrinterW [WINSPOOL.@]
1574 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1576 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1580 /*****************************************************************************
1581 * WINSPOOL_GetDWORDFromReg
1583 * Return DWORD associated with ValueName from hkey.
1585 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1587 DWORD sz = sizeof(DWORD), type, value = 0;
1590 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1592 if(ret != ERROR_SUCCESS) {
1593 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1596 if(type != REG_DWORD) {
1597 ERR("Got type %ld\n", type);
1603 /*****************************************************************************
1604 * WINSPOOL_GetStringFromReg
1606 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1607 * String is stored either as unicode or ascii.
1608 * Bit of a hack here to get the ValueName if we want ascii.
1610 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1611 DWORD buflen, DWORD *needed,
1614 DWORD sz = buflen, type;
1618 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1620 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1621 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1622 HeapFree(GetProcessHeap(),0,ValueNameA);
1624 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1625 WARN("Got ret = %ld\n", ret);
1633 /*****************************************************************************
1634 * WINSPOOL_GetDefaultDevMode
1636 * Get a default DevMode values for wineps.
1640 static void WINSPOOL_GetDefaultDevMode(
1642 DWORD buflen, DWORD *needed,
1647 /* fill default DEVMODE - should be read from ppd... */
1648 ZeroMemory( &dm, sizeof(dm) );
1649 strcpy(dm.dmDeviceName,"wineps");
1650 dm.dmSpecVersion = DM_SPECVERSION;
1651 dm.dmDriverVersion = 1;
1652 dm.dmSize = sizeof(DEVMODEA);
1653 dm.dmDriverExtra = 0;
1655 DM_ORIENTATION | DM_PAPERSIZE |
1656 DM_PAPERLENGTH | DM_PAPERWIDTH |
1659 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1660 DM_YRESOLUTION | DM_TTOPTION;
1662 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1663 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1664 dm.u1.s1.dmPaperLength = 2970;
1665 dm.u1.s1.dmPaperWidth = 2100;
1669 dm.dmDefaultSource = DMBIN_AUTO;
1670 dm.dmPrintQuality = DMRES_MEDIUM;
1673 dm.dmYResolution = 300; /* 300dpi */
1674 dm.dmTTOption = DMTT_BITMAP;
1677 /* dm.dmLogPixels */
1678 /* dm.dmBitsPerPel */
1679 /* dm.dmPelsWidth */
1680 /* dm.dmPelsHeight */
1681 /* dm.dmDisplayFlags */
1682 /* dm.dmDisplayFrequency */
1683 /* dm.dmICMMethod */
1684 /* dm.dmICMIntent */
1685 /* dm.dmMediaType */
1686 /* dm.dmDitherType */
1687 /* dm.dmReserved1 */
1688 /* dm.dmReserved2 */
1689 /* dm.dmPanningWidth */
1690 /* dm.dmPanningHeight */
1693 if(buflen >= sizeof(DEVMODEW)) {
1694 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1695 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1696 HeapFree(GetProcessHeap(),0,pdmW);
1698 *needed = sizeof(DEVMODEW);
1702 if(buflen >= sizeof(DEVMODEA)) {
1703 memcpy(ptr, &dm, sizeof(DEVMODEA));
1705 *needed = sizeof(DEVMODEA);
1709 /*****************************************************************************
1710 * WINSPOOL_GetDevModeFromReg
1712 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1713 * DevMode is stored either as unicode or ascii.
1715 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1717 DWORD buflen, DWORD *needed,
1720 DWORD sz = buflen, type;
1723 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1724 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1725 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1726 if (sz < sizeof(DEVMODEA))
1728 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1731 /* ensures that dmSize is not erratically bogus if registry is invalid */
1732 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1733 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1735 sz += (CCHDEVICENAME + CCHFORMNAME);
1737 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1738 memcpy(ptr, dmW, sz);
1739 HeapFree(GetProcessHeap(),0,dmW);
1746 /*********************************************************************
1747 * WINSPOOL_GetPrinter_2
1749 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1750 * The strings are either stored as unicode or ascii.
1752 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1753 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1756 DWORD size, left = cbBuf;
1757 BOOL space = (cbBuf > 0);
1762 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1764 if(space && size <= left) {
1765 pi2->pPrinterName = (LPWSTR)ptr;
1772 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1774 if(space && size <= left) {
1775 pi2->pShareName = (LPWSTR)ptr;
1782 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1784 if(space && size <= left) {
1785 pi2->pPortName = (LPWSTR)ptr;
1792 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1794 if(space && size <= left) {
1795 pi2->pDriverName = (LPWSTR)ptr;
1802 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1804 if(space && size <= left) {
1805 pi2->pComment = (LPWSTR)ptr;
1812 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1814 if(space && size <= left) {
1815 pi2->pLocation = (LPWSTR)ptr;
1822 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1824 if(space && size <= left) {
1825 pi2->pDevMode = (LPDEVMODEW)ptr;
1834 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1835 if(space && size <= left) {
1836 pi2->pDevMode = (LPDEVMODEW)ptr;
1843 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1845 if(space && size <= left) {
1846 pi2->pSepFile = (LPWSTR)ptr;
1853 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1855 if(space && size <= left) {
1856 pi2->pPrintProcessor = (LPWSTR)ptr;
1863 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1865 if(space && size <= left) {
1866 pi2->pDatatype = (LPWSTR)ptr;
1873 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1875 if(space && size <= left) {
1876 pi2->pParameters = (LPWSTR)ptr;
1884 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1885 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1886 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1887 "Default Priority");
1888 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1889 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1892 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1893 memset(pi2, 0, sizeof(*pi2));
1898 /*********************************************************************
1899 * WINSPOOL_GetPrinter_4
1901 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1903 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1904 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1907 DWORD size, left = cbBuf;
1908 BOOL space = (cbBuf > 0);
1913 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1915 if(space && size <= left) {
1916 pi4->pPrinterName = (LPWSTR)ptr;
1924 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1927 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1928 memset(pi4, 0, sizeof(*pi4));
1933 /*********************************************************************
1934 * WINSPOOL_GetPrinter_5
1936 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1938 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1939 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1942 DWORD size, left = cbBuf;
1943 BOOL space = (cbBuf > 0);
1948 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1950 if(space && size <= left) {
1951 pi5->pPrinterName = (LPWSTR)ptr;
1958 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1960 if(space && size <= left) {
1961 pi5->pPortName = (LPWSTR)ptr;
1969 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1970 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1972 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1976 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1977 memset(pi5, 0, sizeof(*pi5));
1982 /*****************************************************************************
1983 * WINSPOOL_GetPrinter
1985 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1986 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1987 * just a collection of pointers to strings.
1989 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1990 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1993 DWORD size, needed = 0;
1995 HKEY hkeyPrinter, hkeyPrinters;
1998 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2000 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2002 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2004 ERR("Can't create Printers key\n");
2007 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2009 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2010 RegCloseKey(hkeyPrinters);
2011 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2018 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2020 size = sizeof(PRINTER_INFO_2W);
2022 ptr = pPrinter + size;
2024 memset(pPrinter, 0, size);
2029 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2037 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2039 size = sizeof(PRINTER_INFO_4W);
2041 ptr = pPrinter + size;
2043 memset(pPrinter, 0, size);
2048 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2057 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2059 size = sizeof(PRINTER_INFO_5W);
2061 ptr = pPrinter + size;
2063 memset(pPrinter, 0, size);
2069 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2076 FIXME("Unimplemented level %ld\n", Level);
2077 SetLastError(ERROR_INVALID_LEVEL);
2078 RegCloseKey(hkeyPrinters);
2079 RegCloseKey(hkeyPrinter);
2083 RegCloseKey(hkeyPrinter);
2084 RegCloseKey(hkeyPrinters);
2086 TRACE("returning %d needed = %ld\n", ret, needed);
2087 if(pcbNeeded) *pcbNeeded = needed;
2089 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2093 /*****************************************************************************
2094 * GetPrinterW [WINSPOOL.@]
2096 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2097 DWORD cbBuf, LPDWORD pcbNeeded)
2099 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2103 /*****************************************************************************
2104 * GetPrinterA [WINSPOOL.@]
2106 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2107 DWORD cbBuf, LPDWORD pcbNeeded)
2109 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2113 /*****************************************************************************
2114 * WINSPOOL_EnumPrinters
2116 * Implementation of EnumPrintersA|W
2118 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2119 DWORD dwLevel, LPBYTE lpbPrinters,
2120 DWORD cbBuf, LPDWORD lpdwNeeded,
2121 LPDWORD lpdwReturned, BOOL unicode)
2124 HKEY hkeyPrinters, hkeyPrinter;
2125 WCHAR PrinterName[255];
2126 DWORD needed = 0, number = 0;
2127 DWORD used, i, left;
2131 memset(lpbPrinters, 0, cbBuf);
2137 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2138 if(dwType == PRINTER_ENUM_DEFAULT)
2141 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2142 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2143 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2144 if(!dwType) return TRUE;
2147 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2148 FIXME("dwType = %08lx\n", dwType);
2149 SetLastError(ERROR_INVALID_FLAGS);
2153 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2155 ERR("Can't create Printers key\n");
2159 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2160 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2161 RegCloseKey(hkeyPrinters);
2162 ERR("Can't query Printers key\n");
2165 TRACE("Found %ld printers\n", number);
2169 RegCloseKey(hkeyPrinters);
2171 *lpdwReturned = number;
2175 used = number * sizeof(PRINTER_INFO_2W);
2178 used = number * sizeof(PRINTER_INFO_4W);
2181 used = number * sizeof(PRINTER_INFO_5W);
2185 SetLastError(ERROR_INVALID_LEVEL);
2186 RegCloseKey(hkeyPrinters);
2189 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2191 for(i = 0; i < number; i++) {
2192 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2194 ERR("Can't enum key number %ld\n", i);
2195 RegCloseKey(hkeyPrinters);
2198 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2199 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2201 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2202 RegCloseKey(hkeyPrinters);
2207 buf = lpbPrinters + used;
2208 left = cbBuf - used;
2216 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2217 left, &needed, unicode);
2219 if(pi) pi += sizeof(PRINTER_INFO_2W);
2222 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2223 left, &needed, unicode);
2225 if(pi) pi += sizeof(PRINTER_INFO_4W);
2228 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2229 left, &needed, unicode);
2231 if(pi) pi += sizeof(PRINTER_INFO_5W);
2234 ERR("Shouldn't be here!\n");
2235 RegCloseKey(hkeyPrinter);
2236 RegCloseKey(hkeyPrinters);
2239 RegCloseKey(hkeyPrinter);
2241 RegCloseKey(hkeyPrinters);
2248 memset(lpbPrinters, 0, cbBuf);
2249 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2253 *lpdwReturned = number;
2254 SetLastError(ERROR_SUCCESS);
2259 /******************************************************************
2260 * EnumPrintersW [WINSPOOL.@]
2262 * Enumerates the available printers, print servers and print
2263 * providers, depending on the specified flags, name and level.
2267 * If level is set to 1:
2268 * Not implemented yet!
2269 * Returns TRUE with an empty list.
2271 * If level is set to 2:
2272 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2273 * Returns an array of PRINTER_INFO_2 data structures in the
2274 * lpbPrinters buffer. Note that according to MSDN also an
2275 * OpenPrinter should be performed on every remote printer.
2277 * If level is set to 4 (officially WinNT only):
2278 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2279 * Fast: Only the registry is queried to retrieve printer names,
2280 * no connection to the driver is made.
2281 * Returns an array of PRINTER_INFO_4 data structures in the
2282 * lpbPrinters buffer.
2284 * If level is set to 5 (officially WinNT4/Win9x only):
2285 * Fast: Only the registry is queried to retrieve printer names,
2286 * no connection to the driver is made.
2287 * Returns an array of PRINTER_INFO_5 data structures in the
2288 * lpbPrinters buffer.
2290 * If level set to 3 or 6+:
2291 * returns zero (failure!)
2293 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2297 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2298 * - Only levels 2, 4 and 5 are implemented at the moment.
2299 * - 16-bit printer drivers are not enumerated.
2300 * - Returned amount of bytes used/needed does not match the real Windoze
2301 * implementation (as in this implementation, all strings are part
2302 * of the buffer, whereas Win32 keeps them somewhere else)
2303 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2306 * - In a regular Wine installation, no registry settings for printers
2307 * exist, which makes this function return an empty list.
2309 BOOL WINAPI EnumPrintersW(
2310 DWORD dwType, /* [in] Types of print objects to enumerate */
2311 LPWSTR lpszName, /* [in] name of objects to enumerate */
2312 DWORD dwLevel, /* [in] type of printer info structure */
2313 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2314 DWORD cbBuf, /* [in] max size of buffer in bytes */
2315 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2316 LPDWORD lpdwReturned /* [out] number of entries returned */
2319 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2320 lpdwNeeded, lpdwReturned, TRUE);
2323 /******************************************************************
2324 * EnumPrintersA [WINSPOOL.@]
2327 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2328 DWORD dwLevel, LPBYTE lpbPrinters,
2329 DWORD cbBuf, LPDWORD lpdwNeeded,
2330 LPDWORD lpdwReturned)
2333 UNICODE_STRING lpszNameW;
2336 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2337 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2338 lpdwNeeded, lpdwReturned, FALSE);
2339 RtlFreeUnicodeString(&lpszNameW);
2343 /*****************************************************************************
2344 * WINSPOOL_GetDriverInfoFromReg [internal]
2346 * Enters the information from the registry into the DRIVER_INFO struct
2349 * zero if the printer driver does not exist in the registry
2350 * (only if Level > 1) otherwise nonzero
2352 static BOOL WINSPOOL_GetDriverInfoFromReg(
2355 LPWSTR pEnvironment,
2357 LPBYTE ptr, /* DRIVER_INFO */
2358 LPBYTE pDriverStrings, /* strings buffer */
2359 DWORD cbBuf, /* size of string buffer */
2360 LPDWORD pcbNeeded, /* space needed for str. */
2361 BOOL unicode) /* type of strings */
2362 { DWORD dw, size, tmp, type;
2364 LPBYTE strPtr = pDriverStrings;
2366 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2367 debugstr_w(DriverName), debugstr_w(pEnvironment),
2368 Level, ptr, pDriverStrings, cbBuf, unicode);
2371 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2372 if (*pcbNeeded <= cbBuf)
2373 strcpyW((LPWSTR)strPtr, DriverName);
2375 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2377 if(*pcbNeeded <= cbBuf)
2378 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2383 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2387 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2388 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2391 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2392 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2393 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2398 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2400 WARN("Can't get Version\n");
2402 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2405 pEnvironment = (LPWSTR)DefaultEnvironmentW;
2407 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2409 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2412 if(*pcbNeeded <= cbBuf) {
2414 strcpyW((LPWSTR)strPtr, pEnvironment);
2416 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2419 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2420 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2423 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2426 if(*pcbNeeded <= cbBuf)
2427 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2430 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2431 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2434 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2437 if(*pcbNeeded <= cbBuf)
2438 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2441 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2442 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2445 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2446 0, &size, unicode)) {
2448 if(*pcbNeeded <= cbBuf)
2449 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2450 size, &tmp, unicode);
2452 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2453 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2457 RegCloseKey(hkeyDriver);
2458 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2462 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2465 if(*pcbNeeded <= cbBuf)
2466 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2467 size, &tmp, unicode);
2469 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2470 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2473 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2476 if(*pcbNeeded <= cbBuf)
2477 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2478 size, &tmp, unicode);
2480 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2481 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2484 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2487 if(*pcbNeeded <= cbBuf)
2488 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2489 size, &tmp, unicode);
2491 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2492 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2495 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2498 if(*pcbNeeded <= cbBuf)
2499 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2500 size, &tmp, unicode);
2502 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2503 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2506 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2507 RegCloseKey(hkeyDriver);
2511 /*****************************************************************************
2512 * WINSPOOL_GetPrinterDriver
2514 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2515 DWORD Level, LPBYTE pDriverInfo,
2516 DWORD cbBuf, LPDWORD pcbNeeded,
2520 WCHAR DriverName[100];
2521 DWORD ret, type, size, needed = 0;
2523 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2525 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2526 Level,pDriverInfo,cbBuf, pcbNeeded);
2528 ZeroMemory(pDriverInfo, cbBuf);
2530 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2532 if(Level < 1 || Level > 3) {
2533 SetLastError(ERROR_INVALID_LEVEL);
2536 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2538 ERR("Can't create Printers key\n");
2541 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2543 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2544 RegCloseKey(hkeyPrinters);
2545 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2548 size = sizeof(DriverName);
2550 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2551 (LPBYTE)DriverName, &size);
2552 RegCloseKey(hkeyPrinter);
2553 RegCloseKey(hkeyPrinters);
2554 if(ret != ERROR_SUCCESS) {
2555 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2559 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2561 ERR("Can't create Drivers key\n");
2567 size = sizeof(DRIVER_INFO_1W);
2570 size = sizeof(DRIVER_INFO_2W);
2573 size = sizeof(DRIVER_INFO_3W);
2576 ERR("Invalid level\n");
2581 ptr = pDriverInfo + size;
2583 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2584 pEnvironment, Level, pDriverInfo,
2585 (cbBuf < size) ? NULL : ptr,
2586 (cbBuf < size) ? 0 : cbBuf - size,
2587 &needed, unicode)) {
2588 RegCloseKey(hkeyDrivers);
2592 RegCloseKey(hkeyDrivers);
2594 if(pcbNeeded) *pcbNeeded = size + needed;
2595 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2596 if(cbBuf >= needed) return TRUE;
2597 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2601 /*****************************************************************************
2602 * GetPrinterDriverA [WINSPOOL.@]
2604 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2605 DWORD Level, LPBYTE pDriverInfo,
2606 DWORD cbBuf, LPDWORD pcbNeeded)
2609 UNICODE_STRING pEnvW;
2612 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2613 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2614 cbBuf, pcbNeeded, FALSE);
2615 RtlFreeUnicodeString(&pEnvW);
2618 /*****************************************************************************
2619 * GetPrinterDriverW [WINSPOOL.@]
2621 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2622 DWORD Level, LPBYTE pDriverInfo,
2623 DWORD cbBuf, LPDWORD pcbNeeded)
2625 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2626 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2629 /*****************************************************************************
2630 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2632 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2633 DWORD Level, LPBYTE pDriverDirectory,
2634 DWORD cbBuf, LPDWORD pcbNeeded)
2638 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2639 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2641 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2642 SetLastError(ERROR_INVALID_PARAMETER);
2645 if(pEnvironment != NULL) {
2646 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2647 SetLastError(ERROR_INVALID_ENVIRONMENT);
2650 if(Level != 1) /* win95 ignores this so we just carry on */
2651 WARN("Level = %ld - assuming 1\n", Level);
2653 /* FIXME should read from registry */
2654 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2655 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2659 needed*=sizeof(WCHAR);
2662 *pcbNeeded = needed;
2663 TRACE("required <%08lx>\n", *pcbNeeded);
2664 if(needed > cbBuf) {
2665 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2672 /*****************************************************************************
2673 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2675 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2676 DWORD Level, LPBYTE pDriverDirectory,
2677 DWORD cbBuf, LPDWORD pcbNeeded)
2679 UNICODE_STRING nameW, environmentW;
2682 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2683 WCHAR *driverDirectoryW = NULL;
2685 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2687 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2688 else nameW.Buffer = NULL;
2689 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2690 else environmentW.Buffer = NULL;
2692 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2693 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2696 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2697 pDriverDirectory, cbBuf, NULL, NULL);
2699 *pcbNeeded = needed;
2700 ret = (needed <= cbBuf) ? TRUE : FALSE;
2702 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2704 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2706 if(driverDirectoryW)
2707 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2708 RtlFreeUnicodeString(&environmentW);
2709 RtlFreeUnicodeString(&nameW);
2714 /*****************************************************************************
2715 * AddPrinterDriverA [WINSPOOL.@]
2717 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2720 HKEY hkeyDrivers, hkeyName;
2722 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2724 if(level != 2 && level != 3) {
2725 SetLastError(ERROR_INVALID_LEVEL);
2729 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2730 SetLastError(ERROR_INVALID_PARAMETER);
2734 WARN("pDriverInfo == NULL\n");
2735 SetLastError(ERROR_INVALID_PARAMETER);
2740 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2742 memset(&di3, 0, sizeof(di3));
2743 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
2746 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2748 SetLastError(ERROR_INVALID_PARAMETER);
2751 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2752 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2753 if(!di3.pHelpFile) di3.pHelpFile = "";
2754 if(!di3.pMonitorName) di3.pMonitorName = "";
2756 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2759 ERR("Can't create Drivers key\n");
2763 if(level == 2) { /* apparently can't overwrite with level2 */
2764 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2765 RegCloseKey(hkeyName);
2766 RegCloseKey(hkeyDrivers);
2767 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2768 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2772 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2773 RegCloseKey(hkeyDrivers);
2774 ERR("Can't create Name key\n");
2777 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2779 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2780 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2781 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2783 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2784 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2785 di3.pDependentFiles, 0);
2786 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2787 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2788 RegCloseKey(hkeyName);
2789 RegCloseKey(hkeyDrivers);
2793 /*****************************************************************************
2794 * AddPrinterDriverW [WINSPOOL.@]
2796 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2799 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2805 /*****************************************************************************
2806 * PrinterProperties [WINSPOOL.@]
2808 * Displays a dialog to set the properties of the printer.
2811 * nonzero on success or zero on failure
2814 * implemented as stub only
2816 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2817 HANDLE hPrinter /* [in] handle to printer object */
2819 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2820 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2824 /*****************************************************************************
2825 * EnumJobsA [WINSPOOL.@]
2828 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2829 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2832 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2833 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2835 if(pcbNeeded) *pcbNeeded = 0;
2836 if(pcReturned) *pcReturned = 0;
2841 /*****************************************************************************
2842 * EnumJobsW [WINSPOOL.@]
2845 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2846 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2849 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2850 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2852 if(pcbNeeded) *pcbNeeded = 0;
2853 if(pcReturned) *pcReturned = 0;
2857 /*****************************************************************************
2858 * WINSPOOL_EnumPrinterDrivers [internal]
2860 * Delivers information about all printer drivers installed on the
2861 * localhost or a given server
2864 * nonzero on success or zero on failure. If the buffer for the returned
2865 * information is too small the function will return an error
2868 * - only implemented for localhost, foreign hosts will return an error
2870 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2871 DWORD Level, LPBYTE pDriverInfo,
2872 DWORD cbBuf, LPDWORD pcbNeeded,
2873 LPDWORD pcReturned, BOOL unicode)
2876 DWORD i, needed, number = 0, size = 0;
2877 WCHAR DriverNameW[255];
2880 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2881 debugstr_w(pName), debugstr_w(pEnvironment),
2882 Level, pDriverInfo, cbBuf, unicode);
2884 /* check for local drivers */
2886 ERR("remote drivers unsupported! Current remote host is %s\n",
2891 /* check input parameter */
2892 if((Level < 1) || (Level > 3)) {
2893 ERR("unsupported level %ld \n", Level);
2897 /* initialize return values */
2899 memset( pDriverInfo, 0, cbBuf);
2903 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2905 ERR("Can't open Drivers key\n");
2909 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2910 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2911 RegCloseKey(hkeyDrivers);
2912 ERR("Can't query Drivers key\n");
2915 TRACE("Found %ld Drivers\n", number);
2917 /* get size of single struct
2918 * unicode and ascii structure have the same size
2922 size = sizeof(DRIVER_INFO_1A);
2925 size = sizeof(DRIVER_INFO_2A);
2928 size = sizeof(DRIVER_INFO_3A);
2932 /* calculate required buffer size */
2933 *pcbNeeded = size * number;
2935 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2937 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2938 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2940 ERR("Can't enum key number %ld\n", i);
2941 RegCloseKey(hkeyDrivers);
2944 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2945 pEnvironment, Level, ptr,
2946 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2947 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2948 &needed, unicode)) {
2949 RegCloseKey(hkeyDrivers);
2952 (*pcbNeeded) += needed;
2955 RegCloseKey(hkeyDrivers);
2957 if(cbBuf < *pcbNeeded){
2958 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2965 /*****************************************************************************
2966 * EnumPrinterDriversW [WINSPOOL.@]
2968 * see function EnumPrinterDrivers for RETURNS, BUGS
2970 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2971 LPBYTE pDriverInfo, DWORD cbBuf,
2972 LPDWORD pcbNeeded, LPDWORD pcReturned)
2974 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2975 cbBuf, pcbNeeded, pcReturned, TRUE);
2978 /*****************************************************************************
2979 * EnumPrinterDriversA [WINSPOOL.@]
2981 * see function EnumPrinterDrivers for RETURNS, BUGS
2983 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2984 LPBYTE pDriverInfo, DWORD cbBuf,
2985 LPDWORD pcbNeeded, LPDWORD pcReturned)
2987 UNICODE_STRING pNameW, pEnvironmentW;
2988 PWSTR pwstrNameW, pwstrEnvironmentW;
2990 pwstrNameW = asciitounicode(&pNameW, pName);
2991 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
2993 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
2994 Level, pDriverInfo, cbBuf, pcbNeeded,
2996 RtlFreeUnicodeString(&pNameW);
2997 RtlFreeUnicodeString(&pEnvironmentW);
3002 static CHAR PortMonitor[] = "Wine Port Monitor";
3003 static CHAR PortDescription[] = "Wine Port";
3005 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3009 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3010 NULL, OPEN_EXISTING, 0, NULL );
3011 if (handle == INVALID_HANDLE_VALUE)
3013 TRACE("Checking %s exists\n", name );
3014 CloseHandle( handle );
3018 static DWORD WINSPOOL_CountSerialPorts()
3025 strcpy( name, "COMx:" );
3027 if (WINSPOOL_ComPortExists( name ))
3034 /******************************************************************************
3035 * EnumPortsA (WINSPOOL.@)
3037 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3038 LPDWORD bufneeded,LPDWORD bufreturned)
3041 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3042 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3046 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3047 name,level,buffer,bufsize,bufneeded,bufreturned);
3052 info_size = sizeof (PORT_INFO_1A);
3055 info_size = sizeof (PORT_INFO_2A);
3058 SetLastError(ERROR_INVALID_LEVEL);
3062 /* see how many exist */
3065 serial_count = WINSPOOL_CountSerialPorts();
3068 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3069 if ( r == ERROR_SUCCESS )
3071 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3072 &printer_count, NULL, NULL, NULL, NULL);
3074 count = serial_count + printer_count;
3076 /* then fill in the structure info structure once
3077 we know the offset to the first string */
3079 memset( buffer, 0, bufsize );
3081 ofs = info_size*count;
3082 for ( i=0; i<count; i++)
3084 DWORD vallen = sizeof(portname) - 1;
3086 /* get the serial port values, then the printer values */
3087 if ( i < serial_count )
3089 strcpy( portname, "COMx:" );
3090 portname[3] = '1' + i;
3091 if (!WINSPOOL_ComPortExists( portname ))
3094 TRACE("Found %s\n", portname );
3095 vallen = strlen( portname );
3099 r = RegEnumValueA( hkey_printer, i-serial_count,
3100 portname, &vallen, NULL, NULL, NULL, 0 );
3105 /* add a colon if necessary, and make it upper case */
3106 CharUpperBuffA(portname,vallen);
3107 if (strcasecmp(portname,"nul")!=0)
3108 if (vallen && (portname[vallen-1] != ':') )
3109 lstrcatA(portname,":");
3111 /* add the port info structure if we can fit it */
3112 if ( info_size*(n+1) < bufsize )
3116 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3117 info->pName = (LPSTR) &buffer[ofs];
3119 else if ( level == 2)
3121 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3122 info->pPortName = (LPSTR) &buffer[ofs];
3123 /* FIXME: fill in more stuff here */
3124 info->pMonitorName = PortMonitor;
3125 info->pDescription = PortDescription;
3126 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3129 /* add the name of the port if we can fit it */
3130 if ( ofs < bufsize )
3131 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3137 ofs += lstrlenA(portname)+1;
3140 RegCloseKey(hkey_printer);
3152 /******************************************************************************
3153 * GetDefaultPrinterW (WINSPOOL.@)
3156 * This function must read the value from data 'device' of key
3157 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3159 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3163 WCHAR *buffer, *ptr;
3167 SetLastError(ERROR_INVALID_PARAMETER);
3171 /* make the buffer big enough for the stuff from the profile/registry,
3172 * the content must fit into the local buffer to compute the correct
3173 * size even if the extern buffer is to small or not given.
3174 * (20 for ,driver,port) */
3176 len = max(100, (insize + 20));
3177 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3179 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3181 SetLastError (ERROR_FILE_NOT_FOUND);
3185 TRACE("%s\n", debugstr_w(buffer));
3187 if ((ptr = strchrW(buffer, ',')) == NULL)
3189 SetLastError(ERROR_INVALID_NAME);
3195 *namesize = strlenW(buffer) + 1;
3196 if(!name || (*namesize > insize))
3198 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3202 strcpyW(name, buffer);
3205 if(buffer) HeapFree( GetProcessHeap(), 0, buffer);
3210 /******************************************************************************
3211 * GetDefaultPrinterA (WINSPOOL.@)
3213 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3217 WCHAR *bufferW = NULL;
3221 SetLastError(ERROR_INVALID_PARAMETER);
3225 if(name && *namesize) {
3227 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3230 if(!GetDefaultPrinterW( bufferW, namesize)) {
3235 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3239 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3242 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3245 if(bufferW) HeapFree( GetProcessHeap(), 0, bufferW);
3250 /******************************************************************************
3251 * SetPrinterDataExA (WINSPOOL.@)
3253 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3254 LPCSTR pValueName, DWORD Type,
3255 LPBYTE pData, DWORD cbData)
3257 HKEY hkeyPrinter, hkeySubkey;
3260 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3261 debugstr_a(pValueName), Type, pData, cbData);
3263 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3267 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3269 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3270 RegCloseKey(hkeyPrinter);
3273 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3274 RegCloseKey(hkeySubkey);
3275 RegCloseKey(hkeyPrinter);
3279 /******************************************************************************
3280 * SetPrinterDataExW (WINSPOOL.@)
3282 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3283 LPCWSTR pValueName, DWORD Type,
3284 LPBYTE pData, DWORD cbData)
3286 HKEY hkeyPrinter, hkeySubkey;
3289 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3290 debugstr_w(pValueName), Type, pData, cbData);
3292 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3296 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3298 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3299 RegCloseKey(hkeyPrinter);
3302 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3303 RegCloseKey(hkeySubkey);
3304 RegCloseKey(hkeyPrinter);
3308 /******************************************************************************
3309 * SetPrinterDataA (WINSPOOL.@)
3311 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3312 LPBYTE pData, DWORD cbData)
3314 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3318 /******************************************************************************
3319 * SetPrinterDataW (WINSPOOL.@)
3321 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3322 LPBYTE pData, DWORD cbData)
3324 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3328 /******************************************************************************
3329 * GetPrinterDataExA (WINSPOOL.@)
3331 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3332 LPCSTR pValueName, LPDWORD pType,
3333 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3335 HKEY hkeyPrinter, hkeySubkey;
3338 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3339 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3342 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3346 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3348 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3349 RegCloseKey(hkeyPrinter);
3353 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3354 RegCloseKey(hkeySubkey);
3355 RegCloseKey(hkeyPrinter);
3359 /******************************************************************************
3360 * GetPrinterDataExW (WINSPOOL.@)
3362 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3363 LPCWSTR pValueName, LPDWORD pType,
3364 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3366 HKEY hkeyPrinter, hkeySubkey;
3369 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3370 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3373 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3377 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3379 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3380 RegCloseKey(hkeyPrinter);
3384 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3385 RegCloseKey(hkeySubkey);
3386 RegCloseKey(hkeyPrinter);
3390 /******************************************************************************
3391 * GetPrinterDataA (WINSPOOL.@)
3393 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3394 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3396 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3397 pData, nSize, pcbNeeded);
3400 /******************************************************************************
3401 * GetPrinterDataW (WINSPOOL.@)
3403 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3404 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3406 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3407 pData, nSize, pcbNeeded);
3410 /*******************************************************************************
3411 * EnumPrinterDataExW [WINSPOOL.@]
3413 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3414 LPBYTE pEnumValues, DWORD cbEnumValues,
3415 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3417 HKEY hkPrinter, hkSubKey;
3418 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3419 cbValueNameLen, cbMaxValueLen, cbValueLen,
3424 PPRINTER_ENUM_VALUESW ppev;
3426 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3428 if (pKeyName == NULL || *pKeyName == 0)
3429 return ERROR_INVALID_PARAMETER;
3431 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3432 if (ret != ERROR_SUCCESS)
3434 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3439 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3440 if (ret != ERROR_SUCCESS)
3442 r = RegCloseKey (hkPrinter);
3443 if (r != ERROR_SUCCESS)
3444 WARN ("RegCloseKey returned %li\n", r);
3445 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3446 debugstr_w (pKeyName), ret);
3450 ret = RegCloseKey (hkPrinter);
3451 if (ret != ERROR_SUCCESS)
3453 ERR ("RegCloseKey returned %li\n", ret);
3454 r = RegCloseKey (hkSubKey);
3455 if (r != ERROR_SUCCESS)
3456 WARN ("RegCloseKey returned %li\n", r);
3460 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3461 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3462 if (ret != ERROR_SUCCESS)
3464 r = RegCloseKey (hkSubKey);
3465 if (r != ERROR_SUCCESS)
3466 WARN ("RegCloseKey returned %li\n", r);
3467 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3471 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3472 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3474 if (cValues == 0) /* empty key */
3476 r = RegCloseKey (hkSubKey);
3477 if (r != ERROR_SUCCESS)
3478 WARN ("RegCloseKey returned %li\n", r);
3479 *pcbEnumValues = *pnEnumValues = 0;
3480 return ERROR_SUCCESS;
3483 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3485 hHeap = GetProcessHeap ();
3488 ERR ("GetProcessHeap failed\n");
3489 r = RegCloseKey (hkSubKey);
3490 if (r != ERROR_SUCCESS)
3491 WARN ("RegCloseKey returned %li\n", r);
3492 return ERROR_OUTOFMEMORY;
3495 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3496 if (lpValueName == NULL)
3498 ERR ("Failed to allocate %li bytes from process heap\n",
3499 cbMaxValueNameLen * sizeof (WCHAR));
3500 r = RegCloseKey (hkSubKey);
3501 if (r != ERROR_SUCCESS)
3502 WARN ("RegCloseKey returned %li\n", r);
3503 return ERROR_OUTOFMEMORY;
3506 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3507 if (lpValue == NULL)
3509 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3510 if (HeapFree (hHeap, 0, lpValueName) == 0)
3511 WARN ("HeapFree failed with code %li\n", GetLastError ());
3512 r = RegCloseKey (hkSubKey);
3513 if (r != ERROR_SUCCESS)
3514 WARN ("RegCloseKey returned %li\n", r);
3515 return ERROR_OUTOFMEMORY;
3518 TRACE ("pass 1: calculating buffer required for all names and values\n");
3520 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3522 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3524 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3526 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3527 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3528 NULL, NULL, lpValue, &cbValueLen);
3529 if (ret != ERROR_SUCCESS)
3531 if (HeapFree (hHeap, 0, lpValue) == 0)
3532 WARN ("HeapFree failed with code %li\n", GetLastError ());
3533 if (HeapFree (hHeap, 0, lpValueName) == 0)
3534 WARN ("HeapFree failed with code %li\n", GetLastError ());
3535 r = RegCloseKey (hkSubKey);
3536 if (r != ERROR_SUCCESS)
3537 WARN ("RegCloseKey returned %li\n", r);
3538 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3542 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3543 debugstr_w (lpValueName), dwIndex,
3544 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3546 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3547 cbBufSize += cbValueLen;
3550 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3552 *pcbEnumValues = cbBufSize;
3553 *pnEnumValues = cValues;
3555 if (cbEnumValues < cbBufSize) /* buffer too small */
3557 if (HeapFree (hHeap, 0, lpValue) == 0)
3558 WARN ("HeapFree failed with code %li\n", GetLastError ());
3559 if (HeapFree (hHeap, 0, lpValueName) == 0)
3560 WARN ("HeapFree failed with code %li\n", GetLastError ());
3561 r = RegCloseKey (hkSubKey);
3562 if (r != ERROR_SUCCESS)
3563 WARN ("RegCloseKey returned %li\n", r);
3564 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3565 return ERROR_MORE_DATA;
3568 TRACE ("pass 2: copying all names and values to buffer\n");
3570 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3571 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3573 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3575 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3576 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3577 NULL, &dwType, lpValue, &cbValueLen);
3578 if (ret != ERROR_SUCCESS)
3580 if (HeapFree (hHeap, 0, lpValue) == 0)
3581 WARN ("HeapFree failed with code %li\n", GetLastError ());
3582 if (HeapFree (hHeap, 0, lpValueName) == 0)
3583 WARN ("HeapFree failed with code %li\n", GetLastError ());
3584 r = RegCloseKey (hkSubKey);
3585 if (r != ERROR_SUCCESS)
3586 WARN ("RegCloseKey returned %li\n", r);
3587 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3591 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3592 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3593 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3594 pEnumValues += cbValueNameLen;
3596 /* return # of *bytes* (including trailing \0), not # of chars */
3597 ppev[dwIndex].cbValueName = cbValueNameLen;
3599 ppev[dwIndex].dwType = dwType;
3601 memcpy (pEnumValues, lpValue, cbValueLen);
3602 ppev[dwIndex].pData = pEnumValues;
3603 pEnumValues += cbValueLen;
3605 ppev[dwIndex].cbData = cbValueLen;
3607 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3608 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3611 if (HeapFree (hHeap, 0, lpValue) == 0)
3613 ret = GetLastError ();
3614 ERR ("HeapFree failed with code %li\n", ret);
3615 if (HeapFree (hHeap, 0, lpValueName) == 0)
3616 WARN ("HeapFree failed with code %li\n", GetLastError ());
3617 r = RegCloseKey (hkSubKey);
3618 if (r != ERROR_SUCCESS)
3619 WARN ("RegCloseKey returned %li\n", r);
3623 if (HeapFree (hHeap, 0, lpValueName) == 0)
3625 ret = GetLastError ();
3626 ERR ("HeapFree failed with code %li\n", ret);
3627 r = RegCloseKey (hkSubKey);
3628 if (r != ERROR_SUCCESS)
3629 WARN ("RegCloseKey returned %li\n", r);
3633 ret = RegCloseKey (hkSubKey);
3634 if (ret != ERROR_SUCCESS)
3636 ERR ("RegCloseKey returned %li\n", ret);
3640 return ERROR_SUCCESS;
3643 /*******************************************************************************
3644 * EnumPrinterDataExA [WINSPOOL.@]
3646 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3647 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3648 * what Windows 2000 SP1 does.
3651 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3652 LPBYTE pEnumValues, DWORD cbEnumValues,
3653 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3657 DWORD ret, dwIndex, dwBufSize;
3661 TRACE ("%p %s\n", hPrinter, pKeyName);
3663 if (pKeyName == NULL || *pKeyName == 0)
3664 return ERROR_INVALID_PARAMETER;
3666 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3669 ret = GetLastError ();
3670 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3674 hHeap = GetProcessHeap ();
3677 ERR ("GetProcessHeap failed\n");
3678 return ERROR_OUTOFMEMORY;
3681 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3682 if (pKeyNameW == NULL)
3684 ERR ("Failed to allocate %li bytes from process heap\n",
3685 (LONG) len * sizeof (WCHAR));
3686 return ERROR_OUTOFMEMORY;
3689 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3691 ret = GetLastError ();
3692 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3693 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3694 WARN ("HeapFree failed with code %li\n", GetLastError ());
3698 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3699 pcbEnumValues, pnEnumValues);
3700 if (ret != ERROR_SUCCESS)
3702 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3703 WARN ("HeapFree failed with code %li\n", GetLastError ());
3704 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3708 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3710 ret = GetLastError ();
3711 ERR ("HeapFree failed with code %li\n", ret);
3715 if (*pnEnumValues == 0) /* empty key */
3716 return ERROR_SUCCESS;
3719 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3721 PPRINTER_ENUM_VALUESW ppev =
3722 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3724 if (dwBufSize < ppev->cbValueName)
3725 dwBufSize = ppev->cbValueName;
3727 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3728 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3729 dwBufSize = ppev->cbData;
3732 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3734 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3735 if (pBuffer == NULL)
3737 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3738 return ERROR_OUTOFMEMORY;
3741 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3743 PPRINTER_ENUM_VALUESW ppev =
3744 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3746 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3747 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3751 ret = GetLastError ();
3752 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3753 if (HeapFree (hHeap, 0, pBuffer) == 0)
3754 WARN ("HeapFree failed with code %li\n", GetLastError ());
3758 memcpy (ppev->pValueName, pBuffer, len);
3760 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3762 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3763 ppev->dwType != REG_MULTI_SZ)
3766 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3767 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3770 ret = GetLastError ();
3771 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3772 if (HeapFree (hHeap, 0, pBuffer) == 0)
3773 WARN ("HeapFree failed with code %li\n", GetLastError ());
3777 memcpy (ppev->pData, pBuffer, len);
3779 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3780 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3783 if (HeapFree (hHeap, 0, pBuffer) == 0)
3785 ret = GetLastError ();
3786 ERR ("HeapFree failed with code %li\n", ret);
3790 return ERROR_SUCCESS;
3793 /******************************************************************************
3794 * AddPortA (WINSPOOL.@)
3796 BOOL WINAPI AddPortA(LPSTR pName ,HWND hWnd, LPSTR pMonitorName)
3798 FIXME("(%s, %p, %s\n), stub!\n",pName,hWnd,pMonitorName);
3802 /******************************************************************************
3803 * AddPrinterDriverExW (WINSPOOL.@)
3805 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
3806 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3808 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
3809 Level, pDriverInfo, dwFileCopyFlags);
3810 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3814 /******************************************************************************
3815 * AddPrinterDriverExA (WINSPOOL.@)
3817 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
3818 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
3820 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
3821 Level, pDriverInfo, dwFileCopyFlags);
3822 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
3826 /******************************************************************************
3827 * DeletePrinterDriverExW (WINSPOOL.@)
3829 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
3830 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3832 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
3833 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
3837 /******************************************************************************
3838 * DeletePrinterDriverExA (WINSPOOL.@)
3840 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
3841 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
3843 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
3844 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
3848 /******************************************************************************
3849 * DeletePrinterDataExW (WINSPOOL.@)
3851 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
3854 FIXME("%p %s %s\n", hPrinter,
3855 debugstr_w(pKeyName), debugstr_w(pValueName));
3856 return ERROR_INVALID_PARAMETER;
3859 /******************************************************************************
3860 * DeletePrinterDataExA (WINSPOOL.@)
3862 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
3865 FIXME("%p %s %s\n", hPrinter,
3866 debugstr_a(pKeyName), debugstr_a(pValueName));
3867 return ERROR_INVALID_PARAMETER;
3870 /*****************************************************************************
3871 * EnumMonitorsA [WINSPOOL.@]
3874 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
3875 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
3877 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
3878 cbBuf, pcbNeeded, pcReturned);
3879 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3883 /*****************************************************************************
3884 * EnumMonitorsW [WINSPOOL.@]
3887 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
3888 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
3890 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
3891 cbBuf, pcbNeeded, pcReturned);
3892 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3896 /******************************************************************************
3897 * XcvDataW (WINSPOOL.@)
3900 * There doesn't seem to be an A version...
3902 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
3903 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
3904 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
3906 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
3907 pInputData, cbInputData, pOutputData,
3908 cbOutputData, pcbOutputNeeded, pdwStatus);
3913 /*****************************************************************************
3914 * EnumPrintProcessorsA [WINSPOOL.@]
3917 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3918 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
3920 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
3921 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
3925 /*****************************************************************************
3926 * EnumPrintProcessorsW [WINSPOOL.@]
3929 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3930 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
3932 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
3933 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
3934 cbBuf, pcbNeeded, pcbReturned);