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 CRITICAL_SECTION printer_handles_cs;
61 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
63 0, 0, &printer_handles_cs,
64 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
65 0, 0, { 0, (DWORD)(__FILE__ ": printer_handles_cs") }
67 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
73 static opened_printer_t **printer_handles;
74 static int nb_printer_handles;
76 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
77 WORD fwCapability, LPSTR lpszOutput,
79 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
80 LPSTR lpszDevice, LPSTR lpszPort,
81 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
84 static const char Printers[] =
85 "System\\CurrentControlSet\\control\\Print\\Printers\\";
87 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
88 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
89 'c','o','n','t','r','o','l','\\',
90 'P','r','i','n','t','\\',
91 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
92 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
94 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
95 'M','i','c','r','o','s','o','f','t','\\',
96 'W','i','n','d','o','w','s',' ','N','T','\\',
97 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
98 'W','i','n','d','o','w','s',0};
100 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
101 'M','i','c','r','o','s','o','f','t','\\',
102 'W','i','n','d','o','w','s',' ','N','T','\\',
103 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
104 'D','e','v','i','c','e','s',0};
106 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
108 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
109 'i','o','n',' ','F','i','l','e',0};
110 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
111 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
112 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
114 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
116 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
117 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
118 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
119 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
120 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
121 static const WCHAR NameW[] = {'N','a','m','e',0};
122 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
123 static const WCHAR PortW[] = {'P','o','r','t',0};
124 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
126 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
128 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
129 'v','e','r','D','a','t','a',0};
130 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
132 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
133 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
134 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
135 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
136 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
137 static const WCHAR emptyStringW[] = {0};
139 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
141 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
142 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
143 DWORD Level, LPBYTE pDriverInfo,
144 DWORD cbBuf, LPDWORD pcbNeeded,
146 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
148 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
149 if passed a NULL string. This returns NULLs to the result.
151 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
155 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
156 return usBufferPtr->Buffer;
158 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
163 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
166 /* If forcing, or no profile string entry for device yet, set the entry
168 * The always change entry if not WINEPS yet is discussable.
171 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
173 !strstr(qbuf,"WINEPS.DRV")
175 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
178 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
179 WriteProfileStringA("windows","device",buf);
180 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
181 RegSetValueExA(hkey, "Device", 0, REG_SZ, buf, strlen(buf) + 1);
184 HeapFree(GetProcessHeap(),0,buf);
188 #ifdef HAVE_CUPS_CUPS_H
189 static BOOL CUPS_LoadPrinters(void)
191 typeof(cupsGetDests) *pcupsGetDests = NULL;
192 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
194 BOOL hadprinter = FALSE;
196 PRINTER_INFO_2A pinfo2a;
197 void *cupshandle = NULL;
199 HKEY hkeyPrinter, hkeyPrinters, hkey;
201 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
204 TRACE("loaded %s\n", SONAME_LIBCUPS);
207 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
208 if (!p##x) return FALSE;
211 DYNCUPS(cupsGetDests);
214 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
216 ERR("Can't create Printers key\n");
220 nrofdests = pcupsGetDests(&dests);
221 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
222 for (i=0;i<nrofdests;i++) {
223 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
224 sprintf(port,"LPR:%s",dests[i].name);
225 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
226 sprintf(devline,"WINEPS.DRV,%s",port);
227 WriteProfileStringA("devices",dests[i].name,devline);
228 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
229 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, devline, strlen(devline) + 1);
232 HeapFree(GetProcessHeap(),0,devline);
234 TRACE("Printer %d: %s\n", i, dests[i].name);
235 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
236 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
238 TRACE("Printer already exists\n");
239 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
240 RegCloseKey(hkeyPrinter);
242 memset(&pinfo2a,0,sizeof(pinfo2a));
243 pinfo2a.pPrinterName = dests[i].name;
244 pinfo2a.pDatatype = "RAW";
245 pinfo2a.pPrintProcessor = "WinPrint";
246 pinfo2a.pDriverName = "PS Driver";
247 pinfo2a.pComment = "WINEPS Printer using CUPS";
248 pinfo2a.pLocation = "<physical location of printer>";
249 pinfo2a.pPortName = port;
250 pinfo2a.pParameters = "<parameters?>";
251 pinfo2a.pShareName = "<share name?>";
252 pinfo2a.pSepFile = "<sep file?>";
254 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
255 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
256 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
259 HeapFree(GetProcessHeap(),0,port);
262 if (dests[i].is_default)
263 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
265 RegCloseKey(hkeyPrinters);
266 wine_dlclose(cupshandle, NULL, 0);
272 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
273 PRINTER_INFO_2A pinfo2a;
274 char *e,*s,*name,*prettyname,*devname;
275 BOOL ret = FALSE, set_default = FALSE;
276 char *port,*devline,*env_default;
277 HKEY hkeyPrinter, hkeyPrinters, hkey;
279 while (isspace(*pent)) pent++;
280 s = strchr(pent,':');
282 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
290 TRACE("name=%s entry=%s\n",name, pent);
292 if(ispunct(*name)) { /* a tc entry, not a real printer */
293 TRACE("skipping tc entry\n");
297 if(strstr(pent,":server")) { /* server only version so skip */
298 TRACE("skipping server entry\n");
302 /* Determine whether this is a postscript printer. */
305 env_default = getenv("PRINTER");
307 /* Get longest name, usually the one at the right for later display. */
308 while((s=strchr(prettyname,'|'))) {
311 while(isspace(*--e)) *e = '\0';
312 TRACE("\t%s\n", debugstr_a(prettyname));
313 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
314 for(prettyname = s+1; isspace(*prettyname); prettyname++)
317 e = prettyname + strlen(prettyname);
318 while(isspace(*--e)) *e = '\0';
319 TRACE("\t%s\n", debugstr_a(prettyname));
320 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
322 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
323 * if it is too long, we use it as comment below. */
324 devname = prettyname;
325 if (strlen(devname)>=CCHDEVICENAME-1)
327 if (strlen(devname)>=CCHDEVICENAME-1) {
332 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
333 sprintf(port,"LPR:%s",name);
335 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
336 sprintf(devline,"WINEPS.DRV,%s",port);
337 WriteProfileStringA("devices",devname,devline);
338 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
339 RegSetValueExA(hkey, devname, 0, REG_SZ, devline, strlen(devline) + 1);
342 HeapFree(GetProcessHeap(),0,devline);
344 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
346 ERR("Can't create Printers key\n");
350 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
351 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
353 TRACE("Printer already exists\n");
354 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
355 RegCloseKey(hkeyPrinter);
357 memset(&pinfo2a,0,sizeof(pinfo2a));
358 pinfo2a.pPrinterName = devname;
359 pinfo2a.pDatatype = "RAW";
360 pinfo2a.pPrintProcessor = "WinPrint";
361 pinfo2a.pDriverName = "PS Driver";
362 pinfo2a.pComment = "WINEPS Printer using LPR";
363 pinfo2a.pLocation = prettyname;
364 pinfo2a.pPortName = port;
365 pinfo2a.pParameters = "<parameters?>";
366 pinfo2a.pShareName = "<share name?>";
367 pinfo2a.pSepFile = "<sep file?>";
369 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
370 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
371 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
374 RegCloseKey(hkeyPrinters);
376 if (isfirst || set_default)
377 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
379 HeapFree(GetProcessHeap(), 0, port);
381 HeapFree(GetProcessHeap(), 0, name);
386 PRINTCAP_LoadPrinters(void) {
387 BOOL hadprinter = FALSE;
391 BOOL had_bash = FALSE;
393 f = fopen("/etc/printcap","r");
397 while(fgets(buf,sizeof(buf),f)) {
400 end=strchr(buf,'\n');
404 while(isspace(*start)) start++;
405 if(*start == '#' || *start == '\0')
408 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
409 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
410 HeapFree(GetProcessHeap(),0,pent);
414 if (end && *--end == '\\') {
421 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
424 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
430 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
431 HeapFree(GetProcessHeap(),0,pent);
437 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
440 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
441 lstrlenW(value) * sizeof(WCHAR));
443 return ERROR_FILE_NOT_FOUND;
446 void WINSPOOL_LoadSystemPrinters(void)
448 HKEY hkey, hkeyPrinters;
451 DWORD needed, num, i;
452 WCHAR PrinterName[256];
455 di3a.cVersion = 0x400;
456 di3a.pName = "PS Driver";
457 di3a.pEnvironment = NULL; /* NULL means auto */
458 di3a.pDriverPath = "wineps16";
459 di3a.pDataFile = "<datafile?>";
460 di3a.pConfigFile = "wineps16";
461 di3a.pHelpFile = "<helpfile?>";
462 di3a.pDependentFiles = "<dependend files?>";
463 di3a.pMonitorName = "<monitor name?>";
464 di3a.pDefaultDataType = "RAW";
466 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
467 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
471 /* This ensures that all printer entries have a valid Name value. If causes
472 problems later if they don't. If one is found to be missed we create one
473 and set it equal to the name of the key */
474 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
475 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
476 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
477 for(i = 0; i < num; i++) {
478 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
479 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
480 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
481 set_reg_szW(hkey, NameW, PrinterName);
488 RegCloseKey(hkeyPrinters);
491 /* We want to avoid calling AddPrinter on printers as much as
492 possible, because on cups printers this will (eventually) lead
493 to a call to cupsGetPPD which takes forever, even with non-cups
494 printers AddPrinter takes a while. So we'll tag all printers that
495 were automatically added last time around, if they still exist
496 we'll leave them be otherwise we'll delete them. */
497 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
499 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
500 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
501 for(i = 0; i < num; i++) {
502 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
503 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
504 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
506 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
514 HeapFree(GetProcessHeap(), 0, pi);
518 #ifdef HAVE_CUPS_CUPS_H
519 done = CUPS_LoadPrinters();
522 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
523 /* Check for [ppd] section in config file before parsing /etc/printcap */
524 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
525 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
526 &hkey) == ERROR_SUCCESS) {
528 PRINTCAP_LoadPrinters();
532 /* Now enumerate the list again and delete any printers that a still tagged */
533 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
535 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
536 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
537 for(i = 0; i < num; i++) {
538 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
539 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
540 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
541 DWORD dw, type, size = sizeof(dw);
542 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
543 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
553 HeapFree(GetProcessHeap(), 0, pi);
561 /******************************************************************
562 * get_opened_printer_entry
563 * Get the first place empty in the opened printer table
565 static HANDLE get_opened_printer_entry( LPCWSTR name )
569 EnterCriticalSection(&printer_handles_cs);
571 for (handle = 0; handle < nb_printer_handles; handle++)
572 if (!printer_handles[handle])
575 if (handle >= nb_printer_handles)
577 opened_printer_t **new_array;
579 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
580 (nb_printer_handles + 16) * sizeof(*new_array) );
582 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
583 (nb_printer_handles + 16) * sizeof(*new_array) );
590 printer_handles = new_array;
591 nb_printer_handles += 16;
594 if (!(printer_handles[handle] = HeapAlloc(GetProcessHeap(), 0, sizeof(**printer_handles))))
600 printer_handles[handle]->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
601 strcpyW(printer_handles[handle]->name, name);
605 LeaveCriticalSection(&printer_handles_cs);
607 return (HANDLE)handle;
610 /******************************************************************
612 * Get the pointer to the opened printer referred by the handle
614 static opened_printer_t *get_opened_printer(HANDLE hprn)
617 opened_printer_t *ret = NULL;
619 EnterCriticalSection(&printer_handles_cs);
621 if ((idx <= 0) || (idx > nb_printer_handles))
624 ret = printer_handles[idx - 1];
626 LeaveCriticalSection(&printer_handles_cs);
630 /******************************************************************
631 * get_opened_printer_name
632 * Get the pointer to the opened printer name referred by the handle
634 static LPCWSTR get_opened_printer_name(HANDLE hprn)
636 opened_printer_t *printer = get_opened_printer(hprn);
637 if(!printer) return NULL;
638 return printer->name;
641 /******************************************************************
642 * WINSPOOL_GetOpenedPrinterRegKey
645 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
647 LPCWSTR name = get_opened_printer_name(hPrinter);
651 if(!name) return ERROR_INVALID_HANDLE;
653 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
657 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
659 ERR("Can't find opened printer %s in registry\n",
661 RegCloseKey(hkeyPrinters);
662 return ERROR_INVALID_PRINTER_NAME; /* ? */
664 RegCloseKey(hkeyPrinters);
665 return ERROR_SUCCESS;
668 /***********************************************************
671 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
674 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
677 Formname = (dmA->dmSize > off_formname);
678 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
679 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
682 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
683 dmA->dmSize - CCHDEVICENAME);
685 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
686 off_formname - CCHDEVICENAME);
687 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
689 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
690 (off_formname + CCHFORMNAME));
693 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
698 /***********************************************************
700 * Creates an ascii copy of supplied devmode on heap
702 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
707 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
709 if(!dmW) return NULL;
710 Formname = (dmW->dmSize > off_formname);
711 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
712 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
713 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
714 CCHDEVICENAME, NULL, NULL);
716 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
717 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
719 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
720 off_formname - CCHDEVICENAME * sizeof(WCHAR));
721 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
722 CCHFORMNAME, NULL, NULL);
723 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
724 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
727 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
732 /***********************************************************
734 * Creates a unicode copy of PRINTER_INFO_2A on heap
736 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
738 LPPRINTER_INFO_2W piW;
739 UNICODE_STRING usBuffer;
741 if(!piA) return NULL;
742 piW = HeapAlloc(heap, 0, sizeof(*piW));
743 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
745 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
746 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
747 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
748 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
749 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
750 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
751 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
752 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
753 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
754 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
755 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
756 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
760 /***********************************************************
761 * FREE_PRINTER_INFO_2W
762 * Free PRINTER_INFO_2W and all strings
764 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
768 HeapFree(heap,0,piW->pServerName);
769 HeapFree(heap,0,piW->pPrinterName);
770 HeapFree(heap,0,piW->pShareName);
771 HeapFree(heap,0,piW->pPortName);
772 HeapFree(heap,0,piW->pDriverName);
773 HeapFree(heap,0,piW->pComment);
774 HeapFree(heap,0,piW->pLocation);
775 HeapFree(heap,0,piW->pDevMode);
776 HeapFree(heap,0,piW->pSepFile);
777 HeapFree(heap,0,piW->pPrintProcessor);
778 HeapFree(heap,0,piW->pDatatype);
779 HeapFree(heap,0,piW->pParameters);
780 HeapFree(heap,0,piW);
784 /******************************************************************
785 * DeviceCapabilities [WINSPOOL.@]
786 * DeviceCapabilitiesA [WINSPOOL.@]
789 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
790 LPSTR pOutput, LPDEVMODEA lpdm)
794 if (!GDI_CallDeviceCapabilities16)
796 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
798 if (!GDI_CallDeviceCapabilities16) return -1;
800 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
802 /* If DC_PAPERSIZE map POINT16s to POINTs */
803 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
804 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
805 POINT *pt = (POINT *)pOutput;
807 memcpy(tmp, pOutput, ret * sizeof(POINT16));
808 for(i = 0; i < ret; i++, pt++)
813 HeapFree( GetProcessHeap(), 0, tmp );
819 /*****************************************************************************
820 * DeviceCapabilitiesW [WINSPOOL.@]
822 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
825 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
826 WORD fwCapability, LPWSTR pOutput,
827 const DEVMODEW *pDevMode)
829 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
830 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
831 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
834 if(pOutput && (fwCapability == DC_BINNAMES ||
835 fwCapability == DC_FILEDEPENDENCIES ||
836 fwCapability == DC_PAPERNAMES)) {
837 /* These need A -> W translation */
840 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
844 switch(fwCapability) {
849 case DC_FILEDEPENDENCIES:
853 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
854 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
856 for(i = 0; i < ret; i++)
857 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
858 pOutput + (i * size), size);
859 HeapFree(GetProcessHeap(), 0, pOutputA);
861 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
862 (LPSTR)pOutput, dmA);
864 HeapFree(GetProcessHeap(),0,pPortA);
865 HeapFree(GetProcessHeap(),0,pDeviceA);
866 HeapFree(GetProcessHeap(),0,dmA);
870 /******************************************************************
871 * DocumentPropertiesA [WINSPOOL.@]
873 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
875 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
876 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
877 LPDEVMODEA pDevModeInput,DWORD fMode )
879 LPSTR lpName = pDeviceName;
882 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
883 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
887 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
889 ERR("no name from hPrinter?\n");
890 SetLastError(ERROR_INVALID_HANDLE);
893 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
896 if (!GDI_CallExtDeviceMode16)
898 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
900 if (!GDI_CallExtDeviceMode16) {
901 ERR("No CallExtDeviceMode16?\n");
905 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
906 pDevModeInput, NULL, fMode);
909 HeapFree(GetProcessHeap(),0,lpName);
914 /*****************************************************************************
915 * DocumentPropertiesW (WINSPOOL.@)
917 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
919 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
921 LPDEVMODEW pDevModeOutput,
922 LPDEVMODEW pDevModeInput, DWORD fMode)
925 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
926 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
927 LPDEVMODEA pDevModeOutputA = NULL;
930 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
931 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
934 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
935 if(ret < 0) return ret;
936 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
938 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
939 pDevModeInputA, fMode);
941 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
942 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
944 if(fMode == 0 && ret > 0)
945 ret += (CCHDEVICENAME + CCHFORMNAME);
946 HeapFree(GetProcessHeap(),0,pDevModeInputA);
947 HeapFree(GetProcessHeap(),0,pDeviceNameA);
951 /******************************************************************
952 * OpenPrinterA [WINSPOOL.@]
955 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
956 LPPRINTER_DEFAULTSA pDefault)
958 UNICODE_STRING lpPrinterNameW;
959 UNICODE_STRING usBuffer;
960 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
961 PWSTR pwstrPrinterNameW;
964 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
967 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
968 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
969 DefaultW.DesiredAccess = pDefault->DesiredAccess;
970 pDefaultW = &DefaultW;
972 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
974 RtlFreeUnicodeString(&usBuffer);
975 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
977 RtlFreeUnicodeString(&lpPrinterNameW);
981 /******************************************************************
982 * OpenPrinterW [WINSPOOL.@]
985 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
986 LPPRINTER_DEFAULTSW pDefault)
988 HKEY hkeyPrinters, hkeyPrinter;
990 if (!lpPrinterName) {
991 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
992 SetLastError(ERROR_INVALID_PARAMETER);
996 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
999 /* Check Printer exists */
1000 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1002 ERR("Can't create Printers key\n");
1003 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1007 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1008 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1010 TRACE("Can't find printer %s in registry\n",
1011 debugstr_w(lpPrinterName));
1012 RegCloseKey(hkeyPrinters);
1013 SetLastError(ERROR_INVALID_PRINTER_NAME);
1016 RegCloseKey(hkeyPrinter);
1017 RegCloseKey(hkeyPrinters);
1019 if(!phPrinter) /* This seems to be what win95 does anyway */
1022 /* Get the unique handle of the printer*/
1023 *phPrinter = get_opened_printer_entry( lpPrinterName );
1025 if (pDefault != NULL)
1026 FIXME("Not handling pDefault\n");
1031 /******************************************************************
1032 * AddMonitorA [WINSPOOL.@]
1035 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1037 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
1038 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1042 /******************************************************************************
1043 * AddMonitorW [WINSPOOL.@]
1045 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1047 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1048 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1052 /******************************************************************
1053 * DeletePrinterDriverA [WINSPOOL.@]
1057 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1059 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1060 debugstr_a(pDriverName));
1061 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1065 /******************************************************************
1066 * DeletePrinterDriverW [WINSPOOL.@]
1070 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1072 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1073 debugstr_w(pDriverName));
1074 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1078 /******************************************************************
1079 * DeleteMonitorA [WINSPOOL.@]
1083 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1085 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1086 debugstr_a(pMonitorName));
1087 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1091 /******************************************************************
1092 * DeleteMonitorW [WINSPOOL.@]
1096 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1098 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1099 debugstr_w(pMonitorName));
1100 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1104 /******************************************************************
1105 * DeletePortA [WINSPOOL.@]
1109 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1111 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1112 debugstr_a(pPortName));
1113 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1117 /******************************************************************
1118 * DeletePortW [WINSPOOL.@]
1122 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1124 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1125 debugstr_w(pPortName));
1126 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1130 /******************************************************************************
1131 * SetPrinterW [WINSPOOL.@]
1141 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1145 /******************************************************************************
1146 * WritePrinter [WINSPOOL.@]
1153 LPDWORD pcWritten) {
1156 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1160 /*****************************************************************************
1161 * AddFormA [WINSPOOL.@]
1163 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1165 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1169 /*****************************************************************************
1170 * AddFormW [WINSPOOL.@]
1172 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1174 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1178 /*****************************************************************************
1179 * AddJobA [WINSPOOL.@]
1181 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
1182 DWORD cbBuf, LPDWORD pcbNeeded)
1184 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1189 /*****************************************************************************
1190 * AddJobW [WINSPOOL.@]
1192 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
1195 FIXME("(%p,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
1200 /*****************************************************************************
1201 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1203 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1204 DWORD level, LPBYTE Info,
1205 DWORD cbBuf, LPDWORD needed)
1207 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1208 level, Info, cbBuf);
1212 /*****************************************************************************
1213 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1215 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1216 DWORD level, LPBYTE Info,
1217 DWORD cbBuf, LPDWORD needed)
1219 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1220 level, Info, cbBuf);
1224 /*****************************************************************************
1225 * WINSPOOL_OpenDriverReg [internal]
1227 * opens the registry for the printer drivers depending on the given input
1228 * variable pEnvironment
1231 * the opened hkey on success
1234 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1236 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1237 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1239 LPWSTR lpKey, buffer = NULL;
1243 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1247 pEnvW = pEnvironment;
1249 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1250 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1251 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1256 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1258 if(!GetVersionExW( &ver))
1261 switch (ver.dwPlatformId) {
1262 case VER_PLATFORM_WIN32s:
1263 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1265 case VER_PLATFORM_WIN32_NT:
1272 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1275 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1276 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1277 wsprintfW( lpKey, DriversW, pEnvW);
1279 TRACE("%s\n", debugstr_w(lpKey));
1281 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1284 HeapFree( GetProcessHeap(), 0, buffer);
1285 HeapFree( GetProcessHeap(), 0, lpKey);
1290 /*****************************************************************************
1291 * AddPrinterW [WINSPOOL.@]
1293 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1295 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1299 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1302 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1305 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1306 SetLastError(ERROR_INVALID_PARAMETER);
1310 ERR("Level = %ld, unsupported!\n", Level);
1311 SetLastError(ERROR_INVALID_LEVEL);
1314 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1315 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1316 debugstr_w(pi->pPrinterName)
1318 SetLastError(ERROR_INVALID_LEVEL);
1322 SetLastError(ERROR_INVALID_PARAMETER);
1325 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1327 ERR("Can't create Printers key\n");
1330 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1331 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1332 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1333 RegCloseKey(hkeyPrinter);
1334 RegCloseKey(hkeyPrinters);
1337 RegCloseKey(hkeyPrinter);
1339 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1341 ERR("Can't create Drivers key\n");
1342 RegCloseKey(hkeyPrinters);
1345 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1347 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1348 RegCloseKey(hkeyPrinters);
1349 RegCloseKey(hkeyDrivers);
1350 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1353 RegCloseKey(hkeyDriver);
1354 RegCloseKey(hkeyDrivers);
1356 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1357 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1358 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1359 RegCloseKey(hkeyPrinters);
1363 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1365 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1366 SetLastError(ERROR_INVALID_PRINTER_NAME);
1367 RegCloseKey(hkeyPrinters);
1370 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1371 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1372 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1374 /* See if we can load the driver. We may need the devmode structure anyway
1377 * Note that DocumentPropertiesW will briefly try to open the printer we
1378 * just create to find a DEVMODEA struct (it will use the WINEPS default
1379 * one in case it is not there, so we are ok).
1381 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1384 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1385 size = sizeof(DEVMODEW);
1391 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1392 ZeroMemory(dmW,size);
1394 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1396 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1397 HeapFree(GetProcessHeap(),0,dmW);
1402 /* set devmode to printer name */
1403 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1407 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1408 and we support these drivers. NT writes DEVMODEW so somehow
1409 we'll need to distinguish between these when we support NT
1413 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1414 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1415 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1416 HeapFree(GetProcessHeap(), 0, dmA);
1418 HeapFree(GetProcessHeap(), 0, dmW);
1420 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1421 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1422 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1423 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1425 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1426 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1427 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1428 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1429 (LPBYTE)&pi->Priority, sizeof(DWORD));
1430 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1431 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1432 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1433 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1434 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1435 (LPBYTE)&pi->Status, sizeof(DWORD));
1436 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1437 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1439 RegCloseKey(hkeyPrinter);
1440 RegCloseKey(hkeyPrinters);
1441 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1442 ERR("OpenPrinter failing\n");
1448 /*****************************************************************************
1449 * AddPrinterA [WINSPOOL.@]
1451 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1453 UNICODE_STRING pNameW;
1455 PRINTER_INFO_2W *piW;
1456 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1459 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1461 ERR("Level = %ld, unsupported!\n", Level);
1462 SetLastError(ERROR_INVALID_LEVEL);
1465 pwstrNameW = asciitounicode(&pNameW,pName);
1466 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1468 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1470 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1471 RtlFreeUnicodeString(&pNameW);
1476 /*****************************************************************************
1477 * ClosePrinter [WINSPOOL.@]
1479 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1481 int i = (int)hPrinter;
1482 opened_printer_t *printer = NULL;
1484 TRACE("Handle %p\n", hPrinter);
1486 EnterCriticalSection(&printer_handles_cs);
1488 if ((i > 0) && (i <= nb_printer_handles))
1490 printer = printer_handles[i - 1];
1491 printer_handles[i - 1] = NULL;
1494 LeaveCriticalSection(&printer_handles_cs);
1498 HeapFree(GetProcessHeap(), 0, printer->name);
1499 HeapFree(GetProcessHeap(), 0, printer);
1505 /*****************************************************************************
1506 * DeleteFormA [WINSPOOL.@]
1508 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1510 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1514 /*****************************************************************************
1515 * DeleteFormW [WINSPOOL.@]
1517 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1519 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1523 /*****************************************************************************
1524 * WINSPOOL_SHRegDeleteKey
1526 * Recursively delete subkeys.
1527 * Cut & paste from shlwapi.
1530 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1532 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1533 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1536 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1539 /* Find how many subkeys there are */
1540 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1541 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1545 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1546 /* Name too big: alloc a buffer for it */
1547 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1550 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1553 /* Recursively delete all the subkeys */
1554 for(i = 0; i < dwKeyCount && !dwRet; i++)
1556 dwSize = dwMaxSubkeyLen;
1557 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1559 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1562 if (lpszName != szNameBuf)
1563 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1567 RegCloseKey(hSubKey);
1569 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1574 /*****************************************************************************
1575 * DeletePrinter [WINSPOOL.@]
1577 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1579 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1580 HKEY hkeyPrinters, hkey;
1583 SetLastError(ERROR_INVALID_HANDLE);
1586 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1587 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1588 RegCloseKey(hkeyPrinters);
1590 WriteProfileStringW(devicesW, lpNameW, NULL);
1591 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1592 RegDeleteValueW(hkey, lpNameW);
1598 /*****************************************************************************
1599 * SetPrinterA [WINSPOOL.@]
1601 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1604 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1608 /*****************************************************************************
1609 * SetJobA [WINSPOOL.@]
1611 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1612 LPBYTE pJob, DWORD Command)
1614 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1619 /*****************************************************************************
1620 * SetJobW [WINSPOOL.@]
1622 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1623 LPBYTE pJob, DWORD Command)
1625 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1630 /*****************************************************************************
1631 * EndDocPrinter [WINSPOOL.@]
1633 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1635 FIXME("(hPrinter=%p): stub\n", hPrinter);
1639 /*****************************************************************************
1640 * EndPagePrinter [WINSPOOL.@]
1642 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1644 FIXME("(hPrinter=%p): stub\n", hPrinter);
1648 /*****************************************************************************
1649 * StartDocPrinterA [WINSPOOL.@]
1651 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1653 UNICODE_STRING usBuffer;
1655 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
1658 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
1659 or one (DOC_INFO_3) extra DWORDs */
1663 doc2W.JobId = doc2->JobId;
1666 doc2W.dwMode = doc2->dwMode;
1669 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
1670 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
1671 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
1675 SetLastError(ERROR_INVALID_LEVEL);
1679 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
1681 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
1682 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
1683 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
1688 /*****************************************************************************
1689 * StartDocPrinterW [WINSPOOL.@]
1691 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1693 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
1695 FIXME("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}): stub\n",
1696 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
1697 debugstr_w(doc->pDatatype));
1701 /*****************************************************************************
1702 * StartPagePrinter [WINSPOOL.@]
1704 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1706 FIXME("(hPrinter=%p): stub\n", hPrinter);
1710 /*****************************************************************************
1711 * GetFormA [WINSPOOL.@]
1713 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1714 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1716 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1717 Level,pForm,cbBuf,pcbNeeded);
1721 /*****************************************************************************
1722 * GetFormW [WINSPOOL.@]
1724 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1725 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1727 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1728 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1732 /*****************************************************************************
1733 * SetFormA [WINSPOOL.@]
1735 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1738 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1742 /*****************************************************************************
1743 * SetFormW [WINSPOOL.@]
1745 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1748 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1752 /*****************************************************************************
1753 * ReadPrinter [WINSPOOL.@]
1755 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1756 LPDWORD pNoBytesRead)
1758 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1762 /*****************************************************************************
1763 * ResetPrinterA [WINSPOOL.@]
1765 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1767 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1771 /*****************************************************************************
1772 * ResetPrinterW [WINSPOOL.@]
1774 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1776 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1780 /*****************************************************************************
1781 * WINSPOOL_GetDWORDFromReg
1783 * Return DWORD associated with ValueName from hkey.
1785 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1787 DWORD sz = sizeof(DWORD), type, value = 0;
1790 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1792 if(ret != ERROR_SUCCESS) {
1793 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1796 if(type != REG_DWORD) {
1797 ERR("Got type %ld\n", type);
1803 /*****************************************************************************
1804 * WINSPOOL_GetStringFromReg
1806 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1807 * String is stored either as unicode or ascii.
1808 * Bit of a hack here to get the ValueName if we want ascii.
1810 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1811 DWORD buflen, DWORD *needed,
1814 DWORD sz = buflen, type;
1818 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1820 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1821 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1822 HeapFree(GetProcessHeap(),0,ValueNameA);
1824 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1825 WARN("Got ret = %ld\n", ret);
1833 /*****************************************************************************
1834 * WINSPOOL_GetDefaultDevMode
1836 * Get a default DevMode values for wineps.
1840 static void WINSPOOL_GetDefaultDevMode(
1842 DWORD buflen, DWORD *needed,
1847 /* fill default DEVMODE - should be read from ppd... */
1848 ZeroMemory( &dm, sizeof(dm) );
1849 strcpy(dm.dmDeviceName,"wineps.drv");
1850 dm.dmSpecVersion = DM_SPECVERSION;
1851 dm.dmDriverVersion = 1;
1852 dm.dmSize = sizeof(DEVMODEA);
1853 dm.dmDriverExtra = 0;
1855 DM_ORIENTATION | DM_PAPERSIZE |
1856 DM_PAPERLENGTH | DM_PAPERWIDTH |
1859 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1860 DM_YRESOLUTION | DM_TTOPTION;
1862 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1863 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1864 dm.u1.s1.dmPaperLength = 2970;
1865 dm.u1.s1.dmPaperWidth = 2100;
1869 dm.dmDefaultSource = DMBIN_AUTO;
1870 dm.dmPrintQuality = DMRES_MEDIUM;
1873 dm.dmYResolution = 300; /* 300dpi */
1874 dm.dmTTOption = DMTT_BITMAP;
1877 /* dm.dmLogPixels */
1878 /* dm.dmBitsPerPel */
1879 /* dm.dmPelsWidth */
1880 /* dm.dmPelsHeight */
1881 /* dm.dmDisplayFlags */
1882 /* dm.dmDisplayFrequency */
1883 /* dm.dmICMMethod */
1884 /* dm.dmICMIntent */
1885 /* dm.dmMediaType */
1886 /* dm.dmDitherType */
1887 /* dm.dmReserved1 */
1888 /* dm.dmReserved2 */
1889 /* dm.dmPanningWidth */
1890 /* dm.dmPanningHeight */
1893 if(buflen >= sizeof(DEVMODEW)) {
1894 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1895 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1896 HeapFree(GetProcessHeap(),0,pdmW);
1898 *needed = sizeof(DEVMODEW);
1902 if(buflen >= sizeof(DEVMODEA)) {
1903 memcpy(ptr, &dm, sizeof(DEVMODEA));
1905 *needed = sizeof(DEVMODEA);
1909 /*****************************************************************************
1910 * WINSPOOL_GetDevModeFromReg
1912 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1913 * DevMode is stored either as unicode or ascii.
1915 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1917 DWORD buflen, DWORD *needed,
1920 DWORD sz = buflen, type;
1923 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
1924 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1925 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1926 if (sz < sizeof(DEVMODEA))
1928 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1931 /* ensures that dmSize is not erratically bogus if registry is invalid */
1932 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1933 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1935 sz += (CCHDEVICENAME + CCHFORMNAME);
1937 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
1938 memcpy(ptr, dmW, sz);
1939 HeapFree(GetProcessHeap(),0,dmW);
1946 /*********************************************************************
1947 * WINSPOOL_GetPrinter_2
1949 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1950 * The strings are either stored as unicode or ascii.
1952 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1953 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1956 DWORD size, left = cbBuf;
1957 BOOL space = (cbBuf > 0);
1962 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1964 if(space && size <= left) {
1965 pi2->pPrinterName = (LPWSTR)ptr;
1972 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1974 if(space && size <= left) {
1975 pi2->pShareName = (LPWSTR)ptr;
1982 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1984 if(space && size <= left) {
1985 pi2->pPortName = (LPWSTR)ptr;
1992 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1994 if(space && size <= left) {
1995 pi2->pDriverName = (LPWSTR)ptr;
2002 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2004 if(space && size <= left) {
2005 pi2->pComment = (LPWSTR)ptr;
2012 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2014 if(space && size <= left) {
2015 pi2->pLocation = (LPWSTR)ptr;
2022 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2024 if(space && size <= left) {
2025 pi2->pDevMode = (LPDEVMODEW)ptr;
2034 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2035 if(space && size <= left) {
2036 pi2->pDevMode = (LPDEVMODEW)ptr;
2043 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2045 if(space && size <= left) {
2046 pi2->pSepFile = (LPWSTR)ptr;
2053 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2055 if(space && size <= left) {
2056 pi2->pPrintProcessor = (LPWSTR)ptr;
2063 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2065 if(space && size <= left) {
2066 pi2->pDatatype = (LPWSTR)ptr;
2073 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2075 if(space && size <= left) {
2076 pi2->pParameters = (LPWSTR)ptr;
2084 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2085 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2086 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2087 "Default Priority");
2088 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2089 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2092 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2093 memset(pi2, 0, sizeof(*pi2));
2098 /*********************************************************************
2099 * WINSPOOL_GetPrinter_4
2101 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2103 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2104 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2107 DWORD size, left = cbBuf;
2108 BOOL space = (cbBuf > 0);
2113 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2115 if(space && size <= left) {
2116 pi4->pPrinterName = (LPWSTR)ptr;
2124 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2127 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2128 memset(pi4, 0, sizeof(*pi4));
2133 /*********************************************************************
2134 * WINSPOOL_GetPrinter_5
2136 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2138 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2139 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2142 DWORD size, left = cbBuf;
2143 BOOL space = (cbBuf > 0);
2148 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2150 if(space && size <= left) {
2151 pi5->pPrinterName = (LPWSTR)ptr;
2158 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2160 if(space && size <= left) {
2161 pi5->pPortName = (LPWSTR)ptr;
2169 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2170 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2172 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2176 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2177 memset(pi5, 0, sizeof(*pi5));
2182 /*****************************************************************************
2183 * WINSPOOL_GetPrinter
2185 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2186 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2187 * just a collection of pointers to strings.
2189 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2190 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2193 DWORD size, needed = 0;
2195 HKEY hkeyPrinter, hkeyPrinters;
2198 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2200 if (!(name = get_opened_printer_name(hPrinter))) {
2201 SetLastError(ERROR_INVALID_HANDLE);
2205 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2207 ERR("Can't create Printers key\n");
2210 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2212 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2213 RegCloseKey(hkeyPrinters);
2214 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2221 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2223 size = sizeof(PRINTER_INFO_2W);
2225 ptr = pPrinter + size;
2227 memset(pPrinter, 0, size);
2232 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2240 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2242 size = sizeof(PRINTER_INFO_4W);
2244 ptr = pPrinter + size;
2246 memset(pPrinter, 0, size);
2251 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2260 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2262 size = sizeof(PRINTER_INFO_5W);
2264 ptr = pPrinter + size;
2266 memset(pPrinter, 0, size);
2272 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2279 FIXME("Unimplemented level %ld\n", Level);
2280 SetLastError(ERROR_INVALID_LEVEL);
2281 RegCloseKey(hkeyPrinters);
2282 RegCloseKey(hkeyPrinter);
2286 RegCloseKey(hkeyPrinter);
2287 RegCloseKey(hkeyPrinters);
2289 TRACE("returning %d needed = %ld\n", ret, needed);
2290 if(pcbNeeded) *pcbNeeded = needed;
2292 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2296 /*****************************************************************************
2297 * GetPrinterW [WINSPOOL.@]
2299 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2300 DWORD cbBuf, LPDWORD pcbNeeded)
2302 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2306 /*****************************************************************************
2307 * GetPrinterA [WINSPOOL.@]
2309 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2310 DWORD cbBuf, LPDWORD pcbNeeded)
2312 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2316 /*****************************************************************************
2317 * WINSPOOL_EnumPrinters
2319 * Implementation of EnumPrintersA|W
2321 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2322 DWORD dwLevel, LPBYTE lpbPrinters,
2323 DWORD cbBuf, LPDWORD lpdwNeeded,
2324 LPDWORD lpdwReturned, BOOL unicode)
2327 HKEY hkeyPrinters, hkeyPrinter;
2328 WCHAR PrinterName[255];
2329 DWORD needed = 0, number = 0;
2330 DWORD used, i, left;
2334 memset(lpbPrinters, 0, cbBuf);
2340 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2341 if(dwType == PRINTER_ENUM_DEFAULT)
2344 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2345 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2346 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2347 if(!dwType) return TRUE;
2350 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2351 FIXME("dwType = %08lx\n", dwType);
2352 SetLastError(ERROR_INVALID_FLAGS);
2356 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2358 ERR("Can't create Printers key\n");
2362 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2363 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2364 RegCloseKey(hkeyPrinters);
2365 ERR("Can't query Printers key\n");
2368 TRACE("Found %ld printers\n", number);
2372 RegCloseKey(hkeyPrinters);
2374 *lpdwReturned = number;
2378 used = number * sizeof(PRINTER_INFO_2W);
2381 used = number * sizeof(PRINTER_INFO_4W);
2384 used = number * sizeof(PRINTER_INFO_5W);
2388 SetLastError(ERROR_INVALID_LEVEL);
2389 RegCloseKey(hkeyPrinters);
2392 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2394 for(i = 0; i < number; i++) {
2395 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2397 ERR("Can't enum key number %ld\n", i);
2398 RegCloseKey(hkeyPrinters);
2401 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2402 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2404 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2405 RegCloseKey(hkeyPrinters);
2410 buf = lpbPrinters + used;
2411 left = cbBuf - used;
2419 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2420 left, &needed, unicode);
2422 if(pi) pi += sizeof(PRINTER_INFO_2W);
2425 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2426 left, &needed, unicode);
2428 if(pi) pi += sizeof(PRINTER_INFO_4W);
2431 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2432 left, &needed, unicode);
2434 if(pi) pi += sizeof(PRINTER_INFO_5W);
2437 ERR("Shouldn't be here!\n");
2438 RegCloseKey(hkeyPrinter);
2439 RegCloseKey(hkeyPrinters);
2442 RegCloseKey(hkeyPrinter);
2444 RegCloseKey(hkeyPrinters);
2451 memset(lpbPrinters, 0, cbBuf);
2452 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2456 *lpdwReturned = number;
2457 SetLastError(ERROR_SUCCESS);
2462 /******************************************************************
2463 * EnumPrintersW [WINSPOOL.@]
2465 * Enumerates the available printers, print servers and print
2466 * providers, depending on the specified flags, name and level.
2470 * If level is set to 1:
2471 * Not implemented yet!
2472 * Returns TRUE with an empty list.
2474 * If level is set to 2:
2475 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2476 * Returns an array of PRINTER_INFO_2 data structures in the
2477 * lpbPrinters buffer. Note that according to MSDN also an
2478 * OpenPrinter should be performed on every remote printer.
2480 * If level is set to 4 (officially WinNT only):
2481 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2482 * Fast: Only the registry is queried to retrieve printer names,
2483 * no connection to the driver is made.
2484 * Returns an array of PRINTER_INFO_4 data structures in the
2485 * lpbPrinters buffer.
2487 * If level is set to 5 (officially WinNT4/Win9x only):
2488 * Fast: Only the registry is queried to retrieve printer names,
2489 * no connection to the driver is made.
2490 * Returns an array of PRINTER_INFO_5 data structures in the
2491 * lpbPrinters buffer.
2493 * If level set to 3 or 6+:
2494 * returns zero (failure!)
2496 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2500 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2501 * - Only levels 2, 4 and 5 are implemented at the moment.
2502 * - 16-bit printer drivers are not enumerated.
2503 * - Returned amount of bytes used/needed does not match the real Windoze
2504 * implementation (as in this implementation, all strings are part
2505 * of the buffer, whereas Win32 keeps them somewhere else)
2506 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2509 * - In a regular Wine installation, no registry settings for printers
2510 * exist, which makes this function return an empty list.
2512 BOOL WINAPI EnumPrintersW(
2513 DWORD dwType, /* [in] Types of print objects to enumerate */
2514 LPWSTR lpszName, /* [in] name of objects to enumerate */
2515 DWORD dwLevel, /* [in] type of printer info structure */
2516 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2517 DWORD cbBuf, /* [in] max size of buffer in bytes */
2518 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2519 LPDWORD lpdwReturned /* [out] number of entries returned */
2522 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2523 lpdwNeeded, lpdwReturned, TRUE);
2526 /******************************************************************
2527 * EnumPrintersA [WINSPOOL.@]
2530 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2531 DWORD dwLevel, LPBYTE lpbPrinters,
2532 DWORD cbBuf, LPDWORD lpdwNeeded,
2533 LPDWORD lpdwReturned)
2536 UNICODE_STRING lpszNameW;
2539 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2540 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2541 lpdwNeeded, lpdwReturned, FALSE);
2542 RtlFreeUnicodeString(&lpszNameW);
2546 /*****************************************************************************
2547 * WINSPOOL_GetDriverInfoFromReg [internal]
2549 * Enters the information from the registry into the DRIVER_INFO struct
2552 * zero if the printer driver does not exist in the registry
2553 * (only if Level > 1) otherwise nonzero
2555 static BOOL WINSPOOL_GetDriverInfoFromReg(
2558 LPWSTR pEnvironment,
2560 LPBYTE ptr, /* DRIVER_INFO */
2561 LPBYTE pDriverStrings, /* strings buffer */
2562 DWORD cbBuf, /* size of string buffer */
2563 LPDWORD pcbNeeded, /* space needed for str. */
2564 BOOL unicode) /* type of strings */
2565 { DWORD dw, size, tmp, type;
2567 LPBYTE strPtr = pDriverStrings;
2569 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2570 debugstr_w(DriverName), debugstr_w(pEnvironment),
2571 Level, ptr, pDriverStrings, cbBuf, unicode);
2574 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2575 if (*pcbNeeded <= cbBuf)
2576 strcpyW((LPWSTR)strPtr, DriverName);
2578 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2580 if(*pcbNeeded <= cbBuf)
2581 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2586 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2590 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2591 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2594 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2595 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2596 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2601 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2603 WARN("Can't get Version\n");
2605 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2608 pEnvironment = (LPWSTR)DefaultEnvironmentW;
2610 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2612 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2615 if(*pcbNeeded <= cbBuf) {
2617 strcpyW((LPWSTR)strPtr, pEnvironment);
2619 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2622 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2623 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2626 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2629 if(*pcbNeeded <= cbBuf)
2630 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2633 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2634 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2637 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2640 if(*pcbNeeded <= cbBuf)
2641 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2644 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2645 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2648 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2649 0, &size, unicode)) {
2651 if(*pcbNeeded <= cbBuf)
2652 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2653 size, &tmp, unicode);
2655 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2656 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2660 RegCloseKey(hkeyDriver);
2661 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2665 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2668 if(*pcbNeeded <= cbBuf)
2669 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2670 size, &tmp, unicode);
2672 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2673 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2676 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2679 if(*pcbNeeded <= cbBuf)
2680 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2681 size, &tmp, unicode);
2683 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2684 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2687 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2690 if(*pcbNeeded <= cbBuf)
2691 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2692 size, &tmp, unicode);
2694 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2695 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2698 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2701 if(*pcbNeeded <= cbBuf)
2702 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2703 size, &tmp, unicode);
2705 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2706 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2709 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2710 RegCloseKey(hkeyDriver);
2714 /*****************************************************************************
2715 * WINSPOOL_GetPrinterDriver
2717 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2718 DWORD Level, LPBYTE pDriverInfo,
2719 DWORD cbBuf, LPDWORD pcbNeeded,
2723 WCHAR DriverName[100];
2724 DWORD ret, type, size, needed = 0;
2726 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2728 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2729 Level,pDriverInfo,cbBuf, pcbNeeded);
2731 ZeroMemory(pDriverInfo, cbBuf);
2733 if (!(name = get_opened_printer_name(hPrinter))) {
2734 SetLastError(ERROR_INVALID_HANDLE);
2737 if(Level < 1 || Level > 3) {
2738 SetLastError(ERROR_INVALID_LEVEL);
2741 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2743 ERR("Can't create Printers key\n");
2746 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2748 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2749 RegCloseKey(hkeyPrinters);
2750 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2753 size = sizeof(DriverName);
2755 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2756 (LPBYTE)DriverName, &size);
2757 RegCloseKey(hkeyPrinter);
2758 RegCloseKey(hkeyPrinters);
2759 if(ret != ERROR_SUCCESS) {
2760 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2764 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2766 ERR("Can't create Drivers key\n");
2772 size = sizeof(DRIVER_INFO_1W);
2775 size = sizeof(DRIVER_INFO_2W);
2778 size = sizeof(DRIVER_INFO_3W);
2781 ERR("Invalid level\n");
2786 ptr = pDriverInfo + size;
2788 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2789 pEnvironment, Level, pDriverInfo,
2790 (cbBuf < size) ? NULL : ptr,
2791 (cbBuf < size) ? 0 : cbBuf - size,
2792 &needed, unicode)) {
2793 RegCloseKey(hkeyDrivers);
2797 RegCloseKey(hkeyDrivers);
2799 if(pcbNeeded) *pcbNeeded = size + needed;
2800 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2801 if(cbBuf >= needed) return TRUE;
2802 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2806 /*****************************************************************************
2807 * GetPrinterDriverA [WINSPOOL.@]
2809 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2810 DWORD Level, LPBYTE pDriverInfo,
2811 DWORD cbBuf, LPDWORD pcbNeeded)
2814 UNICODE_STRING pEnvW;
2817 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2818 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2819 cbBuf, pcbNeeded, FALSE);
2820 RtlFreeUnicodeString(&pEnvW);
2823 /*****************************************************************************
2824 * GetPrinterDriverW [WINSPOOL.@]
2826 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2827 DWORD Level, LPBYTE pDriverInfo,
2828 DWORD cbBuf, LPDWORD pcbNeeded)
2830 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2831 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2834 /*****************************************************************************
2835 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2837 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2838 DWORD Level, LPBYTE pDriverDirectory,
2839 DWORD cbBuf, LPDWORD pcbNeeded)
2843 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2844 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2846 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2847 SetLastError(ERROR_INVALID_PARAMETER);
2850 if(pEnvironment != NULL) {
2851 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2852 SetLastError(ERROR_INVALID_ENVIRONMENT);
2855 if(Level != 1) /* win95 ignores this so we just carry on */
2856 WARN("Level = %ld - assuming 1\n", Level);
2858 /* FIXME should read from registry */
2859 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2860 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2864 needed*=sizeof(WCHAR);
2867 *pcbNeeded = needed;
2868 TRACE("required <%08lx>\n", *pcbNeeded);
2869 if(needed > cbBuf) {
2870 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2877 /*****************************************************************************
2878 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2880 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2881 DWORD Level, LPBYTE pDriverDirectory,
2882 DWORD cbBuf, LPDWORD pcbNeeded)
2884 UNICODE_STRING nameW, environmentW;
2887 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2888 WCHAR *driverDirectoryW = NULL;
2890 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2892 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2893 else nameW.Buffer = NULL;
2894 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2895 else environmentW.Buffer = NULL;
2897 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2898 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2901 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2902 pDriverDirectory, cbBuf, NULL, NULL);
2904 *pcbNeeded = needed;
2905 ret = (needed <= cbBuf) ? TRUE : FALSE;
2907 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2909 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
2911 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
2912 RtlFreeUnicodeString(&environmentW);
2913 RtlFreeUnicodeString(&nameW);
2918 /*****************************************************************************
2919 * AddPrinterDriverA [WINSPOOL.@]
2921 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2924 HKEY hkeyDrivers, hkeyName;
2926 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2928 if(level != 2 && level != 3) {
2929 SetLastError(ERROR_INVALID_LEVEL);
2933 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2934 SetLastError(ERROR_INVALID_PARAMETER);
2938 WARN("pDriverInfo == NULL\n");
2939 SetLastError(ERROR_INVALID_PARAMETER);
2944 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2946 memset(&di3, 0, sizeof(di3));
2947 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
2950 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2952 SetLastError(ERROR_INVALID_PARAMETER);
2955 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2956 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2957 if(!di3.pHelpFile) di3.pHelpFile = "";
2958 if(!di3.pMonitorName) di3.pMonitorName = "";
2960 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2963 ERR("Can't create Drivers key\n");
2967 if(level == 2) { /* apparently can't overwrite with level2 */
2968 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2969 RegCloseKey(hkeyName);
2970 RegCloseKey(hkeyDrivers);
2971 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2972 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2976 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2977 RegCloseKey(hkeyDrivers);
2978 ERR("Can't create Name key\n");
2981 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2983 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2984 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2985 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2987 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2988 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2989 di3.pDependentFiles, 0);
2990 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2991 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2992 RegCloseKey(hkeyName);
2993 RegCloseKey(hkeyDrivers);
2998 /*****************************************************************************
2999 * AddPrinterDriverW [WINSPOOL.@]
3001 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3004 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3009 /*****************************************************************************
3010 * AddPrintProcessorA [WINSPOOL.@]
3012 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3013 LPSTR pPrintProcessorName)
3015 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3016 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3020 /*****************************************************************************
3021 * AddPrintProcessorW [WINSPOOL.@]
3023 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3024 LPWSTR pPrintProcessorName)
3026 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3027 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3031 /*****************************************************************************
3032 * AddPrintProvidorA [WINSPOOL.@]
3034 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3036 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3040 /*****************************************************************************
3041 * AddPrintProvidorW [WINSPOOL.@]
3043 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3045 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3049 /*****************************************************************************
3050 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3052 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3053 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3055 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3056 pDevModeOutput, pDevModeInput);
3060 /*****************************************************************************
3061 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3063 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3064 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3066 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3067 pDevModeOutput, pDevModeInput);
3071 /*****************************************************************************
3072 * PrinterProperties [WINSPOOL.@]
3074 * Displays a dialog to set the properties of the printer.
3077 * nonzero on success or zero on failure
3080 * implemented as stub only
3082 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3083 HANDLE hPrinter /* [in] handle to printer object */
3085 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3086 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3090 /*****************************************************************************
3091 * EnumJobsA [WINSPOOL.@]
3094 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3095 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3098 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3099 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3101 if(pcbNeeded) *pcbNeeded = 0;
3102 if(pcReturned) *pcReturned = 0;
3107 /*****************************************************************************
3108 * EnumJobsW [WINSPOOL.@]
3111 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3112 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3115 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3116 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3118 if(pcbNeeded) *pcbNeeded = 0;
3119 if(pcReturned) *pcReturned = 0;
3123 /*****************************************************************************
3124 * WINSPOOL_EnumPrinterDrivers [internal]
3126 * Delivers information about all printer drivers installed on the
3127 * localhost or a given server
3130 * nonzero on success or zero on failure. If the buffer for the returned
3131 * information is too small the function will return an error
3134 * - only implemented for localhost, foreign hosts will return an error
3136 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3137 DWORD Level, LPBYTE pDriverInfo,
3138 DWORD cbBuf, LPDWORD pcbNeeded,
3139 LPDWORD pcReturned, BOOL unicode)
3142 DWORD i, needed, number = 0, size = 0;
3143 WCHAR DriverNameW[255];
3146 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3147 debugstr_w(pName), debugstr_w(pEnvironment),
3148 Level, pDriverInfo, cbBuf, unicode);
3150 /* check for local drivers */
3152 ERR("remote drivers unsupported! Current remote host is %s\n",
3157 /* check input parameter */
3158 if((Level < 1) || (Level > 3)) {
3159 ERR("unsupported level %ld\n", Level);
3160 SetLastError(ERROR_INVALID_LEVEL);
3164 /* initialize return values */
3166 memset( pDriverInfo, 0, cbBuf);
3170 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3172 ERR("Can't open Drivers key\n");
3176 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3177 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3178 RegCloseKey(hkeyDrivers);
3179 ERR("Can't query Drivers key\n");
3182 TRACE("Found %ld Drivers\n", number);
3184 /* get size of single struct
3185 * unicode and ascii structure have the same size
3189 size = sizeof(DRIVER_INFO_1A);
3192 size = sizeof(DRIVER_INFO_2A);
3195 size = sizeof(DRIVER_INFO_3A);
3199 /* calculate required buffer size */
3200 *pcbNeeded = size * number;
3202 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3204 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3205 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3207 ERR("Can't enum key number %ld\n", i);
3208 RegCloseKey(hkeyDrivers);
3211 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3212 pEnvironment, Level, ptr,
3213 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3214 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3215 &needed, unicode)) {
3216 RegCloseKey(hkeyDrivers);
3219 (*pcbNeeded) += needed;
3222 RegCloseKey(hkeyDrivers);
3224 if(cbBuf < *pcbNeeded){
3225 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3232 /*****************************************************************************
3233 * EnumPrinterDriversW [WINSPOOL.@]
3235 * see function EnumPrinterDrivers for RETURNS, BUGS
3237 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3238 LPBYTE pDriverInfo, DWORD cbBuf,
3239 LPDWORD pcbNeeded, LPDWORD pcReturned)
3241 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3242 cbBuf, pcbNeeded, pcReturned, TRUE);
3245 /*****************************************************************************
3246 * EnumPrinterDriversA [WINSPOOL.@]
3248 * see function EnumPrinterDrivers for RETURNS, BUGS
3250 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3251 LPBYTE pDriverInfo, DWORD cbBuf,
3252 LPDWORD pcbNeeded, LPDWORD pcReturned)
3254 UNICODE_STRING pNameW, pEnvironmentW;
3255 PWSTR pwstrNameW, pwstrEnvironmentW;
3257 pwstrNameW = asciitounicode(&pNameW, pName);
3258 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3260 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3261 Level, pDriverInfo, cbBuf, pcbNeeded,
3263 RtlFreeUnicodeString(&pNameW);
3264 RtlFreeUnicodeString(&pEnvironmentW);
3269 static CHAR PortMonitor[] = "Wine Port Monitor";
3270 static CHAR PortDescription[] = "Wine Port";
3272 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3276 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3277 NULL, OPEN_EXISTING, 0, NULL );
3278 if (handle == INVALID_HANDLE_VALUE)
3280 TRACE("Checking %s exists\n", name );
3281 CloseHandle( handle );
3285 static DWORD WINSPOOL_CountSerialPorts(void)
3292 strcpy( name, "COMx:" );
3294 if (WINSPOOL_ComPortExists( name ))
3301 /******************************************************************************
3302 * EnumPortsA (WINSPOOL.@)
3304 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3305 LPDWORD bufneeded,LPDWORD bufreturned)
3308 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3309 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3313 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3314 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3319 info_size = sizeof (PORT_INFO_1A);
3322 info_size = sizeof (PORT_INFO_2A);
3325 SetLastError(ERROR_INVALID_LEVEL);
3329 /* see how many exist */
3332 serial_count = WINSPOOL_CountSerialPorts();
3335 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3336 if ( r == ERROR_SUCCESS )
3338 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3339 &printer_count, NULL, NULL, NULL, NULL);
3341 count = serial_count + printer_count;
3343 /* then fill in the structure info structure once
3344 we know the offset to the first string */
3346 memset( buffer, 0, bufsize );
3348 ofs = info_size*count;
3349 for ( i=0; i<count; i++)
3351 DWORD vallen = sizeof(portname) - 1;
3353 /* get the serial port values, then the printer values */
3354 if ( i < serial_count )
3356 strcpy( portname, "COMx:" );
3357 portname[3] = '1' + i;
3358 if (!WINSPOOL_ComPortExists( portname ))
3361 TRACE("Found %s\n", portname );
3362 vallen = strlen( portname );
3366 r = RegEnumValueA( hkey_printer, i-serial_count,
3367 portname, &vallen, NULL, NULL, NULL, 0 );
3372 /* add a colon if necessary, and make it upper case */
3373 CharUpperBuffA(portname,vallen);
3374 if (strcasecmp(portname,"nul")!=0)
3375 if (vallen && (portname[vallen-1] != ':') )
3376 lstrcatA(portname,":");
3378 /* add the port info structure if we can fit it */
3379 if ( info_size*(n+1) < bufsize )
3383 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3384 info->pName = (LPSTR) &buffer[ofs];
3386 else if ( level == 2)
3388 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3389 info->pPortName = (LPSTR) &buffer[ofs];
3390 /* FIXME: fill in more stuff here */
3391 info->pMonitorName = PortMonitor;
3392 info->pDescription = PortDescription;
3393 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3396 /* add the name of the port if we can fit it */
3397 if ( ofs < bufsize )
3398 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3404 ofs += lstrlenA(portname)+1;
3407 RegCloseKey(hkey_printer);
3418 /******************************************************************************
3419 * EnumPortsW (WINSPOOL.@)
3421 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3422 LPDWORD bufneeded,LPDWORD bufreturned)
3424 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3425 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3429 /******************************************************************************
3430 * GetDefaultPrinterW (WINSPOOL.@)
3433 * This function must read the value from data 'device' of key
3434 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3436 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3440 WCHAR *buffer, *ptr;
3444 SetLastError(ERROR_INVALID_PARAMETER);
3448 /* make the buffer big enough for the stuff from the profile/registry,
3449 * the content must fit into the local buffer to compute the correct
3450 * size even if the extern buffer is too small or not given.
3451 * (20 for ,driver,port) */
3453 len = max(100, (insize + 20));
3454 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3456 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3458 SetLastError (ERROR_FILE_NOT_FOUND);
3462 TRACE("%s\n", debugstr_w(buffer));
3464 if ((ptr = strchrW(buffer, ',')) == NULL)
3466 SetLastError(ERROR_INVALID_NAME);
3472 *namesize = strlenW(buffer) + 1;
3473 if(!name || (*namesize > insize))
3475 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3479 strcpyW(name, buffer);
3482 HeapFree( GetProcessHeap(), 0, buffer);
3487 /******************************************************************************
3488 * GetDefaultPrinterA (WINSPOOL.@)
3490 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3494 WCHAR *bufferW = NULL;
3498 SetLastError(ERROR_INVALID_PARAMETER);
3502 if(name && *namesize) {
3504 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3507 if(!GetDefaultPrinterW( bufferW, namesize)) {
3512 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3516 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3519 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3522 HeapFree( GetProcessHeap(), 0, bufferW);
3527 /******************************************************************************
3528 * SetPrinterDataExA (WINSPOOL.@)
3530 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3531 LPCSTR pValueName, DWORD Type,
3532 LPBYTE pData, DWORD cbData)
3534 HKEY hkeyPrinter, hkeySubkey;
3537 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3538 debugstr_a(pValueName), Type, pData, cbData);
3540 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3544 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3546 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3547 RegCloseKey(hkeyPrinter);
3550 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3551 RegCloseKey(hkeySubkey);
3552 RegCloseKey(hkeyPrinter);
3556 /******************************************************************************
3557 * SetPrinterDataExW (WINSPOOL.@)
3559 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3560 LPCWSTR pValueName, DWORD Type,
3561 LPBYTE pData, DWORD cbData)
3563 HKEY hkeyPrinter, hkeySubkey;
3566 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3567 debugstr_w(pValueName), Type, pData, cbData);
3569 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3573 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3575 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3576 RegCloseKey(hkeyPrinter);
3579 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3580 RegCloseKey(hkeySubkey);
3581 RegCloseKey(hkeyPrinter);
3585 /******************************************************************************
3586 * SetPrinterDataA (WINSPOOL.@)
3588 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3589 LPBYTE pData, DWORD cbData)
3591 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3595 /******************************************************************************
3596 * SetPrinterDataW (WINSPOOL.@)
3598 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3599 LPBYTE pData, DWORD cbData)
3601 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3605 /******************************************************************************
3606 * GetPrinterDataExA (WINSPOOL.@)
3608 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3609 LPCSTR pValueName, LPDWORD pType,
3610 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3612 HKEY hkeyPrinter, hkeySubkey;
3615 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3616 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3619 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3623 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3625 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3626 RegCloseKey(hkeyPrinter);
3630 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3631 RegCloseKey(hkeySubkey);
3632 RegCloseKey(hkeyPrinter);
3636 /******************************************************************************
3637 * GetPrinterDataExW (WINSPOOL.@)
3639 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3640 LPCWSTR pValueName, LPDWORD pType,
3641 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3643 HKEY hkeyPrinter, hkeySubkey;
3646 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3647 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3650 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3654 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3656 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3657 RegCloseKey(hkeyPrinter);
3661 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3662 RegCloseKey(hkeySubkey);
3663 RegCloseKey(hkeyPrinter);
3667 /******************************************************************************
3668 * GetPrinterDataA (WINSPOOL.@)
3670 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3671 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3673 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3674 pData, nSize, pcbNeeded);
3677 /******************************************************************************
3678 * GetPrinterDataW (WINSPOOL.@)
3680 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3681 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3683 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3684 pData, nSize, pcbNeeded);
3687 /*******************************************************************************
3688 * EnumPrinterDataExW [WINSPOOL.@]
3690 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3691 LPBYTE pEnumValues, DWORD cbEnumValues,
3692 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3694 HKEY hkPrinter, hkSubKey;
3695 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3696 cbValueNameLen, cbMaxValueLen, cbValueLen,
3701 PPRINTER_ENUM_VALUESW ppev;
3703 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3705 if (pKeyName == NULL || *pKeyName == 0)
3706 return ERROR_INVALID_PARAMETER;
3708 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3709 if (ret != ERROR_SUCCESS)
3711 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3716 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3717 if (ret != ERROR_SUCCESS)
3719 r = RegCloseKey (hkPrinter);
3720 if (r != ERROR_SUCCESS)
3721 WARN ("RegCloseKey returned %li\n", r);
3722 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3723 debugstr_w (pKeyName), ret);
3727 ret = RegCloseKey (hkPrinter);
3728 if (ret != ERROR_SUCCESS)
3730 ERR ("RegCloseKey returned %li\n", ret);
3731 r = RegCloseKey (hkSubKey);
3732 if (r != ERROR_SUCCESS)
3733 WARN ("RegCloseKey returned %li\n", r);
3737 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3738 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3739 if (ret != ERROR_SUCCESS)
3741 r = RegCloseKey (hkSubKey);
3742 if (r != ERROR_SUCCESS)
3743 WARN ("RegCloseKey returned %li\n", r);
3744 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3748 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3749 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3751 if (cValues == 0) /* empty key */
3753 r = RegCloseKey (hkSubKey);
3754 if (r != ERROR_SUCCESS)
3755 WARN ("RegCloseKey returned %li\n", r);
3756 *pcbEnumValues = *pnEnumValues = 0;
3757 return ERROR_SUCCESS;
3760 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3762 hHeap = GetProcessHeap ();
3765 ERR ("GetProcessHeap failed\n");
3766 r = RegCloseKey (hkSubKey);
3767 if (r != ERROR_SUCCESS)
3768 WARN ("RegCloseKey returned %li\n", r);
3769 return ERROR_OUTOFMEMORY;
3772 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3773 if (lpValueName == NULL)
3775 ERR ("Failed to allocate %li bytes from process heap\n",
3776 cbMaxValueNameLen * sizeof (WCHAR));
3777 r = RegCloseKey (hkSubKey);
3778 if (r != ERROR_SUCCESS)
3779 WARN ("RegCloseKey returned %li\n", r);
3780 return ERROR_OUTOFMEMORY;
3783 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3784 if (lpValue == NULL)
3786 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3787 if (HeapFree (hHeap, 0, lpValueName) == 0)
3788 WARN ("HeapFree failed with code %li\n", GetLastError ());
3789 r = RegCloseKey (hkSubKey);
3790 if (r != ERROR_SUCCESS)
3791 WARN ("RegCloseKey returned %li\n", r);
3792 return ERROR_OUTOFMEMORY;
3795 TRACE ("pass 1: calculating buffer required for all names and values\n");
3797 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3799 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3801 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3803 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3804 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3805 NULL, NULL, lpValue, &cbValueLen);
3806 if (ret != ERROR_SUCCESS)
3808 if (HeapFree (hHeap, 0, lpValue) == 0)
3809 WARN ("HeapFree failed with code %li\n", GetLastError ());
3810 if (HeapFree (hHeap, 0, lpValueName) == 0)
3811 WARN ("HeapFree failed with code %li\n", GetLastError ());
3812 r = RegCloseKey (hkSubKey);
3813 if (r != ERROR_SUCCESS)
3814 WARN ("RegCloseKey returned %li\n", r);
3815 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3819 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3820 debugstr_w (lpValueName), dwIndex,
3821 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3823 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3824 cbBufSize += cbValueLen;
3827 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3829 *pcbEnumValues = cbBufSize;
3830 *pnEnumValues = cValues;
3832 if (cbEnumValues < cbBufSize) /* buffer too small */
3834 if (HeapFree (hHeap, 0, lpValue) == 0)
3835 WARN ("HeapFree failed with code %li\n", GetLastError ());
3836 if (HeapFree (hHeap, 0, lpValueName) == 0)
3837 WARN ("HeapFree failed with code %li\n", GetLastError ());
3838 r = RegCloseKey (hkSubKey);
3839 if (r != ERROR_SUCCESS)
3840 WARN ("RegCloseKey returned %li\n", r);
3841 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3842 return ERROR_MORE_DATA;
3845 TRACE ("pass 2: copying all names and values to buffer\n");
3847 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3848 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3850 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3852 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3853 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3854 NULL, &dwType, lpValue, &cbValueLen);
3855 if (ret != ERROR_SUCCESS)
3857 if (HeapFree (hHeap, 0, lpValue) == 0)
3858 WARN ("HeapFree failed with code %li\n", GetLastError ());
3859 if (HeapFree (hHeap, 0, lpValueName) == 0)
3860 WARN ("HeapFree failed with code %li\n", GetLastError ());
3861 r = RegCloseKey (hkSubKey);
3862 if (r != ERROR_SUCCESS)
3863 WARN ("RegCloseKey returned %li\n", r);
3864 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3868 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3869 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3870 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3871 pEnumValues += cbValueNameLen;
3873 /* return # of *bytes* (including trailing \0), not # of chars */
3874 ppev[dwIndex].cbValueName = cbValueNameLen;
3876 ppev[dwIndex].dwType = dwType;
3878 memcpy (pEnumValues, lpValue, cbValueLen);
3879 ppev[dwIndex].pData = pEnumValues;
3880 pEnumValues += cbValueLen;
3882 ppev[dwIndex].cbData = cbValueLen;
3884 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3885 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3888 if (HeapFree (hHeap, 0, lpValue) == 0)
3890 ret = GetLastError ();
3891 ERR ("HeapFree failed with code %li\n", ret);
3892 if (HeapFree (hHeap, 0, lpValueName) == 0)
3893 WARN ("HeapFree failed with code %li\n", GetLastError ());
3894 r = RegCloseKey (hkSubKey);
3895 if (r != ERROR_SUCCESS)
3896 WARN ("RegCloseKey returned %li\n", r);
3900 if (HeapFree (hHeap, 0, lpValueName) == 0)
3902 ret = GetLastError ();
3903 ERR ("HeapFree failed with code %li\n", ret);
3904 r = RegCloseKey (hkSubKey);
3905 if (r != ERROR_SUCCESS)
3906 WARN ("RegCloseKey returned %li\n", r);
3910 ret = RegCloseKey (hkSubKey);
3911 if (ret != ERROR_SUCCESS)
3913 ERR ("RegCloseKey returned %li\n", ret);
3917 return ERROR_SUCCESS;
3920 /*******************************************************************************
3921 * EnumPrinterDataExA [WINSPOOL.@]
3923 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
3924 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
3925 * what Windows 2000 SP1 does.
3928 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3929 LPBYTE pEnumValues, DWORD cbEnumValues,
3930 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3934 DWORD ret, dwIndex, dwBufSize;
3938 TRACE ("%p %s\n", hPrinter, pKeyName);
3940 if (pKeyName == NULL || *pKeyName == 0)
3941 return ERROR_INVALID_PARAMETER;
3943 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
3946 ret = GetLastError ();
3947 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3951 hHeap = GetProcessHeap ();
3954 ERR ("GetProcessHeap failed\n");
3955 return ERROR_OUTOFMEMORY;
3958 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
3959 if (pKeyNameW == NULL)
3961 ERR ("Failed to allocate %li bytes from process heap\n",
3962 (LONG) len * sizeof (WCHAR));
3963 return ERROR_OUTOFMEMORY;
3966 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
3968 ret = GetLastError ();
3969 ERR ("MultiByteToWideChar failed with code %li\n", ret);
3970 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3971 WARN ("HeapFree failed with code %li\n", GetLastError ());
3975 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
3976 pcbEnumValues, pnEnumValues);
3977 if (ret != ERROR_SUCCESS)
3979 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3980 WARN ("HeapFree failed with code %li\n", GetLastError ());
3981 TRACE ("EnumPrinterDataExW returned %li\n", ret);
3985 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
3987 ret = GetLastError ();
3988 ERR ("HeapFree failed with code %li\n", ret);
3992 if (*pnEnumValues == 0) /* empty key */
3993 return ERROR_SUCCESS;
3996 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
3998 PPRINTER_ENUM_VALUESW ppev =
3999 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4001 if (dwBufSize < ppev->cbValueName)
4002 dwBufSize = ppev->cbValueName;
4004 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4005 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4006 dwBufSize = ppev->cbData;
4009 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4011 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4012 if (pBuffer == NULL)
4014 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4015 return ERROR_OUTOFMEMORY;
4018 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4020 PPRINTER_ENUM_VALUESW ppev =
4021 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4023 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4024 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4028 ret = GetLastError ();
4029 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4030 if (HeapFree (hHeap, 0, pBuffer) == 0)
4031 WARN ("HeapFree failed with code %li\n", GetLastError ());
4035 memcpy (ppev->pValueName, pBuffer, len);
4037 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4039 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4040 ppev->dwType != REG_MULTI_SZ)
4043 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4044 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4047 ret = GetLastError ();
4048 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4049 if (HeapFree (hHeap, 0, pBuffer) == 0)
4050 WARN ("HeapFree failed with code %li\n", GetLastError ());
4054 memcpy (ppev->pData, pBuffer, len);
4056 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4057 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4060 if (HeapFree (hHeap, 0, pBuffer) == 0)
4062 ret = GetLastError ();
4063 ERR ("HeapFree failed with code %li\n", ret);
4067 return ERROR_SUCCESS;
4070 /******************************************************************************
4071 * AbortPrinter (WINSPOOL.@)
4073 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4075 FIXME("(%p), stub!\n", hPrinter);
4079 /******************************************************************************
4080 * AddPortA (WINSPOOL.@)
4082 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4084 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4088 /******************************************************************************
4089 * AddPortW (WINSPOOL.@)
4091 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4093 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4097 /******************************************************************************
4098 * AddPortExA (WINSPOOL.@)
4100 * Adds a print spooler port without presenting a user interface.
4102 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4104 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4105 lpBuffer, debugstr_a(lpMonitorName));
4109 /******************************************************************************
4110 * AddPortExW (WINSPOOL.@)
4114 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4116 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4117 lpBuffer, debugstr_w(lpMonitorName));
4121 /******************************************************************************
4122 * AddPrinterConnectionA (WINSPOOL.@)
4124 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4126 FIXME("%s\n", debugstr_a(pName));
4130 /******************************************************************************
4131 * AddPrinterConnectionW (WINSPOOL.@)
4133 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4135 FIXME("%s\n", debugstr_w(pName));
4139 /******************************************************************************
4140 * AddPrinterDriverExW (WINSPOOL.@)
4142 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4143 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4145 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4146 Level, pDriverInfo, dwFileCopyFlags);
4147 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4151 /******************************************************************************
4152 * AddPrinterDriverExA (WINSPOOL.@)
4154 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4155 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4157 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4158 Level, pDriverInfo, dwFileCopyFlags);
4159 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4163 /******************************************************************************
4164 * ConfigurePortA (WINSPOOL.@)
4166 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4168 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4172 /******************************************************************************
4173 * ConfigurePortW (WINSPOOL.@)
4175 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4177 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4181 /******************************************************************************
4182 * ConnectToPrinterDlg (WINSPOOL.@)
4184 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4186 FIXME("%p %lx\n", hWnd, Flags);
4190 /******************************************************************************
4191 * DeletePrinterConnectionA (WINSPOOL.@)
4193 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4195 FIXME("%s\n", debugstr_a(pName));
4199 /******************************************************************************
4200 * DeletePrinterConnectionW (WINSPOOL.@)
4202 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4204 FIXME("%s\n", debugstr_w(pName));
4208 /******************************************************************************
4209 * DeletePrinterDriverExW (WINSPOOL.@)
4211 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4212 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4214 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4215 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4219 /******************************************************************************
4220 * DeletePrinterDriverExA (WINSPOOL.@)
4222 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4223 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4225 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4226 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4230 /******************************************************************************
4231 * DeletePrinterDataExW (WINSPOOL.@)
4233 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4236 FIXME("%p %s %s\n", hPrinter,
4237 debugstr_w(pKeyName), debugstr_w(pValueName));
4238 return ERROR_INVALID_PARAMETER;
4241 /******************************************************************************
4242 * DeletePrinterDataExA (WINSPOOL.@)
4244 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4247 FIXME("%p %s %s\n", hPrinter,
4248 debugstr_a(pKeyName), debugstr_a(pValueName));
4249 return ERROR_INVALID_PARAMETER;
4252 /******************************************************************************
4253 * DeletePrintProcessorA (WINSPOOL.@)
4255 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4257 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4258 debugstr_a(pPrintProcessorName));
4262 /******************************************************************************
4263 * DeletePrintProcessorW (WINSPOOL.@)
4265 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4267 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4268 debugstr_w(pPrintProcessorName));
4272 /******************************************************************************
4273 * DeletePrintProvidorA (WINSPOOL.@)
4275 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4277 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4278 debugstr_a(pPrintProviderName));
4282 /******************************************************************************
4283 * DeletePrintProvidorW (WINSPOOL.@)
4285 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4287 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4288 debugstr_w(pPrintProviderName));
4292 /******************************************************************************
4293 * EnumFormsA (WINSPOOL.@)
4295 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4296 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4298 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4302 /******************************************************************************
4303 * EnumFormsW (WINSPOOL.@)
4305 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4306 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4308 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4312 /*****************************************************************************
4313 * EnumMonitorsA [WINSPOOL.@]
4316 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4317 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4319 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4320 cbBuf, pcbNeeded, pcReturned);
4321 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4325 /*****************************************************************************
4326 * EnumMonitorsW [WINSPOOL.@]
4329 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4330 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4332 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4333 cbBuf, pcbNeeded, pcReturned);
4334 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4338 /******************************************************************************
4339 * XcvDataW (WINSPOOL.@)
4342 * There doesn't seem to be an A version...
4344 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4345 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4346 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4348 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4349 pInputData, cbInputData, pOutputData,
4350 cbOutputData, pcbOutputNeeded, pdwStatus);
4354 /*****************************************************************************
4355 * EnumPrinterDataA [WINSPOOL.@]
4358 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4359 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4360 DWORD cbData, LPDWORD pcbData )
4362 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4363 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4364 return ERROR_NO_MORE_ITEMS;
4367 /*****************************************************************************
4368 * EnumPrinterDataW [WINSPOOL.@]
4371 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4372 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4373 DWORD cbData, LPDWORD pcbData )
4375 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4376 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4377 return ERROR_NO_MORE_ITEMS;
4380 /*****************************************************************************
4381 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4384 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4385 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4386 LPDWORD pcbNeeded, LPDWORD pcReturned)
4388 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4389 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4390 pcbNeeded, pcReturned);
4394 /*****************************************************************************
4395 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4398 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4399 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4400 LPDWORD pcbNeeded, LPDWORD pcReturned)
4402 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4403 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4404 pcbNeeded, pcReturned);
4408 /*****************************************************************************
4409 * EnumPrintProcessorsA [WINSPOOL.@]
4412 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4413 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4415 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4416 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
4420 /*****************************************************************************
4421 * EnumPrintProcessorsW [WINSPOOL.@]
4424 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4425 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4427 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4428 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
4429 cbBuf, pcbNeeded, pcbReturned);
4433 /*****************************************************************************
4434 * ExtDeviceMode [WINSPOOL.@]
4437 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
4438 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
4441 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
4442 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
4443 debugstr_a(pProfile), fMode);
4447 /*****************************************************************************
4448 * FindClosePrinterChangeNotification [WINSPOOL.@]
4451 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
4453 FIXME("Stub: %p\n", hChange);
4457 /*****************************************************************************
4458 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4461 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
4462 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
4464 FIXME("Stub: %p %lx %lx %p\n",
4465 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
4466 return INVALID_HANDLE_VALUE;
4469 /*****************************************************************************
4470 * FindNextPrinterChangeNotification [WINSPOOL.@]
4473 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
4474 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
4476 FIXME("Stub: %p %p %p %p\n",
4477 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
4481 /*****************************************************************************
4482 * FreePrinterNotifyInfo [WINSPOOL.@]
4485 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
4487 FIXME("Stub: %p\n", pPrinterNotifyInfo);
4491 /*****************************************************************************
4492 * GetJobA [WINSPOOL.@]
4495 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4496 DWORD cbBuf, LPDWORD pcbNeeded)
4498 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4503 /*****************************************************************************
4504 * GetJobW [WINSPOOL.@]
4507 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4508 DWORD cbBuf, LPDWORD pcbNeeded)
4510 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4515 /*****************************************************************************
4516 * ScheduleJob [WINSPOOL.@]
4519 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
4521 FIXME("Stub: %p %lx\n", hPrinter, dwJobID);