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 /* @@ Wine registry key: HKLM\Software\Wine\Wine\Config\ppd */
512 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
513 &hkey) == ERROR_SUCCESS) {
515 PRINTCAP_LoadPrinters();
519 /* Now enumerate the list again and delete any printers that a still tagged */
520 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
522 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
523 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
524 for(i = 0; i < num; i++) {
525 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
526 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
527 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
528 DWORD dw, type, size = sizeof(dw);
529 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
530 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
540 HeapFree(GetProcessHeap(), 0, pi);
548 /******************************************************************
549 * WINSPOOL_GetOpenedPrinterEntry
550 * Get the first place empty in the opened printer table
552 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
556 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
558 if (i >= nb_printers)
562 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_array,
563 (nb_printers + 16) * sizeof(*new_array) );
565 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
566 (nb_printers + 16) * sizeof(*new_array) );
568 if (!new_array) return 0;
569 printer_array = new_array;
573 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
575 strcpyW( printer_array[i], name );
576 return (HANDLE)(i + 1);
581 /******************************************************************
582 * WINSPOOL_GetOpenedPrinter
583 * Get the pointer to the opened printer referred by the handle
585 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
587 int idx = (int)printerHandle;
588 if ((idx <= 0) || (idx > nb_printers))
590 SetLastError(ERROR_INVALID_HANDLE);
593 return printer_array[idx - 1];
596 /******************************************************************
597 * WINSPOOL_GetOpenedPrinterRegKey
600 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
602 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
606 if(!name) return ERROR_INVALID_HANDLE;
608 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
612 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
614 ERR("Can't find opened printer %s in registry\n",
616 RegCloseKey(hkeyPrinters);
617 return ERROR_INVALID_PRINTER_NAME; /* ? */
619 RegCloseKey(hkeyPrinters);
620 return ERROR_SUCCESS;
623 /***********************************************************
626 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
629 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
632 Formname = (dmA->dmSize > off_formname);
633 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
634 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
637 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
638 dmA->dmSize - CCHDEVICENAME);
640 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
641 off_formname - CCHDEVICENAME);
642 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
644 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
645 (off_formname + CCHFORMNAME));
648 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
653 /***********************************************************
655 * Creates an ascii copy of supplied devmode on heap
657 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
662 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
664 if(!dmW) return NULL;
665 Formname = (dmW->dmSize > off_formname);
666 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
667 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
668 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
669 CCHDEVICENAME, NULL, NULL);
671 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
672 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
674 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
675 off_formname - CCHDEVICENAME * sizeof(WCHAR));
676 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
677 CCHFORMNAME, NULL, NULL);
678 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
679 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
682 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
687 /***********************************************************
689 * Creates a unicode copy of PRINTER_INFO_2A on heap
691 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
693 LPPRINTER_INFO_2W piW;
694 UNICODE_STRING usBuffer;
696 if(!piA) return NULL;
697 piW = HeapAlloc(heap, 0, sizeof(*piW));
698 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
700 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
701 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
702 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
703 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
704 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
705 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
706 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
707 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
708 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
709 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
710 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
711 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
715 /***********************************************************
716 * FREE_PRINTER_INFO_2W
717 * Free PRINTER_INFO_2W and all strings
719 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
723 HeapFree(heap,0,piW->pServerName);
724 HeapFree(heap,0,piW->pPrinterName);
725 HeapFree(heap,0,piW->pShareName);
726 HeapFree(heap,0,piW->pPortName);
727 HeapFree(heap,0,piW->pDriverName);
728 HeapFree(heap,0,piW->pComment);
729 HeapFree(heap,0,piW->pLocation);
730 HeapFree(heap,0,piW->pDevMode);
731 HeapFree(heap,0,piW->pSepFile);
732 HeapFree(heap,0,piW->pPrintProcessor);
733 HeapFree(heap,0,piW->pDatatype);
734 HeapFree(heap,0,piW->pParameters);
735 HeapFree(heap,0,piW);
739 /******************************************************************
740 * DeviceCapabilities [WINSPOOL.@]
741 * DeviceCapabilitiesA [WINSPOOL.@]
744 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
745 LPSTR pOutput, LPDEVMODEA lpdm)
749 if (!GDI_CallDeviceCapabilities16)
751 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
753 if (!GDI_CallDeviceCapabilities16) return -1;
755 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
757 /* If DC_PAPERSIZE map POINT16s to POINTs */
758 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
759 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
760 POINT *pt = (POINT *)pOutput;
762 memcpy(tmp, pOutput, ret * sizeof(POINT16));
763 for(i = 0; i < ret; i++, pt++)
768 HeapFree( GetProcessHeap(), 0, tmp );
774 /*****************************************************************************
775 * DeviceCapabilitiesW [WINSPOOL.@]
777 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
780 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
781 WORD fwCapability, LPWSTR pOutput,
782 const DEVMODEW *pDevMode)
784 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
785 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
786 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
789 if(pOutput && (fwCapability == DC_BINNAMES ||
790 fwCapability == DC_FILEDEPENDENCIES ||
791 fwCapability == DC_PAPERNAMES)) {
792 /* These need A -> W translation */
795 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
799 switch(fwCapability) {
804 case DC_FILEDEPENDENCIES:
808 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
809 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
811 for(i = 0; i < ret; i++)
812 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
813 pOutput + (i * size), size);
814 HeapFree(GetProcessHeap(), 0, pOutputA);
816 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
817 (LPSTR)pOutput, dmA);
819 HeapFree(GetProcessHeap(),0,pPortA);
820 HeapFree(GetProcessHeap(),0,pDeviceA);
821 HeapFree(GetProcessHeap(),0,dmA);
825 /******************************************************************
826 * DocumentPropertiesA [WINSPOOL.@]
828 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
830 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
831 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
832 LPDEVMODEA pDevModeInput,DWORD fMode )
834 LPSTR lpName = pDeviceName;
837 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
838 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
842 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
844 ERR("no name from hPrinter?\n");
847 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
850 if (!GDI_CallExtDeviceMode16)
852 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
854 if (!GDI_CallExtDeviceMode16) {
855 ERR("No CallExtDeviceMode16?\n");
859 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
860 pDevModeInput, NULL, fMode);
863 HeapFree(GetProcessHeap(),0,lpName);
868 /*****************************************************************************
869 * DocumentPropertiesW (WINSPOOL.@)
871 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
873 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
875 LPDEVMODEW pDevModeOutput,
876 LPDEVMODEW pDevModeInput, DWORD fMode)
879 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
880 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
881 LPDEVMODEA pDevModeOutputA = NULL;
884 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
885 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
888 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
889 if(ret < 0) return ret;
890 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
892 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
893 pDevModeInputA, fMode);
895 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
896 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
898 if(fMode == 0 && ret > 0)
899 ret += (CCHDEVICENAME + CCHFORMNAME);
900 HeapFree(GetProcessHeap(),0,pDevModeInputA);
901 HeapFree(GetProcessHeap(),0,pDeviceNameA);
905 /******************************************************************
906 * OpenPrinterA [WINSPOOL.@]
909 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
910 LPPRINTER_DEFAULTSA pDefault)
912 UNICODE_STRING lpPrinterNameW;
913 UNICODE_STRING usBuffer;
914 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
915 PWSTR pwstrPrinterNameW;
918 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
921 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
922 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
923 DefaultW.DesiredAccess = pDefault->DesiredAccess;
924 pDefaultW = &DefaultW;
926 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
928 RtlFreeUnicodeString(&usBuffer);
929 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
931 RtlFreeUnicodeString(&lpPrinterNameW);
935 /******************************************************************
936 * OpenPrinterW [WINSPOOL.@]
939 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
940 LPPRINTER_DEFAULTSW pDefault)
942 HKEY hkeyPrinters, hkeyPrinter;
944 if (!lpPrinterName) {
945 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
946 SetLastError(ERROR_INVALID_PARAMETER);
950 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
953 /* Check Printer exists */
954 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
956 ERR("Can't create Printers key\n");
957 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
961 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
962 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
964 TRACE("Can't find printer %s in registry\n",
965 debugstr_w(lpPrinterName));
966 RegCloseKey(hkeyPrinters);
967 SetLastError(ERROR_INVALID_PRINTER_NAME);
970 RegCloseKey(hkeyPrinter);
971 RegCloseKey(hkeyPrinters);
973 if(!phPrinter) /* This seems to be what win95 does anyway */
976 /* Get the unique handle of the printer*/
977 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
979 if (pDefault != NULL)
980 FIXME("Not handling pDefault\n");
985 /******************************************************************
986 * AddMonitorA [WINSPOOL.@]
989 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
991 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
992 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
996 /******************************************************************************
997 * AddMonitorW [WINSPOOL.@]
999 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1001 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1002 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1006 /******************************************************************
1007 * DeletePrinterDriverA [WINSPOOL.@]
1011 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1013 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1014 debugstr_a(pDriverName));
1015 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1019 /******************************************************************
1020 * DeletePrinterDriverW [WINSPOOL.@]
1024 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1026 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1027 debugstr_w(pDriverName));
1028 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1032 /******************************************************************
1033 * DeleteMonitorA [WINSPOOL.@]
1037 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1039 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1040 debugstr_a(pMonitorName));
1041 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1045 /******************************************************************
1046 * DeleteMonitorW [WINSPOOL.@]
1050 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1052 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1053 debugstr_w(pMonitorName));
1054 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1058 /******************************************************************
1059 * DeletePortA [WINSPOOL.@]
1063 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1065 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1066 debugstr_a(pPortName));
1067 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1071 /******************************************************************
1072 * DeletePortW [WINSPOOL.@]
1076 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1078 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1079 debugstr_w(pPortName));
1080 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1084 /******************************************************************************
1085 * SetPrinterW [WINSPOOL.@]
1095 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1099 /******************************************************************************
1100 * WritePrinter [WINSPOOL.@]
1107 LPDWORD pcWritten) {
1110 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1114 /*****************************************************************************
1115 * AddFormA [WINSPOOL.@]
1117 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1119 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1123 /*****************************************************************************
1124 * AddFormW [WINSPOOL.@]
1126 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1128 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1132 /*****************************************************************************
1133 * AddJobA [WINSPOOL.@]
1135 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
1136 DWORD cbBuf, LPDWORD pcbNeeded)
1138 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1143 /*****************************************************************************
1144 * AddJobW [WINSPOOL.@]
1146 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
1149 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1154 /*****************************************************************************
1155 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1157 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1158 DWORD level, LPBYTE Info,
1159 DWORD cbBuf, LPDWORD needed)
1161 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1162 level, Info, cbBuf);
1166 /*****************************************************************************
1167 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1169 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1170 DWORD level, LPBYTE Info,
1171 DWORD cbBuf, LPDWORD needed)
1173 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1174 level, Info, cbBuf);
1178 /*****************************************************************************
1179 * WINSPOOL_OpenDriverReg [internal]
1181 * opens the registry for the printer drivers depending on the given input
1182 * variable pEnvironment
1185 * the opened hkey on success
1188 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1190 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1191 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1193 LPWSTR lpKey, buffer = NULL;
1197 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1201 pEnvW = pEnvironment;
1203 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1204 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1205 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1210 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1212 if(!GetVersionExW( &ver))
1215 switch (ver.dwPlatformId) {
1216 case VER_PLATFORM_WIN32s:
1217 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1219 case VER_PLATFORM_WIN32_NT:
1226 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1229 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1230 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1231 wsprintfW( lpKey, DriversW, pEnvW);
1233 TRACE("%s\n", debugstr_w(lpKey));
1235 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1238 HeapFree( GetProcessHeap(), 0, buffer);
1239 HeapFree( GetProcessHeap(), 0, lpKey);
1244 /*****************************************************************************
1245 * AddPrinterW [WINSPOOL.@]
1247 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1249 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1253 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1256 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1259 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1260 SetLastError(ERROR_INVALID_PARAMETER);
1264 ERR("Level = %ld, unsupported!\n", Level);
1265 SetLastError(ERROR_INVALID_LEVEL);
1268 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1269 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1270 debugstr_w(pi->pPrinterName)
1272 SetLastError(ERROR_INVALID_LEVEL);
1276 SetLastError(ERROR_INVALID_PARAMETER);
1279 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1281 ERR("Can't create Printers key\n");
1284 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1285 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1286 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1287 RegCloseKey(hkeyPrinter);
1288 RegCloseKey(hkeyPrinters);
1291 RegCloseKey(hkeyPrinter);
1293 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1295 ERR("Can't create Drivers key\n");
1296 RegCloseKey(hkeyPrinters);
1299 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1301 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1302 RegCloseKey(hkeyPrinters);
1303 RegCloseKey(hkeyDrivers);
1304 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1307 RegCloseKey(hkeyDriver);
1308 RegCloseKey(hkeyDrivers);
1310 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1311 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1312 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1313 RegCloseKey(hkeyPrinters);
1317 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1319 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1320 SetLastError(ERROR_INVALID_PRINTER_NAME);
1321 RegCloseKey(hkeyPrinters);
1324 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1325 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1326 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1328 /* See if we can load the driver. We may need the devmode structure anyway
1331 * Note that DocumentPropertiesW will briefly try to open the printer we
1332 * just create to find a DEVMODEA struct (it will use the WINEPS default
1333 * one in case it is not there, so we are ok).
1335 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1338 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1339 size = sizeof(DEVMODEW);
1345 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1346 ZeroMemory(dmW,size);
1348 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1350 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1351 HeapFree(GetProcessHeap(),0,dmW);
1356 /* set devmode to printer name */
1357 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1361 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1362 and we support these drivers. NT writes DEVMODEW so somehow
1363 we'll need to distinguish between these when we support NT
1367 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1368 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1369 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1370 HeapFree(GetProcessHeap(), 0, dmA);
1372 HeapFree(GetProcessHeap(), 0, dmW);
1374 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1375 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1376 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1377 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1379 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1380 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1381 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1382 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1383 (LPBYTE)&pi->Priority, sizeof(DWORD));
1384 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1385 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1386 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1387 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1388 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1389 (LPBYTE)&pi->Status, sizeof(DWORD));
1390 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1391 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1393 RegCloseKey(hkeyPrinter);
1394 RegCloseKey(hkeyPrinters);
1395 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1396 ERR("OpenPrinter failing\n");
1402 /*****************************************************************************
1403 * AddPrinterA [WINSPOOL.@]
1405 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1407 UNICODE_STRING pNameW;
1409 PRINTER_INFO_2W *piW;
1410 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1413 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1415 ERR("Level = %ld, unsupported!\n", Level);
1416 SetLastError(ERROR_INVALID_LEVEL);
1419 pwstrNameW = asciitounicode(&pNameW,pName);
1420 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1422 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1424 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1425 RtlFreeUnicodeString(&pNameW);
1430 /*****************************************************************************
1431 * ClosePrinter [WINSPOOL.@]
1433 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1435 int i = (int)hPrinter;
1437 TRACE("Handle %p\n", hPrinter);
1439 if ((i <= 0) || (i > nb_printers)) return FALSE;
1440 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1441 printer_array[i - 1] = NULL;
1445 /*****************************************************************************
1446 * DeleteFormA [WINSPOOL.@]
1448 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1450 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1454 /*****************************************************************************
1455 * DeleteFormW [WINSPOOL.@]
1457 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1459 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1463 /*****************************************************************************
1464 * WINSPOOL_SHRegDeleteKey
1466 * Recursively delete subkeys.
1467 * Cut & paste from shlwapi.
1470 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1472 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1473 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1476 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1479 /* Find how many subkeys there are */
1480 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1481 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1485 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1486 /* Name too big: alloc a buffer for it */
1487 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1490 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1493 /* Recursively delete all the subkeys */
1494 for(i = 0; i < dwKeyCount && !dwRet; i++)
1496 dwSize = dwMaxSubkeyLen;
1497 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1499 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1502 if (lpszName != szNameBuf)
1503 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1507 RegCloseKey(hSubKey);
1509 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1514 /*****************************************************************************
1515 * DeletePrinter [WINSPOOL.@]
1517 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1519 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1520 HKEY hkeyPrinters, hkey;
1522 if(!lpNameW) return FALSE;
1523 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1524 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1525 RegCloseKey(hkeyPrinters);
1527 WriteProfileStringW(devicesW, lpNameW, NULL);
1528 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1529 RegDeleteValueW(hkey, lpNameW);
1535 /*****************************************************************************
1536 * SetPrinterA [WINSPOOL.@]
1538 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1541 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1545 /*****************************************************************************
1546 * SetJobA [WINSPOOL.@]
1548 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1549 LPBYTE pJob, DWORD Command)
1551 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1556 /*****************************************************************************
1557 * SetJobW [WINSPOOL.@]
1559 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1560 LPBYTE pJob, DWORD Command)
1562 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1567 /*****************************************************************************
1568 * EndDocPrinter [WINSPOOL.@]
1570 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1572 FIXME("(hPrinter=%p): stub\n", hPrinter);
1576 /*****************************************************************************
1577 * EndPagePrinter [WINSPOOL.@]
1579 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1581 FIXME("(hPrinter=%p): stub\n", hPrinter);
1585 /*****************************************************************************
1586 * StartDocPrinterA [WINSPOOL.@]
1588 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1590 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1594 /*****************************************************************************
1595 * StartDocPrinterW [WINSPOOL.@]
1597 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1599 FIXME("(hPrinter=%p, Level=0x%lx, pDocInfo=%p): stub\n", hPrinter, Level, pDocInfo);
1603 /*****************************************************************************
1604 * StartPagePrinter [WINSPOOL.@]
1606 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1608 FIXME("(hPrinter=%p): stub\n", hPrinter);
1612 /*****************************************************************************
1613 * GetFormA [WINSPOOL.@]
1615 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1616 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1618 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1619 Level,pForm,cbBuf,pcbNeeded);
1623 /*****************************************************************************
1624 * GetFormW [WINSPOOL.@]
1626 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1627 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1629 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1630 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1634 /*****************************************************************************
1635 * SetFormA [WINSPOOL.@]
1637 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1640 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1644 /*****************************************************************************
1645 * SetFormW [WINSPOOL.@]
1647 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1650 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1654 /*****************************************************************************
1655 * ReadPrinter [WINSPOOL.@]
1657 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1658 LPDWORD pNoBytesRead)
1660 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1664 /*****************************************************************************
1665 * ResetPrinterA [WINSPOOL.@]
1667 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1669 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1673 /*****************************************************************************
1674 * ResetPrinterW [WINSPOOL.@]
1676 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1678 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1682 /*****************************************************************************
1683 * WINSPOOL_GetDWORDFromReg
1685 * Return DWORD associated with ValueName from hkey.
1687 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1689 DWORD sz = sizeof(DWORD), type, value = 0;
1692 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1694 if(ret != ERROR_SUCCESS) {
1695 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1698 if(type != REG_DWORD) {
1699 ERR("Got type %ld\n", type);
1705 /*****************************************************************************
1706 * WINSPOOL_GetStringFromReg
1708 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1709 * String is stored either as unicode or ascii.
1710 * Bit of a hack here to get the ValueName if we want ascii.
1712 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1713 DWORD buflen, DWORD *needed,
1716 DWORD sz = buflen, type;
1720 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1722 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1723 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1724 HeapFree(GetProcessHeap(),0,ValueNameA);
1726 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1727 WARN("Got ret = %ld\n", ret);
1735 /*****************************************************************************
1736 * WINSPOOL_GetDefaultDevMode
1738 * Get a default DevMode values for wineps.
1742 static void WINSPOOL_GetDefaultDevMode(
1744 DWORD buflen, DWORD *needed,
1749 /* fill default DEVMODE - should be read from ppd... */
1750 ZeroMemory( &dm, sizeof(dm) );
1751 strcpy(dm.dmDeviceName,"wineps.drv");
1752 dm.dmSpecVersion = DM_SPECVERSION;
1753 dm.dmDriverVersion = 1;
1754 dm.dmSize = sizeof(DEVMODEA);
1755 dm.dmDriverExtra = 0;
1757 DM_ORIENTATION | DM_PAPERSIZE |
1758 DM_PAPERLENGTH | DM_PAPERWIDTH |
1761 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1762 DM_YRESOLUTION | DM_TTOPTION;
1764 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1765 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1766 dm.u1.s1.dmPaperLength = 2970;
1767 dm.u1.s1.dmPaperWidth = 2100;
1771 dm.dmDefaultSource = DMBIN_AUTO;
1772 dm.dmPrintQuality = DMRES_MEDIUM;
1775 dm.dmYResolution = 300; /* 300dpi */
1776 dm.dmTTOption = DMTT_BITMAP;
1779 /* dm.dmLogPixels */
1780 /* dm.dmBitsPerPel */
1781 /* dm.dmPelsWidth */
1782 /* dm.dmPelsHeight */
1783 /* dm.dmDisplayFlags */
1784 /* dm.dmDisplayFrequency */
1785 /* dm.dmICMMethod */
1786 /* dm.dmICMIntent */
1787 /* dm.dmMediaType */
1788 /* dm.dmDitherType */
1789 /* dm.dmReserved1 */
1790 /* dm.dmReserved2 */
1791 /* dm.dmPanningWidth */
1792 /* dm.dmPanningHeight */
1795 if(buflen >= sizeof(DEVMODEW)) {
1796 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1797 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1798 HeapFree(GetProcessHeap(),0,pdmW);
1800 *needed = sizeof(DEVMODEW);
1804 if(buflen >= sizeof(DEVMODEA)) {
1805 memcpy(ptr, &dm, sizeof(DEVMODEA));
1807 *needed = sizeof(DEVMODEA);
1811 /*****************************************************************************
1812 * WINSPOOL_GetDevModeFromReg
1814 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1815 * DevMode is stored either as unicode or ascii.
1817 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1819 DWORD buflen, DWORD *needed,
1822 DWORD sz = buflen, type;
1825 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1826 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1827 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1828 if (sz < sizeof(DEVMODEA))
1830 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1833 /* ensures that dmSize is not erratically bogus if registry is invalid */
1834 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1835 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1837 sz += (CCHDEVICENAME + CCHFORMNAME);
1839 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1840 memcpy(ptr, dmW, sz);
1841 HeapFree(GetProcessHeap(),0,dmW);
1848 /*********************************************************************
1849 * WINSPOOL_GetPrinter_2
1851 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1852 * The strings are either stored as unicode or ascii.
1854 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1855 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1858 DWORD size, left = cbBuf;
1859 BOOL space = (cbBuf > 0);
1864 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1866 if(space && size <= left) {
1867 pi2->pPrinterName = (LPWSTR)ptr;
1874 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1876 if(space && size <= left) {
1877 pi2->pShareName = (LPWSTR)ptr;
1884 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1886 if(space && size <= left) {
1887 pi2->pPortName = (LPWSTR)ptr;
1894 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1896 if(space && size <= left) {
1897 pi2->pDriverName = (LPWSTR)ptr;
1904 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1906 if(space && size <= left) {
1907 pi2->pComment = (LPWSTR)ptr;
1914 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1916 if(space && size <= left) {
1917 pi2->pLocation = (LPWSTR)ptr;
1924 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1926 if(space && size <= left) {
1927 pi2->pDevMode = (LPDEVMODEW)ptr;
1936 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
1937 if(space && size <= left) {
1938 pi2->pDevMode = (LPDEVMODEW)ptr;
1945 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1947 if(space && size <= left) {
1948 pi2->pSepFile = (LPWSTR)ptr;
1955 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1957 if(space && size <= left) {
1958 pi2->pPrintProcessor = (LPWSTR)ptr;
1965 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1967 if(space && size <= left) {
1968 pi2->pDatatype = (LPWSTR)ptr;
1975 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1977 if(space && size <= left) {
1978 pi2->pParameters = (LPWSTR)ptr;
1986 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1987 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1988 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1989 "Default Priority");
1990 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1991 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1994 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1995 memset(pi2, 0, sizeof(*pi2));
2000 /*********************************************************************
2001 * WINSPOOL_GetPrinter_4
2003 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2005 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2006 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2009 DWORD size, left = cbBuf;
2010 BOOL space = (cbBuf > 0);
2015 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2017 if(space && size <= left) {
2018 pi4->pPrinterName = (LPWSTR)ptr;
2026 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2029 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2030 memset(pi4, 0, sizeof(*pi4));
2035 /*********************************************************************
2036 * WINSPOOL_GetPrinter_5
2038 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2040 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2041 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2044 DWORD size, left = cbBuf;
2045 BOOL space = (cbBuf > 0);
2050 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2052 if(space && size <= left) {
2053 pi5->pPrinterName = (LPWSTR)ptr;
2060 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2062 if(space && size <= left) {
2063 pi5->pPortName = (LPWSTR)ptr;
2071 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2072 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2074 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2078 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2079 memset(pi5, 0, sizeof(*pi5));
2084 /*****************************************************************************
2085 * WINSPOOL_GetPrinter
2087 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2088 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2089 * just a collection of pointers to strings.
2091 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2092 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2095 DWORD size, needed = 0;
2097 HKEY hkeyPrinter, hkeyPrinters;
2100 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2102 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2104 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2106 ERR("Can't create Printers key\n");
2109 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2111 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2112 RegCloseKey(hkeyPrinters);
2113 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2120 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2122 size = sizeof(PRINTER_INFO_2W);
2124 ptr = pPrinter + size;
2126 memset(pPrinter, 0, size);
2131 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2139 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2141 size = sizeof(PRINTER_INFO_4W);
2143 ptr = pPrinter + size;
2145 memset(pPrinter, 0, size);
2150 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2159 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2161 size = sizeof(PRINTER_INFO_5W);
2163 ptr = pPrinter + size;
2165 memset(pPrinter, 0, size);
2171 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2178 FIXME("Unimplemented level %ld\n", Level);
2179 SetLastError(ERROR_INVALID_LEVEL);
2180 RegCloseKey(hkeyPrinters);
2181 RegCloseKey(hkeyPrinter);
2185 RegCloseKey(hkeyPrinter);
2186 RegCloseKey(hkeyPrinters);
2188 TRACE("returning %d needed = %ld\n", ret, needed);
2189 if(pcbNeeded) *pcbNeeded = needed;
2191 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2195 /*****************************************************************************
2196 * GetPrinterW [WINSPOOL.@]
2198 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2199 DWORD cbBuf, LPDWORD pcbNeeded)
2201 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2205 /*****************************************************************************
2206 * GetPrinterA [WINSPOOL.@]
2208 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2209 DWORD cbBuf, LPDWORD pcbNeeded)
2211 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2215 /*****************************************************************************
2216 * WINSPOOL_EnumPrinters
2218 * Implementation of EnumPrintersA|W
2220 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2221 DWORD dwLevel, LPBYTE lpbPrinters,
2222 DWORD cbBuf, LPDWORD lpdwNeeded,
2223 LPDWORD lpdwReturned, BOOL unicode)
2226 HKEY hkeyPrinters, hkeyPrinter;
2227 WCHAR PrinterName[255];
2228 DWORD needed = 0, number = 0;
2229 DWORD used, i, left;
2233 memset(lpbPrinters, 0, cbBuf);
2239 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2240 if(dwType == PRINTER_ENUM_DEFAULT)
2243 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2244 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2245 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2246 if(!dwType) return TRUE;
2249 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2250 FIXME("dwType = %08lx\n", dwType);
2251 SetLastError(ERROR_INVALID_FLAGS);
2255 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2257 ERR("Can't create Printers key\n");
2261 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2262 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2263 RegCloseKey(hkeyPrinters);
2264 ERR("Can't query Printers key\n");
2267 TRACE("Found %ld printers\n", number);
2271 RegCloseKey(hkeyPrinters);
2273 *lpdwReturned = number;
2277 used = number * sizeof(PRINTER_INFO_2W);
2280 used = number * sizeof(PRINTER_INFO_4W);
2283 used = number * sizeof(PRINTER_INFO_5W);
2287 SetLastError(ERROR_INVALID_LEVEL);
2288 RegCloseKey(hkeyPrinters);
2291 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2293 for(i = 0; i < number; i++) {
2294 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2296 ERR("Can't enum key number %ld\n", i);
2297 RegCloseKey(hkeyPrinters);
2300 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2301 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2303 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2304 RegCloseKey(hkeyPrinters);
2309 buf = lpbPrinters + used;
2310 left = cbBuf - used;
2318 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2319 left, &needed, unicode);
2321 if(pi) pi += sizeof(PRINTER_INFO_2W);
2324 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2325 left, &needed, unicode);
2327 if(pi) pi += sizeof(PRINTER_INFO_4W);
2330 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2331 left, &needed, unicode);
2333 if(pi) pi += sizeof(PRINTER_INFO_5W);
2336 ERR("Shouldn't be here!\n");
2337 RegCloseKey(hkeyPrinter);
2338 RegCloseKey(hkeyPrinters);
2341 RegCloseKey(hkeyPrinter);
2343 RegCloseKey(hkeyPrinters);
2350 memset(lpbPrinters, 0, cbBuf);
2351 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2355 *lpdwReturned = number;
2356 SetLastError(ERROR_SUCCESS);
2361 /******************************************************************
2362 * EnumPrintersW [WINSPOOL.@]
2364 * Enumerates the available printers, print servers and print
2365 * providers, depending on the specified flags, name and level.
2369 * If level is set to 1:
2370 * Not implemented yet!
2371 * Returns TRUE with an empty list.
2373 * If level is set to 2:
2374 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2375 * Returns an array of PRINTER_INFO_2 data structures in the
2376 * lpbPrinters buffer. Note that according to MSDN also an
2377 * OpenPrinter should be performed on every remote printer.
2379 * If level is set to 4 (officially WinNT only):
2380 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2381 * Fast: Only the registry is queried to retrieve printer names,
2382 * no connection to the driver is made.
2383 * Returns an array of PRINTER_INFO_4 data structures in the
2384 * lpbPrinters buffer.
2386 * If level is set to 5 (officially WinNT4/Win9x only):
2387 * Fast: Only the registry is queried to retrieve printer names,
2388 * no connection to the driver is made.
2389 * Returns an array of PRINTER_INFO_5 data structures in the
2390 * lpbPrinters buffer.
2392 * If level set to 3 or 6+:
2393 * returns zero (failure!)
2395 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2399 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2400 * - Only levels 2, 4 and 5 are implemented at the moment.
2401 * - 16-bit printer drivers are not enumerated.
2402 * - Returned amount of bytes used/needed does not match the real Windoze
2403 * implementation (as in this implementation, all strings are part
2404 * of the buffer, whereas Win32 keeps them somewhere else)
2405 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2408 * - In a regular Wine installation, no registry settings for printers
2409 * exist, which makes this function return an empty list.
2411 BOOL WINAPI EnumPrintersW(
2412 DWORD dwType, /* [in] Types of print objects to enumerate */
2413 LPWSTR lpszName, /* [in] name of objects to enumerate */
2414 DWORD dwLevel, /* [in] type of printer info structure */
2415 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2416 DWORD cbBuf, /* [in] max size of buffer in bytes */
2417 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2418 LPDWORD lpdwReturned /* [out] number of entries returned */
2421 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2422 lpdwNeeded, lpdwReturned, TRUE);
2425 /******************************************************************
2426 * EnumPrintersA [WINSPOOL.@]
2429 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2430 DWORD dwLevel, LPBYTE lpbPrinters,
2431 DWORD cbBuf, LPDWORD lpdwNeeded,
2432 LPDWORD lpdwReturned)
2435 UNICODE_STRING lpszNameW;
2438 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2439 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2440 lpdwNeeded, lpdwReturned, FALSE);
2441 RtlFreeUnicodeString(&lpszNameW);
2445 /*****************************************************************************
2446 * WINSPOOL_GetDriverInfoFromReg [internal]
2448 * Enters the information from the registry into the DRIVER_INFO struct
2451 * zero if the printer driver does not exist in the registry
2452 * (only if Level > 1) otherwise nonzero
2454 static BOOL WINSPOOL_GetDriverInfoFromReg(
2457 LPWSTR pEnvironment,
2459 LPBYTE ptr, /* DRIVER_INFO */
2460 LPBYTE pDriverStrings, /* strings buffer */
2461 DWORD cbBuf, /* size of string buffer */
2462 LPDWORD pcbNeeded, /* space needed for str. */
2463 BOOL unicode) /* type of strings */
2464 { DWORD dw, size, tmp, type;
2466 LPBYTE strPtr = pDriverStrings;
2468 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2469 debugstr_w(DriverName), debugstr_w(pEnvironment),
2470 Level, ptr, pDriverStrings, cbBuf, unicode);
2473 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2474 if (*pcbNeeded <= cbBuf)
2475 strcpyW((LPWSTR)strPtr, DriverName);
2477 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2479 if(*pcbNeeded <= cbBuf)
2480 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2485 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2489 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2490 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2493 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2494 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2495 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2500 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2502 WARN("Can't get Version\n");
2504 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2507 pEnvironment = (LPWSTR)DefaultEnvironmentW;
2509 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2511 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2514 if(*pcbNeeded <= cbBuf) {
2516 strcpyW((LPWSTR)strPtr, pEnvironment);
2518 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2521 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2522 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2525 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2528 if(*pcbNeeded <= cbBuf)
2529 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2532 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2533 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2536 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2539 if(*pcbNeeded <= cbBuf)
2540 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2543 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2544 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2547 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2548 0, &size, unicode)) {
2550 if(*pcbNeeded <= cbBuf)
2551 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2552 size, &tmp, unicode);
2554 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2555 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2559 RegCloseKey(hkeyDriver);
2560 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2564 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2567 if(*pcbNeeded <= cbBuf)
2568 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2569 size, &tmp, unicode);
2571 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2572 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2575 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2578 if(*pcbNeeded <= cbBuf)
2579 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2580 size, &tmp, unicode);
2582 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2583 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2586 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2589 if(*pcbNeeded <= cbBuf)
2590 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2591 size, &tmp, unicode);
2593 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2594 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2597 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2600 if(*pcbNeeded <= cbBuf)
2601 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2602 size, &tmp, unicode);
2604 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2605 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2608 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2609 RegCloseKey(hkeyDriver);
2613 /*****************************************************************************
2614 * WINSPOOL_GetPrinterDriver
2616 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2617 DWORD Level, LPBYTE pDriverInfo,
2618 DWORD cbBuf, LPDWORD pcbNeeded,
2622 WCHAR DriverName[100];
2623 DWORD ret, type, size, needed = 0;
2625 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2627 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2628 Level,pDriverInfo,cbBuf, pcbNeeded);
2630 ZeroMemory(pDriverInfo, cbBuf);
2632 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
2634 if(Level < 1 || Level > 3) {
2635 SetLastError(ERROR_INVALID_LEVEL);
2638 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2640 ERR("Can't create Printers key\n");
2643 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2645 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2646 RegCloseKey(hkeyPrinters);
2647 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2650 size = sizeof(DriverName);
2652 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2653 (LPBYTE)DriverName, &size);
2654 RegCloseKey(hkeyPrinter);
2655 RegCloseKey(hkeyPrinters);
2656 if(ret != ERROR_SUCCESS) {
2657 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2661 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2663 ERR("Can't create Drivers key\n");
2669 size = sizeof(DRIVER_INFO_1W);
2672 size = sizeof(DRIVER_INFO_2W);
2675 size = sizeof(DRIVER_INFO_3W);
2678 ERR("Invalid level\n");
2683 ptr = pDriverInfo + size;
2685 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2686 pEnvironment, Level, pDriverInfo,
2687 (cbBuf < size) ? NULL : ptr,
2688 (cbBuf < size) ? 0 : cbBuf - size,
2689 &needed, unicode)) {
2690 RegCloseKey(hkeyDrivers);
2694 RegCloseKey(hkeyDrivers);
2696 if(pcbNeeded) *pcbNeeded = size + needed;
2697 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2698 if(cbBuf >= needed) return TRUE;
2699 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2703 /*****************************************************************************
2704 * GetPrinterDriverA [WINSPOOL.@]
2706 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2707 DWORD Level, LPBYTE pDriverInfo,
2708 DWORD cbBuf, LPDWORD pcbNeeded)
2711 UNICODE_STRING pEnvW;
2714 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2715 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2716 cbBuf, pcbNeeded, FALSE);
2717 RtlFreeUnicodeString(&pEnvW);
2720 /*****************************************************************************
2721 * GetPrinterDriverW [WINSPOOL.@]
2723 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2724 DWORD Level, LPBYTE pDriverInfo,
2725 DWORD cbBuf, LPDWORD pcbNeeded)
2727 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2728 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2731 /*****************************************************************************
2732 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2734 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2735 DWORD Level, LPBYTE pDriverDirectory,
2736 DWORD cbBuf, LPDWORD pcbNeeded)
2740 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2741 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2743 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2744 SetLastError(ERROR_INVALID_PARAMETER);
2747 if(pEnvironment != NULL) {
2748 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2749 SetLastError(ERROR_INVALID_ENVIRONMENT);
2752 if(Level != 1) /* win95 ignores this so we just carry on */
2753 WARN("Level = %ld - assuming 1\n", Level);
2755 /* FIXME should read from registry */
2756 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2757 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2761 needed*=sizeof(WCHAR);
2764 *pcbNeeded = needed;
2765 TRACE("required <%08lx>\n", *pcbNeeded);
2766 if(needed > cbBuf) {
2767 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2774 /*****************************************************************************
2775 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2777 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2778 DWORD Level, LPBYTE pDriverDirectory,
2779 DWORD cbBuf, LPDWORD pcbNeeded)
2781 UNICODE_STRING nameW, environmentW;
2784 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2785 WCHAR *driverDirectoryW = NULL;
2787 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2789 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2790 else nameW.Buffer = NULL;
2791 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2792 else environmentW.Buffer = NULL;
2794 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2795 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2798 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2799 pDriverDirectory, cbBuf, NULL, NULL);
2801 *pcbNeeded = needed;
2802 ret = (needed <= cbBuf) ? TRUE : FALSE;
2804 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2806 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2808 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2809 RtlFreeUnicodeString(&environmentW);
2810 RtlFreeUnicodeString(&nameW);
2815 /*****************************************************************************
2816 * AddPrinterDriverA [WINSPOOL.@]
2818 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2821 HKEY hkeyDrivers, hkeyName;
2823 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2825 if(level != 2 && level != 3) {
2826 SetLastError(ERROR_INVALID_LEVEL);
2830 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2831 SetLastError(ERROR_INVALID_PARAMETER);
2835 WARN("pDriverInfo == NULL\n");
2836 SetLastError(ERROR_INVALID_PARAMETER);
2841 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2843 memset(&di3, 0, sizeof(di3));
2844 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
2847 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2849 SetLastError(ERROR_INVALID_PARAMETER);
2852 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2853 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2854 if(!di3.pHelpFile) di3.pHelpFile = "";
2855 if(!di3.pMonitorName) di3.pMonitorName = "";
2857 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2860 ERR("Can't create Drivers key\n");
2864 if(level == 2) { /* apparently can't overwrite with level2 */
2865 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2866 RegCloseKey(hkeyName);
2867 RegCloseKey(hkeyDrivers);
2868 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2869 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2873 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2874 RegCloseKey(hkeyDrivers);
2875 ERR("Can't create Name key\n");
2878 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2880 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2881 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2882 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2884 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2885 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2886 di3.pDependentFiles, 0);
2887 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2888 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2889 RegCloseKey(hkeyName);
2890 RegCloseKey(hkeyDrivers);
2895 /*****************************************************************************
2896 * AddPrinterDriverW [WINSPOOL.@]
2898 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2901 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2906 /*****************************************************************************
2907 * AddPrintProcessorA [WINSPOOL.@]
2909 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
2910 LPSTR pPrintProcessorName)
2912 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
2913 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
2917 /*****************************************************************************
2918 * AddPrintProcessorW [WINSPOOL.@]
2920 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
2921 LPWSTR pPrintProcessorName)
2923 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
2924 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
2928 /*****************************************************************************
2929 * AddPrintProvidorA [WINSPOOL.@]
2931 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
2933 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
2937 /*****************************************************************************
2938 * AddPrintProvidorW [WINSPOOL.@]
2940 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
2942 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
2946 /*****************************************************************************
2947 * AdvancedDocumentPropertiesA [WINSPOOL.@]
2949 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
2950 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
2952 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
2953 pDevModeOutput, pDevModeInput);
2957 /*****************************************************************************
2958 * AdvancedDocumentPropertiesW [WINSPOOL.@]
2960 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
2961 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
2963 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
2964 pDevModeOutput, pDevModeInput);
2968 /*****************************************************************************
2969 * PrinterProperties [WINSPOOL.@]
2971 * Displays a dialog to set the properties of the printer.
2974 * nonzero on success or zero on failure
2977 * implemented as stub only
2979 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2980 HANDLE hPrinter /* [in] handle to printer object */
2982 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
2983 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2987 /*****************************************************************************
2988 * EnumJobsA [WINSPOOL.@]
2991 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2992 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2995 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
2996 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
2998 if(pcbNeeded) *pcbNeeded = 0;
2999 if(pcReturned) *pcReturned = 0;
3004 /*****************************************************************************
3005 * EnumJobsW [WINSPOOL.@]
3008 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3009 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3012 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3013 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3015 if(pcbNeeded) *pcbNeeded = 0;
3016 if(pcReturned) *pcReturned = 0;
3020 /*****************************************************************************
3021 * WINSPOOL_EnumPrinterDrivers [internal]
3023 * Delivers information about all printer drivers installed on the
3024 * localhost or a given server
3027 * nonzero on success or zero on failure. If the buffer for the returned
3028 * information is too small the function will return an error
3031 * - only implemented for localhost, foreign hosts will return an error
3033 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3034 DWORD Level, LPBYTE pDriverInfo,
3035 DWORD cbBuf, LPDWORD pcbNeeded,
3036 LPDWORD pcReturned, BOOL unicode)
3039 DWORD i, needed, number = 0, size = 0;
3040 WCHAR DriverNameW[255];
3043 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3044 debugstr_w(pName), debugstr_w(pEnvironment),
3045 Level, pDriverInfo, cbBuf, unicode);
3047 /* check for local drivers */
3049 ERR("remote drivers unsupported! Current remote host is %s\n",
3054 /* check input parameter */
3055 if((Level < 1) || (Level > 3)) {
3056 ERR("unsupported level %ld\n", Level);
3057 SetLastError(ERROR_INVALID_LEVEL);
3061 /* initialize return values */
3063 memset( pDriverInfo, 0, cbBuf);
3067 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3069 ERR("Can't open Drivers key\n");
3073 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3074 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3075 RegCloseKey(hkeyDrivers);
3076 ERR("Can't query Drivers key\n");
3079 TRACE("Found %ld Drivers\n", number);
3081 /* get size of single struct
3082 * unicode and ascii structure have the same size
3086 size = sizeof(DRIVER_INFO_1A);
3089 size = sizeof(DRIVER_INFO_2A);
3092 size = sizeof(DRIVER_INFO_3A);
3096 /* calculate required buffer size */
3097 *pcbNeeded = size * number;
3099 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3101 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3102 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3104 ERR("Can't enum key number %ld\n", i);
3105 RegCloseKey(hkeyDrivers);
3108 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3109 pEnvironment, Level, ptr,
3110 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3111 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3112 &needed, unicode)) {
3113 RegCloseKey(hkeyDrivers);
3116 (*pcbNeeded) += needed;
3119 RegCloseKey(hkeyDrivers);
3121 if(cbBuf < *pcbNeeded){
3122 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3129 /*****************************************************************************
3130 * EnumPrinterDriversW [WINSPOOL.@]
3132 * see function EnumPrinterDrivers for RETURNS, BUGS
3134 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3135 LPBYTE pDriverInfo, DWORD cbBuf,
3136 LPDWORD pcbNeeded, LPDWORD pcReturned)
3138 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3139 cbBuf, pcbNeeded, pcReturned, TRUE);
3142 /*****************************************************************************
3143 * EnumPrinterDriversA [WINSPOOL.@]
3145 * see function EnumPrinterDrivers for RETURNS, BUGS
3147 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3148 LPBYTE pDriverInfo, DWORD cbBuf,
3149 LPDWORD pcbNeeded, LPDWORD pcReturned)
3151 UNICODE_STRING pNameW, pEnvironmentW;
3152 PWSTR pwstrNameW, pwstrEnvironmentW;
3154 pwstrNameW = asciitounicode(&pNameW, pName);
3155 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3157 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3158 Level, pDriverInfo, cbBuf, pcbNeeded,
3160 RtlFreeUnicodeString(&pNameW);
3161 RtlFreeUnicodeString(&pEnvironmentW);
3166 static CHAR PortMonitor[] = "Wine Port Monitor";
3167 static CHAR PortDescription[] = "Wine Port";
3169 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3173 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3174 NULL, OPEN_EXISTING, 0, NULL );
3175 if (handle == INVALID_HANDLE_VALUE)
3177 TRACE("Checking %s exists\n", name );
3178 CloseHandle( handle );
3182 static DWORD WINSPOOL_CountSerialPorts()
3189 strcpy( name, "COMx:" );
3191 if (WINSPOOL_ComPortExists( name ))
3198 /******************************************************************************
3199 * EnumPortsA (WINSPOOL.@)
3201 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3202 LPDWORD bufneeded,LPDWORD bufreturned)
3205 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3206 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3210 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3211 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3216 info_size = sizeof (PORT_INFO_1A);
3219 info_size = sizeof (PORT_INFO_2A);
3222 SetLastError(ERROR_INVALID_LEVEL);
3226 /* see how many exist */
3229 serial_count = WINSPOOL_CountSerialPorts();
3232 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3233 if ( r == ERROR_SUCCESS )
3235 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3236 &printer_count, NULL, NULL, NULL, NULL);
3238 count = serial_count + printer_count;
3240 /* then fill in the structure info structure once
3241 we know the offset to the first string */
3243 memset( buffer, 0, bufsize );
3245 ofs = info_size*count;
3246 for ( i=0; i<count; i++)
3248 DWORD vallen = sizeof(portname) - 1;
3250 /* get the serial port values, then the printer values */
3251 if ( i < serial_count )
3253 strcpy( portname, "COMx:" );
3254 portname[3] = '1' + i;
3255 if (!WINSPOOL_ComPortExists( portname ))
3258 TRACE("Found %s\n", portname );
3259 vallen = strlen( portname );
3263 r = RegEnumValueA( hkey_printer, i-serial_count,
3264 portname, &vallen, NULL, NULL, NULL, 0 );
3269 /* add a colon if necessary, and make it upper case */
3270 CharUpperBuffA(portname,vallen);
3271 if (strcasecmp(portname,"nul")!=0)
3272 if (vallen && (portname[vallen-1] != ':') )
3273 lstrcatA(portname,":");
3275 /* add the port info structure if we can fit it */
3276 if ( info_size*(n+1) < bufsize )
3280 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3281 info->pName = (LPSTR) &buffer[ofs];
3283 else if ( level == 2)
3285 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3286 info->pPortName = (LPSTR) &buffer[ofs];
3287 /* FIXME: fill in more stuff here */
3288 info->pMonitorName = PortMonitor;
3289 info->pDescription = PortDescription;
3290 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3293 /* add the name of the port if we can fit it */
3294 if ( ofs < bufsize )
3295 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3301 ofs += lstrlenA(portname)+1;
3304 RegCloseKey(hkey_printer);
3315 /******************************************************************************
3316 * EnumPortsW (WINSPOOL.@)
3318 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3319 LPDWORD bufneeded,LPDWORD bufreturned)
3321 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3322 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3326 /******************************************************************************
3327 * GetDefaultPrinterW (WINSPOOL.@)
3330 * This function must read the value from data 'device' of key
3331 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3333 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3337 WCHAR *buffer, *ptr;
3341 SetLastError(ERROR_INVALID_PARAMETER);
3345 /* make the buffer big enough for the stuff from the profile/registry,
3346 * the content must fit into the local buffer to compute the correct
3347 * size even if the extern buffer is too small or not given.
3348 * (20 for ,driver,port) */
3350 len = max(100, (insize + 20));
3351 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3353 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3355 SetLastError (ERROR_FILE_NOT_FOUND);
3359 TRACE("%s\n", debugstr_w(buffer));
3361 if ((ptr = strchrW(buffer, ',')) == NULL)
3363 SetLastError(ERROR_INVALID_NAME);
3369 *namesize = strlenW(buffer) + 1;
3370 if(!name || (*namesize > insize))
3372 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3376 strcpyW(name, buffer);
3379 HeapFree( GetProcessHeap(), 0, buffer);
3384 /******************************************************************************
3385 * GetDefaultPrinterA (WINSPOOL.@)
3387 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3391 WCHAR *bufferW = NULL;
3395 SetLastError(ERROR_INVALID_PARAMETER);
3399 if(name && *namesize) {
3401 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3404 if(!GetDefaultPrinterW( bufferW, namesize)) {
3409 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3413 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3416 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3419 HeapFree( GetProcessHeap(), 0, bufferW);
3424 /******************************************************************************
3425 * SetPrinterDataExA (WINSPOOL.@)
3427 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3428 LPCSTR pValueName, DWORD Type,
3429 LPBYTE pData, DWORD cbData)
3431 HKEY hkeyPrinter, hkeySubkey;
3434 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3435 debugstr_a(pValueName), Type, pData, cbData);
3437 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3441 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3443 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3444 RegCloseKey(hkeyPrinter);
3447 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3448 RegCloseKey(hkeySubkey);
3449 RegCloseKey(hkeyPrinter);
3453 /******************************************************************************
3454 * SetPrinterDataExW (WINSPOOL.@)
3456 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3457 LPCWSTR pValueName, DWORD Type,
3458 LPBYTE pData, DWORD cbData)
3460 HKEY hkeyPrinter, hkeySubkey;
3463 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3464 debugstr_w(pValueName), Type, pData, cbData);
3466 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3470 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3472 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3473 RegCloseKey(hkeyPrinter);
3476 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3477 RegCloseKey(hkeySubkey);
3478 RegCloseKey(hkeyPrinter);
3482 /******************************************************************************
3483 * SetPrinterDataA (WINSPOOL.@)
3485 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3486 LPBYTE pData, DWORD cbData)
3488 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3492 /******************************************************************************
3493 * SetPrinterDataW (WINSPOOL.@)
3495 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3496 LPBYTE pData, DWORD cbData)
3498 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3502 /******************************************************************************
3503 * GetPrinterDataExA (WINSPOOL.@)
3505 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3506 LPCSTR pValueName, LPDWORD pType,
3507 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3509 HKEY hkeyPrinter, hkeySubkey;
3512 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3513 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3516 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3520 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3522 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3523 RegCloseKey(hkeyPrinter);
3527 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3528 RegCloseKey(hkeySubkey);
3529 RegCloseKey(hkeyPrinter);
3533 /******************************************************************************
3534 * GetPrinterDataExW (WINSPOOL.@)
3536 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3537 LPCWSTR pValueName, LPDWORD pType,
3538 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3540 HKEY hkeyPrinter, hkeySubkey;
3543 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3544 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3547 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3551 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3553 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3554 RegCloseKey(hkeyPrinter);
3558 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3559 RegCloseKey(hkeySubkey);
3560 RegCloseKey(hkeyPrinter);
3564 /******************************************************************************
3565 * GetPrinterDataA (WINSPOOL.@)
3567 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3568 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3570 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3571 pData, nSize, pcbNeeded);
3574 /******************************************************************************
3575 * GetPrinterDataW (WINSPOOL.@)
3577 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3578 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3580 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3581 pData, nSize, pcbNeeded);
3584 /*******************************************************************************
3585 * EnumPrinterDataExW [WINSPOOL.@]
3587 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3588 LPBYTE pEnumValues, DWORD cbEnumValues,
3589 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3591 HKEY hkPrinter, hkSubKey;
3592 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3593 cbValueNameLen, cbMaxValueLen, cbValueLen,
3598 PPRINTER_ENUM_VALUESW ppev;
3600 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3602 if (pKeyName == NULL || *pKeyName == 0)
3603 return ERROR_INVALID_PARAMETER;
3605 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3606 if (ret != ERROR_SUCCESS)
3608 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3613 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3614 if (ret != ERROR_SUCCESS)
3616 r = RegCloseKey (hkPrinter);
3617 if (r != ERROR_SUCCESS)
3618 WARN ("RegCloseKey returned %li\n", r);
3619 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3620 debugstr_w (pKeyName), ret);
3624 ret = RegCloseKey (hkPrinter);
3625 if (ret != ERROR_SUCCESS)
3627 ERR ("RegCloseKey returned %li\n", ret);
3628 r = RegCloseKey (hkSubKey);
3629 if (r != ERROR_SUCCESS)
3630 WARN ("RegCloseKey returned %li\n", r);
3634 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3635 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3636 if (ret != ERROR_SUCCESS)
3638 r = RegCloseKey (hkSubKey);
3639 if (r != ERROR_SUCCESS)
3640 WARN ("RegCloseKey returned %li\n", r);
3641 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3645 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3646 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3648 if (cValues == 0) /* empty key */
3650 r = RegCloseKey (hkSubKey);
3651 if (r != ERROR_SUCCESS)
3652 WARN ("RegCloseKey returned %li\n", r);
3653 *pcbEnumValues = *pnEnumValues = 0;
3654 return ERROR_SUCCESS;
3657 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3659 hHeap = GetProcessHeap ();
3662 ERR ("GetProcessHeap failed\n");
3663 r = RegCloseKey (hkSubKey);
3664 if (r != ERROR_SUCCESS)
3665 WARN ("RegCloseKey returned %li\n", r);
3666 return ERROR_OUTOFMEMORY;
3669 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3670 if (lpValueName == NULL)
3672 ERR ("Failed to allocate %li bytes from process heap\n",
3673 cbMaxValueNameLen * sizeof (WCHAR));
3674 r = RegCloseKey (hkSubKey);
3675 if (r != ERROR_SUCCESS)
3676 WARN ("RegCloseKey returned %li\n", r);
3677 return ERROR_OUTOFMEMORY;
3680 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3681 if (lpValue == NULL)
3683 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3684 if (HeapFree (hHeap, 0, lpValueName) == 0)
3685 WARN ("HeapFree failed with code %li\n", GetLastError ());
3686 r = RegCloseKey (hkSubKey);
3687 if (r != ERROR_SUCCESS)
3688 WARN ("RegCloseKey returned %li\n", r);
3689 return ERROR_OUTOFMEMORY;
3692 TRACE ("pass 1: calculating buffer required for all names and values\n");
3694 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3696 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3698 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3700 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3701 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3702 NULL, NULL, lpValue, &cbValueLen);
3703 if (ret != ERROR_SUCCESS)
3705 if (HeapFree (hHeap, 0, lpValue) == 0)
3706 WARN ("HeapFree failed with code %li\n", GetLastError ());
3707 if (HeapFree (hHeap, 0, lpValueName) == 0)
3708 WARN ("HeapFree failed with code %li\n", GetLastError ());
3709 r = RegCloseKey (hkSubKey);
3710 if (r != ERROR_SUCCESS)
3711 WARN ("RegCloseKey returned %li\n", r);
3712 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3716 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3717 debugstr_w (lpValueName), dwIndex,
3718 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3720 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3721 cbBufSize += cbValueLen;
3724 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3726 *pcbEnumValues = cbBufSize;
3727 *pnEnumValues = cValues;
3729 if (cbEnumValues < cbBufSize) /* buffer too small */
3731 if (HeapFree (hHeap, 0, lpValue) == 0)
3732 WARN ("HeapFree failed with code %li\n", GetLastError ());
3733 if (HeapFree (hHeap, 0, lpValueName) == 0)
3734 WARN ("HeapFree failed with code %li\n", GetLastError ());
3735 r = RegCloseKey (hkSubKey);
3736 if (r != ERROR_SUCCESS)
3737 WARN ("RegCloseKey returned %li\n", r);
3738 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3739 return ERROR_MORE_DATA;
3742 TRACE ("pass 2: copying all names and values to buffer\n");
3744 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3745 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3747 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3749 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3750 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3751 NULL, &dwType, lpValue, &cbValueLen);
3752 if (ret != ERROR_SUCCESS)
3754 if (HeapFree (hHeap, 0, lpValue) == 0)
3755 WARN ("HeapFree failed with code %li\n", GetLastError ());
3756 if (HeapFree (hHeap, 0, lpValueName) == 0)
3757 WARN ("HeapFree failed with code %li\n", GetLastError ());
3758 r = RegCloseKey (hkSubKey);
3759 if (r != ERROR_SUCCESS)
3760 WARN ("RegCloseKey returned %li\n", r);
3761 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3765 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3766 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3767 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3768 pEnumValues += cbValueNameLen;
3770 /* return # of *bytes* (including trailing \0), not # of chars */
3771 ppev[dwIndex].cbValueName = cbValueNameLen;
3773 ppev[dwIndex].dwType = dwType;
3775 memcpy (pEnumValues, lpValue, cbValueLen);
3776 ppev[dwIndex].pData = pEnumValues;
3777 pEnumValues += cbValueLen;
3779 ppev[dwIndex].cbData = cbValueLen;
3781 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3782 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3785 if (HeapFree (hHeap, 0, lpValue) == 0)
3787 ret = GetLastError ();
3788 ERR ("HeapFree failed with code %li\n", ret);
3789 if (HeapFree (hHeap, 0, lpValueName) == 0)
3790 WARN ("HeapFree failed with code %li\n", GetLastError ());
3791 r = RegCloseKey (hkSubKey);
3792 if (r != ERROR_SUCCESS)
3793 WARN ("RegCloseKey returned %li\n", r);
3797 if (HeapFree (hHeap, 0, lpValueName) == 0)
3799 ret = GetLastError ();
3800 ERR ("HeapFree failed with code %li\n", ret);
3801 r = RegCloseKey (hkSubKey);
3802 if (r != ERROR_SUCCESS)
3803 WARN ("RegCloseKey returned %li\n", r);
3807 ret = RegCloseKey (hkSubKey);
3808 if (ret != ERROR_SUCCESS)
3810 ERR ("RegCloseKey returned %li\n", ret);
3814 return ERROR_SUCCESS;
3817 /*******************************************************************************
3818 * EnumPrinterDataExA [WINSPOOL.@]
3820 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3821 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3822 * what Windows 2000 SP1 does.
3825 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3826 LPBYTE pEnumValues, DWORD cbEnumValues,
3827 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3831 DWORD ret, dwIndex, dwBufSize;
3835 TRACE ("%p %s\n", hPrinter, pKeyName);
3837 if (pKeyName == NULL || *pKeyName == 0)
3838 return ERROR_INVALID_PARAMETER;
3840 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3843 ret = GetLastError ();
3844 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3848 hHeap = GetProcessHeap ();
3851 ERR ("GetProcessHeap failed\n");
3852 return ERROR_OUTOFMEMORY;
3855 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3856 if (pKeyNameW == NULL)
3858 ERR ("Failed to allocate %li bytes from process heap\n",
3859 (LONG) len * sizeof (WCHAR));
3860 return ERROR_OUTOFMEMORY;
3863 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3865 ret = GetLastError ();
3866 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3867 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3868 WARN ("HeapFree failed with code %li\n", GetLastError ());
3872 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3873 pcbEnumValues, pnEnumValues);
3874 if (ret != ERROR_SUCCESS)
3876 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3877 WARN ("HeapFree failed with code %li\n", GetLastError ());
3878 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3882 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3884 ret = GetLastError ();
3885 ERR ("HeapFree failed with code %li\n", ret);
3889 if (*pnEnumValues == 0) /* empty key */
3890 return ERROR_SUCCESS;
3893 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3895 PPRINTER_ENUM_VALUESW ppev =
3896 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3898 if (dwBufSize < ppev->cbValueName)
3899 dwBufSize = ppev->cbValueName;
3901 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
3902 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
3903 dwBufSize = ppev->cbData;
3906 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
3908 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
3909 if (pBuffer == NULL)
3911 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
3912 return ERROR_OUTOFMEMORY;
3915 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3917 PPRINTER_ENUM_VALUESW ppev =
3918 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
3920 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
3921 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
3925 ret = GetLastError ();
3926 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3927 if (HeapFree (hHeap, 0, pBuffer) == 0)
3928 WARN ("HeapFree failed with code %li\n", GetLastError ());
3932 memcpy (ppev->pValueName, pBuffer, len);
3934 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3936 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
3937 ppev->dwType != REG_MULTI_SZ)
3940 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
3941 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
3944 ret = GetLastError ();
3945 ERR ("WideCharToMultiByte failed with code %li\n", ret);
3946 if (HeapFree (hHeap, 0, pBuffer) == 0)
3947 WARN ("HeapFree failed with code %li\n", GetLastError ());
3951 memcpy (ppev->pData, pBuffer, len);
3953 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
3954 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
3957 if (HeapFree (hHeap, 0, pBuffer) == 0)
3959 ret = GetLastError ();
3960 ERR ("HeapFree failed with code %li\n", ret);
3964 return ERROR_SUCCESS;
3967 /******************************************************************************
3968 * AbortPrinter (WINSPOOL.@)
3970 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
3972 FIXME("(%p), stub!\n", hPrinter);
3976 /******************************************************************************
3977 * AddPortA (WINSPOOL.@)
3979 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
3981 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
3985 /******************************************************************************
3986 * AddPortW (WINSPOOL.@)
3988 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
3990 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
3994 /******************************************************************************
3995 * AddPortExA (WINSPOOL.@)
3997 * Adds a print spooler port without presenting a user interface.
3999 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4001 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4002 lpBuffer, debugstr_a(lpMonitorName));
4006 /******************************************************************************
4007 * AddPortExW (WINSPOOL.@)
4011 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4013 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4014 lpBuffer, debugstr_w(lpMonitorName));
4018 /******************************************************************************
4019 * AddPrinterConnectionA (WINSPOOL.@)
4021 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4023 FIXME("%s\n", debugstr_a(pName));
4027 /******************************************************************************
4028 * AddPrinterConnectionW (WINSPOOL.@)
4030 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4032 FIXME("%s\n", debugstr_w(pName));
4036 /******************************************************************************
4037 * AddPrinterDriverExW (WINSPOOL.@)
4039 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4040 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4042 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4043 Level, pDriverInfo, dwFileCopyFlags);
4044 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4048 /******************************************************************************
4049 * AddPrinterDriverExA (WINSPOOL.@)
4051 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4052 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4054 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4055 Level, pDriverInfo, dwFileCopyFlags);
4056 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4060 /******************************************************************************
4061 * ConfigurePortA (WINSPOOL.@)
4063 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4065 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4069 /******************************************************************************
4070 * ConfigurePortW (WINSPOOL.@)
4072 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4074 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4078 /******************************************************************************
4079 * ConnectToPrinterDlg (WINSPOOL.@)
4081 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4083 FIXME("%p %lx\n", hWnd, Flags);
4087 /******************************************************************************
4088 * DeletePrinterConnectionA (WINSPOOL.@)
4090 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4092 FIXME("%s\n", debugstr_a(pName));
4096 /******************************************************************************
4097 * DeletePrinterConnectionW (WINSPOOL.@)
4099 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4101 FIXME("%s\n", debugstr_w(pName));
4105 /******************************************************************************
4106 * DeletePrinterDriverExW (WINSPOOL.@)
4108 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4109 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4111 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4112 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4116 /******************************************************************************
4117 * DeletePrinterDriverExA (WINSPOOL.@)
4119 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4120 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4122 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4123 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4127 /******************************************************************************
4128 * DeletePrinterDataExW (WINSPOOL.@)
4130 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4133 FIXME("%p %s %s\n", hPrinter,
4134 debugstr_w(pKeyName), debugstr_w(pValueName));
4135 return ERROR_INVALID_PARAMETER;
4138 /******************************************************************************
4139 * DeletePrinterDataExA (WINSPOOL.@)
4141 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4144 FIXME("%p %s %s\n", hPrinter,
4145 debugstr_a(pKeyName), debugstr_a(pValueName));
4146 return ERROR_INVALID_PARAMETER;
4149 /******************************************************************************
4150 * DeletePrintProcessorA (WINSPOOL.@)
4152 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4154 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4155 debugstr_a(pPrintProcessorName));
4159 /******************************************************************************
4160 * DeletePrintProcessorW (WINSPOOL.@)
4162 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4164 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4165 debugstr_w(pPrintProcessorName));
4169 /******************************************************************************
4170 * DeletePrintProvidorA (WINSPOOL.@)
4172 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4174 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4175 debugstr_a(pPrintProviderName));
4179 /******************************************************************************
4180 * DeletePrintProvidorW (WINSPOOL.@)
4182 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4184 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4185 debugstr_w(pPrintProviderName));
4189 /******************************************************************************
4190 * EnumFormsA (WINSPOOL.@)
4192 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4193 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4195 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4199 /******************************************************************************
4200 * EnumFormsW (WINSPOOL.@)
4202 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4203 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4205 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4209 /*****************************************************************************
4210 * EnumMonitorsA [WINSPOOL.@]
4213 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4214 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4216 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4217 cbBuf, pcbNeeded, pcReturned);
4218 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4222 /*****************************************************************************
4223 * EnumMonitorsW [WINSPOOL.@]
4226 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4227 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4229 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4230 cbBuf, pcbNeeded, pcReturned);
4231 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4235 /******************************************************************************
4236 * XcvDataW (WINSPOOL.@)
4239 * There doesn't seem to be an A version...
4241 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4242 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4243 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4245 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4246 pInputData, cbInputData, pOutputData,
4247 cbOutputData, pcbOutputNeeded, pdwStatus);
4251 /*****************************************************************************
4252 * EnumPrinterDataA [WINSPOOL.@]
4255 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4256 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4257 DWORD cbData, LPDWORD pcbData )
4259 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4260 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4261 return ERROR_NO_MORE_ITEMS;
4264 /*****************************************************************************
4265 * EnumPrinterDataW [WINSPOOL.@]
4268 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4269 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4270 DWORD cbData, LPDWORD pcbData )
4272 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4273 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4274 return ERROR_NO_MORE_ITEMS;
4277 /*****************************************************************************
4278 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4281 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4282 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4283 LPDWORD pcbNeeded, LPDWORD pcReturned)
4285 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4286 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4287 pcbNeeded, pcReturned);
4291 /*****************************************************************************
4292 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4295 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4296 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4297 LPDWORD pcbNeeded, LPDWORD pcReturned)
4299 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4300 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4301 pcbNeeded, pcReturned);
4305 /*****************************************************************************
4306 * EnumPrintProcessorsA [WINSPOOL.@]
4309 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4310 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4312 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4313 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
4317 /*****************************************************************************
4318 * EnumPrintProcessorsW [WINSPOOL.@]
4321 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4322 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4324 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4325 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
4326 cbBuf, pcbNeeded, pcbReturned);
4330 /*****************************************************************************
4331 * ExtDeviceMode [WINSPOOL.@]
4334 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
4335 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
4338 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
4339 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
4340 debugstr_a(pProfile), fMode);
4344 /*****************************************************************************
4345 * FindClosePrinterChangeNotification [WINSPOOL.@]
4348 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
4350 FIXME("Stub: %p\n", hChange);
4354 /*****************************************************************************
4355 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4358 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
4359 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
4361 FIXME("Stub: %p %lx %lx %p\n",
4362 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
4363 return INVALID_HANDLE_VALUE;
4366 /*****************************************************************************
4367 * FindNextPrinterChangeNotification [WINSPOOL.@]
4370 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
4371 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
4373 FIXME("Stub: %p %p %p %p\n",
4374 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
4378 /*****************************************************************************
4379 * FreePrinterNotifyInfo [WINSPOOL.@]
4382 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
4384 FIXME("Stub: %p\n", pPrinterNotifyInfo);
4388 /*****************************************************************************
4389 * GetJobA [WINSPOOL.@]
4392 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4393 DWORD cbBuf, LPDWORD pcbNeeded)
4395 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4400 /*****************************************************************************
4401 * GetJobW [WINSPOOL.@]
4404 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4405 DWORD cbBuf, LPDWORD pcbNeeded)
4407 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4412 /*****************************************************************************
4413 * ScheduleJob [WINSPOOL.@]
4416 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
4418 FIXME("Stub: %p %lx\n", hPrinter, dwJobID);