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, (const BYTE*)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 = (const char *)dmA->dmFormName - (const 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, (const 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 = (const char *)dmW->dmFormName - (const 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, (const 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,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
961 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
965 /******************************************************************************
966 * AddMonitorW [WINSPOOL.@]
968 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
970 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
971 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
975 /******************************************************************
976 * DeletePrinterDriverA [WINSPOOL.@]
980 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
982 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
983 debugstr_a(pDriverName));
984 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
988 /******************************************************************
989 * DeletePrinterDriverW [WINSPOOL.@]
993 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
995 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
996 debugstr_w(pDriverName));
997 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1001 /******************************************************************
1002 * DeleteMonitorA [WINSPOOL.@]
1006 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1008 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1009 debugstr_a(pMonitorName));
1010 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1014 /******************************************************************
1015 * DeleteMonitorW [WINSPOOL.@]
1019 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1021 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1022 debugstr_w(pMonitorName));
1023 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1027 /******************************************************************
1028 * DeletePortA [WINSPOOL.@]
1032 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1034 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1035 debugstr_a(pPortName));
1036 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1040 /******************************************************************
1041 * DeletePortW [WINSPOOL.@]
1045 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1047 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1048 debugstr_w(pPortName));
1049 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1053 /******************************************************************************
1054 * SetPrinterW [WINSPOOL.@]
1064 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1068 /******************************************************************************
1069 * WritePrinter [WINSPOOL.@]
1076 LPDWORD pcWritten) {
1079 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1083 /*****************************************************************************
1084 * AddFormA [WINSPOOL.@]
1086 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1088 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1092 /*****************************************************************************
1093 * AddFormW [WINSPOOL.@]
1095 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1097 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1101 /*****************************************************************************
1102 * AddJobA [WINSPOOL.@]
1104 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
1105 DWORD cbBuf, LPDWORD pcbNeeded)
1107 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1112 /*****************************************************************************
1113 * AddJobW [WINSPOOL.@]
1115 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
1118 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1123 /*****************************************************************************
1124 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1126 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1127 DWORD level, LPBYTE Info,
1128 DWORD cbBuf, LPDWORD needed)
1130 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1131 level, Info, cbBuf);
1135 /*****************************************************************************
1136 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1138 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1139 DWORD level, LPBYTE Info,
1140 DWORD cbBuf, LPDWORD needed)
1142 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1143 level, Info, cbBuf);
1147 /*****************************************************************************
1148 * WINSPOOL_OpenDriverReg [internal]
1150 * opens the registry for the printer drivers depending on the given input
1151 * variable pEnvironment
1154 * the opened hkey on success
1157 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1159 LPSTR lpKey, p = NULL;
1162 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1165 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
1169 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1171 if(!GetVersionExA( &ver))
1174 switch (ver.dwPlatformId) {
1175 case VER_PLATFORM_WIN32s:
1176 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1179 case VER_PLATFORM_WIN32_NT:
1180 p = "Windows NT x86";
1186 TRACE("set environment to %s\n", p);
1189 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1190 strlen(p) + strlen(Drivers));
1191 sprintf( lpKey, Drivers, p);
1193 TRACE("%s\n", lpKey);
1195 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
1199 if(pEnvironment && unicode)
1200 HeapFree( GetProcessHeap(), 0, p);
1201 HeapFree( GetProcessHeap(), 0, lpKey);
1206 /*****************************************************************************
1207 * AddPrinterW [WINSPOOL.@]
1209 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1211 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1215 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1218 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1221 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1222 SetLastError(ERROR_INVALID_PARAMETER);
1226 ERR("Level = %ld, unsupported!\n", Level);
1227 SetLastError(ERROR_INVALID_LEVEL);
1230 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1231 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1232 debugstr_w(pi->pPrinterName)
1234 SetLastError(ERROR_INVALID_LEVEL);
1238 SetLastError(ERROR_INVALID_PARAMETER);
1241 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1243 ERR("Can't create Printers key\n");
1246 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1247 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1248 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1249 RegCloseKey(hkeyPrinter);
1250 RegCloseKey(hkeyPrinters);
1253 RegCloseKey(hkeyPrinter);
1255 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1257 ERR("Can't create Drivers key\n");
1258 RegCloseKey(hkeyPrinters);
1261 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1263 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1264 RegCloseKey(hkeyPrinters);
1265 RegCloseKey(hkeyDrivers);
1266 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1269 RegCloseKey(hkeyDriver);
1270 RegCloseKey(hkeyDrivers);
1272 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1273 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1274 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1275 RegCloseKey(hkeyPrinters);
1279 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1281 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1282 SetLastError(ERROR_INVALID_PRINTER_NAME);
1283 RegCloseKey(hkeyPrinters);
1286 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1287 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1288 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1290 /* See if we can load the driver. We may need the devmode structure anyway
1293 * Note that DocumentPropertiesW will briefly try to open the printer we
1294 * just create to find a DEVMODEA struct (it will use the WINEPS default
1295 * one in case it is not there, so we are ok).
1297 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1300 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1301 size = sizeof(DEVMODEW);
1307 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1308 ZeroMemory(dmW,size);
1310 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1312 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1313 HeapFree(GetProcessHeap(),0,dmW);
1318 /* set devmode to printer name */
1319 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1323 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1324 and we support these drivers. NT writes DEVMODEW so somehow
1325 we'll need to distinguish between these when we support NT
1329 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1330 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1331 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1332 HeapFree(GetProcessHeap(), 0, dmA);
1334 HeapFree(GetProcessHeap(), 0, dmW);
1336 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1337 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1338 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1339 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1341 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1342 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1343 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1344 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1345 (LPBYTE)&pi->Priority, sizeof(DWORD));
1346 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1347 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1348 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1349 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1350 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1351 (LPBYTE)&pi->Status, sizeof(DWORD));
1352 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1353 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1355 RegCloseKey(hkeyPrinter);
1356 RegCloseKey(hkeyPrinters);
1357 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1358 ERR("OpenPrinter failing\n");
1364 /*****************************************************************************
1365 * AddPrinterA [WINSPOOL.@]
1367 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1369 UNICODE_STRING pNameW;
1371 PRINTER_INFO_2W *piW;
1372 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1375 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1377 ERR("Level = %ld, unsupported!\n", Level);
1378 SetLastError(ERROR_INVALID_LEVEL);
1381 pwstrNameW = asciitounicode(&pNameW,pName);
1382 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1384 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1386 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1387 RtlFreeUnicodeString(&pNameW);
1392 /*****************************************************************************
1393 * ClosePrinter [WINSPOOL.@]
1395 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1397 int i = (int)hPrinter;
1399 TRACE("Handle %p\n", hPrinter);
1401 if ((i <= 0) || (i > nb_printers)) return FALSE;
1402 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1403 printer_array[i - 1] = NULL;
1407 /*****************************************************************************
1408 * DeleteFormA [WINSPOOL.@]
1410 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1412 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1416 /*****************************************************************************
1417 * DeleteFormW [WINSPOOL.@]
1419 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1421 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1425 /*****************************************************************************
1426 * WINSPOOL_SHRegDeleteKey
1428 * Recursively delete subkeys.
1429 * Cut & paste from shlwapi.
1432 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1434 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1435 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1438 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1441 /* Find how many subkeys there are */
1442 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1443 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1447 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1448 /* Name too big: alloc a buffer for it */
1449 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1452 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1455 /* Recursively delete all the subkeys */
1456 for(i = 0; i < dwKeyCount && !dwRet; i++)
1458 dwSize = dwMaxSubkeyLen;
1459 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1461 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1464 if (lpszName != szNameBuf)
1465 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1469 RegCloseKey(hSubKey);
1471 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1476 /*****************************************************************************
1477 * DeletePrinter [WINSPOOL.@]
1479 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1481 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1484 if(!lpNameW) return FALSE;
1485 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1486 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1487 RegCloseKey(hkeyPrinters);
1489 WriteProfileStringW(devicesW, lpNameW, NULL);
1493 /*****************************************************************************
1494 * SetPrinterA [WINSPOOL.@]
1496 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1499 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1503 /*****************************************************************************
1504 * SetJobA [WINSPOOL.@]
1506 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1507 LPBYTE pJob, DWORD Command)
1509 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1514 /*****************************************************************************
1515 * SetJobW [WINSPOOL.@]
1517 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1518 LPBYTE pJob, DWORD Command)
1520 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1525 /*****************************************************************************
1526 * EndDocPrinter [WINSPOOL.@]
1528 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1530 FIXME("(hPrinter=%p): stub\n", hPrinter);
1534 /*****************************************************************************
1535 * EndPagePrinter [WINSPOOL.@]
1537 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1539 FIXME("(hPrinter=%p): stub\n", hPrinter);
1543 /*****************************************************************************
1544 * StartDocPrinterA [WINSPOOL.@]
1546 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1548 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1552 /*****************************************************************************
1553 * StartDocPrinterW [WINSPOOL.@]
1555 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1557 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1561 /*****************************************************************************
1562 * StartPagePrinter [WINSPOOL.@]
1564 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1566 FIXME("(hPrinter=%p): stub\n", hPrinter);
1570 /*****************************************************************************
1571 * GetFormA [WINSPOOL.@]
1573 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1574 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1576 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1577 Level,pForm,cbBuf,pcbNeeded);
1581 /*****************************************************************************
1582 * GetFormW [WINSPOOL.@]
1584 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1585 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1587 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1588 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1592 /*****************************************************************************
1593 * SetFormA [WINSPOOL.@]
1595 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1598 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1602 /*****************************************************************************
1603 * SetFormW [WINSPOOL.@]
1605 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1608 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1612 /*****************************************************************************
1613 * ReadPrinter [WINSPOOL.@]
1615 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1616 LPDWORD pNoBytesRead)
1618 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1622 /*****************************************************************************
1623 * ResetPrinterA [WINSPOOL.@]
1625 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1627 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1631 /*****************************************************************************
1632 * ResetPrinterW [WINSPOOL.@]
1634 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1636 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1640 /*****************************************************************************
1641 * WINSPOOL_GetDWORDFromReg
1643 * Return DWORD associated with ValueName from hkey.
1645 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1647 DWORD sz = sizeof(DWORD), type, value = 0;
1650 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1652 if(ret != ERROR_SUCCESS) {
1653 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1656 if(type != REG_DWORD) {
1657 ERR("Got type %ld\n", type);
1663 /*****************************************************************************
1664 * WINSPOOL_GetStringFromReg
1666 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1667 * String is stored either as unicode or ascii.
1668 * Bit of a hack here to get the ValueName if we want ascii.
1670 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1671 DWORD buflen, DWORD *needed,
1674 DWORD sz = buflen, type;
1678 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1680 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1681 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1682 HeapFree(GetProcessHeap(),0,ValueNameA);
1684 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1685 WARN("Got ret = %ld\n", ret);
1693 /*****************************************************************************
1694 * WINSPOOL_GetDefaultDevMode
1696 * Get a default DevMode values for wineps.
1700 static void WINSPOOL_GetDefaultDevMode(
1702 DWORD buflen, DWORD *needed,
1707 /* fill default DEVMODE - should be read from ppd... */
1708 ZeroMemory( &dm, sizeof(dm) );
1709 strcpy(dm.dmDeviceName,"wineps");
1710 dm.dmSpecVersion = DM_SPECVERSION;
1711 dm.dmDriverVersion = 1;
1712 dm.dmSize = sizeof(DEVMODEA);
1713 dm.dmDriverExtra = 0;
1715 DM_ORIENTATION | DM_PAPERSIZE |
1716 DM_PAPERLENGTH | DM_PAPERWIDTH |
1719 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1720 DM_YRESOLUTION | DM_TTOPTION;
1722 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1723 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1724 dm.u1.s1.dmPaperLength = 2970;
1725 dm.u1.s1.dmPaperWidth = 2100;
1729 dm.dmDefaultSource = DMBIN_AUTO;
1730 dm.dmPrintQuality = DMRES_MEDIUM;
1733 dm.dmYResolution = 300; /* 300dpi */
1734 dm.dmTTOption = DMTT_BITMAP;
1737 /* dm.dmLogPixels */
1738 /* dm.dmBitsPerPel */
1739 /* dm.dmPelsWidth */
1740 /* dm.dmPelsHeight */
1741 /* dm.dmDisplayFlags */
1742 /* dm.dmDisplayFrequency */
1743 /* dm.dmICMMethod */
1744 /* dm.dmICMIntent */
1745 /* dm.dmMediaType */
1746 /* dm.dmDitherType */
1747 /* dm.dmReserved1 */
1748 /* dm.dmReserved2 */
1749 /* dm.dmPanningWidth */
1750 /* dm.dmPanningHeight */
1753 if(buflen >= sizeof(DEVMODEW)) {
1754 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1755 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1756 HeapFree(GetProcessHeap(),0,pdmW);
1758 *needed = sizeof(DEVMODEW);
1762 if(buflen >= sizeof(DEVMODEA)) {
1763 memcpy(ptr, &dm, sizeof(DEVMODEA));
1765 *needed = sizeof(DEVMODEA);
1769 /*****************************************************************************
1770 * WINSPOOL_GetDevModeFromReg
1772 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1773 * DevMode is stored either as unicode or ascii.
1775 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1777 DWORD buflen, DWORD *needed,
1780 DWORD sz = buflen, type;
1783 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1784 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1785 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1786 if (sz < sizeof(DEVMODEA))
1788 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1791 /* ensures that dmSize is not erratically bogus if registry is invalid */
1792 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1793 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1795 sz += (CCHDEVICENAME + CCHFORMNAME);
1797 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1798 memcpy(ptr, dmW, sz);
1799 HeapFree(GetProcessHeap(),0,dmW);
1806 /*********************************************************************
1807 * WINSPOOL_GetPrinter_2
1809 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1810 * The strings are either stored as unicode or ascii.
1812 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1813 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1816 DWORD size, left = cbBuf;
1817 BOOL space = (cbBuf > 0);
1822 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1824 if(space && size <= left) {
1825 pi2->pPrinterName = (LPWSTR)ptr;
1832 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1834 if(space && size <= left) {
1835 pi2->pShareName = (LPWSTR)ptr;
1842 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1844 if(space && size <= left) {
1845 pi2->pPortName = (LPWSTR)ptr;
1852 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1854 if(space && size <= left) {
1855 pi2->pDriverName = (LPWSTR)ptr;
1862 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1864 if(space && size <= left) {
1865 pi2->pComment = (LPWSTR)ptr;
1872 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1874 if(space && size <= left) {
1875 pi2->pLocation = (LPWSTR)ptr;
1882 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1884 if(space && size <= left) {
1885 pi2->pDevMode = (LPDEVMODEW)ptr;
1894 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1895 if(space && size <= left) {
1896 pi2->pDevMode = (LPDEVMODEW)ptr;
1903 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1905 if(space && size <= left) {
1906 pi2->pSepFile = (LPWSTR)ptr;
1913 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1915 if(space && size <= left) {
1916 pi2->pPrintProcessor = (LPWSTR)ptr;
1923 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1925 if(space && size <= left) {
1926 pi2->pDatatype = (LPWSTR)ptr;
1933 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1935 if(space && size <= left) {
1936 pi2->pParameters = (LPWSTR)ptr;
1944 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1945 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1946 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1947 "Default Priority");
1948 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1949 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1952 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1953 memset(pi2, 0, sizeof(*pi2));
1958 /*********************************************************************
1959 * WINSPOOL_GetPrinter_4
1961 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1963 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1964 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1967 DWORD size, left = cbBuf;
1968 BOOL space = (cbBuf > 0);
1973 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1975 if(space && size <= left) {
1976 pi4->pPrinterName = (LPWSTR)ptr;
1984 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1987 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1988 memset(pi4, 0, sizeof(*pi4));
1993 /*********************************************************************
1994 * WINSPOOL_GetPrinter_5
1996 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1998 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1999 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2002 DWORD size, left = cbBuf;
2003 BOOL space = (cbBuf > 0);
2008 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2010 if(space && size <= left) {
2011 pi5->pPrinterName = (LPWSTR)ptr;
2018 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2020 if(space && size <= left) {
2021 pi5->pPortName = (LPWSTR)ptr;
2029 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2030 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2032 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2036 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2037 memset(pi5, 0, sizeof(*pi5));
2042 /*****************************************************************************
2043 * WINSPOOL_GetPrinter
2045 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2046 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2047 * just a collection of pointers to strings.
2049 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2050 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2053 DWORD size, needed = 0;
2055 HKEY hkeyPrinter, hkeyPrinters;
2058 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2060 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2062 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2064 ERR("Can't create Printers key\n");
2067 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2069 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2070 RegCloseKey(hkeyPrinters);
2071 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2078 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2080 size = sizeof(PRINTER_INFO_2W);
2082 ptr = pPrinter + size;
2084 memset(pPrinter, 0, size);
2089 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2097 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2099 size = sizeof(PRINTER_INFO_4W);
2101 ptr = pPrinter + size;
2103 memset(pPrinter, 0, size);
2108 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2117 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2119 size = sizeof(PRINTER_INFO_5W);
2121 ptr = pPrinter + size;
2123 memset(pPrinter, 0, size);
2129 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2136 FIXME("Unimplemented level %ld\n", Level);
2137 SetLastError(ERROR_INVALID_LEVEL);
2138 RegCloseKey(hkeyPrinters);
2139 RegCloseKey(hkeyPrinter);
2143 RegCloseKey(hkeyPrinter);
2144 RegCloseKey(hkeyPrinters);
2146 TRACE("returning %d needed = %ld\n", ret, needed);
2147 if(pcbNeeded) *pcbNeeded = needed;
2149 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2153 /*****************************************************************************
2154 * GetPrinterW [WINSPOOL.@]
2156 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2157 DWORD cbBuf, LPDWORD pcbNeeded)
2159 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2163 /*****************************************************************************
2164 * GetPrinterA [WINSPOOL.@]
2166 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2167 DWORD cbBuf, LPDWORD pcbNeeded)
2169 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2173 /*****************************************************************************
2174 * WINSPOOL_EnumPrinters
2176 * Implementation of EnumPrintersA|W
2178 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2179 DWORD dwLevel, LPBYTE lpbPrinters,
2180 DWORD cbBuf, LPDWORD lpdwNeeded,
2181 LPDWORD lpdwReturned, BOOL unicode)
2184 HKEY hkeyPrinters, hkeyPrinter;
2185 WCHAR PrinterName[255];
2186 DWORD needed = 0, number = 0;
2187 DWORD used, i, left;
2191 memset(lpbPrinters, 0, cbBuf);
2197 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2198 if(dwType == PRINTER_ENUM_DEFAULT)
2201 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2202 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2203 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2204 if(!dwType) return TRUE;
2207 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2208 FIXME("dwType = %08lx\n", dwType);
2209 SetLastError(ERROR_INVALID_FLAGS);
2213 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2215 ERR("Can't create Printers key\n");
2219 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2220 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2221 RegCloseKey(hkeyPrinters);
2222 ERR("Can't query Printers key\n");
2225 TRACE("Found %ld printers\n", number);
2229 RegCloseKey(hkeyPrinters);
2231 *lpdwReturned = number;
2235 used = number * sizeof(PRINTER_INFO_2W);
2238 used = number * sizeof(PRINTER_INFO_4W);
2241 used = number * sizeof(PRINTER_INFO_5W);
2245 SetLastError(ERROR_INVALID_LEVEL);
2246 RegCloseKey(hkeyPrinters);
2249 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2251 for(i = 0; i < number; i++) {
2252 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2254 ERR("Can't enum key number %ld\n", i);
2255 RegCloseKey(hkeyPrinters);
2258 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2259 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2261 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2262 RegCloseKey(hkeyPrinters);
2267 buf = lpbPrinters + used;
2268 left = cbBuf - used;
2276 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2277 left, &needed, unicode);
2279 if(pi) pi += sizeof(PRINTER_INFO_2W);
2282 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2283 left, &needed, unicode);
2285 if(pi) pi += sizeof(PRINTER_INFO_4W);
2288 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2289 left, &needed, unicode);
2291 if(pi) pi += sizeof(PRINTER_INFO_5W);
2294 ERR("Shouldn't be here!\n");
2295 RegCloseKey(hkeyPrinter);
2296 RegCloseKey(hkeyPrinters);
2299 RegCloseKey(hkeyPrinter);
2301 RegCloseKey(hkeyPrinters);
2308 memset(lpbPrinters, 0, cbBuf);
2309 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2313 *lpdwReturned = number;
2314 SetLastError(ERROR_SUCCESS);
2319 /******************************************************************
2320 * EnumPrintersW [WINSPOOL.@]
2322 * Enumerates the available printers, print servers and print
2323 * providers, depending on the specified flags, name and level.
2327 * If level is set to 1:
2328 * Not implemented yet!
2329 * Returns TRUE with an empty list.
2331 * If level is set to 2:
2332 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2333 * Returns an array of PRINTER_INFO_2 data structures in the
2334 * lpbPrinters buffer. Note that according to MSDN also an
2335 * OpenPrinter should be performed on every remote printer.
2337 * If level is set to 4 (officially WinNT only):
2338 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2339 * Fast: Only the registry is queried to retrieve printer names,
2340 * no connection to the driver is made.
2341 * Returns an array of PRINTER_INFO_4 data structures in the
2342 * lpbPrinters buffer.
2344 * If level is set to 5 (officially WinNT4/Win9x only):
2345 * Fast: Only the registry is queried to retrieve printer names,
2346 * no connection to the driver is made.
2347 * Returns an array of PRINTER_INFO_5 data structures in the
2348 * lpbPrinters buffer.
2350 * If level set to 3 or 6+:
2351 * returns zero (failure!)
2353 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2357 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2358 * - Only levels 2, 4 and 5 are implemented at the moment.
2359 * - 16-bit printer drivers are not enumerated.
2360 * - Returned amount of bytes used/needed does not match the real Windoze
2361 * implementation (as in this implementation, all strings are part
2362 * of the buffer, whereas Win32 keeps them somewhere else)
2363 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2366 * - In a regular Wine installation, no registry settings for printers
2367 * exist, which makes this function return an empty list.
2369 BOOL WINAPI EnumPrintersW(
2370 DWORD dwType, /* [in] Types of print objects to enumerate */
2371 LPWSTR lpszName, /* [in] name of objects to enumerate */
2372 DWORD dwLevel, /* [in] type of printer info structure */
2373 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2374 DWORD cbBuf, /* [in] max size of buffer in bytes */
2375 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2376 LPDWORD lpdwReturned /* [out] number of entries returned */
2379 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2380 lpdwNeeded, lpdwReturned, TRUE);
2383 /******************************************************************
2384 * EnumPrintersA [WINSPOOL.@]
2387 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2388 DWORD dwLevel, LPBYTE lpbPrinters,
2389 DWORD cbBuf, LPDWORD lpdwNeeded,
2390 LPDWORD lpdwReturned)
2393 UNICODE_STRING lpszNameW;
2396 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2397 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2398 lpdwNeeded, lpdwReturned, FALSE);
2399 RtlFreeUnicodeString(&lpszNameW);
2403 /*****************************************************************************
2404 * WINSPOOL_GetDriverInfoFromReg [internal]
2406 * Enters the information from the registry into the DRIVER_INFO struct
2409 * zero if the printer driver does not exist in the registry
2410 * (only if Level > 1) otherwise nonzero
2412 static BOOL WINSPOOL_GetDriverInfoFromReg(
2415 LPWSTR pEnvironment,
2417 LPBYTE ptr, /* DRIVER_INFO */
2418 LPBYTE pDriverStrings, /* strings buffer */
2419 DWORD cbBuf, /* size of string buffer */
2420 LPDWORD pcbNeeded, /* space needed for str. */
2421 BOOL unicode) /* type of strings */
2422 { DWORD dw, size, tmp, type;
2424 LPBYTE strPtr = pDriverStrings;
2426 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2427 debugstr_w(DriverName), debugstr_w(pEnvironment),
2428 Level, ptr, pDriverStrings, cbBuf, unicode);
2431 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2432 if (*pcbNeeded <= cbBuf)
2433 strcpyW((LPWSTR)strPtr, DriverName);
2435 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2437 if(*pcbNeeded <= cbBuf)
2438 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2443 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2447 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2448 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2451 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2452 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2453 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2458 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2460 WARN("Can't get Version\n");
2462 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2465 pEnvironment = (LPWSTR)DefaultEnvironmentW;
2467 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2469 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2472 if(*pcbNeeded <= cbBuf) {
2474 strcpyW((LPWSTR)strPtr, pEnvironment);
2476 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2479 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2480 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2483 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2486 if(*pcbNeeded <= cbBuf)
2487 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2490 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2491 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2494 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2497 if(*pcbNeeded <= cbBuf)
2498 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2501 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2502 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2505 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2506 0, &size, unicode)) {
2508 if(*pcbNeeded <= cbBuf)
2509 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2510 size, &tmp, unicode);
2512 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2513 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2517 RegCloseKey(hkeyDriver);
2518 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2522 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2525 if(*pcbNeeded <= cbBuf)
2526 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2527 size, &tmp, unicode);
2529 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2530 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2533 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2536 if(*pcbNeeded <= cbBuf)
2537 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2538 size, &tmp, unicode);
2540 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2541 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2544 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2547 if(*pcbNeeded <= cbBuf)
2548 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2549 size, &tmp, unicode);
2551 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2552 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2555 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2558 if(*pcbNeeded <= cbBuf)
2559 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2560 size, &tmp, unicode);
2562 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2563 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2566 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2567 RegCloseKey(hkeyDriver);
2571 /*****************************************************************************
2572 * WINSPOOL_GetPrinterDriver
2574 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2575 DWORD Level, LPBYTE pDriverInfo,
2576 DWORD cbBuf, LPDWORD pcbNeeded,
2580 WCHAR DriverName[100];
2581 DWORD ret, type, size, needed = 0;
2583 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2585 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2586 Level,pDriverInfo,cbBuf, pcbNeeded);
2588 ZeroMemory(pDriverInfo, cbBuf);
2590 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2592 if(Level < 1 || Level > 3) {
2593 SetLastError(ERROR_INVALID_LEVEL);
2596 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2598 ERR("Can't create Printers key\n");
2601 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2603 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2604 RegCloseKey(hkeyPrinters);
2605 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2608 size = sizeof(DriverName);
2610 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2611 (LPBYTE)DriverName, &size);
2612 RegCloseKey(hkeyPrinter);
2613 RegCloseKey(hkeyPrinters);
2614 if(ret != ERROR_SUCCESS) {
2615 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2619 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2621 ERR("Can't create Drivers key\n");
2627 size = sizeof(DRIVER_INFO_1W);
2630 size = sizeof(DRIVER_INFO_2W);
2633 size = sizeof(DRIVER_INFO_3W);
2636 ERR("Invalid level\n");
2641 ptr = pDriverInfo + size;
2643 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2644 pEnvironment, Level, pDriverInfo,
2645 (cbBuf < size) ? NULL : ptr,
2646 (cbBuf < size) ? 0 : cbBuf - size,
2647 &needed, unicode)) {
2648 RegCloseKey(hkeyDrivers);
2652 RegCloseKey(hkeyDrivers);
2654 if(pcbNeeded) *pcbNeeded = size + needed;
2655 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2656 if(cbBuf >= needed) return TRUE;
2657 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2661 /*****************************************************************************
2662 * GetPrinterDriverA [WINSPOOL.@]
2664 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2665 DWORD Level, LPBYTE pDriverInfo,
2666 DWORD cbBuf, LPDWORD pcbNeeded)
2669 UNICODE_STRING pEnvW;
2672 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2673 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2674 cbBuf, pcbNeeded, FALSE);
2675 RtlFreeUnicodeString(&pEnvW);
2678 /*****************************************************************************
2679 * GetPrinterDriverW [WINSPOOL.@]
2681 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2682 DWORD Level, LPBYTE pDriverInfo,
2683 DWORD cbBuf, LPDWORD pcbNeeded)
2685 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2686 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2689 /*****************************************************************************
2690 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2692 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2693 DWORD Level, LPBYTE pDriverDirectory,
2694 DWORD cbBuf, LPDWORD pcbNeeded)
2698 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2699 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2701 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2702 SetLastError(ERROR_INVALID_PARAMETER);
2705 if(pEnvironment != NULL) {
2706 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2707 SetLastError(ERROR_INVALID_ENVIRONMENT);
2710 if(Level != 1) /* win95 ignores this so we just carry on */
2711 WARN("Level = %ld - assuming 1\n", Level);
2713 /* FIXME should read from registry */
2714 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2715 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2719 needed*=sizeof(WCHAR);
2722 *pcbNeeded = needed;
2723 TRACE("required <%08lx>\n", *pcbNeeded);
2724 if(needed > cbBuf) {
2725 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2732 /*****************************************************************************
2733 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2735 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2736 DWORD Level, LPBYTE pDriverDirectory,
2737 DWORD cbBuf, LPDWORD pcbNeeded)
2739 UNICODE_STRING nameW, environmentW;
2742 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2743 WCHAR *driverDirectoryW = NULL;
2745 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2747 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2748 else nameW.Buffer = NULL;
2749 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2750 else environmentW.Buffer = NULL;
2752 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2753 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2756 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2757 pDriverDirectory, cbBuf, NULL, NULL);
2759 *pcbNeeded = needed;
2760 ret = (needed <= cbBuf) ? TRUE : FALSE;
2762 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2764 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2766 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2767 RtlFreeUnicodeString(&environmentW);
2768 RtlFreeUnicodeString(&nameW);
2773 /*****************************************************************************
2774 * AddPrinterDriverA [WINSPOOL.@]
2776 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2779 HKEY hkeyDrivers, hkeyName;
2781 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2783 if(level != 2 && level != 3) {
2784 SetLastError(ERROR_INVALID_LEVEL);
2788 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2789 SetLastError(ERROR_INVALID_PARAMETER);
2793 WARN("pDriverInfo == NULL\n");
2794 SetLastError(ERROR_INVALID_PARAMETER);
2799 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2801 memset(&di3, 0, sizeof(di3));
2802 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
2805 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2807 SetLastError(ERROR_INVALID_PARAMETER);
2810 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2811 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2812 if(!di3.pHelpFile) di3.pHelpFile = "";
2813 if(!di3.pMonitorName) di3.pMonitorName = "";
2815 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2818 ERR("Can't create Drivers key\n");
2822 if(level == 2) { /* apparently can't overwrite with level2 */
2823 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2824 RegCloseKey(hkeyName);
2825 RegCloseKey(hkeyDrivers);
2826 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2827 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2831 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2832 RegCloseKey(hkeyDrivers);
2833 ERR("Can't create Name key\n");
2836 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2838 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2839 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2840 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2842 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2843 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2844 di3.pDependentFiles, 0);
2845 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2846 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2847 RegCloseKey(hkeyName);
2848 RegCloseKey(hkeyDrivers);
2853 /*****************************************************************************
2854 * AddPrinterDriverW [WINSPOOL.@]
2856 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2859 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2864 /*****************************************************************************
2865 * AddPrintProcessorA [WINSPOOL.@]
2867 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
2868 LPSTR pPrintProcessorName)
2870 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
2871 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
2875 /*****************************************************************************
2876 * AddPrintProcessorW [WINSPOOL.@]
2878 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
2879 LPWSTR pPrintProcessorName)
2881 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
2882 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
2886 /*****************************************************************************
2887 * AddPrintProvidorA [WINSPOOL.@]
2889 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
2891 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
2895 /*****************************************************************************
2896 * AddPrintProvidorW [WINSPOOL.@]
2898 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
2900 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
2904 /*****************************************************************************
2905 * AdvancedDocumentPropertiesA [WINSPOOL.@]
2907 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
2908 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
2910 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
2911 pDevModeOutput, pDevModeInput);
2915 /*****************************************************************************
2916 * AdvancedDocumentPropertiesW [WINSPOOL.@]
2918 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
2919 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
2921 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
2922 pDevModeOutput, pDevModeInput);
2926 /*****************************************************************************
2927 * PrinterProperties [WINSPOOL.@]
2929 * Displays a dialog to set the properties of the printer.
2932 * nonzero on success or zero on failure
2935 * implemented as stub only
2937 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2938 HANDLE hPrinter /* [in] handle to printer object */
2940 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2941 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2945 /*****************************************************************************
2946 * EnumJobsA [WINSPOOL.@]
2949 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2950 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2953 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2954 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2956 if(pcbNeeded) *pcbNeeded = 0;
2957 if(pcReturned) *pcReturned = 0;
2962 /*****************************************************************************
2963 * EnumJobsW [WINSPOOL.@]
2966 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2967 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2970 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2971 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2973 if(pcbNeeded) *pcbNeeded = 0;
2974 if(pcReturned) *pcReturned = 0;
2978 /*****************************************************************************
2979 * WINSPOOL_EnumPrinterDrivers [internal]
2981 * Delivers information about all printer drivers installed on the
2982 * localhost or a given server
2985 * nonzero on success or zero on failure. If the buffer for the returned
2986 * information is too small the function will return an error
2989 * - only implemented for localhost, foreign hosts will return an error
2991 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2992 DWORD Level, LPBYTE pDriverInfo,
2993 DWORD cbBuf, LPDWORD pcbNeeded,
2994 LPDWORD pcReturned, BOOL unicode)
2997 DWORD i, needed, number = 0, size = 0;
2998 WCHAR DriverNameW[255];
3001 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3002 debugstr_w(pName), debugstr_w(pEnvironment),
3003 Level, pDriverInfo, cbBuf, unicode);
3005 /* check for local drivers */
3007 ERR("remote drivers unsupported! Current remote host is %s\n",
3012 /* check input parameter */
3013 if((Level < 1) || (Level > 3)) {
3014 ERR("unsupported level %ld\n", Level);
3015 SetLastError(ERROR_INVALID_LEVEL);
3019 /* initialize return values */
3021 memset( pDriverInfo, 0, cbBuf);
3025 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3027 ERR("Can't open Drivers key\n");
3031 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3032 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3033 RegCloseKey(hkeyDrivers);
3034 ERR("Can't query Drivers key\n");
3037 TRACE("Found %ld Drivers\n", number);
3039 /* get size of single struct
3040 * unicode and ascii structure have the same size
3044 size = sizeof(DRIVER_INFO_1A);
3047 size = sizeof(DRIVER_INFO_2A);
3050 size = sizeof(DRIVER_INFO_3A);
3054 /* calculate required buffer size */
3055 *pcbNeeded = size * number;
3057 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3059 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3060 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3062 ERR("Can't enum key number %ld\n", i);
3063 RegCloseKey(hkeyDrivers);
3066 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3067 pEnvironment, Level, ptr,
3068 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3069 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3070 &needed, unicode)) {
3071 RegCloseKey(hkeyDrivers);
3074 (*pcbNeeded) += needed;
3077 RegCloseKey(hkeyDrivers);
3079 if(cbBuf < *pcbNeeded){
3080 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3087 /*****************************************************************************
3088 * EnumPrinterDriversW [WINSPOOL.@]
3090 * see function EnumPrinterDrivers for RETURNS, BUGS
3092 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3093 LPBYTE pDriverInfo, DWORD cbBuf,
3094 LPDWORD pcbNeeded, LPDWORD pcReturned)
3096 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3097 cbBuf, pcbNeeded, pcReturned, TRUE);
3100 /*****************************************************************************
3101 * EnumPrinterDriversA [WINSPOOL.@]
3103 * see function EnumPrinterDrivers for RETURNS, BUGS
3105 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3106 LPBYTE pDriverInfo, DWORD cbBuf,
3107 LPDWORD pcbNeeded, LPDWORD pcReturned)
3109 UNICODE_STRING pNameW, pEnvironmentW;
3110 PWSTR pwstrNameW, pwstrEnvironmentW;
3112 pwstrNameW = asciitounicode(&pNameW, pName);
3113 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3115 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3116 Level, pDriverInfo, cbBuf, pcbNeeded,
3118 RtlFreeUnicodeString(&pNameW);
3119 RtlFreeUnicodeString(&pEnvironmentW);
3124 static CHAR PortMonitor[] = "Wine Port Monitor";
3125 static CHAR PortDescription[] = "Wine Port";
3127 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3131 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3132 NULL, OPEN_EXISTING, 0, NULL );
3133 if (handle == INVALID_HANDLE_VALUE)
3135 TRACE("Checking %s exists\n", name );
3136 CloseHandle( handle );
3140 static DWORD WINSPOOL_CountSerialPorts()
3147 strcpy( name, "COMx:" );
3149 if (WINSPOOL_ComPortExists( name ))
3156 /******************************************************************************
3157 * EnumPortsA (WINSPOOL.@)
3159 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3160 LPDWORD bufneeded,LPDWORD bufreturned)
3163 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3164 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3168 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3169 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3174 info_size = sizeof (PORT_INFO_1A);
3177 info_size = sizeof (PORT_INFO_2A);
3180 SetLastError(ERROR_INVALID_LEVEL);
3184 /* see how many exist */
3187 serial_count = WINSPOOL_CountSerialPorts();
3190 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3191 if ( r == ERROR_SUCCESS )
3193 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3194 &printer_count, NULL, NULL, NULL, NULL);
3196 count = serial_count + printer_count;
3198 /* then fill in the structure info structure once
3199 we know the offset to the first string */
3201 memset( buffer, 0, bufsize );
3203 ofs = info_size*count;
3204 for ( i=0; i<count; i++)
3206 DWORD vallen = sizeof(portname) - 1;
3208 /* get the serial port values, then the printer values */
3209 if ( i < serial_count )
3211 strcpy( portname, "COMx:" );
3212 portname[3] = '1' + i;
3213 if (!WINSPOOL_ComPortExists( portname ))
3216 TRACE("Found %s\n", portname );
3217 vallen = strlen( portname );
3221 r = RegEnumValueA( hkey_printer, i-serial_count,
3222 portname, &vallen, NULL, NULL, NULL, 0 );
3227 /* add a colon if necessary, and make it upper case */
3228 CharUpperBuffA(portname,vallen);
3229 if (strcasecmp(portname,"nul")!=0)
3230 if (vallen && (portname[vallen-1] != ':') )
3231 lstrcatA(portname,":");
3233 /* add the port info structure if we can fit it */
3234 if ( info_size*(n+1) < bufsize )
3238 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3239 info->pName = (LPSTR) &buffer[ofs];
3241 else if ( level == 2)
3243 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3244 info->pPortName = (LPSTR) &buffer[ofs];
3245 /* FIXME: fill in more stuff here */
3246 info->pMonitorName = PortMonitor;
3247 info->pDescription = PortDescription;
3248 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3251 /* add the name of the port if we can fit it */
3252 if ( ofs < bufsize )
3253 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3259 ofs += lstrlenA(portname)+1;
3262 RegCloseKey(hkey_printer);
3273 /******************************************************************************
3274 * EnumPortsW (WINSPOOL.@)
3276 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3277 LPDWORD bufneeded,LPDWORD bufreturned)
3279 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3280 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3284 /******************************************************************************
3285 * GetDefaultPrinterW (WINSPOOL.@)
3288 * This function must read the value from data 'device' of key
3289 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3291 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3295 WCHAR *buffer, *ptr;
3299 SetLastError(ERROR_INVALID_PARAMETER);
3303 /* make the buffer big enough for the stuff from the profile/registry,
3304 * the content must fit into the local buffer to compute the correct
3305 * size even if the extern buffer is to small or not given.
3306 * (20 for ,driver,port) */
3308 len = max(100, (insize + 20));
3309 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3311 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3313 SetLastError (ERROR_FILE_NOT_FOUND);
3317 TRACE("%s\n", debugstr_w(buffer));
3319 if ((ptr = strchrW(buffer, ',')) == NULL)
3321 SetLastError(ERROR_INVALID_NAME);
3327 *namesize = strlenW(buffer) + 1;
3328 if(!name || (*namesize > insize))
3330 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3334 strcpyW(name, buffer);
3337 HeapFree( GetProcessHeap(), 0, buffer);
3342 /******************************************************************************
3343 * GetDefaultPrinterA (WINSPOOL.@)
3345 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3349 WCHAR *bufferW = NULL;
3353 SetLastError(ERROR_INVALID_PARAMETER);
3357 if(name && *namesize) {
3359 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3362 if(!GetDefaultPrinterW( bufferW, namesize)) {
3367 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3371 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3374 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3377 HeapFree( GetProcessHeap(), 0, bufferW);
3382 /******************************************************************************
3383 * SetPrinterDataExA (WINSPOOL.@)
3385 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3386 LPCSTR pValueName, DWORD Type,
3387 LPBYTE pData, DWORD cbData)
3389 HKEY hkeyPrinter, hkeySubkey;
3392 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3393 debugstr_a(pValueName), Type, pData, cbData);
3395 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3399 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3401 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3402 RegCloseKey(hkeyPrinter);
3405 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3406 RegCloseKey(hkeySubkey);
3407 RegCloseKey(hkeyPrinter);
3411 /******************************************************************************
3412 * SetPrinterDataExW (WINSPOOL.@)
3414 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3415 LPCWSTR pValueName, DWORD Type,
3416 LPBYTE pData, DWORD cbData)
3418 HKEY hkeyPrinter, hkeySubkey;
3421 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3422 debugstr_w(pValueName), Type, pData, cbData);
3424 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3428 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3430 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3431 RegCloseKey(hkeyPrinter);
3434 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3435 RegCloseKey(hkeySubkey);
3436 RegCloseKey(hkeyPrinter);
3440 /******************************************************************************
3441 * SetPrinterDataA (WINSPOOL.@)
3443 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3444 LPBYTE pData, DWORD cbData)
3446 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3450 /******************************************************************************
3451 * SetPrinterDataW (WINSPOOL.@)
3453 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3454 LPBYTE pData, DWORD cbData)
3456 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3460 /******************************************************************************
3461 * GetPrinterDataExA (WINSPOOL.@)
3463 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3464 LPCSTR pValueName, LPDWORD pType,
3465 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3467 HKEY hkeyPrinter, hkeySubkey;
3470 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3471 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3474 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3478 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3480 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3481 RegCloseKey(hkeyPrinter);
3485 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3486 RegCloseKey(hkeySubkey);
3487 RegCloseKey(hkeyPrinter);
3491 /******************************************************************************
3492 * GetPrinterDataExW (WINSPOOL.@)
3494 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3495 LPCWSTR pValueName, LPDWORD pType,
3496 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3498 HKEY hkeyPrinter, hkeySubkey;
3501 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3502 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3505 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3509 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3511 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3512 RegCloseKey(hkeyPrinter);
3516 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3517 RegCloseKey(hkeySubkey);
3518 RegCloseKey(hkeyPrinter);
3522 /******************************************************************************
3523 * GetPrinterDataA (WINSPOOL.@)
3525 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3526 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3528 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3529 pData, nSize, pcbNeeded);
3532 /******************************************************************************
3533 * GetPrinterDataW (WINSPOOL.@)
3535 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3536 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3538 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3539 pData, nSize, pcbNeeded);
3542 /*******************************************************************************
3543 * EnumPrinterDataExW [WINSPOOL.@]
3545 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3546 LPBYTE pEnumValues, DWORD cbEnumValues,
3547 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3549 HKEY hkPrinter, hkSubKey;
3550 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3551 cbValueNameLen, cbMaxValueLen, cbValueLen,
3556 PPRINTER_ENUM_VALUESW ppev;
3558 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3560 if (pKeyName == NULL || *pKeyName == 0)
3561 return ERROR_INVALID_PARAMETER;
3563 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3564 if (ret != ERROR_SUCCESS)
3566 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3571 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3572 if (ret != ERROR_SUCCESS)
3574 r = RegCloseKey (hkPrinter);
3575 if (r != ERROR_SUCCESS)
3576 WARN ("RegCloseKey returned %li\n", r);
3577 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3578 debugstr_w (pKeyName), ret);
3582 ret = RegCloseKey (hkPrinter);
3583 if (ret != ERROR_SUCCESS)
3585 ERR ("RegCloseKey returned %li\n", ret);
3586 r = RegCloseKey (hkSubKey);
3587 if (r != ERROR_SUCCESS)
3588 WARN ("RegCloseKey returned %li\n", r);
3592 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3593 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3594 if (ret != ERROR_SUCCESS)
3596 r = RegCloseKey (hkSubKey);
3597 if (r != ERROR_SUCCESS)
3598 WARN ("RegCloseKey returned %li\n", r);
3599 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3603 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3604 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3606 if (cValues == 0) /* empty key */
3608 r = RegCloseKey (hkSubKey);
3609 if (r != ERROR_SUCCESS)
3610 WARN ("RegCloseKey returned %li\n", r);
3611 *pcbEnumValues = *pnEnumValues = 0;
3612 return ERROR_SUCCESS;
3615 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3617 hHeap = GetProcessHeap ();
3620 ERR ("GetProcessHeap failed\n");
3621 r = RegCloseKey (hkSubKey);
3622 if (r != ERROR_SUCCESS)
3623 WARN ("RegCloseKey returned %li\n", r);
3624 return ERROR_OUTOFMEMORY;
3627 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3628 if (lpValueName == NULL)
3630 ERR ("Failed to allocate %li bytes from process heap\n",
3631 cbMaxValueNameLen * sizeof (WCHAR));
3632 r = RegCloseKey (hkSubKey);
3633 if (r != ERROR_SUCCESS)
3634 WARN ("RegCloseKey returned %li\n", r);
3635 return ERROR_OUTOFMEMORY;
3638 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3639 if (lpValue == NULL)
3641 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3642 if (HeapFree (hHeap, 0, lpValueName) == 0)
3643 WARN ("HeapFree failed with code %li\n", GetLastError ());
3644 r = RegCloseKey (hkSubKey);
3645 if (r != ERROR_SUCCESS)
3646 WARN ("RegCloseKey returned %li\n", r);
3647 return ERROR_OUTOFMEMORY;
3650 TRACE ("pass 1: calculating buffer required for all names and values\n");
3652 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3654 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3656 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3658 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3659 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3660 NULL, NULL, lpValue, &cbValueLen);
3661 if (ret != ERROR_SUCCESS)
3663 if (HeapFree (hHeap, 0, lpValue) == 0)
3664 WARN ("HeapFree failed with code %li\n", GetLastError ());
3665 if (HeapFree (hHeap, 0, lpValueName) == 0)
3666 WARN ("HeapFree failed with code %li\n", GetLastError ());
3667 r = RegCloseKey (hkSubKey);
3668 if (r != ERROR_SUCCESS)
3669 WARN ("RegCloseKey returned %li\n", r);
3670 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3674 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3675 debugstr_w (lpValueName), dwIndex,
3676 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3678 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3679 cbBufSize += cbValueLen;
3682 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3684 *pcbEnumValues = cbBufSize;
3685 *pnEnumValues = cValues;
3687 if (cbEnumValues < cbBufSize) /* buffer too small */
3689 if (HeapFree (hHeap, 0, lpValue) == 0)
3690 WARN ("HeapFree failed with code %li\n", GetLastError ());
3691 if (HeapFree (hHeap, 0, lpValueName) == 0)
3692 WARN ("HeapFree failed with code %li\n", GetLastError ());
3693 r = RegCloseKey (hkSubKey);
3694 if (r != ERROR_SUCCESS)
3695 WARN ("RegCloseKey returned %li\n", r);
3696 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3697 return ERROR_MORE_DATA;
3700 TRACE ("pass 2: copying all names and values to buffer\n");
3702 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3703 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3705 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3707 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3708 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3709 NULL, &dwType, lpValue, &cbValueLen);
3710 if (ret != ERROR_SUCCESS)
3712 if (HeapFree (hHeap, 0, lpValue) == 0)
3713 WARN ("HeapFree failed with code %li\n", GetLastError ());
3714 if (HeapFree (hHeap, 0, lpValueName) == 0)
3715 WARN ("HeapFree failed with code %li\n", GetLastError ());
3716 r = RegCloseKey (hkSubKey);
3717 if (r != ERROR_SUCCESS)
3718 WARN ("RegCloseKey returned %li\n", r);
3719 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3723 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3724 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3725 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3726 pEnumValues += cbValueNameLen;
3728 /* return # of *bytes* (including trailing \0), not # of chars */
3729 ppev[dwIndex].cbValueName = cbValueNameLen;
3731 ppev[dwIndex].dwType = dwType;
3733 memcpy (pEnumValues, lpValue, cbValueLen);
3734 ppev[dwIndex].pData = pEnumValues;
3735 pEnumValues += cbValueLen;
3737 ppev[dwIndex].cbData = cbValueLen;
3739 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3740 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3743 if (HeapFree (hHeap, 0, lpValue) == 0)
3745 ret = GetLastError ();
3746 ERR ("HeapFree failed with code %li\n", ret);
3747 if (HeapFree (hHeap, 0, lpValueName) == 0)
3748 WARN ("HeapFree failed with code %li\n", GetLastError ());
3749 r = RegCloseKey (hkSubKey);
3750 if (r != ERROR_SUCCESS)
3751 WARN ("RegCloseKey returned %li\n", r);
3755 if (HeapFree (hHeap, 0, lpValueName) == 0)
3757 ret = GetLastError ();
3758 ERR ("HeapFree failed with code %li\n", ret);
3759 r = RegCloseKey (hkSubKey);
3760 if (r != ERROR_SUCCESS)
3761 WARN ("RegCloseKey returned %li\n", r);
3765 ret = RegCloseKey (hkSubKey);
3766 if (ret != ERROR_SUCCESS)
3768 ERR ("RegCloseKey returned %li\n", ret);
3772 return ERROR_SUCCESS;
3775 /*******************************************************************************
3776 * EnumPrinterDataExA [WINSPOOL.@]
3778 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3779 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3780 * what Windows 2000 SP1 does.
3783 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3784 LPBYTE pEnumValues, DWORD cbEnumValues,
3785 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3789 DWORD ret, dwIndex, dwBufSize;
3793 TRACE ("%p %s\n", hPrinter, pKeyName);
3795 if (pKeyName == NULL || *pKeyName == 0)
3796 return ERROR_INVALID_PARAMETER;
3798 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3801 ret = GetLastError ();
3802 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3806 hHeap = GetProcessHeap ();
3809 ERR ("GetProcessHeap failed\n");
3810 return ERROR_OUTOFMEMORY;
3813 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3814 if (pKeyNameW == NULL)
3816 ERR ("Failed to allocate %li bytes from process heap\n",
3817 (LONG) len * sizeof (WCHAR));
3818 return ERROR_OUTOFMEMORY;
3821 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3823 ret = GetLastError ();
3824 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3825 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3826 WARN ("HeapFree failed with code %li\n", GetLastError ());
3830 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3831 pcbEnumValues, pnEnumValues);
3832 if (ret != ERROR_SUCCESS)
3834 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3835 WARN ("HeapFree failed with code %li\n", GetLastError ());
3836 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3840 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3842 ret = GetLastError ();
3843 ERR ("HeapFree failed with code %li\n", ret);
3847 if (*pnEnumValues == 0) /* empty key */
3848 return ERROR_SUCCESS;
3851 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3853 PPRINTER_ENUM_VALUESW ppev =
3854 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3856 if (dwBufSize < ppev->cbValueName)
3857 dwBufSize = ppev->cbValueName;
3859 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3860 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3861 dwBufSize = ppev->cbData;
3864 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3866 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3867 if (pBuffer == NULL)
3869 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3870 return ERROR_OUTOFMEMORY;
3873 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3875 PPRINTER_ENUM_VALUESW ppev =
3876 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3878 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3879 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3883 ret = GetLastError ();
3884 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3885 if (HeapFree (hHeap, 0, pBuffer) == 0)
3886 WARN ("HeapFree failed with code %li\n", GetLastError ());
3890 memcpy (ppev->pValueName, pBuffer, len);
3892 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3894 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3895 ppev->dwType != REG_MULTI_SZ)
3898 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3899 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3902 ret = GetLastError ();
3903 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3904 if (HeapFree (hHeap, 0, pBuffer) == 0)
3905 WARN ("HeapFree failed with code %li\n", GetLastError ());
3909 memcpy (ppev->pData, pBuffer, len);
3911 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3912 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3915 if (HeapFree (hHeap, 0, pBuffer) == 0)
3917 ret = GetLastError ();
3918 ERR ("HeapFree failed with code %li\n", ret);
3922 return ERROR_SUCCESS;
3925 /******************************************************************************
3926 * AbortPrinter (WINSPOOL.@)
3928 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
3930 FIXME("(%p), stub!\n", hPrinter);
3934 /******************************************************************************
3935 * AddPortA (WINSPOOL.@)
3937 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
3939 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
3943 /******************************************************************************
3944 * AddPortW (WINSPOOL.@)
3946 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
3948 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
3952 /******************************************************************************
3953 * AddPortExA (WINSPOOL.@)
3955 * Adds a print spooler port without presenting a user interface.
3957 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
3959 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
3960 lpBuffer, debugstr_a(lpMonitorName));
3964 /******************************************************************************
3965 * AddPortExW (WINSPOOL.@)
3969 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
3971 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
3972 lpBuffer, debugstr_w(lpMonitorName));
3976 /******************************************************************************
3977 * AddPrinterConnectionA (WINSPOOL.@)
3979 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
3981 FIXME("%s\n", debugstr_a(pName));
3985 /******************************************************************************
3986 * AddPrinterConnectionW (WINSPOOL.@)
3988 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
3990 FIXME("%s\n", debugstr_w(pName));
3994 /******************************************************************************
3995 * AddPrinterDriverExW (WINSPOOL.@)
3997 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
3998 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4000 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4001 Level, pDriverInfo, dwFileCopyFlags);
4002 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4006 /******************************************************************************
4007 * AddPrinterDriverExA (WINSPOOL.@)
4009 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4010 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4012 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4013 Level, pDriverInfo, dwFileCopyFlags);
4014 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4018 /******************************************************************************
4019 * ConfigurePortA (WINSPOOL.@)
4021 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4023 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4027 /******************************************************************************
4028 * ConfigurePortW (WINSPOOL.@)
4030 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4032 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4036 /******************************************************************************
4037 * ConnectToPrinterDlg (WINSPOOL.@)
4039 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4041 FIXME("%p %lx\n", hWnd, Flags);
4045 /******************************************************************************
4046 * DeletePrinterConnectionA (WINSPOOL.@)
4048 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4050 FIXME("%s\n", debugstr_a(pName));
4054 /******************************************************************************
4055 * DeletePrinterConnectionW (WINSPOOL.@)
4057 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4059 FIXME("%s\n", debugstr_w(pName));
4063 /******************************************************************************
4064 * DeletePrinterDriverExW (WINSPOOL.@)
4066 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4067 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4069 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4070 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4074 /******************************************************************************
4075 * DeletePrinterDriverExA (WINSPOOL.@)
4077 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4078 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4080 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4081 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4085 /******************************************************************************
4086 * DeletePrinterDataExW (WINSPOOL.@)
4088 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4091 FIXME("%p %s %s\n", hPrinter,
4092 debugstr_w(pKeyName), debugstr_w(pValueName));
4093 return ERROR_INVALID_PARAMETER;
4096 /******************************************************************************
4097 * DeletePrinterDataExA (WINSPOOL.@)
4099 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4102 FIXME("%p %s %s\n", hPrinter,
4103 debugstr_a(pKeyName), debugstr_a(pValueName));
4104 return ERROR_INVALID_PARAMETER;
4107 /******************************************************************************
4108 * DeletePrintProcessorA (WINSPOOL.@)
4110 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4112 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4113 debugstr_a(pPrintProcessorName));
4117 /******************************************************************************
4118 * DeletePrintProcessorW (WINSPOOL.@)
4120 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4122 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4123 debugstr_w(pPrintProcessorName));
4127 /******************************************************************************
4128 * DeletePrintProvidorA (WINSPOOL.@)
4130 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4132 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4133 debugstr_a(pPrintProviderName));
4137 /******************************************************************************
4138 * DeletePrintProvidorW (WINSPOOL.@)
4140 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4142 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4143 debugstr_w(pPrintProviderName));
4147 /******************************************************************************
4148 * EnumFormsA (WINSPOOL.@)
4150 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4151 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4153 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4157 /******************************************************************************
4158 * EnumFormsW (WINSPOOL.@)
4160 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4161 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4163 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4167 /*****************************************************************************
4168 * EnumMonitorsA [WINSPOOL.@]
4171 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4172 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4174 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4175 cbBuf, pcbNeeded, pcReturned);
4176 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4180 /*****************************************************************************
4181 * EnumMonitorsW [WINSPOOL.@]
4184 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4185 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4187 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4188 cbBuf, pcbNeeded, pcReturned);
4189 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4193 /******************************************************************************
4194 * XcvDataW (WINSPOOL.@)
4197 * There doesn't seem to be an A version...
4199 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4200 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4201 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4203 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4204 pInputData, cbInputData, pOutputData,
4205 cbOutputData, pcbOutputNeeded, pdwStatus);
4209 /*****************************************************************************
4210 * EnumPrinterDataA [WINSPOOL.@]
4213 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4214 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4215 DWORD cbData, LPDWORD pcbData )
4217 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4218 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4219 return ERROR_NO_MORE_ITEMS;
4222 /*****************************************************************************
4223 * EnumPrinterDataW [WINSPOOL.@]
4226 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4227 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4228 DWORD cbData, LPDWORD pcbData )
4230 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4231 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4232 return ERROR_NO_MORE_ITEMS;
4235 /*****************************************************************************
4236 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4239 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4240 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4241 LPDWORD pcbNeeded, LPDWORD pcReturned)
4243 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4244 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4245 pcbNeeded, pcReturned);
4249 /*****************************************************************************
4250 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4253 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4254 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4255 LPDWORD pcbNeeded, LPDWORD pcReturned)
4257 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4258 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4259 pcbNeeded, pcReturned);
4263 /*****************************************************************************
4264 * EnumPrintProcessorsA [WINSPOOL.@]
4267 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4268 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4270 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4271 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
4275 /*****************************************************************************
4276 * EnumPrintProcessorsW [WINSPOOL.@]
4279 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4280 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4282 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4283 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
4284 cbBuf, pcbNeeded, pcbReturned);
4288 /*****************************************************************************
4289 * ExtDeviceMode [WINSPOOL.@]
4292 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
4293 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
4296 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
4297 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
4298 debugstr_a(pProfile), fMode);
4302 /*****************************************************************************
4303 * FindClosePrinterChangeNotification [WINSPOOL.@]
4306 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
4308 FIXME("Stub: %p\n", hChange);
4312 /*****************************************************************************
4313 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4316 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
4317 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
4319 FIXME("Stub: %p %lx %lx %p\n",
4320 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
4321 return INVALID_HANDLE_VALUE;
4324 /*****************************************************************************
4325 * FindNextPrinterChangeNotification [WINSPOOL.@]
4328 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
4329 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
4331 FIXME("Stub: %p %p %p %p\n",
4332 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
4336 /*****************************************************************************
4337 * FreePrinterNotifyInfo [WINSPOOL.@]
4340 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
4342 FIXME("Stub: %p\n", pPrinterNotifyInfo);
4346 /*****************************************************************************
4347 * GetJobA [WINSPOOL.@]
4350 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4351 DWORD cbBuf, LPDWORD pcbNeeded)
4353 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4358 /*****************************************************************************
4359 * GetJobW [WINSPOOL.@]
4362 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4363 DWORD cbBuf, LPDWORD pcbNeeded)
4365 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4370 /*****************************************************************************
4371 * ScheduleJob [WINSPOOL.@]
4374 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
4376 FIXME("Stub: %p %lx\n", hPrinter, dwJobID);