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\\";
74 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
75 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
76 'c','o','n','t','r','o','l','\\',
77 'P','r','i','n','t','\\',
78 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
79 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
81 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
82 'M','i','c','r','o','s','o','f','t','\\',
83 'W','i','n','d','o','w','s',' ','N','T','\\',
84 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
85 'W','i','n','d','o','w','s',0};
87 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
88 'M','i','c','r','o','s','o','f','t','\\',
89 'W','i','n','d','o','w','s',' ','N','T','\\',
90 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
91 'D','e','v','i','c','e','s',0};
93 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
95 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
96 'i','o','n',' ','F','i','l','e',0};
97 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
98 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
99 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
101 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
103 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
104 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
105 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
106 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
107 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
108 static const WCHAR NameW[] = {'N','a','m','e',0};
109 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
110 static const WCHAR PortW[] = {'P','o','r','t',0};
111 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
113 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
115 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
116 'v','e','r','D','a','t','a',0};
117 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
119 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
120 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
121 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
122 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
123 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
124 static const WCHAR emptyStringW[] = {0};
126 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
128 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
129 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
130 DWORD Level, LPBYTE pDriverInfo,
131 DWORD cbBuf, LPDWORD pcbNeeded,
133 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
135 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
136 if passed a NULL string. This returns NULLs to the result.
138 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
142 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
143 return usBufferPtr->Buffer;
145 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
150 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
153 /* If forcing, or no profile string entry for device yet, set the entry
155 * The always change entry if not WINEPS yet is discussable.
158 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
160 !strstr(qbuf,"WINEPS.DRV")
162 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
165 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
166 WriteProfileStringA("windows","device",buf);
167 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
168 RegSetValueExA(hkey, "Device", 0, REG_SZ, buf, strlen(buf) + 1);
171 HeapFree(GetProcessHeap(),0,buf);
175 #ifdef HAVE_CUPS_CUPS_H
176 static BOOL CUPS_LoadPrinters(void)
178 typeof(cupsGetDests) *pcupsGetDests = NULL;
179 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
181 BOOL hadprinter = FALSE;
183 PRINTER_INFO_2A pinfo2a;
184 void *cupshandle = NULL;
186 HKEY hkeyPrinter, hkeyPrinters, hkey;
188 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
191 TRACE("loaded %s\n", SONAME_LIBCUPS);
194 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
195 if (!p##x) return FALSE;
198 DYNCUPS(cupsGetDests);
201 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
203 ERR("Can't create Printers key\n");
207 nrofdests = pcupsGetDests(&dests);
208 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
209 for (i=0;i<nrofdests;i++) {
210 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
211 sprintf(port,"LPR:%s",dests[i].name);
212 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
213 sprintf(devline,"WINEPS.DRV,%s",port);
214 WriteProfileStringA("devices",dests[i].name,devline);
215 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
216 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, devline, strlen(devline) + 1);
219 HeapFree(GetProcessHeap(),0,devline);
221 TRACE("Printer %d: %s\n", i, dests[i].name);
222 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
223 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
225 TRACE("Printer already exists\n");
226 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
227 RegCloseKey(hkeyPrinter);
229 memset(&pinfo2a,0,sizeof(pinfo2a));
230 pinfo2a.pPrinterName = dests[i].name;
231 pinfo2a.pDatatype = "RAW";
232 pinfo2a.pPrintProcessor = "WinPrint";
233 pinfo2a.pDriverName = "PS Driver";
234 pinfo2a.pComment = "WINEPS Printer using CUPS";
235 pinfo2a.pLocation = "<physical location of printer>";
236 pinfo2a.pPortName = port;
237 pinfo2a.pParameters = "<parameters?>";
238 pinfo2a.pShareName = "<share name?>";
239 pinfo2a.pSepFile = "<sep file?>";
241 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
242 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
243 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
246 HeapFree(GetProcessHeap(),0,port);
249 if (dests[i].is_default)
250 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
252 RegCloseKey(hkeyPrinters);
253 wine_dlclose(cupshandle, NULL, 0);
259 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
260 PRINTER_INFO_2A pinfo2a;
261 char *e,*s,*name,*prettyname,*devname;
262 BOOL ret = FALSE, set_default = FALSE;
263 char *port,*devline,*env_default;
264 HKEY hkeyPrinter, hkeyPrinters, hkey;
266 while (isspace(*pent)) pent++;
267 s = strchr(pent,':');
269 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
277 TRACE("name=%s entry=%s\n",name, pent);
279 if(ispunct(*name)) { /* a tc entry, not a real printer */
280 TRACE("skipping tc entry\n");
284 if(strstr(pent,":server")) { /* server only version so skip */
285 TRACE("skipping server entry\n");
289 /* Determine whether this is a postscript printer. */
292 env_default = getenv("PRINTER");
294 /* Get longest name, usually the one at the right for later display. */
295 while((s=strchr(prettyname,'|'))) {
298 while(isspace(*--e)) *e = '\0';
299 TRACE("\t%s\n", debugstr_a(prettyname));
300 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
301 for(prettyname = s+1; isspace(*prettyname); prettyname++)
304 e = prettyname + strlen(prettyname);
305 while(isspace(*--e)) *e = '\0';
306 TRACE("\t%s\n", debugstr_a(prettyname));
307 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
309 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
310 * if it is too long, we use it as comment below. */
311 devname = prettyname;
312 if (strlen(devname)>=CCHDEVICENAME-1)
314 if (strlen(devname)>=CCHDEVICENAME-1) {
319 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
320 sprintf(port,"LPR:%s",name);
322 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
323 sprintf(devline,"WINEPS.DRV,%s",port);
324 WriteProfileStringA("devices",devname,devline);
325 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
326 RegSetValueExA(hkey, devname, 0, REG_SZ, devline, strlen(devline) + 1);
329 HeapFree(GetProcessHeap(),0,devline);
331 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
333 ERR("Can't create Printers key\n");
337 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
338 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
340 TRACE("Printer already exists\n");
341 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
342 RegCloseKey(hkeyPrinter);
344 memset(&pinfo2a,0,sizeof(pinfo2a));
345 pinfo2a.pPrinterName = devname;
346 pinfo2a.pDatatype = "RAW";
347 pinfo2a.pPrintProcessor = "WinPrint";
348 pinfo2a.pDriverName = "PS Driver";
349 pinfo2a.pComment = "WINEPS Printer using LPR";
350 pinfo2a.pLocation = prettyname;
351 pinfo2a.pPortName = port;
352 pinfo2a.pParameters = "<parameters?>";
353 pinfo2a.pShareName = "<share name?>";
354 pinfo2a.pSepFile = "<sep file?>";
356 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
357 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
358 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
361 RegCloseKey(hkeyPrinters);
363 if (isfirst || set_default)
364 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
366 HeapFree(GetProcessHeap(), 0, port);
368 HeapFree(GetProcessHeap(), 0, name);
373 PRINTCAP_LoadPrinters(void) {
374 BOOL hadprinter = FALSE;
378 BOOL had_bash = FALSE;
380 f = fopen("/etc/printcap","r");
384 while(fgets(buf,sizeof(buf),f)) {
387 end=strchr(buf,'\n');
391 while(isspace(*start)) start++;
392 if(*start == '#' || *start == '\0')
395 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
396 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
397 HeapFree(GetProcessHeap(),0,pent);
401 if (end && *--end == '\\') {
408 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
411 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
417 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
418 HeapFree(GetProcessHeap(),0,pent);
424 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
427 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
428 lstrlenW(value) * sizeof(WCHAR));
430 return ERROR_FILE_NOT_FOUND;
433 void WINSPOOL_LoadSystemPrinters(void)
435 HKEY hkey, hkeyPrinters;
438 DWORD needed, num, i;
439 WCHAR PrinterName[256];
442 di3a.cVersion = 0x400;
443 di3a.pName = "PS Driver";
444 di3a.pEnvironment = NULL; /* NULL means auto */
445 di3a.pDriverPath = "wineps16";
446 di3a.pDataFile = "<datafile?>";
447 di3a.pConfigFile = "wineps16";
448 di3a.pHelpFile = "<helpfile?>";
449 di3a.pDependentFiles = "<dependend files?>";
450 di3a.pMonitorName = "<monitor name?>";
451 di3a.pDefaultDataType = "RAW";
453 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
454 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
458 /* This ensures that all printer entries have a valid Name value. If causes
459 problems later if they don't. If one is found to be missed we create one
460 and set it equal to the name of the key */
461 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
462 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
463 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
464 for(i = 0; i < num; i++) {
465 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
466 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
467 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
468 set_reg_szW(hkey, NameW, PrinterName);
475 RegCloseKey(hkeyPrinters);
478 /* We want to avoid calling AddPrinter on printers as much as
479 possible, because on cups printers this will (eventually) lead
480 to a call to cupsGetPPD which takes forever, even with non-cups
481 printers AddPrinter takes a while. So we'll tag all printers that
482 were automatically added last time around, if they still exist
483 we'll leave them be otherwise we'll delete them. */
484 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
486 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
487 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
488 for(i = 0; i < num; i++) {
489 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
490 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
491 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
493 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
501 HeapFree(GetProcessHeap(), 0, pi);
505 #ifdef HAVE_CUPS_CUPS_H
506 done = CUPS_LoadPrinters();
509 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
510 /* Check for [ppd] section in config file before parsing /etc/printcap */
511 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
512 &hkey) == ERROR_SUCCESS) {
514 PRINTCAP_LoadPrinters();
518 /* Now enumerate the list again and delete any printers that a still tagged */
519 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
521 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
522 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
523 for(i = 0; i < num; i++) {
524 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
525 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
526 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
527 DWORD dw, type, size = sizeof(dw);
528 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
529 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
539 HeapFree(GetProcessHeap(), 0, pi);
547 /******************************************************************
548 * WINSPOOL_GetOpenedPrinterEntry
549 * Get the first place empty in the opened printer table
551 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
555 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
557 if (i >= nb_printers)
561 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
562 (nb_printers + 16) * sizeof(*new_array) );
564 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
565 (nb_printers + 16) * sizeof(*new_array) );
567 if (!new_array) return 0;
568 printer_array = new_array;
572 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
574 strcpyW( printer_array[i], name );
575 return (HANDLE)(i + 1);
580 /******************************************************************
581 * WINSPOOL_GetOpenedPrinter
582 * Get the pointer to the opened printer referred by the handle
584 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
586 int idx = (int)printerHandle;
587 if ((idx <= 0) || (idx > nb_printers))
589 SetLastError(ERROR_INVALID_HANDLE);
592 return printer_array[idx - 1];
595 /******************************************************************
596 * WINSPOOL_GetOpenedPrinterRegKey
599 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
601 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
605 if(!name) return ERROR_INVALID_HANDLE;
607 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
611 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
613 ERR("Can't find opened printer %s in registry\n",
615 RegCloseKey(hkeyPrinters);
616 return ERROR_INVALID_PRINTER_NAME; /* ? */
618 RegCloseKey(hkeyPrinters);
619 return ERROR_SUCCESS;
622 /***********************************************************
625 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
628 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
631 Formname = (dmA->dmSize > off_formname);
632 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
633 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
636 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
637 dmA->dmSize - CCHDEVICENAME);
639 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
640 off_formname - CCHDEVICENAME);
641 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
643 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
644 (off_formname + CCHFORMNAME));
647 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
652 /***********************************************************
654 * Creates an ascii copy of supplied devmode on heap
656 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
661 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
663 if(!dmW) return NULL;
664 Formname = (dmW->dmSize > off_formname);
665 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
666 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
667 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
668 CCHDEVICENAME, NULL, NULL);
670 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
671 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
673 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
674 off_formname - CCHDEVICENAME * sizeof(WCHAR));
675 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
676 CCHFORMNAME, NULL, NULL);
677 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
678 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
681 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
686 /***********************************************************
688 * Creates a unicode copy of PRINTER_INFO_2A on heap
690 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
692 LPPRINTER_INFO_2W piW;
693 UNICODE_STRING usBuffer;
695 if(!piA) return NULL;
696 piW = HeapAlloc(heap, 0, sizeof(*piW));
697 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
699 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
700 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
701 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
702 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
703 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
704 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
705 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
706 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
707 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
708 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
709 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
710 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
714 /***********************************************************
715 * FREE_PRINTER_INFO_2W
716 * Free PRINTER_INFO_2W and all strings
718 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
722 HeapFree(heap,0,piW->pServerName);
723 HeapFree(heap,0,piW->pPrinterName);
724 HeapFree(heap,0,piW->pShareName);
725 HeapFree(heap,0,piW->pPortName);
726 HeapFree(heap,0,piW->pDriverName);
727 HeapFree(heap,0,piW->pComment);
728 HeapFree(heap,0,piW->pLocation);
729 HeapFree(heap,0,piW->pDevMode);
730 HeapFree(heap,0,piW->pSepFile);
731 HeapFree(heap,0,piW->pPrintProcessor);
732 HeapFree(heap,0,piW->pDatatype);
733 HeapFree(heap,0,piW->pParameters);
734 HeapFree(heap,0,piW);
738 /******************************************************************
739 * DeviceCapabilities [WINSPOOL.@]
740 * DeviceCapabilitiesA [WINSPOOL.@]
743 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
744 LPSTR pOutput, LPDEVMODEA lpdm)
748 if (!GDI_CallDeviceCapabilities16)
750 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
752 if (!GDI_CallDeviceCapabilities16) return -1;
754 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
756 /* If DC_PAPERSIZE map POINT16s to POINTs */
757 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
758 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
759 POINT *pt = (POINT *)pOutput;
761 memcpy(tmp, pOutput, ret * sizeof(POINT16));
762 for(i = 0; i < ret; i++, pt++)
767 HeapFree( GetProcessHeap(), 0, tmp );
773 /*****************************************************************************
774 * DeviceCapabilitiesW [WINSPOOL.@]
776 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
779 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
780 WORD fwCapability, LPWSTR pOutput,
781 const DEVMODEW *pDevMode)
783 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
784 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
785 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
788 if(pOutput && (fwCapability == DC_BINNAMES ||
789 fwCapability == DC_FILEDEPENDENCIES ||
790 fwCapability == DC_PAPERNAMES)) {
791 /* These need A -> W translation */
794 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
798 switch(fwCapability) {
803 case DC_FILEDEPENDENCIES:
807 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
808 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
810 for(i = 0; i < ret; i++)
811 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
812 pOutput + (i * size), size);
813 HeapFree(GetProcessHeap(), 0, pOutputA);
815 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
816 (LPSTR)pOutput, dmA);
818 HeapFree(GetProcessHeap(),0,pPortA);
819 HeapFree(GetProcessHeap(),0,pDeviceA);
820 HeapFree(GetProcessHeap(),0,dmA);
824 /******************************************************************
825 * DocumentPropertiesA [WINSPOOL.@]
827 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
829 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
830 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
831 LPDEVMODEA pDevModeInput,DWORD fMode )
833 LPSTR lpName = pDeviceName;
836 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
837 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
841 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
843 ERR("no name from hPrinter?\n");
846 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
849 if (!GDI_CallExtDeviceMode16)
851 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
853 if (!GDI_CallExtDeviceMode16) {
854 ERR("No CallExtDeviceMode16?\n");
858 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
859 pDevModeInput, NULL, fMode);
862 HeapFree(GetProcessHeap(),0,lpName);
867 /*****************************************************************************
868 * DocumentPropertiesW (WINSPOOL.@)
870 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
872 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
874 LPDEVMODEW pDevModeOutput,
875 LPDEVMODEW pDevModeInput, DWORD fMode)
878 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
879 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
880 LPDEVMODEA pDevModeOutputA = NULL;
883 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
884 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
887 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
888 if(ret < 0) return ret;
889 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
891 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
892 pDevModeInputA, fMode);
894 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
895 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
897 if(fMode == 0 && ret > 0)
898 ret += (CCHDEVICENAME + CCHFORMNAME);
899 HeapFree(GetProcessHeap(),0,pDevModeInputA);
900 HeapFree(GetProcessHeap(),0,pDeviceNameA);
904 /******************************************************************
905 * OpenPrinterA [WINSPOOL.@]
908 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
909 LPPRINTER_DEFAULTSA pDefault)
911 UNICODE_STRING lpPrinterNameW;
912 UNICODE_STRING usBuffer;
913 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
914 PWSTR pwstrPrinterNameW;
917 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
920 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
921 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
922 DefaultW.DesiredAccess = pDefault->DesiredAccess;
923 pDefaultW = &DefaultW;
925 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
927 RtlFreeUnicodeString(&usBuffer);
928 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
930 RtlFreeUnicodeString(&lpPrinterNameW);
934 /******************************************************************
935 * OpenPrinterW [WINSPOOL.@]
938 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
939 LPPRINTER_DEFAULTSW pDefault)
941 HKEY hkeyPrinters, hkeyPrinter;
943 if (!lpPrinterName) {
944 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
945 SetLastError(ERROR_INVALID_PARAMETER);
949 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
952 /* Check Printer exists */
953 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
955 ERR("Can't create Printers key\n");
956 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
960 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
961 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
963 TRACE("Can't find printer %s in registry\n",
964 debugstr_w(lpPrinterName));
965 RegCloseKey(hkeyPrinters);
966 SetLastError(ERROR_INVALID_PRINTER_NAME);
969 RegCloseKey(hkeyPrinter);
970 RegCloseKey(hkeyPrinters);
972 if(!phPrinter) /* This seems to be what win95 does anyway */
975 /* Get the unique handle of the printer*/
976 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
978 if (pDefault != NULL)
979 FIXME("Not handling pDefault\n");
984 /******************************************************************
985 * AddMonitorA [WINSPOOL.@]
988 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
990 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
991 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
995 /******************************************************************************
996 * AddMonitorW [WINSPOOL.@]
998 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1000 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1001 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1005 /******************************************************************
1006 * DeletePrinterDriverA [WINSPOOL.@]
1010 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1012 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1013 debugstr_a(pDriverName));
1014 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1018 /******************************************************************
1019 * DeletePrinterDriverW [WINSPOOL.@]
1023 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1025 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1026 debugstr_w(pDriverName));
1027 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1031 /******************************************************************
1032 * DeleteMonitorA [WINSPOOL.@]
1036 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1038 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1039 debugstr_a(pMonitorName));
1040 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1044 /******************************************************************
1045 * DeleteMonitorW [WINSPOOL.@]
1049 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1051 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1052 debugstr_w(pMonitorName));
1053 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1057 /******************************************************************
1058 * DeletePortA [WINSPOOL.@]
1062 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1064 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1065 debugstr_a(pPortName));
1066 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1070 /******************************************************************
1071 * DeletePortW [WINSPOOL.@]
1075 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1077 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1078 debugstr_w(pPortName));
1079 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1083 /******************************************************************************
1084 * SetPrinterW [WINSPOOL.@]
1094 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1098 /******************************************************************************
1099 * WritePrinter [WINSPOOL.@]
1106 LPDWORD pcWritten) {
1109 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1113 /*****************************************************************************
1114 * AddFormA [WINSPOOL.@]
1116 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1118 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1122 /*****************************************************************************
1123 * AddFormW [WINSPOOL.@]
1125 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1127 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1131 /*****************************************************************************
1132 * AddJobA [WINSPOOL.@]
1134 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
1135 DWORD cbBuf, LPDWORD pcbNeeded)
1137 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1142 /*****************************************************************************
1143 * AddJobW [WINSPOOL.@]
1145 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
1148 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1153 /*****************************************************************************
1154 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1156 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1157 DWORD level, LPBYTE Info,
1158 DWORD cbBuf, LPDWORD needed)
1160 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1161 level, Info, cbBuf);
1165 /*****************************************************************************
1166 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1168 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1169 DWORD level, LPBYTE Info,
1170 DWORD cbBuf, LPDWORD needed)
1172 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1173 level, Info, cbBuf);
1177 /*****************************************************************************
1178 * WINSPOOL_OpenDriverReg [internal]
1180 * opens the registry for the printer drivers depending on the given input
1181 * variable pEnvironment
1184 * the opened hkey on success
1187 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1189 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1190 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1192 LPWSTR lpKey, buffer = NULL;
1196 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1200 pEnvW = pEnvironment;
1202 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1203 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1204 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1209 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1211 if(!GetVersionExW( &ver))
1214 switch (ver.dwPlatformId) {
1215 case VER_PLATFORM_WIN32s:
1216 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1218 case VER_PLATFORM_WIN32_NT:
1225 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1228 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1229 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1230 wsprintfW( lpKey, DriversW, pEnvW);
1232 TRACE("%s\n", debugstr_w(lpKey));
1234 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1237 HeapFree( GetProcessHeap(), 0, buffer);
1238 HeapFree( GetProcessHeap(), 0, lpKey);
1243 /*****************************************************************************
1244 * AddPrinterW [WINSPOOL.@]
1246 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1248 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1252 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1255 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1258 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1259 SetLastError(ERROR_INVALID_PARAMETER);
1263 ERR("Level = %ld, unsupported!\n", Level);
1264 SetLastError(ERROR_INVALID_LEVEL);
1267 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1268 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1269 debugstr_w(pi->pPrinterName)
1271 SetLastError(ERROR_INVALID_LEVEL);
1275 SetLastError(ERROR_INVALID_PARAMETER);
1278 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1280 ERR("Can't create Printers key\n");
1283 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1284 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1285 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1286 RegCloseKey(hkeyPrinter);
1287 RegCloseKey(hkeyPrinters);
1290 RegCloseKey(hkeyPrinter);
1292 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1294 ERR("Can't create Drivers key\n");
1295 RegCloseKey(hkeyPrinters);
1298 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1300 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1301 RegCloseKey(hkeyPrinters);
1302 RegCloseKey(hkeyDrivers);
1303 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1306 RegCloseKey(hkeyDriver);
1307 RegCloseKey(hkeyDrivers);
1309 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1310 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1311 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1312 RegCloseKey(hkeyPrinters);
1316 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1318 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1319 SetLastError(ERROR_INVALID_PRINTER_NAME);
1320 RegCloseKey(hkeyPrinters);
1323 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1324 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1325 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1327 /* See if we can load the driver. We may need the devmode structure anyway
1330 * Note that DocumentPropertiesW will briefly try to open the printer we
1331 * just create to find a DEVMODEA struct (it will use the WINEPS default
1332 * one in case it is not there, so we are ok).
1334 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1337 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1338 size = sizeof(DEVMODEW);
1344 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1345 ZeroMemory(dmW,size);
1347 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1349 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1350 HeapFree(GetProcessHeap(),0,dmW);
1355 /* set devmode to printer name */
1356 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1360 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1361 and we support these drivers. NT writes DEVMODEW so somehow
1362 we'll need to distinguish between these when we support NT
1366 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1367 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1368 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1369 HeapFree(GetProcessHeap(), 0, dmA);
1371 HeapFree(GetProcessHeap(), 0, dmW);
1373 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1374 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1375 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1376 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1378 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1379 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1380 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1381 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1382 (LPBYTE)&pi->Priority, sizeof(DWORD));
1383 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1384 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1385 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1386 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1387 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1388 (LPBYTE)&pi->Status, sizeof(DWORD));
1389 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1390 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1392 RegCloseKey(hkeyPrinter);
1393 RegCloseKey(hkeyPrinters);
1394 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1395 ERR("OpenPrinter failing\n");
1401 /*****************************************************************************
1402 * AddPrinterA [WINSPOOL.@]
1404 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1406 UNICODE_STRING pNameW;
1408 PRINTER_INFO_2W *piW;
1409 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1412 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1414 ERR("Level = %ld, unsupported!\n", Level);
1415 SetLastError(ERROR_INVALID_LEVEL);
1418 pwstrNameW = asciitounicode(&pNameW,pName);
1419 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1421 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1423 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1424 RtlFreeUnicodeString(&pNameW);
1429 /*****************************************************************************
1430 * ClosePrinter [WINSPOOL.@]
1432 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1434 int i = (int)hPrinter;
1436 TRACE("Handle %p\n", hPrinter);
1438 if ((i <= 0) || (i > nb_printers)) return FALSE;
1439 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1440 printer_array[i - 1] = NULL;
1444 /*****************************************************************************
1445 * DeleteFormA [WINSPOOL.@]
1447 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1449 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1453 /*****************************************************************************
1454 * DeleteFormW [WINSPOOL.@]
1456 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1458 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1462 /*****************************************************************************
1463 * WINSPOOL_SHRegDeleteKey
1465 * Recursively delete subkeys.
1466 * Cut & paste from shlwapi.
1469 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1471 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1472 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1475 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1478 /* Find how many subkeys there are */
1479 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1480 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1484 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1485 /* Name too big: alloc a buffer for it */
1486 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1489 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1492 /* Recursively delete all the subkeys */
1493 for(i = 0; i < dwKeyCount && !dwRet; i++)
1495 dwSize = dwMaxSubkeyLen;
1496 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1498 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1501 if (lpszName != szNameBuf)
1502 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1506 RegCloseKey(hSubKey);
1508 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1513 /*****************************************************************************
1514 * DeletePrinter [WINSPOOL.@]
1516 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1518 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1519 HKEY hkeyPrinters, hkey;
1521 if(!lpNameW) return FALSE;
1522 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1523 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1524 RegCloseKey(hkeyPrinters);
1526 WriteProfileStringW(devicesW, lpNameW, NULL);
1527 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1528 RegDeleteValueW(hkey, lpNameW);
1534 /*****************************************************************************
1535 * SetPrinterA [WINSPOOL.@]
1537 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1540 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1544 /*****************************************************************************
1545 * SetJobA [WINSPOOL.@]
1547 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1548 LPBYTE pJob, DWORD Command)
1550 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1555 /*****************************************************************************
1556 * SetJobW [WINSPOOL.@]
1558 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1559 LPBYTE pJob, DWORD Command)
1561 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1566 /*****************************************************************************
1567 * EndDocPrinter [WINSPOOL.@]
1569 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1571 FIXME("(hPrinter=%p): stub\n", hPrinter);
1575 /*****************************************************************************
1576 * EndPagePrinter [WINSPOOL.@]
1578 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1580 FIXME("(hPrinter=%p): stub\n", hPrinter);
1584 /*****************************************************************************
1585 * StartDocPrinterA [WINSPOOL.@]
1587 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1589 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1593 /*****************************************************************************
1594 * StartDocPrinterW [WINSPOOL.@]
1596 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1598 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1602 /*****************************************************************************
1603 * StartPagePrinter [WINSPOOL.@]
1605 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1607 FIXME("(hPrinter=%p): stub\n", hPrinter);
1611 /*****************************************************************************
1612 * GetFormA [WINSPOOL.@]
1614 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1615 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1617 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1618 Level,pForm,cbBuf,pcbNeeded);
1622 /*****************************************************************************
1623 * GetFormW [WINSPOOL.@]
1625 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1626 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1628 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1629 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1633 /*****************************************************************************
1634 * SetFormA [WINSPOOL.@]
1636 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1639 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1643 /*****************************************************************************
1644 * SetFormW [WINSPOOL.@]
1646 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1649 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1653 /*****************************************************************************
1654 * ReadPrinter [WINSPOOL.@]
1656 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1657 LPDWORD pNoBytesRead)
1659 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1663 /*****************************************************************************
1664 * ResetPrinterA [WINSPOOL.@]
1666 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1668 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1672 /*****************************************************************************
1673 * ResetPrinterW [WINSPOOL.@]
1675 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1677 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1681 /*****************************************************************************
1682 * WINSPOOL_GetDWORDFromReg
1684 * Return DWORD associated with ValueName from hkey.
1686 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1688 DWORD sz = sizeof(DWORD), type, value = 0;
1691 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1693 if(ret != ERROR_SUCCESS) {
1694 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1697 if(type != REG_DWORD) {
1698 ERR("Got type %ld\n", type);
1704 /*****************************************************************************
1705 * WINSPOOL_GetStringFromReg
1707 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1708 * String is stored either as unicode or ascii.
1709 * Bit of a hack here to get the ValueName if we want ascii.
1711 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1712 DWORD buflen, DWORD *needed,
1715 DWORD sz = buflen, type;
1719 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1721 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1722 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1723 HeapFree(GetProcessHeap(),0,ValueNameA);
1725 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1726 WARN("Got ret = %ld\n", ret);
1734 /*****************************************************************************
1735 * WINSPOOL_GetDefaultDevMode
1737 * Get a default DevMode values for wineps.
1741 static void WINSPOOL_GetDefaultDevMode(
1743 DWORD buflen, DWORD *needed,
1748 /* fill default DEVMODE - should be read from ppd... */
1749 ZeroMemory( &dm, sizeof(dm) );
1750 strcpy(dm.dmDeviceName,"wineps.drv");
1751 dm.dmSpecVersion = DM_SPECVERSION;
1752 dm.dmDriverVersion = 1;
1753 dm.dmSize = sizeof(DEVMODEA);
1754 dm.dmDriverExtra = 0;
1756 DM_ORIENTATION | DM_PAPERSIZE |
1757 DM_PAPERLENGTH | DM_PAPERWIDTH |
1760 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1761 DM_YRESOLUTION | DM_TTOPTION;
1763 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1764 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1765 dm.u1.s1.dmPaperLength = 2970;
1766 dm.u1.s1.dmPaperWidth = 2100;
1770 dm.dmDefaultSource = DMBIN_AUTO;
1771 dm.dmPrintQuality = DMRES_MEDIUM;
1774 dm.dmYResolution = 300; /* 300dpi */
1775 dm.dmTTOption = DMTT_BITMAP;
1778 /* dm.dmLogPixels */
1779 /* dm.dmBitsPerPel */
1780 /* dm.dmPelsWidth */
1781 /* dm.dmPelsHeight */
1782 /* dm.dmDisplayFlags */
1783 /* dm.dmDisplayFrequency */
1784 /* dm.dmICMMethod */
1785 /* dm.dmICMIntent */
1786 /* dm.dmMediaType */
1787 /* dm.dmDitherType */
1788 /* dm.dmReserved1 */
1789 /* dm.dmReserved2 */
1790 /* dm.dmPanningWidth */
1791 /* dm.dmPanningHeight */
1794 if(buflen >= sizeof(DEVMODEW)) {
1795 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1796 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1797 HeapFree(GetProcessHeap(),0,pdmW);
1799 *needed = sizeof(DEVMODEW);
1803 if(buflen >= sizeof(DEVMODEA)) {
1804 memcpy(ptr, &dm, sizeof(DEVMODEA));
1806 *needed = sizeof(DEVMODEA);
1810 /*****************************************************************************
1811 * WINSPOOL_GetDevModeFromReg
1813 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1814 * DevMode is stored either as unicode or ascii.
1816 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1818 DWORD buflen, DWORD *needed,
1821 DWORD sz = buflen, type;
1824 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1825 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1826 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1827 if (sz < sizeof(DEVMODEA))
1829 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1832 /* ensures that dmSize is not erratically bogus if registry is invalid */
1833 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1834 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1836 sz += (CCHDEVICENAME + CCHFORMNAME);
1838 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1839 memcpy(ptr, dmW, sz);
1840 HeapFree(GetProcessHeap(),0,dmW);
1847 /*********************************************************************
1848 * WINSPOOL_GetPrinter_2
1850 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1851 * The strings are either stored as unicode or ascii.
1853 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1854 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1857 DWORD size, left = cbBuf;
1858 BOOL space = (cbBuf > 0);
1863 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1865 if(space && size <= left) {
1866 pi2->pPrinterName = (LPWSTR)ptr;
1873 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1875 if(space && size <= left) {
1876 pi2->pShareName = (LPWSTR)ptr;
1883 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1885 if(space && size <= left) {
1886 pi2->pPortName = (LPWSTR)ptr;
1893 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1895 if(space && size <= left) {
1896 pi2->pDriverName = (LPWSTR)ptr;
1903 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1905 if(space && size <= left) {
1906 pi2->pComment = (LPWSTR)ptr;
1913 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1915 if(space && size <= left) {
1916 pi2->pLocation = (LPWSTR)ptr;
1923 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1925 if(space && size <= left) {
1926 pi2->pDevMode = (LPDEVMODEW)ptr;
1935 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1936 if(space && size <= left) {
1937 pi2->pDevMode = (LPDEVMODEW)ptr;
1944 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1946 if(space && size <= left) {
1947 pi2->pSepFile = (LPWSTR)ptr;
1954 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1956 if(space && size <= left) {
1957 pi2->pPrintProcessor = (LPWSTR)ptr;
1964 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1966 if(space && size <= left) {
1967 pi2->pDatatype = (LPWSTR)ptr;
1974 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1976 if(space && size <= left) {
1977 pi2->pParameters = (LPWSTR)ptr;
1985 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1986 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1987 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1988 "Default Priority");
1989 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1990 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1993 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1994 memset(pi2, 0, sizeof(*pi2));
1999 /*********************************************************************
2000 * WINSPOOL_GetPrinter_4
2002 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2004 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2005 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2008 DWORD size, left = cbBuf;
2009 BOOL space = (cbBuf > 0);
2014 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2016 if(space && size <= left) {
2017 pi4->pPrinterName = (LPWSTR)ptr;
2025 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2028 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2029 memset(pi4, 0, sizeof(*pi4));
2034 /*********************************************************************
2035 * WINSPOOL_GetPrinter_5
2037 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2039 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2040 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2043 DWORD size, left = cbBuf;
2044 BOOL space = (cbBuf > 0);
2049 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2051 if(space && size <= left) {
2052 pi5->pPrinterName = (LPWSTR)ptr;
2059 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2061 if(space && size <= left) {
2062 pi5->pPortName = (LPWSTR)ptr;
2070 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2071 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2073 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2077 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2078 memset(pi5, 0, sizeof(*pi5));
2083 /*****************************************************************************
2084 * WINSPOOL_GetPrinter
2086 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2087 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2088 * just a collection of pointers to strings.
2090 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2091 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2094 DWORD size, needed = 0;
2096 HKEY hkeyPrinter, hkeyPrinters;
2099 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2101 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2103 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2105 ERR("Can't create Printers key\n");
2108 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2110 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2111 RegCloseKey(hkeyPrinters);
2112 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2119 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2121 size = sizeof(PRINTER_INFO_2W);
2123 ptr = pPrinter + size;
2125 memset(pPrinter, 0, size);
2130 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2138 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2140 size = sizeof(PRINTER_INFO_4W);
2142 ptr = pPrinter + size;
2144 memset(pPrinter, 0, size);
2149 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2158 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2160 size = sizeof(PRINTER_INFO_5W);
2162 ptr = pPrinter + size;
2164 memset(pPrinter, 0, size);
2170 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2177 FIXME("Unimplemented level %ld\n", Level);
2178 SetLastError(ERROR_INVALID_LEVEL);
2179 RegCloseKey(hkeyPrinters);
2180 RegCloseKey(hkeyPrinter);
2184 RegCloseKey(hkeyPrinter);
2185 RegCloseKey(hkeyPrinters);
2187 TRACE("returning %d needed = %ld\n", ret, needed);
2188 if(pcbNeeded) *pcbNeeded = needed;
2190 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2194 /*****************************************************************************
2195 * GetPrinterW [WINSPOOL.@]
2197 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2198 DWORD cbBuf, LPDWORD pcbNeeded)
2200 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2204 /*****************************************************************************
2205 * GetPrinterA [WINSPOOL.@]
2207 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2208 DWORD cbBuf, LPDWORD pcbNeeded)
2210 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2214 /*****************************************************************************
2215 * WINSPOOL_EnumPrinters
2217 * Implementation of EnumPrintersA|W
2219 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2220 DWORD dwLevel, LPBYTE lpbPrinters,
2221 DWORD cbBuf, LPDWORD lpdwNeeded,
2222 LPDWORD lpdwReturned, BOOL unicode)
2225 HKEY hkeyPrinters, hkeyPrinter;
2226 WCHAR PrinterName[255];
2227 DWORD needed = 0, number = 0;
2228 DWORD used, i, left;
2232 memset(lpbPrinters, 0, cbBuf);
2238 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2239 if(dwType == PRINTER_ENUM_DEFAULT)
2242 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2243 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2244 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2245 if(!dwType) return TRUE;
2248 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2249 FIXME("dwType = %08lx\n", dwType);
2250 SetLastError(ERROR_INVALID_FLAGS);
2254 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2256 ERR("Can't create Printers key\n");
2260 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2261 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2262 RegCloseKey(hkeyPrinters);
2263 ERR("Can't query Printers key\n");
2266 TRACE("Found %ld printers\n", number);
2270 RegCloseKey(hkeyPrinters);
2272 *lpdwReturned = number;
2276 used = number * sizeof(PRINTER_INFO_2W);
2279 used = number * sizeof(PRINTER_INFO_4W);
2282 used = number * sizeof(PRINTER_INFO_5W);
2286 SetLastError(ERROR_INVALID_LEVEL);
2287 RegCloseKey(hkeyPrinters);
2290 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2292 for(i = 0; i < number; i++) {
2293 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2295 ERR("Can't enum key number %ld\n", i);
2296 RegCloseKey(hkeyPrinters);
2299 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2300 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2302 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2303 RegCloseKey(hkeyPrinters);
2308 buf = lpbPrinters + used;
2309 left = cbBuf - used;
2317 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2318 left, &needed, unicode);
2320 if(pi) pi += sizeof(PRINTER_INFO_2W);
2323 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2324 left, &needed, unicode);
2326 if(pi) pi += sizeof(PRINTER_INFO_4W);
2329 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2330 left, &needed, unicode);
2332 if(pi) pi += sizeof(PRINTER_INFO_5W);
2335 ERR("Shouldn't be here!\n");
2336 RegCloseKey(hkeyPrinter);
2337 RegCloseKey(hkeyPrinters);
2340 RegCloseKey(hkeyPrinter);
2342 RegCloseKey(hkeyPrinters);
2349 memset(lpbPrinters, 0, cbBuf);
2350 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2354 *lpdwReturned = number;
2355 SetLastError(ERROR_SUCCESS);
2360 /******************************************************************
2361 * EnumPrintersW [WINSPOOL.@]
2363 * Enumerates the available printers, print servers and print
2364 * providers, depending on the specified flags, name and level.
2368 * If level is set to 1:
2369 * Not implemented yet!
2370 * Returns TRUE with an empty list.
2372 * If level is set to 2:
2373 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2374 * Returns an array of PRINTER_INFO_2 data structures in the
2375 * lpbPrinters buffer. Note that according to MSDN also an
2376 * OpenPrinter should be performed on every remote printer.
2378 * If level is set to 4 (officially WinNT only):
2379 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2380 * Fast: Only the registry is queried to retrieve printer names,
2381 * no connection to the driver is made.
2382 * Returns an array of PRINTER_INFO_4 data structures in the
2383 * lpbPrinters buffer.
2385 * If level is set to 5 (officially WinNT4/Win9x only):
2386 * Fast: Only the registry is queried to retrieve printer names,
2387 * no connection to the driver is made.
2388 * Returns an array of PRINTER_INFO_5 data structures in the
2389 * lpbPrinters buffer.
2391 * If level set to 3 or 6+:
2392 * returns zero (failure!)
2394 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2398 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2399 * - Only levels 2, 4 and 5 are implemented at the moment.
2400 * - 16-bit printer drivers are not enumerated.
2401 * - Returned amount of bytes used/needed does not match the real Windoze
2402 * implementation (as in this implementation, all strings are part
2403 * of the buffer, whereas Win32 keeps them somewhere else)
2404 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2407 * - In a regular Wine installation, no registry settings for printers
2408 * exist, which makes this function return an empty list.
2410 BOOL WINAPI EnumPrintersW(
2411 DWORD dwType, /* [in] Types of print objects to enumerate */
2412 LPWSTR lpszName, /* [in] name of objects to enumerate */
2413 DWORD dwLevel, /* [in] type of printer info structure */
2414 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2415 DWORD cbBuf, /* [in] max size of buffer in bytes */
2416 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2417 LPDWORD lpdwReturned /* [out] number of entries returned */
2420 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2421 lpdwNeeded, lpdwReturned, TRUE);
2424 /******************************************************************
2425 * EnumPrintersA [WINSPOOL.@]
2428 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2429 DWORD dwLevel, LPBYTE lpbPrinters,
2430 DWORD cbBuf, LPDWORD lpdwNeeded,
2431 LPDWORD lpdwReturned)
2434 UNICODE_STRING lpszNameW;
2437 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2438 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2439 lpdwNeeded, lpdwReturned, FALSE);
2440 RtlFreeUnicodeString(&lpszNameW);
2444 /*****************************************************************************
2445 * WINSPOOL_GetDriverInfoFromReg [internal]
2447 * Enters the information from the registry into the DRIVER_INFO struct
2450 * zero if the printer driver does not exist in the registry
2451 * (only if Level > 1) otherwise nonzero
2453 static BOOL WINSPOOL_GetDriverInfoFromReg(
2456 LPWSTR pEnvironment,
2458 LPBYTE ptr, /* DRIVER_INFO */
2459 LPBYTE pDriverStrings, /* strings buffer */
2460 DWORD cbBuf, /* size of string buffer */
2461 LPDWORD pcbNeeded, /* space needed for str. */
2462 BOOL unicode) /* type of strings */
2463 { DWORD dw, size, tmp, type;
2465 LPBYTE strPtr = pDriverStrings;
2467 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2468 debugstr_w(DriverName), debugstr_w(pEnvironment),
2469 Level, ptr, pDriverStrings, cbBuf, unicode);
2472 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2473 if (*pcbNeeded <= cbBuf)
2474 strcpyW((LPWSTR)strPtr, DriverName);
2476 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2478 if(*pcbNeeded <= cbBuf)
2479 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2484 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2488 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2489 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2492 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2493 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2494 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2499 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2501 WARN("Can't get Version\n");
2503 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2506 pEnvironment = (LPWSTR)DefaultEnvironmentW;
2508 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2510 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2513 if(*pcbNeeded <= cbBuf) {
2515 strcpyW((LPWSTR)strPtr, pEnvironment);
2517 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2520 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2521 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2524 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2527 if(*pcbNeeded <= cbBuf)
2528 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2531 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2532 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2535 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2538 if(*pcbNeeded <= cbBuf)
2539 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2542 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2543 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2546 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2547 0, &size, unicode)) {
2549 if(*pcbNeeded <= cbBuf)
2550 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2551 size, &tmp, unicode);
2553 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2554 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2558 RegCloseKey(hkeyDriver);
2559 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2563 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2566 if(*pcbNeeded <= cbBuf)
2567 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2568 size, &tmp, unicode);
2570 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2571 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2574 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2577 if(*pcbNeeded <= cbBuf)
2578 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2579 size, &tmp, unicode);
2581 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2582 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2585 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2588 if(*pcbNeeded <= cbBuf)
2589 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2590 size, &tmp, unicode);
2592 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2593 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2596 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2599 if(*pcbNeeded <= cbBuf)
2600 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2601 size, &tmp, unicode);
2603 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2604 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2607 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2608 RegCloseKey(hkeyDriver);
2612 /*****************************************************************************
2613 * WINSPOOL_GetPrinterDriver
2615 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2616 DWORD Level, LPBYTE pDriverInfo,
2617 DWORD cbBuf, LPDWORD pcbNeeded,
2621 WCHAR DriverName[100];
2622 DWORD ret, type, size, needed = 0;
2624 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2626 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2627 Level,pDriverInfo,cbBuf, pcbNeeded);
2629 ZeroMemory(pDriverInfo, cbBuf);
2631 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2633 if(Level < 1 || Level > 3) {
2634 SetLastError(ERROR_INVALID_LEVEL);
2637 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2639 ERR("Can't create Printers key\n");
2642 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2644 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2645 RegCloseKey(hkeyPrinters);
2646 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2649 size = sizeof(DriverName);
2651 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2652 (LPBYTE)DriverName, &size);
2653 RegCloseKey(hkeyPrinter);
2654 RegCloseKey(hkeyPrinters);
2655 if(ret != ERROR_SUCCESS) {
2656 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2660 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2662 ERR("Can't create Drivers key\n");
2668 size = sizeof(DRIVER_INFO_1W);
2671 size = sizeof(DRIVER_INFO_2W);
2674 size = sizeof(DRIVER_INFO_3W);
2677 ERR("Invalid level\n");
2682 ptr = pDriverInfo + size;
2684 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2685 pEnvironment, Level, pDriverInfo,
2686 (cbBuf < size) ? NULL : ptr,
2687 (cbBuf < size) ? 0 : cbBuf - size,
2688 &needed, unicode)) {
2689 RegCloseKey(hkeyDrivers);
2693 RegCloseKey(hkeyDrivers);
2695 if(pcbNeeded) *pcbNeeded = size + needed;
2696 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2697 if(cbBuf >= needed) return TRUE;
2698 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2702 /*****************************************************************************
2703 * GetPrinterDriverA [WINSPOOL.@]
2705 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2706 DWORD Level, LPBYTE pDriverInfo,
2707 DWORD cbBuf, LPDWORD pcbNeeded)
2710 UNICODE_STRING pEnvW;
2713 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2714 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2715 cbBuf, pcbNeeded, FALSE);
2716 RtlFreeUnicodeString(&pEnvW);
2719 /*****************************************************************************
2720 * GetPrinterDriverW [WINSPOOL.@]
2722 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2723 DWORD Level, LPBYTE pDriverInfo,
2724 DWORD cbBuf, LPDWORD pcbNeeded)
2726 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2727 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2730 /*****************************************************************************
2731 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2733 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2734 DWORD Level, LPBYTE pDriverDirectory,
2735 DWORD cbBuf, LPDWORD pcbNeeded)
2739 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2740 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2742 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2743 SetLastError(ERROR_INVALID_PARAMETER);
2746 if(pEnvironment != NULL) {
2747 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2748 SetLastError(ERROR_INVALID_ENVIRONMENT);
2751 if(Level != 1) /* win95 ignores this so we just carry on */
2752 WARN("Level = %ld - assuming 1\n", Level);
2754 /* FIXME should read from registry */
2755 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2756 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2760 needed*=sizeof(WCHAR);
2763 *pcbNeeded = needed;
2764 TRACE("required <%08lx>\n", *pcbNeeded);
2765 if(needed > cbBuf) {
2766 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2773 /*****************************************************************************
2774 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2776 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2777 DWORD Level, LPBYTE pDriverDirectory,
2778 DWORD cbBuf, LPDWORD pcbNeeded)
2780 UNICODE_STRING nameW, environmentW;
2783 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2784 WCHAR *driverDirectoryW = NULL;
2786 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2788 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2789 else nameW.Buffer = NULL;
2790 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2791 else environmentW.Buffer = NULL;
2793 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2794 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2797 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2798 pDriverDirectory, cbBuf, NULL, NULL);
2800 *pcbNeeded = needed;
2801 ret = (needed <= cbBuf) ? TRUE : FALSE;
2803 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2805 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2807 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2808 RtlFreeUnicodeString(&environmentW);
2809 RtlFreeUnicodeString(&nameW);
2814 /*****************************************************************************
2815 * AddPrinterDriverA [WINSPOOL.@]
2817 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2820 HKEY hkeyDrivers, hkeyName;
2822 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2824 if(level != 2 && level != 3) {
2825 SetLastError(ERROR_INVALID_LEVEL);
2829 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2830 SetLastError(ERROR_INVALID_PARAMETER);
2834 WARN("pDriverInfo == NULL\n");
2835 SetLastError(ERROR_INVALID_PARAMETER);
2840 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2842 memset(&di3, 0, sizeof(di3));
2843 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
2846 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2848 SetLastError(ERROR_INVALID_PARAMETER);
2851 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2852 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2853 if(!di3.pHelpFile) di3.pHelpFile = "";
2854 if(!di3.pMonitorName) di3.pMonitorName = "";
2856 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2859 ERR("Can't create Drivers key\n");
2863 if(level == 2) { /* apparently can't overwrite with level2 */
2864 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2865 RegCloseKey(hkeyName);
2866 RegCloseKey(hkeyDrivers);
2867 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2868 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2872 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2873 RegCloseKey(hkeyDrivers);
2874 ERR("Can't create Name key\n");
2877 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2879 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2880 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2881 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2883 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2884 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2885 di3.pDependentFiles, 0);
2886 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2887 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2888 RegCloseKey(hkeyName);
2889 RegCloseKey(hkeyDrivers);
2894 /*****************************************************************************
2895 * AddPrinterDriverW [WINSPOOL.@]
2897 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2900 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2905 /*****************************************************************************
2906 * AddPrintProcessorA [WINSPOOL.@]
2908 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
2909 LPSTR pPrintProcessorName)
2911 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
2912 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
2916 /*****************************************************************************
2917 * AddPrintProcessorW [WINSPOOL.@]
2919 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
2920 LPWSTR pPrintProcessorName)
2922 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
2923 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
2927 /*****************************************************************************
2928 * AddPrintProvidorA [WINSPOOL.@]
2930 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
2932 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
2936 /*****************************************************************************
2937 * AddPrintProvidorW [WINSPOOL.@]
2939 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
2941 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
2945 /*****************************************************************************
2946 * AdvancedDocumentPropertiesA [WINSPOOL.@]
2948 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
2949 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
2951 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
2952 pDevModeOutput, pDevModeInput);
2956 /*****************************************************************************
2957 * AdvancedDocumentPropertiesW [WINSPOOL.@]
2959 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
2960 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
2962 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
2963 pDevModeOutput, pDevModeInput);
2967 /*****************************************************************************
2968 * PrinterProperties [WINSPOOL.@]
2970 * Displays a dialog to set the properties of the printer.
2973 * nonzero on success or zero on failure
2976 * implemented as stub only
2978 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2979 HANDLE hPrinter /* [in] handle to printer object */
2981 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2982 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2986 /*****************************************************************************
2987 * EnumJobsA [WINSPOOL.@]
2990 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2991 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2994 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2995 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2997 if(pcbNeeded) *pcbNeeded = 0;
2998 if(pcReturned) *pcReturned = 0;
3003 /*****************************************************************************
3004 * EnumJobsW [WINSPOOL.@]
3007 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3008 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3011 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3012 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3014 if(pcbNeeded) *pcbNeeded = 0;
3015 if(pcReturned) *pcReturned = 0;
3019 /*****************************************************************************
3020 * WINSPOOL_EnumPrinterDrivers [internal]
3022 * Delivers information about all printer drivers installed on the
3023 * localhost or a given server
3026 * nonzero on success or zero on failure. If the buffer for the returned
3027 * information is too small the function will return an error
3030 * - only implemented for localhost, foreign hosts will return an error
3032 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3033 DWORD Level, LPBYTE pDriverInfo,
3034 DWORD cbBuf, LPDWORD pcbNeeded,
3035 LPDWORD pcReturned, BOOL unicode)
3038 DWORD i, needed, number = 0, size = 0;
3039 WCHAR DriverNameW[255];
3042 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3043 debugstr_w(pName), debugstr_w(pEnvironment),
3044 Level, pDriverInfo, cbBuf, unicode);
3046 /* check for local drivers */
3048 ERR("remote drivers unsupported! Current remote host is %s\n",
3053 /* check input parameter */
3054 if((Level < 1) || (Level > 3)) {
3055 ERR("unsupported level %ld\n", Level);
3056 SetLastError(ERROR_INVALID_LEVEL);
3060 /* initialize return values */
3062 memset( pDriverInfo, 0, cbBuf);
3066 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3068 ERR("Can't open Drivers key\n");
3072 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3073 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3074 RegCloseKey(hkeyDrivers);
3075 ERR("Can't query Drivers key\n");
3078 TRACE("Found %ld Drivers\n", number);
3080 /* get size of single struct
3081 * unicode and ascii structure have the same size
3085 size = sizeof(DRIVER_INFO_1A);
3088 size = sizeof(DRIVER_INFO_2A);
3091 size = sizeof(DRIVER_INFO_3A);
3095 /* calculate required buffer size */
3096 *pcbNeeded = size * number;
3098 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3100 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3101 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3103 ERR("Can't enum key number %ld\n", i);
3104 RegCloseKey(hkeyDrivers);
3107 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3108 pEnvironment, Level, ptr,
3109 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3110 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3111 &needed, unicode)) {
3112 RegCloseKey(hkeyDrivers);
3115 (*pcbNeeded) += needed;
3118 RegCloseKey(hkeyDrivers);
3120 if(cbBuf < *pcbNeeded){
3121 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3128 /*****************************************************************************
3129 * EnumPrinterDriversW [WINSPOOL.@]
3131 * see function EnumPrinterDrivers for RETURNS, BUGS
3133 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3134 LPBYTE pDriverInfo, DWORD cbBuf,
3135 LPDWORD pcbNeeded, LPDWORD pcReturned)
3137 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3138 cbBuf, pcbNeeded, pcReturned, TRUE);
3141 /*****************************************************************************
3142 * EnumPrinterDriversA [WINSPOOL.@]
3144 * see function EnumPrinterDrivers for RETURNS, BUGS
3146 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3147 LPBYTE pDriverInfo, DWORD cbBuf,
3148 LPDWORD pcbNeeded, LPDWORD pcReturned)
3150 UNICODE_STRING pNameW, pEnvironmentW;
3151 PWSTR pwstrNameW, pwstrEnvironmentW;
3153 pwstrNameW = asciitounicode(&pNameW, pName);
3154 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3156 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3157 Level, pDriverInfo, cbBuf, pcbNeeded,
3159 RtlFreeUnicodeString(&pNameW);
3160 RtlFreeUnicodeString(&pEnvironmentW);
3165 static CHAR PortMonitor[] = "Wine Port Monitor";
3166 static CHAR PortDescription[] = "Wine Port";
3168 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3172 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3173 NULL, OPEN_EXISTING, 0, NULL );
3174 if (handle == INVALID_HANDLE_VALUE)
3176 TRACE("Checking %s exists\n", name );
3177 CloseHandle( handle );
3181 static DWORD WINSPOOL_CountSerialPorts()
3188 strcpy( name, "COMx:" );
3190 if (WINSPOOL_ComPortExists( name ))
3197 /******************************************************************************
3198 * EnumPortsA (WINSPOOL.@)
3200 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3201 LPDWORD bufneeded,LPDWORD bufreturned)
3204 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3205 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3209 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3210 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3215 info_size = sizeof (PORT_INFO_1A);
3218 info_size = sizeof (PORT_INFO_2A);
3221 SetLastError(ERROR_INVALID_LEVEL);
3225 /* see how many exist */
3228 serial_count = WINSPOOL_CountSerialPorts();
3231 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3232 if ( r == ERROR_SUCCESS )
3234 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3235 &printer_count, NULL, NULL, NULL, NULL);
3237 count = serial_count + printer_count;
3239 /* then fill in the structure info structure once
3240 we know the offset to the first string */
3242 memset( buffer, 0, bufsize );
3244 ofs = info_size*count;
3245 for ( i=0; i<count; i++)
3247 DWORD vallen = sizeof(portname) - 1;
3249 /* get the serial port values, then the printer values */
3250 if ( i < serial_count )
3252 strcpy( portname, "COMx:" );
3253 portname[3] = '1' + i;
3254 if (!WINSPOOL_ComPortExists( portname ))
3257 TRACE("Found %s\n", portname );
3258 vallen = strlen( portname );
3262 r = RegEnumValueA( hkey_printer, i-serial_count,
3263 portname, &vallen, NULL, NULL, NULL, 0 );
3268 /* add a colon if necessary, and make it upper case */
3269 CharUpperBuffA(portname,vallen);
3270 if (strcasecmp(portname,"nul")!=0)
3271 if (vallen && (portname[vallen-1] != ':') )
3272 lstrcatA(portname,":");
3274 /* add the port info structure if we can fit it */
3275 if ( info_size*(n+1) < bufsize )
3279 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3280 info->pName = (LPSTR) &buffer[ofs];
3282 else if ( level == 2)
3284 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3285 info->pPortName = (LPSTR) &buffer[ofs];
3286 /* FIXME: fill in more stuff here */
3287 info->pMonitorName = PortMonitor;
3288 info->pDescription = PortDescription;
3289 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3292 /* add the name of the port if we can fit it */
3293 if ( ofs < bufsize )
3294 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3300 ofs += lstrlenA(portname)+1;
3303 RegCloseKey(hkey_printer);
3314 /******************************************************************************
3315 * EnumPortsW (WINSPOOL.@)
3317 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3318 LPDWORD bufneeded,LPDWORD bufreturned)
3320 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3321 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3325 /******************************************************************************
3326 * GetDefaultPrinterW (WINSPOOL.@)
3329 * This function must read the value from data 'device' of key
3330 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3332 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3336 WCHAR *buffer, *ptr;
3340 SetLastError(ERROR_INVALID_PARAMETER);
3344 /* make the buffer big enough for the stuff from the profile/registry,
3345 * the content must fit into the local buffer to compute the correct
3346 * size even if the extern buffer is too small or not given.
3347 * (20 for ,driver,port) */
3349 len = max(100, (insize + 20));
3350 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3352 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3354 SetLastError (ERROR_FILE_NOT_FOUND);
3358 TRACE("%s\n", debugstr_w(buffer));
3360 if ((ptr = strchrW(buffer, ',')) == NULL)
3362 SetLastError(ERROR_INVALID_NAME);
3368 *namesize = strlenW(buffer) + 1;
3369 if(!name || (*namesize > insize))
3371 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3375 strcpyW(name, buffer);
3378 HeapFree( GetProcessHeap(), 0, buffer);
3383 /******************************************************************************
3384 * GetDefaultPrinterA (WINSPOOL.@)
3386 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3390 WCHAR *bufferW = NULL;
3394 SetLastError(ERROR_INVALID_PARAMETER);
3398 if(name && *namesize) {
3400 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3403 if(!GetDefaultPrinterW( bufferW, namesize)) {
3408 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3412 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3415 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3418 HeapFree( GetProcessHeap(), 0, bufferW);
3423 /******************************************************************************
3424 * SetPrinterDataExA (WINSPOOL.@)
3426 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3427 LPCSTR pValueName, DWORD Type,
3428 LPBYTE pData, DWORD cbData)
3430 HKEY hkeyPrinter, hkeySubkey;
3433 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3434 debugstr_a(pValueName), Type, pData, cbData);
3436 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3440 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3442 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3443 RegCloseKey(hkeyPrinter);
3446 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3447 RegCloseKey(hkeySubkey);
3448 RegCloseKey(hkeyPrinter);
3452 /******************************************************************************
3453 * SetPrinterDataExW (WINSPOOL.@)
3455 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3456 LPCWSTR pValueName, DWORD Type,
3457 LPBYTE pData, DWORD cbData)
3459 HKEY hkeyPrinter, hkeySubkey;
3462 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3463 debugstr_w(pValueName), Type, pData, cbData);
3465 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3469 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3471 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3472 RegCloseKey(hkeyPrinter);
3475 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3476 RegCloseKey(hkeySubkey);
3477 RegCloseKey(hkeyPrinter);
3481 /******************************************************************************
3482 * SetPrinterDataA (WINSPOOL.@)
3484 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3485 LPBYTE pData, DWORD cbData)
3487 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3491 /******************************************************************************
3492 * SetPrinterDataW (WINSPOOL.@)
3494 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3495 LPBYTE pData, DWORD cbData)
3497 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3501 /******************************************************************************
3502 * GetPrinterDataExA (WINSPOOL.@)
3504 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3505 LPCSTR pValueName, LPDWORD pType,
3506 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3508 HKEY hkeyPrinter, hkeySubkey;
3511 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3512 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3515 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3519 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3521 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3522 RegCloseKey(hkeyPrinter);
3526 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3527 RegCloseKey(hkeySubkey);
3528 RegCloseKey(hkeyPrinter);
3532 /******************************************************************************
3533 * GetPrinterDataExW (WINSPOOL.@)
3535 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3536 LPCWSTR pValueName, LPDWORD pType,
3537 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3539 HKEY hkeyPrinter, hkeySubkey;
3542 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3543 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3546 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3550 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3552 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3553 RegCloseKey(hkeyPrinter);
3557 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3558 RegCloseKey(hkeySubkey);
3559 RegCloseKey(hkeyPrinter);
3563 /******************************************************************************
3564 * GetPrinterDataA (WINSPOOL.@)
3566 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3567 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3569 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3570 pData, nSize, pcbNeeded);
3573 /******************************************************************************
3574 * GetPrinterDataW (WINSPOOL.@)
3576 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3577 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3579 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3580 pData, nSize, pcbNeeded);
3583 /*******************************************************************************
3584 * EnumPrinterDataExW [WINSPOOL.@]
3586 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3587 LPBYTE pEnumValues, DWORD cbEnumValues,
3588 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3590 HKEY hkPrinter, hkSubKey;
3591 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3592 cbValueNameLen, cbMaxValueLen, cbValueLen,
3597 PPRINTER_ENUM_VALUESW ppev;
3599 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3601 if (pKeyName == NULL || *pKeyName == 0)
3602 return ERROR_INVALID_PARAMETER;
3604 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3605 if (ret != ERROR_SUCCESS)
3607 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3612 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3613 if (ret != ERROR_SUCCESS)
3615 r = RegCloseKey (hkPrinter);
3616 if (r != ERROR_SUCCESS)
3617 WARN ("RegCloseKey returned %li\n", r);
3618 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3619 debugstr_w (pKeyName), ret);
3623 ret = RegCloseKey (hkPrinter);
3624 if (ret != ERROR_SUCCESS)
3626 ERR ("RegCloseKey returned %li\n", ret);
3627 r = RegCloseKey (hkSubKey);
3628 if (r != ERROR_SUCCESS)
3629 WARN ("RegCloseKey returned %li\n", r);
3633 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3634 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3635 if (ret != ERROR_SUCCESS)
3637 r = RegCloseKey (hkSubKey);
3638 if (r != ERROR_SUCCESS)
3639 WARN ("RegCloseKey returned %li\n", r);
3640 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3644 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3645 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3647 if (cValues == 0) /* empty key */
3649 r = RegCloseKey (hkSubKey);
3650 if (r != ERROR_SUCCESS)
3651 WARN ("RegCloseKey returned %li\n", r);
3652 *pcbEnumValues = *pnEnumValues = 0;
3653 return ERROR_SUCCESS;
3656 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3658 hHeap = GetProcessHeap ();
3661 ERR ("GetProcessHeap failed\n");
3662 r = RegCloseKey (hkSubKey);
3663 if (r != ERROR_SUCCESS)
3664 WARN ("RegCloseKey returned %li\n", r);
3665 return ERROR_OUTOFMEMORY;
3668 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3669 if (lpValueName == NULL)
3671 ERR ("Failed to allocate %li bytes from process heap\n",
3672 cbMaxValueNameLen * sizeof (WCHAR));
3673 r = RegCloseKey (hkSubKey);
3674 if (r != ERROR_SUCCESS)
3675 WARN ("RegCloseKey returned %li\n", r);
3676 return ERROR_OUTOFMEMORY;
3679 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3680 if (lpValue == NULL)
3682 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3683 if (HeapFree (hHeap, 0, lpValueName) == 0)
3684 WARN ("HeapFree failed with code %li\n", GetLastError ());
3685 r = RegCloseKey (hkSubKey);
3686 if (r != ERROR_SUCCESS)
3687 WARN ("RegCloseKey returned %li\n", r);
3688 return ERROR_OUTOFMEMORY;
3691 TRACE ("pass 1: calculating buffer required for all names and values\n");
3693 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3695 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3697 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3699 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3700 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3701 NULL, NULL, lpValue, &cbValueLen);
3702 if (ret != ERROR_SUCCESS)
3704 if (HeapFree (hHeap, 0, lpValue) == 0)
3705 WARN ("HeapFree failed with code %li\n", GetLastError ());
3706 if (HeapFree (hHeap, 0, lpValueName) == 0)
3707 WARN ("HeapFree failed with code %li\n", GetLastError ());
3708 r = RegCloseKey (hkSubKey);
3709 if (r != ERROR_SUCCESS)
3710 WARN ("RegCloseKey returned %li\n", r);
3711 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3715 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3716 debugstr_w (lpValueName), dwIndex,
3717 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3719 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3720 cbBufSize += cbValueLen;
3723 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3725 *pcbEnumValues = cbBufSize;
3726 *pnEnumValues = cValues;
3728 if (cbEnumValues < cbBufSize) /* buffer too small */
3730 if (HeapFree (hHeap, 0, lpValue) == 0)
3731 WARN ("HeapFree failed with code %li\n", GetLastError ());
3732 if (HeapFree (hHeap, 0, lpValueName) == 0)
3733 WARN ("HeapFree failed with code %li\n", GetLastError ());
3734 r = RegCloseKey (hkSubKey);
3735 if (r != ERROR_SUCCESS)
3736 WARN ("RegCloseKey returned %li\n", r);
3737 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3738 return ERROR_MORE_DATA;
3741 TRACE ("pass 2: copying all names and values to buffer\n");
3743 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3744 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3746 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3748 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3749 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3750 NULL, &dwType, lpValue, &cbValueLen);
3751 if (ret != ERROR_SUCCESS)
3753 if (HeapFree (hHeap, 0, lpValue) == 0)
3754 WARN ("HeapFree failed with code %li\n", GetLastError ());
3755 if (HeapFree (hHeap, 0, lpValueName) == 0)
3756 WARN ("HeapFree failed with code %li\n", GetLastError ());
3757 r = RegCloseKey (hkSubKey);
3758 if (r != ERROR_SUCCESS)
3759 WARN ("RegCloseKey returned %li\n", r);
3760 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3764 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3765 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3766 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3767 pEnumValues += cbValueNameLen;
3769 /* return # of *bytes* (including trailing \0), not # of chars */
3770 ppev[dwIndex].cbValueName = cbValueNameLen;
3772 ppev[dwIndex].dwType = dwType;
3774 memcpy (pEnumValues, lpValue, cbValueLen);
3775 ppev[dwIndex].pData = pEnumValues;
3776 pEnumValues += cbValueLen;
3778 ppev[dwIndex].cbData = cbValueLen;
3780 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3781 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3784 if (HeapFree (hHeap, 0, lpValue) == 0)
3786 ret = GetLastError ();
3787 ERR ("HeapFree failed with code %li\n", ret);
3788 if (HeapFree (hHeap, 0, lpValueName) == 0)
3789 WARN ("HeapFree failed with code %li\n", GetLastError ());
3790 r = RegCloseKey (hkSubKey);
3791 if (r != ERROR_SUCCESS)
3792 WARN ("RegCloseKey returned %li\n", r);
3796 if (HeapFree (hHeap, 0, lpValueName) == 0)
3798 ret = GetLastError ();
3799 ERR ("HeapFree failed with code %li\n", ret);
3800 r = RegCloseKey (hkSubKey);
3801 if (r != ERROR_SUCCESS)
3802 WARN ("RegCloseKey returned %li\n", r);
3806 ret = RegCloseKey (hkSubKey);
3807 if (ret != ERROR_SUCCESS)
3809 ERR ("RegCloseKey returned %li\n", ret);
3813 return ERROR_SUCCESS;
3816 /*******************************************************************************
3817 * EnumPrinterDataExA [WINSPOOL.@]
3819 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3820 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3821 * what Windows 2000 SP1 does.
3824 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3825 LPBYTE pEnumValues, DWORD cbEnumValues,
3826 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3830 DWORD ret, dwIndex, dwBufSize;
3834 TRACE ("%p %s\n", hPrinter, pKeyName);
3836 if (pKeyName == NULL || *pKeyName == 0)
3837 return ERROR_INVALID_PARAMETER;
3839 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3842 ret = GetLastError ();
3843 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3847 hHeap = GetProcessHeap ();
3850 ERR ("GetProcessHeap failed\n");
3851 return ERROR_OUTOFMEMORY;
3854 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3855 if (pKeyNameW == NULL)
3857 ERR ("Failed to allocate %li bytes from process heap\n",
3858 (LONG) len * sizeof (WCHAR));
3859 return ERROR_OUTOFMEMORY;
3862 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3864 ret = GetLastError ();
3865 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3866 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3867 WARN ("HeapFree failed with code %li\n", GetLastError ());
3871 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3872 pcbEnumValues, pnEnumValues);
3873 if (ret != ERROR_SUCCESS)
3875 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3876 WARN ("HeapFree failed with code %li\n", GetLastError ());
3877 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3881 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3883 ret = GetLastError ();
3884 ERR ("HeapFree failed with code %li\n", ret);
3888 if (*pnEnumValues == 0) /* empty key */
3889 return ERROR_SUCCESS;
3892 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3894 PPRINTER_ENUM_VALUESW ppev =
3895 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3897 if (dwBufSize < ppev->cbValueName)
3898 dwBufSize = ppev->cbValueName;
3900 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3901 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3902 dwBufSize = ppev->cbData;
3905 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3907 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3908 if (pBuffer == NULL)
3910 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3911 return ERROR_OUTOFMEMORY;
3914 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3916 PPRINTER_ENUM_VALUESW ppev =
3917 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3919 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3920 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3924 ret = GetLastError ();
3925 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3926 if (HeapFree (hHeap, 0, pBuffer) == 0)
3927 WARN ("HeapFree failed with code %li\n", GetLastError ());
3931 memcpy (ppev->pValueName, pBuffer, len);
3933 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3935 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3936 ppev->dwType != REG_MULTI_SZ)
3939 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3940 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3943 ret = GetLastError ();
3944 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3945 if (HeapFree (hHeap, 0, pBuffer) == 0)
3946 WARN ("HeapFree failed with code %li\n", GetLastError ());
3950 memcpy (ppev->pData, pBuffer, len);
3952 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3953 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3956 if (HeapFree (hHeap, 0, pBuffer) == 0)
3958 ret = GetLastError ();
3959 ERR ("HeapFree failed with code %li\n", ret);
3963 return ERROR_SUCCESS;
3966 /******************************************************************************
3967 * AbortPrinter (WINSPOOL.@)
3969 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
3971 FIXME("(%p), stub!\n", hPrinter);
3975 /******************************************************************************
3976 * AddPortA (WINSPOOL.@)
3978 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
3980 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
3984 /******************************************************************************
3985 * AddPortW (WINSPOOL.@)
3987 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
3989 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
3993 /******************************************************************************
3994 * AddPortExA (WINSPOOL.@)
3996 * Adds a print spooler port without presenting a user interface.
3998 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4000 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4001 lpBuffer, debugstr_a(lpMonitorName));
4005 /******************************************************************************
4006 * AddPortExW (WINSPOOL.@)
4010 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4012 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4013 lpBuffer, debugstr_w(lpMonitorName));
4017 /******************************************************************************
4018 * AddPrinterConnectionA (WINSPOOL.@)
4020 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4022 FIXME("%s\n", debugstr_a(pName));
4026 /******************************************************************************
4027 * AddPrinterConnectionW (WINSPOOL.@)
4029 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4031 FIXME("%s\n", debugstr_w(pName));
4035 /******************************************************************************
4036 * AddPrinterDriverExW (WINSPOOL.@)
4038 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4039 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4041 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4042 Level, pDriverInfo, dwFileCopyFlags);
4043 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4047 /******************************************************************************
4048 * AddPrinterDriverExA (WINSPOOL.@)
4050 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4051 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4053 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4054 Level, pDriverInfo, dwFileCopyFlags);
4055 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4059 /******************************************************************************
4060 * ConfigurePortA (WINSPOOL.@)
4062 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4064 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4068 /******************************************************************************
4069 * ConfigurePortW (WINSPOOL.@)
4071 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4073 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4077 /******************************************************************************
4078 * ConnectToPrinterDlg (WINSPOOL.@)
4080 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4082 FIXME("%p %lx\n", hWnd, Flags);
4086 /******************************************************************************
4087 * DeletePrinterConnectionA (WINSPOOL.@)
4089 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4091 FIXME("%s\n", debugstr_a(pName));
4095 /******************************************************************************
4096 * DeletePrinterConnectionW (WINSPOOL.@)
4098 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4100 FIXME("%s\n", debugstr_w(pName));
4104 /******************************************************************************
4105 * DeletePrinterDriverExW (WINSPOOL.@)
4107 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4108 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4110 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4111 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4115 /******************************************************************************
4116 * DeletePrinterDriverExA (WINSPOOL.@)
4118 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4119 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4121 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4122 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4126 /******************************************************************************
4127 * DeletePrinterDataExW (WINSPOOL.@)
4129 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4132 FIXME("%p %s %s\n", hPrinter,
4133 debugstr_w(pKeyName), debugstr_w(pValueName));
4134 return ERROR_INVALID_PARAMETER;
4137 /******************************************************************************
4138 * DeletePrinterDataExA (WINSPOOL.@)
4140 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4143 FIXME("%p %s %s\n", hPrinter,
4144 debugstr_a(pKeyName), debugstr_a(pValueName));
4145 return ERROR_INVALID_PARAMETER;
4148 /******************************************************************************
4149 * DeletePrintProcessorA (WINSPOOL.@)
4151 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4153 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4154 debugstr_a(pPrintProcessorName));
4158 /******************************************************************************
4159 * DeletePrintProcessorW (WINSPOOL.@)
4161 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4163 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4164 debugstr_w(pPrintProcessorName));
4168 /******************************************************************************
4169 * DeletePrintProvidorA (WINSPOOL.@)
4171 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4173 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4174 debugstr_a(pPrintProviderName));
4178 /******************************************************************************
4179 * DeletePrintProvidorW (WINSPOOL.@)
4181 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4183 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4184 debugstr_w(pPrintProviderName));
4188 /******************************************************************************
4189 * EnumFormsA (WINSPOOL.@)
4191 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4192 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4194 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4198 /******************************************************************************
4199 * EnumFormsW (WINSPOOL.@)
4201 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4202 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4204 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4208 /*****************************************************************************
4209 * EnumMonitorsA [WINSPOOL.@]
4212 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4213 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4215 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4216 cbBuf, pcbNeeded, pcReturned);
4217 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4221 /*****************************************************************************
4222 * EnumMonitorsW [WINSPOOL.@]
4225 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4226 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4228 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4229 cbBuf, pcbNeeded, pcReturned);
4230 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4234 /******************************************************************************
4235 * XcvDataW (WINSPOOL.@)
4238 * There doesn't seem to be an A version...
4240 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4241 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4242 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4244 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4245 pInputData, cbInputData, pOutputData,
4246 cbOutputData, pcbOutputNeeded, pdwStatus);
4250 /*****************************************************************************
4251 * EnumPrinterDataA [WINSPOOL.@]
4254 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4255 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4256 DWORD cbData, LPDWORD pcbData )
4258 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4259 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4260 return ERROR_NO_MORE_ITEMS;
4263 /*****************************************************************************
4264 * EnumPrinterDataW [WINSPOOL.@]
4267 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4268 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4269 DWORD cbData, LPDWORD pcbData )
4271 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4272 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4273 return ERROR_NO_MORE_ITEMS;
4276 /*****************************************************************************
4277 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4280 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4281 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4282 LPDWORD pcbNeeded, LPDWORD pcReturned)
4284 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4285 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4286 pcbNeeded, pcReturned);
4290 /*****************************************************************************
4291 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4294 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4295 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4296 LPDWORD pcbNeeded, LPDWORD pcReturned)
4298 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4299 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4300 pcbNeeded, pcReturned);
4304 /*****************************************************************************
4305 * EnumPrintProcessorsA [WINSPOOL.@]
4308 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4309 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4311 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4312 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
4316 /*****************************************************************************
4317 * EnumPrintProcessorsW [WINSPOOL.@]
4320 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4321 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4323 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4324 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
4325 cbBuf, pcbNeeded, pcbReturned);
4329 /*****************************************************************************
4330 * ExtDeviceMode [WINSPOOL.@]
4333 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
4334 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
4337 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
4338 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
4339 debugstr_a(pProfile), fMode);
4343 /*****************************************************************************
4344 * FindClosePrinterChangeNotification [WINSPOOL.@]
4347 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
4349 FIXME("Stub: %p\n", hChange);
4353 /*****************************************************************************
4354 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4357 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
4358 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
4360 FIXME("Stub: %p %lx %lx %p\n",
4361 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
4362 return INVALID_HANDLE_VALUE;
4365 /*****************************************************************************
4366 * FindNextPrinterChangeNotification [WINSPOOL.@]
4369 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
4370 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
4372 FIXME("Stub: %p %p %p %p\n",
4373 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
4377 /*****************************************************************************
4378 * FreePrinterNotifyInfo [WINSPOOL.@]
4381 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
4383 FIXME("Stub: %p\n", pPrinterNotifyInfo);
4387 /*****************************************************************************
4388 * GetJobA [WINSPOOL.@]
4391 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4392 DWORD cbBuf, LPDWORD pcbNeeded)
4394 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4399 /*****************************************************************************
4400 * GetJobW [WINSPOOL.@]
4403 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4404 DWORD cbBuf, LPDWORD pcbNeeded)
4406 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4411 /*****************************************************************************
4412 * ScheduleJob [WINSPOOL.@]
4415 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
4417 FIXME("Stub: %p %lx\n", hPrinter, dwJobID);