Add an implementation of AddJob and a partial one of ScheduleJob.
[wine/wine-kai.git] / dlls / winspool / info.c
blob6fa0cb298bdc836a2f8ebfcad320141292a6f310
1 /*
2 * WINSPOOL functions
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
25 #include "config.h"
26 #include "wine/port.h"
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stddef.h>
34 #ifdef HAVE_CUPS_CUPS_H
35 # include <cups/cups.h>
36 # ifndef SONAME_LIBCUPS
37 # define SONAME_LIBCUPS "libcups.so"
38 # endif
39 #endif
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
43 #include "wine/library.h"
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winuser.h"
47 #include "winerror.h"
48 #include "winreg.h"
49 #include "wingdi.h"
50 #include "winspool.h"
51 #include "winternl.h"
52 #include "wine/windef16.h"
53 #include "wine/unicode.h"
54 #include "wine/debug.h"
55 #include "wine/list.h"
56 #include "heap.h"
57 #include "winnls.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
61 static CRITICAL_SECTION printer_handles_cs;
62 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
64 0, 0, &printer_handles_cs,
65 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
66 0, 0, { 0, (DWORD)(__FILE__ ": printer_handles_cs") }
68 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
70 typedef struct {
71 LPWSTR name;
72 struct list jobs;
73 } opened_printer_t;
75 typedef struct {
76 struct list entry;
77 DWORD job_id;
78 WCHAR *filename;
79 } job_t;
81 static opened_printer_t **printer_handles;
82 static int nb_printer_handles;
83 static long next_job_id = 1;
85 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
86 WORD fwCapability, LPSTR lpszOutput,
87 LPDEVMODEA lpdm );
88 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
89 LPSTR lpszDevice, LPSTR lpszPort,
90 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
91 DWORD fwMode );
93 static const char Printers[] =
94 "System\\CurrentControlSet\\control\\Print\\Printers\\";
96 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
97 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
98 'c','o','n','t','r','o','l','\\',
99 'P','r','i','n','t','\\',
100 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
101 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
103 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
104 'M','i','c','r','o','s','o','f','t','\\',
105 'W','i','n','d','o','w','s',' ','N','T','\\',
106 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
107 'W','i','n','d','o','w','s',0};
109 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
110 'M','i','c','r','o','s','o','f','t','\\',
111 'W','i','n','d','o','w','s',' ','N','T','\\',
112 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
113 'D','e','v','i','c','e','s',0};
115 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
117 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
118 'i','o','n',' ','F','i','l','e',0};
119 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
120 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
121 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
122 'M','o','d','e',0};
123 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
124 'i','l','e','s',0};
125 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
126 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
127 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
128 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
129 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
130 static const WCHAR NameW[] = {'N','a','m','e',0};
131 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
132 static const WCHAR PortW[] = {'P','o','r','t',0};
133 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
134 's','s','o','r',0};
135 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
136 'v','e','r',0};
137 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
138 'v','e','r','D','a','t','a',0};
139 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
140 'i','l','e',0};
141 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
142 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
143 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
144 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
145 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
146 static const WCHAR emptyStringW[] = {0};
148 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
150 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
151 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
152 DWORD Level, LPBYTE pDriverInfo,
153 DWORD cbBuf, LPDWORD pcbNeeded,
154 BOOL unicode);
155 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
157 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
158 if passed a NULL string. This returns NULLs to the result.
160 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
162 if ( (src) )
164 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
165 return usBufferPtr->Buffer;
167 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
168 return NULL;
171 static void
172 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
173 char qbuf[200];
175 /* If forcing, or no profile string entry for device yet, set the entry
177 * The always change entry if not WINEPS yet is discussable.
179 if (force ||
180 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
181 !strcmp(qbuf,"*") ||
182 !strstr(qbuf,"WINEPS.DRV")
184 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
185 HKEY hkey;
187 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
188 WriteProfileStringA("windows","device",buf);
189 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
190 RegSetValueExA(hkey, "Device", 0, REG_SZ, buf, strlen(buf) + 1);
191 RegCloseKey(hkey);
193 HeapFree(GetProcessHeap(),0,buf);
197 #ifdef HAVE_CUPS_CUPS_H
198 static BOOL CUPS_LoadPrinters(void)
200 typeof(cupsGetDests) *pcupsGetDests = NULL;
201 typeof(cupsGetPPD) *pcupsGetPPD = NULL;
202 int i, nrofdests;
203 BOOL hadprinter = FALSE;
204 cups_dest_t *dests;
205 PRINTER_INFO_2A pinfo2a;
206 void *cupshandle = NULL;
207 char *port,*devline;
208 HKEY hkeyPrinter, hkeyPrinters, hkey;
210 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
211 if (!cupshandle)
212 return FALSE;
213 TRACE("loaded %s\n", SONAME_LIBCUPS);
215 #define DYNCUPS(x) \
216 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
217 if (!p##x) return FALSE;
219 DYNCUPS(cupsGetPPD);
220 DYNCUPS(cupsGetDests);
221 #undef DYNCUPS
223 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
224 ERROR_SUCCESS) {
225 ERR("Can't create Printers key\n");
226 return FALSE;
229 nrofdests = pcupsGetDests(&dests);
230 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
231 for (i=0;i<nrofdests;i++) {
232 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
233 sprintf(port,"LPR:%s",dests[i].name);
234 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
235 sprintf(devline,"WINEPS.DRV,%s",port);
236 WriteProfileStringA("devices",dests[i].name,devline);
237 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
238 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, devline, strlen(devline) + 1);
239 RegCloseKey(hkey);
241 HeapFree(GetProcessHeap(),0,devline);
243 TRACE("Printer %d: %s\n", i, dests[i].name);
244 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
245 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
246 and continue */
247 TRACE("Printer already exists\n");
248 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
249 RegCloseKey(hkeyPrinter);
250 } else {
251 memset(&pinfo2a,0,sizeof(pinfo2a));
252 pinfo2a.pPrinterName = dests[i].name;
253 pinfo2a.pDatatype = "RAW";
254 pinfo2a.pPrintProcessor = "WinPrint";
255 pinfo2a.pDriverName = "PS Driver";
256 pinfo2a.pComment = "WINEPS Printer using CUPS";
257 pinfo2a.pLocation = "<physical location of printer>";
258 pinfo2a.pPortName = port;
259 pinfo2a.pParameters = "<parameters?>";
260 pinfo2a.pShareName = "<share name?>";
261 pinfo2a.pSepFile = "<sep file?>";
263 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
264 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
265 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
268 HeapFree(GetProcessHeap(),0,port);
270 hadprinter = TRUE;
271 if (dests[i].is_default)
272 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
274 RegCloseKey(hkeyPrinters);
275 wine_dlclose(cupshandle, NULL, 0);
276 return hadprinter;
278 #endif
280 static BOOL
281 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
282 PRINTER_INFO_2A pinfo2a;
283 char *e,*s,*name,*prettyname,*devname;
284 BOOL ret = FALSE, set_default = FALSE;
285 char *port,*devline,*env_default;
286 HKEY hkeyPrinter, hkeyPrinters, hkey;
288 while (isspace(*pent)) pent++;
289 s = strchr(pent,':');
290 if(s) *s='\0';
291 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
292 strcpy(name,pent);
293 if(s) {
294 *s=':';
295 pent = s;
296 } else
297 pent = "";
299 TRACE("name=%s entry=%s\n",name, pent);
301 if(ispunct(*name)) { /* a tc entry, not a real printer */
302 TRACE("skipping tc entry\n");
303 goto end;
306 if(strstr(pent,":server")) { /* server only version so skip */
307 TRACE("skipping server entry\n");
308 goto end;
311 /* Determine whether this is a postscript printer. */
313 ret = TRUE;
314 env_default = getenv("PRINTER");
315 prettyname = name;
316 /* Get longest name, usually the one at the right for later display. */
317 while((s=strchr(prettyname,'|'))) {
318 *s = '\0';
319 e = s;
320 while(isspace(*--e)) *e = '\0';
321 TRACE("\t%s\n", debugstr_a(prettyname));
322 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
323 for(prettyname = s+1; isspace(*prettyname); prettyname++)
326 e = prettyname + strlen(prettyname);
327 while(isspace(*--e)) *e = '\0';
328 TRACE("\t%s\n", debugstr_a(prettyname));
329 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
331 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
332 * if it is too long, we use it as comment below. */
333 devname = prettyname;
334 if (strlen(devname)>=CCHDEVICENAME-1)
335 devname = name;
336 if (strlen(devname)>=CCHDEVICENAME-1) {
337 ret = FALSE;
338 goto end;
341 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
342 sprintf(port,"LPR:%s",name);
344 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
345 sprintf(devline,"WINEPS.DRV,%s",port);
346 WriteProfileStringA("devices",devname,devline);
347 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
348 RegSetValueExA(hkey, devname, 0, REG_SZ, devline, strlen(devline) + 1);
349 RegCloseKey(hkey);
351 HeapFree(GetProcessHeap(),0,devline);
353 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
354 ERROR_SUCCESS) {
355 ERR("Can't create Printers key\n");
356 ret = FALSE;
357 goto end;
359 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
360 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
361 and continue */
362 TRACE("Printer already exists\n");
363 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
364 RegCloseKey(hkeyPrinter);
365 } else {
366 memset(&pinfo2a,0,sizeof(pinfo2a));
367 pinfo2a.pPrinterName = devname;
368 pinfo2a.pDatatype = "RAW";
369 pinfo2a.pPrintProcessor = "WinPrint";
370 pinfo2a.pDriverName = "PS Driver";
371 pinfo2a.pComment = "WINEPS Printer using LPR";
372 pinfo2a.pLocation = prettyname;
373 pinfo2a.pPortName = port;
374 pinfo2a.pParameters = "<parameters?>";
375 pinfo2a.pShareName = "<share name?>";
376 pinfo2a.pSepFile = "<sep file?>";
378 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
379 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
380 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
383 RegCloseKey(hkeyPrinters);
385 if (isfirst || set_default)
386 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
388 HeapFree(GetProcessHeap(), 0, port);
389 end:
390 HeapFree(GetProcessHeap(), 0, name);
391 return ret;
394 static BOOL
395 PRINTCAP_LoadPrinters(void) {
396 BOOL hadprinter = FALSE;
397 char buf[200];
398 FILE *f;
399 char *pent = NULL;
400 BOOL had_bash = FALSE;
402 f = fopen("/etc/printcap","r");
403 if (!f)
404 return FALSE;
406 while(fgets(buf,sizeof(buf),f)) {
407 char *start, *end;
409 end=strchr(buf,'\n');
410 if (end) *end='\0';
412 start = buf;
413 while(isspace(*start)) start++;
414 if(*start == '#' || *start == '\0')
415 continue;
417 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
418 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
419 HeapFree(GetProcessHeap(),0,pent);
420 pent = NULL;
423 if (end && *--end == '\\') {
424 *end = '\0';
425 had_bash = TRUE;
426 } else
427 had_bash = FALSE;
429 if (pent) {
430 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
431 strcat(pent,start);
432 } else {
433 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
434 strcpy(pent,start);
438 if(pent) {
439 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
440 HeapFree(GetProcessHeap(),0,pent);
442 fclose(f);
443 return hadprinter;
446 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
448 if (value)
449 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
450 lstrlenW(value) * sizeof(WCHAR));
451 else
452 return ERROR_FILE_NOT_FOUND;
455 void WINSPOOL_LoadSystemPrinters(void)
457 HKEY hkey, hkeyPrinters;
458 DRIVER_INFO_3A di3a;
459 HANDLE hprn;
460 DWORD needed, num, i;
461 WCHAR PrinterName[256];
462 BOOL done = FALSE;
464 di3a.cVersion = 0x400;
465 di3a.pName = "PS Driver";
466 di3a.pEnvironment = NULL; /* NULL means auto */
467 di3a.pDriverPath = "wineps16";
468 di3a.pDataFile = "<datafile?>";
469 di3a.pConfigFile = "wineps16";
470 di3a.pHelpFile = "<helpfile?>";
471 di3a.pDependentFiles = "<dependend files?>";
472 di3a.pMonitorName = "<monitor name?>";
473 di3a.pDefaultDataType = "RAW";
475 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
476 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
477 return;
480 /* This ensures that all printer entries have a valid Name value. If causes
481 problems later if they don't. If one is found to be missed we create one
482 and set it equal to the name of the key */
483 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
484 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
485 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
486 for(i = 0; i < num; i++) {
487 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
488 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
489 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
490 set_reg_szW(hkey, NameW, PrinterName);
492 RegCloseKey(hkey);
497 RegCloseKey(hkeyPrinters);
500 /* We want to avoid calling AddPrinter on printers as much as
501 possible, because on cups printers this will (eventually) lead
502 to a call to cupsGetPPD which takes forever, even with non-cups
503 printers AddPrinter takes a while. So we'll tag all printers that
504 were automatically added last time around, if they still exist
505 we'll leave them be otherwise we'll delete them. */
506 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
507 if(needed) {
508 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
509 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
510 for(i = 0; i < num; i++) {
511 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
512 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
513 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
514 DWORD dw = 1;
515 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
516 RegCloseKey(hkey);
518 ClosePrinter(hprn);
523 HeapFree(GetProcessHeap(), 0, pi);
527 #ifdef HAVE_CUPS_CUPS_H
528 done = CUPS_LoadPrinters();
529 #endif
531 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
532 /* Check for [ppd] section in config file before parsing /etc/printcap */
533 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
534 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
535 &hkey) == ERROR_SUCCESS) {
536 RegCloseKey(hkey);
537 PRINTCAP_LoadPrinters();
541 /* Now enumerate the list again and delete any printers that a still tagged */
542 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
543 if(needed) {
544 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
545 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
546 for(i = 0; i < num; i++) {
547 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
548 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
549 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
550 DWORD dw, type, size = sizeof(dw);
551 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
552 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
553 DeletePrinter(hprn);
555 RegCloseKey(hkey);
557 ClosePrinter(hprn);
562 HeapFree(GetProcessHeap(), 0, pi);
565 return;
570 /******************************************************************
571 * get_opened_printer_entry
572 * Get the first place empty in the opened printer table
574 static HANDLE get_opened_printer_entry( LPCWSTR name )
576 UINT handle;
577 opened_printer_t *printer;
579 EnterCriticalSection(&printer_handles_cs);
581 for (handle = 0; handle < nb_printer_handles; handle++)
582 if (!printer_handles[handle])
583 break;
585 if (handle >= nb_printer_handles)
587 opened_printer_t **new_array;
588 if (printer_handles)
589 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
590 (nb_printer_handles + 16) * sizeof(*new_array) );
591 else
592 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
593 (nb_printer_handles + 16) * sizeof(*new_array) );
595 if (!new_array)
597 handle = 0;
598 goto end;
600 printer_handles = new_array;
601 nb_printer_handles += 16;
604 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
606 handle = 0;
607 goto end;
610 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
611 strcpyW(printer->name, name);
612 list_init(&printer->jobs);
614 printer_handles[handle] = printer;
615 handle++;
616 end:
617 LeaveCriticalSection(&printer_handles_cs);
619 return (HANDLE)handle;
622 /******************************************************************
623 * get_opened_printer
624 * Get the pointer to the opened printer referred by the handle
626 static opened_printer_t *get_opened_printer(HANDLE hprn)
628 int idx = (int)hprn;
629 opened_printer_t *ret = NULL;
631 EnterCriticalSection(&printer_handles_cs);
633 if ((idx <= 0) || (idx > nb_printer_handles))
634 goto end;
636 ret = printer_handles[idx - 1];
637 end:
638 LeaveCriticalSection(&printer_handles_cs);
639 return ret;
642 /******************************************************************
643 * get_opened_printer_name
644 * Get the pointer to the opened printer name referred by the handle
646 static LPCWSTR get_opened_printer_name(HANDLE hprn)
648 opened_printer_t *printer = get_opened_printer(hprn);
649 if(!printer) return NULL;
650 return printer->name;
653 /******************************************************************
654 * WINSPOOL_GetOpenedPrinterRegKey
657 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
659 LPCWSTR name = get_opened_printer_name(hPrinter);
660 DWORD ret;
661 HKEY hkeyPrinters;
663 if(!name) return ERROR_INVALID_HANDLE;
665 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
666 ERROR_SUCCESS)
667 return ret;
669 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
671 ERR("Can't find opened printer %s in registry\n",
672 debugstr_w(name));
673 RegCloseKey(hkeyPrinters);
674 return ERROR_INVALID_PRINTER_NAME; /* ? */
676 RegCloseKey(hkeyPrinters);
677 return ERROR_SUCCESS;
680 /***********************************************************
681 * DEVMODEcpyAtoW
683 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
685 BOOL Formname;
686 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
687 DWORD size;
689 Formname = (dmA->dmSize > off_formname);
690 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
691 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
692 CCHDEVICENAME);
693 if(!Formname) {
694 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
695 dmA->dmSize - CCHDEVICENAME);
696 } else {
697 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
698 off_formname - CCHDEVICENAME);
699 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
700 CCHFORMNAME);
701 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
702 (off_formname + CCHFORMNAME));
704 dmW->dmSize = size;
705 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
706 dmA->dmDriverExtra);
707 return dmW;
710 /***********************************************************
711 * DEVMODEdupWtoA
712 * Creates an ascii copy of supplied devmode on heap
714 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
716 LPDEVMODEA dmA;
717 DWORD size;
718 BOOL Formname;
719 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
721 if(!dmW) return NULL;
722 Formname = (dmW->dmSize > off_formname);
723 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
724 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
725 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
726 CCHDEVICENAME, NULL, NULL);
727 if(!Formname) {
728 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
729 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
730 } else {
731 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
732 off_formname - CCHDEVICENAME * sizeof(WCHAR));
733 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
734 CCHFORMNAME, NULL, NULL);
735 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
736 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
738 dmA->dmSize = size;
739 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
740 dmW->dmDriverExtra);
741 return dmA;
744 /***********************************************************
745 * PRINTER_INFO_2AtoW
746 * Creates a unicode copy of PRINTER_INFO_2A on heap
748 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
750 LPPRINTER_INFO_2W piW;
751 UNICODE_STRING usBuffer;
753 if(!piA) return NULL;
754 piW = HeapAlloc(heap, 0, sizeof(*piW));
755 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
757 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
758 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
759 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
760 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
761 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
762 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
763 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
764 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
765 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
766 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
767 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
768 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
769 return piW;
772 /***********************************************************
773 * FREE_PRINTER_INFO_2W
774 * Free PRINTER_INFO_2W and all strings
776 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
778 if(!piW) return;
780 HeapFree(heap,0,piW->pServerName);
781 HeapFree(heap,0,piW->pPrinterName);
782 HeapFree(heap,0,piW->pShareName);
783 HeapFree(heap,0,piW->pPortName);
784 HeapFree(heap,0,piW->pDriverName);
785 HeapFree(heap,0,piW->pComment);
786 HeapFree(heap,0,piW->pLocation);
787 HeapFree(heap,0,piW->pDevMode);
788 HeapFree(heap,0,piW->pSepFile);
789 HeapFree(heap,0,piW->pPrintProcessor);
790 HeapFree(heap,0,piW->pDatatype);
791 HeapFree(heap,0,piW->pParameters);
792 HeapFree(heap,0,piW);
793 return;
796 /******************************************************************
797 * DeviceCapabilities [WINSPOOL.@]
798 * DeviceCapabilitiesA [WINSPOOL.@]
801 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
802 LPSTR pOutput, LPDEVMODEA lpdm)
804 INT ret;
806 if (!GDI_CallDeviceCapabilities16)
808 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
809 (LPCSTR)104 );
810 if (!GDI_CallDeviceCapabilities16) return -1;
812 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
814 /* If DC_PAPERSIZE map POINT16s to POINTs */
815 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
816 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
817 POINT *pt = (POINT *)pOutput;
818 INT i;
819 memcpy(tmp, pOutput, ret * sizeof(POINT16));
820 for(i = 0; i < ret; i++, pt++)
822 pt->x = tmp[i].x;
823 pt->y = tmp[i].y;
825 HeapFree( GetProcessHeap(), 0, tmp );
827 return ret;
831 /*****************************************************************************
832 * DeviceCapabilitiesW [WINSPOOL.@]
834 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
837 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
838 WORD fwCapability, LPWSTR pOutput,
839 const DEVMODEW *pDevMode)
841 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
842 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
843 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
844 INT ret;
846 if(pOutput && (fwCapability == DC_BINNAMES ||
847 fwCapability == DC_FILEDEPENDENCIES ||
848 fwCapability == DC_PAPERNAMES)) {
849 /* These need A -> W translation */
850 INT size = 0, i;
851 LPSTR pOutputA;
852 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
853 dmA);
854 if(ret == -1)
855 return ret;
856 switch(fwCapability) {
857 case DC_BINNAMES:
858 size = 24;
859 break;
860 case DC_PAPERNAMES:
861 case DC_FILEDEPENDENCIES:
862 size = 64;
863 break;
865 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
866 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
867 dmA);
868 for(i = 0; i < ret; i++)
869 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
870 pOutput + (i * size), size);
871 HeapFree(GetProcessHeap(), 0, pOutputA);
872 } else {
873 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
874 (LPSTR)pOutput, dmA);
876 HeapFree(GetProcessHeap(),0,pPortA);
877 HeapFree(GetProcessHeap(),0,pDeviceA);
878 HeapFree(GetProcessHeap(),0,dmA);
879 return ret;
882 /******************************************************************
883 * DocumentPropertiesA [WINSPOOL.@]
885 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
887 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
888 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
889 LPDEVMODEA pDevModeInput,DWORD fMode )
891 LPSTR lpName = pDeviceName;
892 LONG ret;
894 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
895 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
898 if(!pDeviceName) {
899 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
900 if(!lpNameW) {
901 ERR("no name from hPrinter?\n");
902 SetLastError(ERROR_INVALID_HANDLE);
903 return -1;
905 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
908 if (!GDI_CallExtDeviceMode16)
910 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
911 (LPCSTR)102 );
912 if (!GDI_CallExtDeviceMode16) {
913 ERR("No CallExtDeviceMode16?\n");
914 return -1;
917 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
918 pDevModeInput, NULL, fMode);
920 if(!pDeviceName)
921 HeapFree(GetProcessHeap(),0,lpName);
922 return ret;
926 /*****************************************************************************
927 * DocumentPropertiesW (WINSPOOL.@)
929 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
931 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
932 LPWSTR pDeviceName,
933 LPDEVMODEW pDevModeOutput,
934 LPDEVMODEW pDevModeInput, DWORD fMode)
937 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
938 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
939 LPDEVMODEA pDevModeOutputA = NULL;
940 LONG ret;
942 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
943 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
944 fMode);
945 if(pDevModeOutput) {
946 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
947 if(ret < 0) return ret;
948 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
950 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
951 pDevModeInputA, fMode);
952 if(pDevModeOutput) {
953 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
954 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
956 if(fMode == 0 && ret > 0)
957 ret += (CCHDEVICENAME + CCHFORMNAME);
958 HeapFree(GetProcessHeap(),0,pDevModeInputA);
959 HeapFree(GetProcessHeap(),0,pDeviceNameA);
960 return ret;
963 /******************************************************************
964 * OpenPrinterA [WINSPOOL.@]
967 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
968 LPPRINTER_DEFAULTSA pDefault)
970 UNICODE_STRING lpPrinterNameW;
971 UNICODE_STRING usBuffer;
972 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
973 PWSTR pwstrPrinterNameW;
974 BOOL ret;
976 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
978 if(pDefault) {
979 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
980 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
981 DefaultW.DesiredAccess = pDefault->DesiredAccess;
982 pDefaultW = &DefaultW;
984 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
985 if(pDefault) {
986 RtlFreeUnicodeString(&usBuffer);
987 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
989 RtlFreeUnicodeString(&lpPrinterNameW);
990 return ret;
993 /******************************************************************
994 * OpenPrinterW [WINSPOOL.@]
997 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
998 LPPRINTER_DEFAULTSW pDefault)
1000 HKEY hkeyPrinters, hkeyPrinter;
1002 if (!lpPrinterName) {
1003 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1004 SetLastError(ERROR_INVALID_PARAMETER);
1005 return FALSE;
1008 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1009 pDefault);
1011 /* Check Printer exists */
1012 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1013 ERROR_SUCCESS) {
1014 ERR("Can't create Printers key\n");
1015 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1016 return FALSE;
1019 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1020 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1021 != ERROR_SUCCESS) {
1022 TRACE("Can't find printer %s in registry\n",
1023 debugstr_w(lpPrinterName));
1024 RegCloseKey(hkeyPrinters);
1025 SetLastError(ERROR_INVALID_PRINTER_NAME);
1026 return FALSE;
1028 RegCloseKey(hkeyPrinter);
1029 RegCloseKey(hkeyPrinters);
1031 if(!phPrinter) /* This seems to be what win95 does anyway */
1032 return TRUE;
1034 /* Get the unique handle of the printer*/
1035 *phPrinter = get_opened_printer_entry( lpPrinterName );
1037 if (pDefault != NULL)
1038 FIXME("Not handling pDefault\n");
1040 return TRUE;
1043 /******************************************************************
1044 * AddMonitorA [WINSPOOL.@]
1047 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1049 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
1050 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1051 return FALSE;
1054 /******************************************************************************
1055 * AddMonitorW [WINSPOOL.@]
1057 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1059 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1060 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1061 return FALSE;
1064 /******************************************************************
1065 * DeletePrinterDriverA [WINSPOOL.@]
1068 BOOL WINAPI
1069 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1071 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1072 debugstr_a(pDriverName));
1073 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1074 return FALSE;
1077 /******************************************************************
1078 * DeletePrinterDriverW [WINSPOOL.@]
1081 BOOL WINAPI
1082 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1084 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1085 debugstr_w(pDriverName));
1086 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1087 return FALSE;
1090 /******************************************************************
1091 * DeleteMonitorA [WINSPOOL.@]
1094 BOOL WINAPI
1095 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1097 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1098 debugstr_a(pMonitorName));
1099 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1100 return FALSE;
1103 /******************************************************************
1104 * DeleteMonitorW [WINSPOOL.@]
1107 BOOL WINAPI
1108 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1110 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1111 debugstr_w(pMonitorName));
1112 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1113 return FALSE;
1116 /******************************************************************
1117 * DeletePortA [WINSPOOL.@]
1120 BOOL WINAPI
1121 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1123 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1124 debugstr_a(pPortName));
1125 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1126 return FALSE;
1129 /******************************************************************
1130 * DeletePortW [WINSPOOL.@]
1133 BOOL WINAPI
1134 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1136 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1137 debugstr_w(pPortName));
1138 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1139 return FALSE;
1142 /******************************************************************************
1143 * SetPrinterW [WINSPOOL.@]
1145 BOOL WINAPI
1146 SetPrinterW(
1147 HANDLE hPrinter,
1148 DWORD Level,
1149 LPBYTE pPrinter,
1150 DWORD Command) {
1152 FIXME("():stub\n");
1153 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1154 return FALSE;
1157 /******************************************************************************
1158 * WritePrinter [WINSPOOL.@]
1160 BOOL WINAPI
1161 WritePrinter(
1162 HANDLE hPrinter,
1163 LPVOID pBuf,
1164 DWORD cbBuf,
1165 LPDWORD pcWritten) {
1167 FIXME("():stub\n");
1168 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1169 return FALSE;
1172 /*****************************************************************************
1173 * AddFormA [WINSPOOL.@]
1175 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1177 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1178 return 1;
1181 /*****************************************************************************
1182 * AddFormW [WINSPOOL.@]
1184 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1186 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1187 return 1;
1190 /*****************************************************************************
1191 * AddJobA [WINSPOOL.@]
1193 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1195 BOOL ret;
1196 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1197 DWORD needed;
1199 if(Level != 1) {
1200 SetLastError(ERROR_INVALID_LEVEL);
1201 return FALSE;
1204 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1206 if(ret) {
1207 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1208 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1209 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1210 if(*pcbNeeded > cbBuf) {
1211 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1212 ret = FALSE;
1213 } else {
1214 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1215 addjobA->JobId = addjobW->JobId;
1216 addjobA->Path = (char *)(addjobA + 1);
1217 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1220 return ret;
1223 /*****************************************************************************
1224 * AddJobW [WINSPOOL.@]
1226 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1228 opened_printer_t *printer;
1229 job_t *job;
1230 BOOL ret = FALSE;
1231 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1232 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1233 WCHAR path[MAX_PATH], filename[MAX_PATH];
1234 DWORD len;
1235 ADDJOB_INFO_1W *addjob;
1237 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1239 EnterCriticalSection(&printer_handles_cs);
1241 printer = get_opened_printer(hPrinter);
1243 if(!printer) {
1244 SetLastError(ERROR_INVALID_HANDLE);
1245 goto end;
1248 if(Level != 1) {
1249 SetLastError(ERROR_INVALID_LEVEL);
1250 goto end;
1253 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1254 if(!job)
1255 goto end;
1257 job->job_id = InterlockedIncrement(&next_job_id);
1259 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1260 if(path[len - 1] != '\\')
1261 path[len++] = '\\';
1262 memcpy(path + len, spool_path, sizeof(spool_path));
1263 sprintfW(filename, fmtW, path, job->job_id);
1265 len = strlenW(filename);
1266 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1267 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1268 list_add_tail(&printer->jobs, &job->entry);
1270 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1271 if(*pcbNeeded <= cbBuf) {
1272 addjob = (ADDJOB_INFO_1W*)pData;
1273 addjob->JobId = job->job_id;
1274 addjob->Path = (WCHAR *)(addjob + 1);
1275 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1276 ret = TRUE;
1277 } else
1278 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1280 end:
1281 LeaveCriticalSection(&printer_handles_cs);
1282 return ret;
1285 /*****************************************************************************
1286 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1288 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1289 DWORD level, LPBYTE Info,
1290 DWORD cbBuf, LPDWORD needed)
1292 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1293 level, Info, cbBuf);
1294 return 0;
1297 /*****************************************************************************
1298 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1300 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1301 DWORD level, LPBYTE Info,
1302 DWORD cbBuf, LPDWORD needed)
1304 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1305 level, Info, cbBuf);
1306 return 0;
1309 /*****************************************************************************
1310 * WINSPOOL_OpenDriverReg [internal]
1312 * opens the registry for the printer drivers depending on the given input
1313 * variable pEnvironment
1315 * RETURNS:
1316 * the opened hkey on success
1317 * NULL on error
1319 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1321 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1322 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1323 HKEY retval;
1324 LPWSTR lpKey, buffer = NULL;
1325 LPCWSTR pEnvW;
1327 TRACE("%s\n",
1328 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1330 if(pEnvironment) {
1331 if (unicode) {
1332 pEnvW = pEnvironment;
1333 } else {
1334 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1335 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1336 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1337 pEnvW = buffer;
1339 } else {
1340 OSVERSIONINFOW ver;
1341 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1343 if(!GetVersionExW( &ver))
1344 return 0;
1346 switch (ver.dwPlatformId) {
1347 case VER_PLATFORM_WIN32s:
1348 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1349 return 0;
1350 case VER_PLATFORM_WIN32_NT:
1351 pEnvW = WinNTW;
1352 break;
1353 default:
1354 pEnvW = Win40W;
1355 break;
1357 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1360 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1361 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1362 wsprintfW( lpKey, DriversW, pEnvW);
1364 TRACE("%s\n", debugstr_w(lpKey));
1366 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1367 retval = 0;
1369 HeapFree( GetProcessHeap(), 0, buffer);
1370 HeapFree( GetProcessHeap(), 0, lpKey);
1372 return retval;
1375 /*****************************************************************************
1376 * AddPrinterW [WINSPOOL.@]
1378 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1380 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1381 LPDEVMODEA dmA;
1382 LPDEVMODEW dmW;
1383 HANDLE retval;
1384 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1385 LONG size;
1387 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1389 if(pName != NULL) {
1390 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1391 SetLastError(ERROR_INVALID_PARAMETER);
1392 return 0;
1394 if(Level != 2) {
1395 ERR("Level = %ld, unsupported!\n", Level);
1396 SetLastError(ERROR_INVALID_LEVEL);
1397 return 0;
1399 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1400 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1401 debugstr_w(pi->pPrinterName)
1403 SetLastError(ERROR_INVALID_LEVEL);
1404 return 0;
1406 if(!pPrinter) {
1407 SetLastError(ERROR_INVALID_PARAMETER);
1408 return 0;
1410 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1411 ERROR_SUCCESS) {
1412 ERR("Can't create Printers key\n");
1413 return 0;
1415 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1416 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1417 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1418 RegCloseKey(hkeyPrinter);
1419 RegCloseKey(hkeyPrinters);
1420 return 0;
1422 RegCloseKey(hkeyPrinter);
1424 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1425 if(!hkeyDrivers) {
1426 ERR("Can't create Drivers key\n");
1427 RegCloseKey(hkeyPrinters);
1428 return 0;
1430 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1431 ERROR_SUCCESS) {
1432 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1433 RegCloseKey(hkeyPrinters);
1434 RegCloseKey(hkeyDrivers);
1435 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1436 return 0;
1438 RegCloseKey(hkeyDriver);
1439 RegCloseKey(hkeyDrivers);
1441 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1442 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1443 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1444 RegCloseKey(hkeyPrinters);
1445 return 0;
1448 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1449 ERROR_SUCCESS) {
1450 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1451 SetLastError(ERROR_INVALID_PRINTER_NAME);
1452 RegCloseKey(hkeyPrinters);
1453 return 0;
1455 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1456 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1457 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1459 /* See if we can load the driver. We may need the devmode structure anyway
1461 * FIXME:
1462 * Note that DocumentPropertiesW will briefly try to open the printer we
1463 * just create to find a DEVMODEA struct (it will use the WINEPS default
1464 * one in case it is not there, so we are ok).
1466 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1468 if(size < 0) {
1469 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1470 size = sizeof(DEVMODEW);
1472 if(pi->pDevMode)
1473 dmW = pi->pDevMode;
1474 else
1476 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1477 ZeroMemory(dmW,size);
1478 dmW->dmSize = size;
1479 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1481 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1482 HeapFree(GetProcessHeap(),0,dmW);
1483 dmW=NULL;
1485 else
1487 /* set devmode to printer name */
1488 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1492 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1493 and we support these drivers. NT writes DEVMODEW so somehow
1494 we'll need to distinguish between these when we support NT
1495 drivers */
1496 if (dmW)
1498 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1499 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1500 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1501 HeapFree(GetProcessHeap(), 0, dmA);
1502 if(!pi->pDevMode)
1503 HeapFree(GetProcessHeap(), 0, dmW);
1505 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1506 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1507 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1508 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1510 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1511 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1512 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1513 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1514 (LPBYTE)&pi->Priority, sizeof(DWORD));
1515 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1516 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1517 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1518 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1519 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1520 (LPBYTE)&pi->Status, sizeof(DWORD));
1521 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1522 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1524 RegCloseKey(hkeyPrinter);
1525 RegCloseKey(hkeyPrinters);
1526 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1527 ERR("OpenPrinter failing\n");
1528 return 0;
1530 return retval;
1533 /*****************************************************************************
1534 * AddPrinterA [WINSPOOL.@]
1536 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1538 UNICODE_STRING pNameW;
1539 PWSTR pwstrNameW;
1540 PRINTER_INFO_2W *piW;
1541 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1542 HANDLE ret;
1544 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1545 if(Level != 2) {
1546 ERR("Level = %ld, unsupported!\n", Level);
1547 SetLastError(ERROR_INVALID_LEVEL);
1548 return 0;
1550 pwstrNameW = asciitounicode(&pNameW,pName);
1551 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1553 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1555 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1556 RtlFreeUnicodeString(&pNameW);
1557 return ret;
1561 /*****************************************************************************
1562 * ClosePrinter [WINSPOOL.@]
1564 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1566 int i = (int)hPrinter;
1567 opened_printer_t *printer = NULL;
1568 BOOL ret = FALSE;
1570 TRACE("Handle %p\n", hPrinter);
1572 EnterCriticalSection(&printer_handles_cs);
1574 if ((i > 0) && (i <= nb_printer_handles))
1575 printer = printer_handles[i - 1];
1577 if(printer)
1579 struct list *cursor, *cursor2;
1580 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->jobs)
1582 job_t *job = LIST_ENTRY(cursor, job_t, entry);
1583 ScheduleJob(hPrinter, job->job_id);
1585 HeapFree(GetProcessHeap(), 0, printer->name);
1586 HeapFree(GetProcessHeap(), 0, printer);
1587 printer_handles[i - 1] = NULL;
1588 ret = TRUE;
1590 LeaveCriticalSection(&printer_handles_cs);
1591 return ret;
1594 /*****************************************************************************
1595 * DeleteFormA [WINSPOOL.@]
1597 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1599 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1600 return 1;
1603 /*****************************************************************************
1604 * DeleteFormW [WINSPOOL.@]
1606 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1608 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1609 return 1;
1612 /*****************************************************************************
1613 * WINSPOOL_SHRegDeleteKey
1615 * Recursively delete subkeys.
1616 * Cut & paste from shlwapi.
1619 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1621 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1622 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1623 HKEY hSubKey = 0;
1625 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1626 if(!dwRet)
1628 /* Find how many subkeys there are */
1629 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1630 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1631 if(!dwRet)
1633 dwMaxSubkeyLen++;
1634 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1635 /* Name too big: alloc a buffer for it */
1636 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1638 if(!lpszName)
1639 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1640 else
1642 /* Recursively delete all the subkeys */
1643 for(i = 0; i < dwKeyCount && !dwRet; i++)
1645 dwSize = dwMaxSubkeyLen;
1646 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1647 if(!dwRet)
1648 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1651 if (lpszName != szNameBuf)
1652 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1656 RegCloseKey(hSubKey);
1657 if(!dwRet)
1658 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1660 return dwRet;
1663 /*****************************************************************************
1664 * DeletePrinter [WINSPOOL.@]
1666 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1668 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1669 HKEY hkeyPrinters, hkey;
1671 if(!lpNameW) {
1672 SetLastError(ERROR_INVALID_HANDLE);
1673 return FALSE;
1675 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1676 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1677 RegCloseKey(hkeyPrinters);
1679 WriteProfileStringW(devicesW, lpNameW, NULL);
1680 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1681 RegDeleteValueW(hkey, lpNameW);
1682 RegCloseKey(hkey);
1684 return TRUE;
1687 /*****************************************************************************
1688 * SetPrinterA [WINSPOOL.@]
1690 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1691 DWORD Command)
1693 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1694 return FALSE;
1697 /*****************************************************************************
1698 * SetJobA [WINSPOOL.@]
1700 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1701 LPBYTE pJob, DWORD Command)
1703 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1704 Command);
1705 return FALSE;
1708 /*****************************************************************************
1709 * SetJobW [WINSPOOL.@]
1711 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1712 LPBYTE pJob, DWORD Command)
1714 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1715 Command);
1716 return FALSE;
1719 /*****************************************************************************
1720 * EndDocPrinter [WINSPOOL.@]
1722 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1724 FIXME("(hPrinter=%p): stub\n", hPrinter);
1725 return FALSE;
1728 /*****************************************************************************
1729 * EndPagePrinter [WINSPOOL.@]
1731 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1733 FIXME("(hPrinter=%p): stub\n", hPrinter);
1734 return FALSE;
1737 /*****************************************************************************
1738 * StartDocPrinterA [WINSPOOL.@]
1740 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1742 UNICODE_STRING usBuffer;
1743 DOC_INFO_2W doc2W;
1744 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
1745 DWORD ret;
1747 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
1748 or one (DOC_INFO_3) extra DWORDs */
1750 switch(Level) {
1751 case 2:
1752 doc2W.JobId = doc2->JobId;
1753 /* fall through */
1754 case 3:
1755 doc2W.dwMode = doc2->dwMode;
1756 /* fall through */
1757 case 1:
1758 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
1759 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
1760 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
1761 break;
1763 default:
1764 SetLastError(ERROR_INVALID_LEVEL);
1765 return FALSE;
1768 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
1770 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
1771 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
1772 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
1774 return ret;
1777 /*****************************************************************************
1778 * StartDocPrinterW [WINSPOOL.@]
1780 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1782 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
1784 FIXME("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}): stub\n",
1785 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
1786 debugstr_w(doc->pDatatype));
1787 return FALSE;
1790 /*****************************************************************************
1791 * StartPagePrinter [WINSPOOL.@]
1793 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
1795 FIXME("(hPrinter=%p): stub\n", hPrinter);
1796 return FALSE;
1799 /*****************************************************************************
1800 * GetFormA [WINSPOOL.@]
1802 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1803 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1805 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1806 Level,pForm,cbBuf,pcbNeeded);
1807 return FALSE;
1810 /*****************************************************************************
1811 * GetFormW [WINSPOOL.@]
1813 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1814 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1816 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1817 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1818 return FALSE;
1821 /*****************************************************************************
1822 * SetFormA [WINSPOOL.@]
1824 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1825 LPBYTE pForm)
1827 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1828 return FALSE;
1831 /*****************************************************************************
1832 * SetFormW [WINSPOOL.@]
1834 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1835 LPBYTE pForm)
1837 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1838 return FALSE;
1841 /*****************************************************************************
1842 * ReadPrinter [WINSPOOL.@]
1844 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1845 LPDWORD pNoBytesRead)
1847 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1848 return FALSE;
1851 /*****************************************************************************
1852 * ResetPrinterA [WINSPOOL.@]
1854 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1856 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1857 return FALSE;
1860 /*****************************************************************************
1861 * ResetPrinterW [WINSPOOL.@]
1863 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1865 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
1866 return FALSE;
1869 /*****************************************************************************
1870 * WINSPOOL_GetDWORDFromReg
1872 * Return DWORD associated with ValueName from hkey.
1874 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1876 DWORD sz = sizeof(DWORD), type, value = 0;
1877 LONG ret;
1879 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1881 if(ret != ERROR_SUCCESS) {
1882 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1883 return 0;
1885 if(type != REG_DWORD) {
1886 ERR("Got type %ld\n", type);
1887 return 0;
1889 return value;
1892 /*****************************************************************************
1893 * WINSPOOL_GetStringFromReg
1895 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1896 * String is stored either as unicode or ascii.
1897 * Bit of a hack here to get the ValueName if we want ascii.
1899 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1900 DWORD buflen, DWORD *needed,
1901 BOOL unicode)
1903 DWORD sz = buflen, type;
1904 LONG ret;
1906 if(unicode)
1907 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1908 else {
1909 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1910 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1911 HeapFree(GetProcessHeap(),0,ValueNameA);
1913 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1914 WARN("Got ret = %ld\n", ret);
1915 *needed = 0;
1916 return FALSE;
1918 *needed = sz;
1919 return TRUE;
1922 /*****************************************************************************
1923 * WINSPOOL_GetDefaultDevMode
1925 * Get a default DevMode values for wineps.
1926 * FIXME - use ppd.
1929 static void WINSPOOL_GetDefaultDevMode(
1930 LPBYTE ptr,
1931 DWORD buflen, DWORD *needed,
1932 BOOL unicode)
1934 DEVMODEA dm;
1936 /* fill default DEVMODE - should be read from ppd... */
1937 ZeroMemory( &dm, sizeof(dm) );
1938 strcpy(dm.dmDeviceName,"wineps.drv");
1939 dm.dmSpecVersion = DM_SPECVERSION;
1940 dm.dmDriverVersion = 1;
1941 dm.dmSize = sizeof(DEVMODEA);
1942 dm.dmDriverExtra = 0;
1943 dm.dmFields =
1944 DM_ORIENTATION | DM_PAPERSIZE |
1945 DM_PAPERLENGTH | DM_PAPERWIDTH |
1946 DM_SCALE |
1947 DM_COPIES |
1948 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
1949 DM_YRESOLUTION | DM_TTOPTION;
1951 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
1952 dm.u1.s1.dmPaperSize = DMPAPER_A4;
1953 dm.u1.s1.dmPaperLength = 2970;
1954 dm.u1.s1.dmPaperWidth = 2100;
1956 dm.dmScale = 100;
1957 dm.dmCopies = 1;
1958 dm.dmDefaultSource = DMBIN_AUTO;
1959 dm.dmPrintQuality = DMRES_MEDIUM;
1960 /* dm.dmColor */
1961 /* dm.dmDuplex */
1962 dm.dmYResolution = 300; /* 300dpi */
1963 dm.dmTTOption = DMTT_BITMAP;
1964 /* dm.dmCollate */
1965 /* dm.dmFormName */
1966 /* dm.dmLogPixels */
1967 /* dm.dmBitsPerPel */
1968 /* dm.dmPelsWidth */
1969 /* dm.dmPelsHeight */
1970 /* dm.dmDisplayFlags */
1971 /* dm.dmDisplayFrequency */
1972 /* dm.dmICMMethod */
1973 /* dm.dmICMIntent */
1974 /* dm.dmMediaType */
1975 /* dm.dmDitherType */
1976 /* dm.dmReserved1 */
1977 /* dm.dmReserved2 */
1978 /* dm.dmPanningWidth */
1979 /* dm.dmPanningHeight */
1981 if(unicode) {
1982 if(buflen >= sizeof(DEVMODEW)) {
1983 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
1984 memcpy(ptr, pdmW, sizeof(DEVMODEW));
1985 HeapFree(GetProcessHeap(),0,pdmW);
1987 *needed = sizeof(DEVMODEW);
1989 else
1991 if(buflen >= sizeof(DEVMODEA)) {
1992 memcpy(ptr, &dm, sizeof(DEVMODEA));
1994 *needed = sizeof(DEVMODEA);
1998 /*****************************************************************************
1999 * WINSPOOL_GetDevModeFromReg
2001 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2002 * DevMode is stored either as unicode or ascii.
2004 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2005 LPBYTE ptr,
2006 DWORD buflen, DWORD *needed,
2007 BOOL unicode)
2009 DWORD sz = buflen, type;
2010 LONG ret;
2012 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2013 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2014 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2015 if (sz < sizeof(DEVMODEA))
2017 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2018 return FALSE;
2020 /* ensures that dmSize is not erratically bogus if registry is invalid */
2021 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2022 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2023 if(unicode) {
2024 sz += (CCHDEVICENAME + CCHFORMNAME);
2025 if(buflen >= sz) {
2026 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2027 memcpy(ptr, dmW, sz);
2028 HeapFree(GetProcessHeap(),0,dmW);
2031 *needed = sz;
2032 return TRUE;
2035 /*********************************************************************
2036 * WINSPOOL_GetPrinter_2
2038 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2039 * The strings are either stored as unicode or ascii.
2041 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2042 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2043 BOOL unicode)
2045 DWORD size, left = cbBuf;
2046 BOOL space = (cbBuf > 0);
2047 LPBYTE ptr = buf;
2049 *pcbNeeded = 0;
2051 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2052 unicode)) {
2053 if(space && size <= left) {
2054 pi2->pPrinterName = (LPWSTR)ptr;
2055 ptr += size;
2056 left -= size;
2057 } else
2058 space = FALSE;
2059 *pcbNeeded += size;
2061 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2062 unicode)) {
2063 if(space && size <= left) {
2064 pi2->pShareName = (LPWSTR)ptr;
2065 ptr += size;
2066 left -= size;
2067 } else
2068 space = FALSE;
2069 *pcbNeeded += size;
2071 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2072 unicode)) {
2073 if(space && size <= left) {
2074 pi2->pPortName = (LPWSTR)ptr;
2075 ptr += size;
2076 left -= size;
2077 } else
2078 space = FALSE;
2079 *pcbNeeded += size;
2081 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2082 &size, unicode)) {
2083 if(space && size <= left) {
2084 pi2->pDriverName = (LPWSTR)ptr;
2085 ptr += size;
2086 left -= size;
2087 } else
2088 space = FALSE;
2089 *pcbNeeded += size;
2091 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2092 unicode)) {
2093 if(space && size <= left) {
2094 pi2->pComment = (LPWSTR)ptr;
2095 ptr += size;
2096 left -= size;
2097 } else
2098 space = FALSE;
2099 *pcbNeeded += size;
2101 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2102 unicode)) {
2103 if(space && size <= left) {
2104 pi2->pLocation = (LPWSTR)ptr;
2105 ptr += size;
2106 left -= size;
2107 } else
2108 space = FALSE;
2109 *pcbNeeded += size;
2111 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2112 &size, unicode)) {
2113 if(space && size <= left) {
2114 pi2->pDevMode = (LPDEVMODEW)ptr;
2115 ptr += size;
2116 left -= size;
2117 } else
2118 space = FALSE;
2119 *pcbNeeded += size;
2121 else
2123 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2124 if(space && size <= left) {
2125 pi2->pDevMode = (LPDEVMODEW)ptr;
2126 ptr += size;
2127 left -= size;
2128 } else
2129 space = FALSE;
2130 *pcbNeeded += size;
2132 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2133 &size, unicode)) {
2134 if(space && size <= left) {
2135 pi2->pSepFile = (LPWSTR)ptr;
2136 ptr += size;
2137 left -= size;
2138 } else
2139 space = FALSE;
2140 *pcbNeeded += size;
2142 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2143 &size, unicode)) {
2144 if(space && size <= left) {
2145 pi2->pPrintProcessor = (LPWSTR)ptr;
2146 ptr += size;
2147 left -= size;
2148 } else
2149 space = FALSE;
2150 *pcbNeeded += size;
2152 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2153 &size, unicode)) {
2154 if(space && size <= left) {
2155 pi2->pDatatype = (LPWSTR)ptr;
2156 ptr += size;
2157 left -= size;
2158 } else
2159 space = FALSE;
2160 *pcbNeeded += size;
2162 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2163 &size, unicode)) {
2164 if(space && size <= left) {
2165 pi2->pParameters = (LPWSTR)ptr;
2166 ptr += size;
2167 left -= size;
2168 } else
2169 space = FALSE;
2170 *pcbNeeded += size;
2172 if(pi2) {
2173 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2174 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2175 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2176 "Default Priority");
2177 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2178 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2181 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2182 memset(pi2, 0, sizeof(*pi2));
2184 return space;
2187 /*********************************************************************
2188 * WINSPOOL_GetPrinter_4
2190 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2192 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2193 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2194 BOOL unicode)
2196 DWORD size, left = cbBuf;
2197 BOOL space = (cbBuf > 0);
2198 LPBYTE ptr = buf;
2200 *pcbNeeded = 0;
2202 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2203 unicode)) {
2204 if(space && size <= left) {
2205 pi4->pPrinterName = (LPWSTR)ptr;
2206 ptr += size;
2207 left -= size;
2208 } else
2209 space = FALSE;
2210 *pcbNeeded += size;
2212 if(pi4) {
2213 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2216 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2217 memset(pi4, 0, sizeof(*pi4));
2219 return space;
2222 /*********************************************************************
2223 * WINSPOOL_GetPrinter_5
2225 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2227 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2228 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2229 BOOL unicode)
2231 DWORD size, left = cbBuf;
2232 BOOL space = (cbBuf > 0);
2233 LPBYTE ptr = buf;
2235 *pcbNeeded = 0;
2237 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2238 unicode)) {
2239 if(space && size <= left) {
2240 pi5->pPrinterName = (LPWSTR)ptr;
2241 ptr += size;
2242 left -= size;
2243 } else
2244 space = FALSE;
2245 *pcbNeeded += size;
2247 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2248 unicode)) {
2249 if(space && size <= left) {
2250 pi5->pPortName = (LPWSTR)ptr;
2251 ptr += size;
2252 left -= size;
2253 } else
2254 space = FALSE;
2255 *pcbNeeded += size;
2257 if(pi5) {
2258 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2259 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2260 "dnsTimeout");
2261 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2262 "txTimeout");
2265 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2266 memset(pi5, 0, sizeof(*pi5));
2268 return space;
2271 /*****************************************************************************
2272 * WINSPOOL_GetPrinter
2274 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2275 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2276 * just a collection of pointers to strings.
2278 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2279 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2281 LPCWSTR name;
2282 DWORD size, needed = 0;
2283 LPBYTE ptr = NULL;
2284 HKEY hkeyPrinter, hkeyPrinters;
2285 BOOL ret;
2287 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2289 if (!(name = get_opened_printer_name(hPrinter))) {
2290 SetLastError(ERROR_INVALID_HANDLE);
2291 return FALSE;
2294 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2295 ERROR_SUCCESS) {
2296 ERR("Can't create Printers key\n");
2297 return FALSE;
2299 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2301 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2302 RegCloseKey(hkeyPrinters);
2303 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2304 return FALSE;
2307 switch(Level) {
2308 case 2:
2310 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2312 size = sizeof(PRINTER_INFO_2W);
2313 if(size <= cbBuf) {
2314 ptr = pPrinter + size;
2315 cbBuf -= size;
2316 memset(pPrinter, 0, size);
2317 } else {
2318 pi2 = NULL;
2319 cbBuf = 0;
2321 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2322 unicode);
2323 needed += size;
2324 break;
2327 case 4:
2329 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2331 size = sizeof(PRINTER_INFO_4W);
2332 if(size <= cbBuf) {
2333 ptr = pPrinter + size;
2334 cbBuf -= size;
2335 memset(pPrinter, 0, size);
2336 } else {
2337 pi4 = NULL;
2338 cbBuf = 0;
2340 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2341 unicode);
2342 needed += size;
2343 break;
2347 case 5:
2349 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2351 size = sizeof(PRINTER_INFO_5W);
2352 if(size <= cbBuf) {
2353 ptr = pPrinter + size;
2354 cbBuf -= size;
2355 memset(pPrinter, 0, size);
2356 } else {
2357 pi5 = NULL;
2358 cbBuf = 0;
2361 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2362 unicode);
2363 needed += size;
2364 break;
2367 default:
2368 FIXME("Unimplemented level %ld\n", Level);
2369 SetLastError(ERROR_INVALID_LEVEL);
2370 RegCloseKey(hkeyPrinters);
2371 RegCloseKey(hkeyPrinter);
2372 return FALSE;
2375 RegCloseKey(hkeyPrinter);
2376 RegCloseKey(hkeyPrinters);
2378 TRACE("returning %d needed = %ld\n", ret, needed);
2379 if(pcbNeeded) *pcbNeeded = needed;
2380 if(!ret)
2381 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2382 return ret;
2385 /*****************************************************************************
2386 * GetPrinterW [WINSPOOL.@]
2388 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2389 DWORD cbBuf, LPDWORD pcbNeeded)
2391 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2392 TRUE);
2395 /*****************************************************************************
2396 * GetPrinterA [WINSPOOL.@]
2398 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2399 DWORD cbBuf, LPDWORD pcbNeeded)
2401 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2402 FALSE);
2405 /*****************************************************************************
2406 * WINSPOOL_EnumPrinters
2408 * Implementation of EnumPrintersA|W
2410 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2411 DWORD dwLevel, LPBYTE lpbPrinters,
2412 DWORD cbBuf, LPDWORD lpdwNeeded,
2413 LPDWORD lpdwReturned, BOOL unicode)
2416 HKEY hkeyPrinters, hkeyPrinter;
2417 WCHAR PrinterName[255];
2418 DWORD needed = 0, number = 0;
2419 DWORD used, i, left;
2420 PBYTE pi, buf;
2422 if(lpbPrinters)
2423 memset(lpbPrinters, 0, cbBuf);
2424 if(lpdwReturned)
2425 *lpdwReturned = 0;
2426 if(lpdwNeeded)
2427 *lpdwNeeded = 0;
2429 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2430 if(dwType == PRINTER_ENUM_DEFAULT)
2431 return TRUE;
2433 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2434 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2435 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2436 if(!dwType) return TRUE;
2439 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2440 FIXME("dwType = %08lx\n", dwType);
2441 SetLastError(ERROR_INVALID_FLAGS);
2442 return FALSE;
2445 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2446 ERROR_SUCCESS) {
2447 ERR("Can't create Printers key\n");
2448 return FALSE;
2451 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2452 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2453 RegCloseKey(hkeyPrinters);
2454 ERR("Can't query Printers key\n");
2455 return FALSE;
2457 TRACE("Found %ld printers\n", number);
2459 switch(dwLevel) {
2460 case 1:
2461 RegCloseKey(hkeyPrinters);
2462 if (lpdwReturned)
2463 *lpdwReturned = number;
2464 return TRUE;
2466 case 2:
2467 used = number * sizeof(PRINTER_INFO_2W);
2468 break;
2469 case 4:
2470 used = number * sizeof(PRINTER_INFO_4W);
2471 break;
2472 case 5:
2473 used = number * sizeof(PRINTER_INFO_5W);
2474 break;
2476 default:
2477 SetLastError(ERROR_INVALID_LEVEL);
2478 RegCloseKey(hkeyPrinters);
2479 return FALSE;
2481 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2483 for(i = 0; i < number; i++) {
2484 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2485 ERROR_SUCCESS) {
2486 ERR("Can't enum key number %ld\n", i);
2487 RegCloseKey(hkeyPrinters);
2488 return FALSE;
2490 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2491 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2492 ERROR_SUCCESS) {
2493 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2494 RegCloseKey(hkeyPrinters);
2495 return FALSE;
2498 if(cbBuf > used) {
2499 buf = lpbPrinters + used;
2500 left = cbBuf - used;
2501 } else {
2502 buf = NULL;
2503 left = 0;
2506 switch(dwLevel) {
2507 case 2:
2508 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2509 left, &needed, unicode);
2510 used += needed;
2511 if(pi) pi += sizeof(PRINTER_INFO_2W);
2512 break;
2513 case 4:
2514 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2515 left, &needed, unicode);
2516 used += needed;
2517 if(pi) pi += sizeof(PRINTER_INFO_4W);
2518 break;
2519 case 5:
2520 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2521 left, &needed, unicode);
2522 used += needed;
2523 if(pi) pi += sizeof(PRINTER_INFO_5W);
2524 break;
2525 default:
2526 ERR("Shouldn't be here!\n");
2527 RegCloseKey(hkeyPrinter);
2528 RegCloseKey(hkeyPrinters);
2529 return FALSE;
2531 RegCloseKey(hkeyPrinter);
2533 RegCloseKey(hkeyPrinters);
2535 if(lpdwNeeded)
2536 *lpdwNeeded = used;
2538 if(used > cbBuf) {
2539 if(lpbPrinters)
2540 memset(lpbPrinters, 0, cbBuf);
2541 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2542 return FALSE;
2544 if(lpdwReturned)
2545 *lpdwReturned = number;
2546 SetLastError(ERROR_SUCCESS);
2547 return TRUE;
2551 /******************************************************************
2552 * EnumPrintersW [WINSPOOL.@]
2554 * Enumerates the available printers, print servers and print
2555 * providers, depending on the specified flags, name and level.
2557 * RETURNS:
2559 * If level is set to 1:
2560 * Not implemented yet!
2561 * Returns TRUE with an empty list.
2563 * If level is set to 2:
2564 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2565 * Returns an array of PRINTER_INFO_2 data structures in the
2566 * lpbPrinters buffer. Note that according to MSDN also an
2567 * OpenPrinter should be performed on every remote printer.
2569 * If level is set to 4 (officially WinNT only):
2570 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2571 * Fast: Only the registry is queried to retrieve printer names,
2572 * no connection to the driver is made.
2573 * Returns an array of PRINTER_INFO_4 data structures in the
2574 * lpbPrinters buffer.
2576 * If level is set to 5 (officially WinNT4/Win9x only):
2577 * Fast: Only the registry is queried to retrieve printer names,
2578 * no connection to the driver is made.
2579 * Returns an array of PRINTER_INFO_5 data structures in the
2580 * lpbPrinters buffer.
2582 * If level set to 3 or 6+:
2583 * returns zero (failure!)
2585 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2586 * for information.
2588 * BUGS:
2589 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2590 * - Only levels 2, 4 and 5 are implemented at the moment.
2591 * - 16-bit printer drivers are not enumerated.
2592 * - Returned amount of bytes used/needed does not match the real Windoze
2593 * implementation (as in this implementation, all strings are part
2594 * of the buffer, whereas Win32 keeps them somewhere else)
2595 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2597 * NOTE:
2598 * - In a regular Wine installation, no registry settings for printers
2599 * exist, which makes this function return an empty list.
2601 BOOL WINAPI EnumPrintersW(
2602 DWORD dwType, /* [in] Types of print objects to enumerate */
2603 LPWSTR lpszName, /* [in] name of objects to enumerate */
2604 DWORD dwLevel, /* [in] type of printer info structure */
2605 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2606 DWORD cbBuf, /* [in] max size of buffer in bytes */
2607 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2608 LPDWORD lpdwReturned /* [out] number of entries returned */
2611 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2612 lpdwNeeded, lpdwReturned, TRUE);
2615 /******************************************************************
2616 * EnumPrintersA [WINSPOOL.@]
2619 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2620 DWORD dwLevel, LPBYTE lpbPrinters,
2621 DWORD cbBuf, LPDWORD lpdwNeeded,
2622 LPDWORD lpdwReturned)
2624 BOOL ret;
2625 UNICODE_STRING lpszNameW;
2626 PWSTR pwstrNameW;
2628 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2629 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2630 lpdwNeeded, lpdwReturned, FALSE);
2631 RtlFreeUnicodeString(&lpszNameW);
2632 return ret;
2635 /*****************************************************************************
2636 * WINSPOOL_GetDriverInfoFromReg [internal]
2638 * Enters the information from the registry into the DRIVER_INFO struct
2640 * RETURNS
2641 * zero if the printer driver does not exist in the registry
2642 * (only if Level > 1) otherwise nonzero
2644 static BOOL WINSPOOL_GetDriverInfoFromReg(
2645 HKEY hkeyDrivers,
2646 LPWSTR DriverName,
2647 LPWSTR pEnvironment,
2648 DWORD Level,
2649 LPBYTE ptr, /* DRIVER_INFO */
2650 LPBYTE pDriverStrings, /* strings buffer */
2651 DWORD cbBuf, /* size of string buffer */
2652 LPDWORD pcbNeeded, /* space needed for str. */
2653 BOOL unicode) /* type of strings */
2654 { DWORD dw, size, tmp, type;
2655 HKEY hkeyDriver;
2656 LPBYTE strPtr = pDriverStrings;
2658 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2659 debugstr_w(DriverName), debugstr_w(pEnvironment),
2660 Level, ptr, pDriverStrings, cbBuf, unicode);
2662 if(unicode) {
2663 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2664 if (*pcbNeeded <= cbBuf)
2665 strcpyW((LPWSTR)strPtr, DriverName);
2666 } else {
2667 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2668 NULL, NULL);
2669 if(*pcbNeeded <= cbBuf)
2670 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
2671 NULL, NULL);
2673 if(Level == 1) {
2674 if(ptr)
2675 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2676 return TRUE;
2677 } else {
2678 if(ptr)
2679 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2680 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2683 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2684 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2685 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2686 return FALSE;
2689 size = sizeof(dw);
2690 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2691 ERROR_SUCCESS)
2692 WARN("Can't get Version\n");
2693 else if(ptr)
2694 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
2696 if(!pEnvironment)
2697 pEnvironment = (LPWSTR)DefaultEnvironmentW;
2698 if(unicode)
2699 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
2700 else
2701 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
2702 NULL, NULL);
2703 *pcbNeeded += size;
2704 if(*pcbNeeded <= cbBuf) {
2705 if(unicode)
2706 strcpyW((LPWSTR)strPtr, pEnvironment);
2707 else
2708 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
2709 NULL, NULL);
2710 if(ptr)
2711 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
2712 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2715 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
2716 unicode)) {
2717 *pcbNeeded += size;
2718 if(*pcbNeeded <= cbBuf)
2719 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
2720 unicode);
2721 if(ptr)
2722 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
2723 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2726 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
2727 unicode)) {
2728 *pcbNeeded += size;
2729 if(*pcbNeeded <= cbBuf)
2730 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
2731 &tmp, unicode);
2732 if(ptr)
2733 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
2734 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2737 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2738 0, &size, unicode)) {
2739 *pcbNeeded += size;
2740 if(*pcbNeeded <= cbBuf)
2741 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
2742 size, &tmp, unicode);
2743 if(ptr)
2744 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
2745 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2748 if(Level == 2 ) {
2749 RegCloseKey(hkeyDriver);
2750 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2751 return TRUE;
2754 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
2755 unicode)) {
2756 *pcbNeeded += size;
2757 if(*pcbNeeded <= cbBuf)
2758 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
2759 size, &tmp, unicode);
2760 if(ptr)
2761 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
2762 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2765 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
2766 &size, unicode)) {
2767 *pcbNeeded += size;
2768 if(*pcbNeeded <= cbBuf)
2769 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
2770 size, &tmp, unicode);
2771 if(ptr)
2772 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
2773 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2776 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
2777 unicode)) {
2778 *pcbNeeded += size;
2779 if(*pcbNeeded <= cbBuf)
2780 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2781 size, &tmp, unicode);
2782 if(ptr)
2783 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
2784 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2787 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
2788 unicode)) {
2789 *pcbNeeded += size;
2790 if(*pcbNeeded <= cbBuf)
2791 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
2792 size, &tmp, unicode);
2793 if(ptr)
2794 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
2795 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
2798 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2799 RegCloseKey(hkeyDriver);
2800 return TRUE;
2803 /*****************************************************************************
2804 * WINSPOOL_GetPrinterDriver
2806 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
2807 DWORD Level, LPBYTE pDriverInfo,
2808 DWORD cbBuf, LPDWORD pcbNeeded,
2809 BOOL unicode)
2811 LPCWSTR name;
2812 WCHAR DriverName[100];
2813 DWORD ret, type, size, needed = 0;
2814 LPBYTE ptr = NULL;
2815 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
2817 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
2818 Level,pDriverInfo,cbBuf, pcbNeeded);
2820 ZeroMemory(pDriverInfo, cbBuf);
2822 if (!(name = get_opened_printer_name(hPrinter))) {
2823 SetLastError(ERROR_INVALID_HANDLE);
2824 return FALSE;
2826 if(Level < 1 || Level > 3) {
2827 SetLastError(ERROR_INVALID_LEVEL);
2828 return FALSE;
2830 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2831 ERROR_SUCCESS) {
2832 ERR("Can't create Printers key\n");
2833 return FALSE;
2835 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
2836 != ERROR_SUCCESS) {
2837 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2838 RegCloseKey(hkeyPrinters);
2839 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2840 return FALSE;
2842 size = sizeof(DriverName);
2843 DriverName[0] = 0;
2844 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
2845 (LPBYTE)DriverName, &size);
2846 RegCloseKey(hkeyPrinter);
2847 RegCloseKey(hkeyPrinters);
2848 if(ret != ERROR_SUCCESS) {
2849 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
2850 return FALSE;
2853 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
2854 if(!hkeyDrivers) {
2855 ERR("Can't create Drivers key\n");
2856 return FALSE;
2859 switch(Level) {
2860 case 1:
2861 size = sizeof(DRIVER_INFO_1W);
2862 break;
2863 case 2:
2864 size = sizeof(DRIVER_INFO_2W);
2865 break;
2866 case 3:
2867 size = sizeof(DRIVER_INFO_3W);
2868 break;
2869 default:
2870 ERR("Invalid level\n");
2871 return FALSE;
2874 if(size <= cbBuf)
2875 ptr = pDriverInfo + size;
2877 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2878 pEnvironment, Level, pDriverInfo,
2879 (cbBuf < size) ? NULL : ptr,
2880 (cbBuf < size) ? 0 : cbBuf - size,
2881 &needed, unicode)) {
2882 RegCloseKey(hkeyDrivers);
2883 return FALSE;
2886 RegCloseKey(hkeyDrivers);
2888 if(pcbNeeded) *pcbNeeded = size + needed;
2889 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2890 if(cbBuf >= needed) return TRUE;
2891 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2892 return FALSE;
2895 /*****************************************************************************
2896 * GetPrinterDriverA [WINSPOOL.@]
2898 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2899 DWORD Level, LPBYTE pDriverInfo,
2900 DWORD cbBuf, LPDWORD pcbNeeded)
2902 BOOL ret;
2903 UNICODE_STRING pEnvW;
2904 PWSTR pwstrEnvW;
2906 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
2907 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
2908 cbBuf, pcbNeeded, FALSE);
2909 RtlFreeUnicodeString(&pEnvW);
2910 return ret;
2912 /*****************************************************************************
2913 * GetPrinterDriverW [WINSPOOL.@]
2915 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2916 DWORD Level, LPBYTE pDriverInfo,
2917 DWORD cbBuf, LPDWORD pcbNeeded)
2919 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2920 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2923 /*****************************************************************************
2924 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2926 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2927 DWORD Level, LPBYTE pDriverDirectory,
2928 DWORD cbBuf, LPDWORD pcbNeeded)
2930 DWORD needed;
2932 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
2933 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
2934 if(pName != NULL) {
2935 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2936 SetLastError(ERROR_INVALID_PARAMETER);
2937 return FALSE;
2939 if(pEnvironment != NULL) {
2940 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2941 SetLastError(ERROR_INVALID_ENVIRONMENT);
2942 return FALSE;
2944 if(Level != 1) /* win95 ignores this so we just carry on */
2945 WARN("Level = %ld - assuming 1\n", Level);
2947 /* FIXME should read from registry */
2948 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
2949 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2950 * adjust this now
2952 needed++;
2953 needed*=sizeof(WCHAR);
2955 if(pcbNeeded)
2956 *pcbNeeded = needed;
2957 TRACE("required <%08lx>\n", *pcbNeeded);
2958 if(needed > cbBuf) {
2959 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2960 return FALSE;
2962 return TRUE;
2966 /*****************************************************************************
2967 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2969 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2970 DWORD Level, LPBYTE pDriverDirectory,
2971 DWORD cbBuf, LPDWORD pcbNeeded)
2973 UNICODE_STRING nameW, environmentW;
2974 BOOL ret;
2975 DWORD pcbNeededW;
2976 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
2977 WCHAR *driverDirectoryW = NULL;
2979 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
2981 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
2982 else nameW.Buffer = NULL;
2983 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
2984 else environmentW.Buffer = NULL;
2986 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
2987 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
2988 if (ret) {
2989 DWORD needed;
2990 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
2991 pDriverDirectory, cbBuf, NULL, NULL);
2992 if(pcbNeeded)
2993 *pcbNeeded = needed;
2994 ret = (needed <= cbBuf) ? TRUE : FALSE;
2995 } else
2996 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
2998 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
3000 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3001 RtlFreeUnicodeString(&environmentW);
3002 RtlFreeUnicodeString(&nameW);
3004 return ret;
3007 /*****************************************************************************
3008 * AddPrinterDriverA [WINSPOOL.@]
3010 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3012 DRIVER_INFO_3A di3;
3013 HKEY hkeyDrivers, hkeyName;
3015 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3017 if(level != 2 && level != 3) {
3018 SetLastError(ERROR_INVALID_LEVEL);
3019 return FALSE;
3021 if(pName != NULL) {
3022 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3023 SetLastError(ERROR_INVALID_PARAMETER);
3024 return FALSE;
3026 if(!pDriverInfo) {
3027 WARN("pDriverInfo == NULL\n");
3028 SetLastError(ERROR_INVALID_PARAMETER);
3029 return FALSE;
3032 if(level == 3)
3033 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3034 else {
3035 memset(&di3, 0, sizeof(di3));
3036 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3039 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3040 !di3.pDataFile) {
3041 SetLastError(ERROR_INVALID_PARAMETER);
3042 return FALSE;
3044 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3045 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3046 if(!di3.pHelpFile) di3.pHelpFile = "";
3047 if(!di3.pMonitorName) di3.pMonitorName = "";
3049 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3051 if(!hkeyDrivers) {
3052 ERR("Can't create Drivers key\n");
3053 return FALSE;
3056 if(level == 2) { /* apparently can't overwrite with level2 */
3057 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3058 RegCloseKey(hkeyName);
3059 RegCloseKey(hkeyDrivers);
3060 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3061 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3062 return FALSE;
3065 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3066 RegCloseKey(hkeyDrivers);
3067 ERR("Can't create Name key\n");
3068 return FALSE;
3070 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
3072 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
3073 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
3074 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
3075 sizeof(DWORD));
3076 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
3077 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3078 di3.pDependentFiles, 0);
3079 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
3080 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
3081 RegCloseKey(hkeyName);
3082 RegCloseKey(hkeyDrivers);
3084 return TRUE;
3087 /*****************************************************************************
3088 * AddPrinterDriverW [WINSPOOL.@]
3090 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3091 LPBYTE pDriverInfo)
3093 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3094 level,pDriverInfo);
3095 return FALSE;
3098 /*****************************************************************************
3099 * AddPrintProcessorA [WINSPOOL.@]
3101 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3102 LPSTR pPrintProcessorName)
3104 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3105 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3106 return FALSE;
3109 /*****************************************************************************
3110 * AddPrintProcessorW [WINSPOOL.@]
3112 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3113 LPWSTR pPrintProcessorName)
3115 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3116 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3117 return FALSE;
3120 /*****************************************************************************
3121 * AddPrintProvidorA [WINSPOOL.@]
3123 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3125 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3126 return FALSE;
3129 /*****************************************************************************
3130 * AddPrintProvidorW [WINSPOOL.@]
3132 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3134 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3135 return FALSE;
3138 /*****************************************************************************
3139 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3141 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3142 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3144 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3145 pDevModeOutput, pDevModeInput);
3146 return 0;
3149 /*****************************************************************************
3150 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3152 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3153 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3155 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3156 pDevModeOutput, pDevModeInput);
3157 return 0;
3160 /*****************************************************************************
3161 * PrinterProperties [WINSPOOL.@]
3163 * Displays a dialog to set the properties of the printer.
3165 * RETURNS
3166 * nonzero on success or zero on failure
3168 * BUGS
3169 * implemented as stub only
3171 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3172 HANDLE hPrinter /* [in] handle to printer object */
3174 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3175 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3176 return FALSE;
3179 /*****************************************************************************
3180 * EnumJobsA [WINSPOOL.@]
3183 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3184 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3185 LPDWORD pcReturned)
3187 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3188 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3190 if(pcbNeeded) *pcbNeeded = 0;
3191 if(pcReturned) *pcReturned = 0;
3192 return FALSE;
3196 /*****************************************************************************
3197 * EnumJobsW [WINSPOOL.@]
3200 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3201 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3202 LPDWORD pcReturned)
3204 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3205 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3207 if(pcbNeeded) *pcbNeeded = 0;
3208 if(pcReturned) *pcReturned = 0;
3209 return FALSE;
3212 /*****************************************************************************
3213 * WINSPOOL_EnumPrinterDrivers [internal]
3215 * Delivers information about all printer drivers installed on the
3216 * localhost or a given server
3218 * RETURNS
3219 * nonzero on success or zero on failure. If the buffer for the returned
3220 * information is too small the function will return an error
3222 * BUGS
3223 * - only implemented for localhost, foreign hosts will return an error
3225 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3226 DWORD Level, LPBYTE pDriverInfo,
3227 DWORD cbBuf, LPDWORD pcbNeeded,
3228 LPDWORD pcReturned, BOOL unicode)
3230 { HKEY hkeyDrivers;
3231 DWORD i, needed, number = 0, size = 0;
3232 WCHAR DriverNameW[255];
3233 PBYTE ptr;
3235 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3236 debugstr_w(pName), debugstr_w(pEnvironment),
3237 Level, pDriverInfo, cbBuf, unicode);
3239 /* check for local drivers */
3240 if(pName) {
3241 ERR("remote drivers unsupported! Current remote host is %s\n",
3242 debugstr_w(pName));
3243 return FALSE;
3246 /* check input parameter */
3247 if((Level < 1) || (Level > 3)) {
3248 ERR("unsupported level %ld\n", Level);
3249 SetLastError(ERROR_INVALID_LEVEL);
3250 return FALSE;
3253 /* initialize return values */
3254 if(pDriverInfo)
3255 memset( pDriverInfo, 0, cbBuf);
3256 *pcbNeeded = 0;
3257 *pcReturned = 0;
3259 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3260 if(!hkeyDrivers) {
3261 ERR("Can't open Drivers key\n");
3262 return FALSE;
3265 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3266 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3267 RegCloseKey(hkeyDrivers);
3268 ERR("Can't query Drivers key\n");
3269 return FALSE;
3271 TRACE("Found %ld Drivers\n", number);
3273 /* get size of single struct
3274 * unicode and ascii structure have the same size
3276 switch (Level) {
3277 case 1:
3278 size = sizeof(DRIVER_INFO_1A);
3279 break;
3280 case 2:
3281 size = sizeof(DRIVER_INFO_2A);
3282 break;
3283 case 3:
3284 size = sizeof(DRIVER_INFO_3A);
3285 break;
3288 /* calculate required buffer size */
3289 *pcbNeeded = size * number;
3291 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3292 i < number;
3293 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3294 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3295 != ERROR_SUCCESS) {
3296 ERR("Can't enum key number %ld\n", i);
3297 RegCloseKey(hkeyDrivers);
3298 return FALSE;
3300 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3301 pEnvironment, Level, ptr,
3302 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3303 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3304 &needed, unicode)) {
3305 RegCloseKey(hkeyDrivers);
3306 return FALSE;
3308 (*pcbNeeded) += needed;
3311 RegCloseKey(hkeyDrivers);
3313 if(cbBuf < *pcbNeeded){
3314 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3315 return FALSE;
3318 return TRUE;
3321 /*****************************************************************************
3322 * EnumPrinterDriversW [WINSPOOL.@]
3324 * see function EnumPrinterDrivers for RETURNS, BUGS
3326 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3327 LPBYTE pDriverInfo, DWORD cbBuf,
3328 LPDWORD pcbNeeded, LPDWORD pcReturned)
3330 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3331 cbBuf, pcbNeeded, pcReturned, TRUE);
3334 /*****************************************************************************
3335 * EnumPrinterDriversA [WINSPOOL.@]
3337 * see function EnumPrinterDrivers for RETURNS, BUGS
3339 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3340 LPBYTE pDriverInfo, DWORD cbBuf,
3341 LPDWORD pcbNeeded, LPDWORD pcReturned)
3342 { BOOL ret;
3343 UNICODE_STRING pNameW, pEnvironmentW;
3344 PWSTR pwstrNameW, pwstrEnvironmentW;
3346 pwstrNameW = asciitounicode(&pNameW, pName);
3347 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3349 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3350 Level, pDriverInfo, cbBuf, pcbNeeded,
3351 pcReturned, FALSE);
3352 RtlFreeUnicodeString(&pNameW);
3353 RtlFreeUnicodeString(&pEnvironmentW);
3355 return ret;
3358 static CHAR PortMonitor[] = "Wine Port Monitor";
3359 static CHAR PortDescription[] = "Wine Port";
3361 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3363 HANDLE handle;
3365 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3366 NULL, OPEN_EXISTING, 0, NULL );
3367 if (handle == INVALID_HANDLE_VALUE)
3368 return FALSE;
3369 TRACE("Checking %s exists\n", name );
3370 CloseHandle( handle );
3371 return TRUE;
3374 static DWORD WINSPOOL_CountSerialPorts(void)
3376 CHAR name[6];
3377 DWORD n = 0, i;
3379 for (i=0; i<4; i++)
3381 strcpy( name, "COMx:" );
3382 name[3] = '1' + i;
3383 if (WINSPOOL_ComPortExists( name ))
3384 n++;
3387 return n;
3390 /******************************************************************************
3391 * EnumPortsA (WINSPOOL.@)
3393 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3394 LPDWORD bufneeded,LPDWORD bufreturned)
3396 CHAR portname[10];
3397 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3398 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3399 HKEY hkey_printer;
3400 BOOL retval = TRUE;
3402 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3403 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3405 switch( level )
3407 case 1:
3408 info_size = sizeof (PORT_INFO_1A);
3409 break;
3410 case 2:
3411 info_size = sizeof (PORT_INFO_2A);
3412 break;
3413 default:
3414 SetLastError(ERROR_INVALID_LEVEL);
3415 return FALSE;
3418 /* see how many exist */
3420 hkey_printer = 0;
3421 serial_count = WINSPOOL_CountSerialPorts();
3422 printer_count = 0;
3424 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3425 if ( r == ERROR_SUCCESS )
3427 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3428 &printer_count, NULL, NULL, NULL, NULL);
3430 count = serial_count + printer_count;
3432 /* then fill in the structure info structure once
3433 we know the offset to the first string */
3435 memset( buffer, 0, bufsize );
3436 n = 0;
3437 ofs = info_size*count;
3438 for ( i=0; i<count; i++)
3440 DWORD vallen = sizeof(portname) - 1;
3442 /* get the serial port values, then the printer values */
3443 if ( i < serial_count )
3445 strcpy( portname, "COMx:" );
3446 portname[3] = '1' + i;
3447 if (!WINSPOOL_ComPortExists( portname ))
3448 continue;
3450 TRACE("Found %s\n", portname );
3451 vallen = strlen( portname );
3453 else
3455 r = RegEnumValueA( hkey_printer, i-serial_count,
3456 portname, &vallen, NULL, NULL, NULL, 0 );
3457 if ( r )
3458 continue;
3461 /* add a colon if necessary, and make it upper case */
3462 CharUpperBuffA(portname,vallen);
3463 if (strcasecmp(portname,"nul")!=0)
3464 if (vallen && (portname[vallen-1] != ':') )
3465 lstrcatA(portname,":");
3467 /* add the port info structure if we can fit it */
3468 if ( info_size*(n+1) < bufsize )
3470 if ( level == 1)
3472 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3473 info->pName = (LPSTR) &buffer[ofs];
3475 else if ( level == 2)
3477 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3478 info->pPortName = (LPSTR) &buffer[ofs];
3479 /* FIXME: fill in more stuff here */
3480 info->pMonitorName = PortMonitor;
3481 info->pDescription = PortDescription;
3482 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3485 /* add the name of the port if we can fit it */
3486 if ( ofs < bufsize )
3487 lstrcpynA(&buffer[ofs],portname,bufsize - ofs);
3489 n++;
3491 else
3492 retval = FALSE;
3493 ofs += lstrlenA(portname)+1;
3496 RegCloseKey(hkey_printer);
3498 if(bufneeded)
3499 *bufneeded = ofs;
3501 if(bufreturned)
3502 *bufreturned = n;
3504 return retval;
3507 /******************************************************************************
3508 * EnumPortsW (WINSPOOL.@)
3510 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3511 LPDWORD bufneeded,LPDWORD bufreturned)
3513 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3514 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3515 return FALSE;
3518 /******************************************************************************
3519 * GetDefaultPrinterW (WINSPOOL.@)
3521 * FIXME
3522 * This function must read the value from data 'device' of key
3523 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3525 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3527 BOOL retval = TRUE;
3528 DWORD insize, len;
3529 WCHAR *buffer, *ptr;
3531 if (!namesize)
3533 SetLastError(ERROR_INVALID_PARAMETER);
3534 return FALSE;
3537 /* make the buffer big enough for the stuff from the profile/registry,
3538 * the content must fit into the local buffer to compute the correct
3539 * size even if the extern buffer is too small or not given.
3540 * (20 for ,driver,port) */
3541 insize = *namesize;
3542 len = max(100, (insize + 20));
3543 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3545 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3547 SetLastError (ERROR_FILE_NOT_FOUND);
3548 retval = FALSE;
3549 goto end;
3551 TRACE("%s\n", debugstr_w(buffer));
3553 if ((ptr = strchrW(buffer, ',')) == NULL)
3555 SetLastError(ERROR_INVALID_NAME);
3556 retval = FALSE;
3557 goto end;
3560 *ptr = 0;
3561 *namesize = strlenW(buffer) + 1;
3562 if(!name || (*namesize > insize))
3564 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3565 retval = FALSE;
3566 goto end;
3568 strcpyW(name, buffer);
3570 end:
3571 HeapFree( GetProcessHeap(), 0, buffer);
3572 return retval;
3576 /******************************************************************************
3577 * GetDefaultPrinterA (WINSPOOL.@)
3579 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3581 BOOL retval = TRUE;
3582 DWORD insize = 0;
3583 WCHAR *bufferW = NULL;
3585 if (!namesize)
3587 SetLastError(ERROR_INVALID_PARAMETER);
3588 return FALSE;
3591 if(name && *namesize) {
3592 insize = *namesize;
3593 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3596 if(!GetDefaultPrinterW( bufferW, namesize)) {
3597 retval = FALSE;
3598 goto end;
3601 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3602 NULL, NULL);
3603 if (!*namesize)
3605 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3606 retval = FALSE;
3608 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3610 end:
3611 HeapFree( GetProcessHeap(), 0, bufferW);
3612 return retval;
3616 /******************************************************************************
3617 * SetPrinterDataExA (WINSPOOL.@)
3619 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3620 LPCSTR pValueName, DWORD Type,
3621 LPBYTE pData, DWORD cbData)
3623 HKEY hkeyPrinter, hkeySubkey;
3624 DWORD ret;
3626 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3627 debugstr_a(pValueName), Type, pData, cbData);
3629 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3630 != ERROR_SUCCESS)
3631 return ret;
3633 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3634 != ERROR_SUCCESS) {
3635 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3636 RegCloseKey(hkeyPrinter);
3637 return ret;
3639 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3640 RegCloseKey(hkeySubkey);
3641 RegCloseKey(hkeyPrinter);
3642 return ret;
3645 /******************************************************************************
3646 * SetPrinterDataExW (WINSPOOL.@)
3648 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3649 LPCWSTR pValueName, DWORD Type,
3650 LPBYTE pData, DWORD cbData)
3652 HKEY hkeyPrinter, hkeySubkey;
3653 DWORD ret;
3655 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3656 debugstr_w(pValueName), Type, pData, cbData);
3658 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3659 != ERROR_SUCCESS)
3660 return ret;
3662 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3663 != ERROR_SUCCESS) {
3664 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3665 RegCloseKey(hkeyPrinter);
3666 return ret;
3668 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3669 RegCloseKey(hkeySubkey);
3670 RegCloseKey(hkeyPrinter);
3671 return ret;
3674 /******************************************************************************
3675 * SetPrinterDataA (WINSPOOL.@)
3677 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3678 LPBYTE pData, DWORD cbData)
3680 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3681 pData, cbData);
3684 /******************************************************************************
3685 * SetPrinterDataW (WINSPOOL.@)
3687 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3688 LPBYTE pData, DWORD cbData)
3690 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3691 pData, cbData);
3694 /******************************************************************************
3695 * GetPrinterDataExA (WINSPOOL.@)
3697 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3698 LPCSTR pValueName, LPDWORD pType,
3699 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3701 HKEY hkeyPrinter, hkeySubkey;
3702 DWORD ret;
3704 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3705 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
3706 pcbNeeded);
3708 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3709 != ERROR_SUCCESS)
3710 return ret;
3712 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3713 != ERROR_SUCCESS) {
3714 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
3715 RegCloseKey(hkeyPrinter);
3716 return ret;
3718 *pcbNeeded = nSize;
3719 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3720 RegCloseKey(hkeySubkey);
3721 RegCloseKey(hkeyPrinter);
3722 return ret;
3725 /******************************************************************************
3726 * GetPrinterDataExW (WINSPOOL.@)
3728 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3729 LPCWSTR pValueName, LPDWORD pType,
3730 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3732 HKEY hkeyPrinter, hkeySubkey;
3733 DWORD ret;
3735 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
3736 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
3737 pcbNeeded);
3739 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3740 != ERROR_SUCCESS)
3741 return ret;
3743 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3744 != ERROR_SUCCESS) {
3745 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
3746 RegCloseKey(hkeyPrinter);
3747 return ret;
3749 *pcbNeeded = nSize;
3750 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
3751 RegCloseKey(hkeySubkey);
3752 RegCloseKey(hkeyPrinter);
3753 return ret;
3756 /******************************************************************************
3757 * GetPrinterDataA (WINSPOOL.@)
3759 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
3760 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3762 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
3763 pData, nSize, pcbNeeded);
3766 /******************************************************************************
3767 * GetPrinterDataW (WINSPOOL.@)
3769 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
3770 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
3772 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
3773 pData, nSize, pcbNeeded);
3776 /*******************************************************************************
3777 * EnumPrinterDataExW [WINSPOOL.@]
3779 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3780 LPBYTE pEnumValues, DWORD cbEnumValues,
3781 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
3783 HKEY hkPrinter, hkSubKey;
3784 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
3785 cbValueNameLen, cbMaxValueLen, cbValueLen,
3786 cbBufSize, dwType;
3787 LPWSTR lpValueName;
3788 HANDLE hHeap;
3789 PBYTE lpValue;
3790 PPRINTER_ENUM_VALUESW ppev;
3792 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
3794 if (pKeyName == NULL || *pKeyName == 0)
3795 return ERROR_INVALID_PARAMETER;
3797 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
3798 if (ret != ERROR_SUCCESS)
3800 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3801 hPrinter, ret);
3802 return ret;
3805 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
3806 if (ret != ERROR_SUCCESS)
3808 r = RegCloseKey (hkPrinter);
3809 if (r != ERROR_SUCCESS)
3810 WARN ("RegCloseKey returned %li\n", r);
3811 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
3812 debugstr_w (pKeyName), ret);
3813 return ret;
3816 ret = RegCloseKey (hkPrinter);
3817 if (ret != ERROR_SUCCESS)
3819 ERR ("RegCloseKey returned %li\n", ret);
3820 r = RegCloseKey (hkSubKey);
3821 if (r != ERROR_SUCCESS)
3822 WARN ("RegCloseKey returned %li\n", r);
3823 return ret;
3826 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
3827 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
3828 if (ret != ERROR_SUCCESS)
3830 r = RegCloseKey (hkSubKey);
3831 if (r != ERROR_SUCCESS)
3832 WARN ("RegCloseKey returned %li\n", r);
3833 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
3834 return ret;
3837 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3838 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
3840 if (cValues == 0) /* empty key */
3842 r = RegCloseKey (hkSubKey);
3843 if (r != ERROR_SUCCESS)
3844 WARN ("RegCloseKey returned %li\n", r);
3845 *pcbEnumValues = *pnEnumValues = 0;
3846 return ERROR_SUCCESS;
3849 ++cbMaxValueNameLen; /* allow for trailing '\0' */
3851 hHeap = GetProcessHeap ();
3852 if (hHeap == NULL)
3854 ERR ("GetProcessHeap failed\n");
3855 r = RegCloseKey (hkSubKey);
3856 if (r != ERROR_SUCCESS)
3857 WARN ("RegCloseKey returned %li\n", r);
3858 return ERROR_OUTOFMEMORY;
3861 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
3862 if (lpValueName == NULL)
3864 ERR ("Failed to allocate %li bytes from process heap\n",
3865 cbMaxValueNameLen * sizeof (WCHAR));
3866 r = RegCloseKey (hkSubKey);
3867 if (r != ERROR_SUCCESS)
3868 WARN ("RegCloseKey returned %li\n", r);
3869 return ERROR_OUTOFMEMORY;
3872 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
3873 if (lpValue == NULL)
3875 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
3876 if (HeapFree (hHeap, 0, lpValueName) == 0)
3877 WARN ("HeapFree failed with code %li\n", GetLastError ());
3878 r = RegCloseKey (hkSubKey);
3879 if (r != ERROR_SUCCESS)
3880 WARN ("RegCloseKey returned %li\n", r);
3881 return ERROR_OUTOFMEMORY;
3884 TRACE ("pass 1: calculating buffer required for all names and values\n");
3886 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
3888 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
3890 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3892 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3893 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3894 NULL, NULL, lpValue, &cbValueLen);
3895 if (ret != ERROR_SUCCESS)
3897 if (HeapFree (hHeap, 0, lpValue) == 0)
3898 WARN ("HeapFree failed with code %li\n", GetLastError ());
3899 if (HeapFree (hHeap, 0, lpValueName) == 0)
3900 WARN ("HeapFree failed with code %li\n", GetLastError ());
3901 r = RegCloseKey (hkSubKey);
3902 if (r != ERROR_SUCCESS)
3903 WARN ("RegCloseKey returned %li\n", r);
3904 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3905 return ret;
3908 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3909 debugstr_w (lpValueName), dwIndex,
3910 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
3912 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
3913 cbBufSize += cbValueLen;
3916 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
3918 *pcbEnumValues = cbBufSize;
3919 *pnEnumValues = cValues;
3921 if (cbEnumValues < cbBufSize) /* buffer too small */
3923 if (HeapFree (hHeap, 0, lpValue) == 0)
3924 WARN ("HeapFree failed with code %li\n", GetLastError ());
3925 if (HeapFree (hHeap, 0, lpValueName) == 0)
3926 WARN ("HeapFree failed with code %li\n", GetLastError ());
3927 r = RegCloseKey (hkSubKey);
3928 if (r != ERROR_SUCCESS)
3929 WARN ("RegCloseKey returned %li\n", r);
3930 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
3931 return ERROR_MORE_DATA;
3934 TRACE ("pass 2: copying all names and values to buffer\n");
3936 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
3937 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
3939 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
3941 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
3942 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
3943 NULL, &dwType, lpValue, &cbValueLen);
3944 if (ret != ERROR_SUCCESS)
3946 if (HeapFree (hHeap, 0, lpValue) == 0)
3947 WARN ("HeapFree failed with code %li\n", GetLastError ());
3948 if (HeapFree (hHeap, 0, lpValueName) == 0)
3949 WARN ("HeapFree failed with code %li\n", GetLastError ());
3950 r = RegCloseKey (hkSubKey);
3951 if (r != ERROR_SUCCESS)
3952 WARN ("RegCloseKey returned %li\n", r);
3953 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
3954 return ret;
3957 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
3958 memcpy (pEnumValues, lpValueName, cbValueNameLen);
3959 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
3960 pEnumValues += cbValueNameLen;
3962 /* return # of *bytes* (including trailing \0), not # of chars */
3963 ppev[dwIndex].cbValueName = cbValueNameLen;
3965 ppev[dwIndex].dwType = dwType;
3967 memcpy (pEnumValues, lpValue, cbValueLen);
3968 ppev[dwIndex].pData = pEnumValues;
3969 pEnumValues += cbValueLen;
3971 ppev[dwIndex].cbData = cbValueLen;
3973 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3974 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
3977 if (HeapFree (hHeap, 0, lpValue) == 0)
3979 ret = GetLastError ();
3980 ERR ("HeapFree failed with code %li\n", ret);
3981 if (HeapFree (hHeap, 0, lpValueName) == 0)
3982 WARN ("HeapFree failed with code %li\n", GetLastError ());
3983 r = RegCloseKey (hkSubKey);
3984 if (r != ERROR_SUCCESS)
3985 WARN ("RegCloseKey returned %li\n", r);
3986 return ret;
3989 if (HeapFree (hHeap, 0, lpValueName) == 0)
3991 ret = GetLastError ();
3992 ERR ("HeapFree failed with code %li\n", ret);
3993 r = RegCloseKey (hkSubKey);
3994 if (r != ERROR_SUCCESS)
3995 WARN ("RegCloseKey returned %li\n", r);
3996 return ret;
3999 ret = RegCloseKey (hkSubKey);
4000 if (ret != ERROR_SUCCESS)
4002 ERR ("RegCloseKey returned %li\n", ret);
4003 return ret;
4006 return ERROR_SUCCESS;
4009 /*******************************************************************************
4010 * EnumPrinterDataExA [WINSPOOL.@]
4012 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4013 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4014 * what Windows 2000 SP1 does.
4017 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4018 LPBYTE pEnumValues, DWORD cbEnumValues,
4019 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4021 INT len;
4022 LPWSTR pKeyNameW;
4023 DWORD ret, dwIndex, dwBufSize;
4024 HANDLE hHeap;
4025 LPSTR pBuffer;
4027 TRACE ("%p %s\n", hPrinter, pKeyName);
4029 if (pKeyName == NULL || *pKeyName == 0)
4030 return ERROR_INVALID_PARAMETER;
4032 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4033 if (len == 0)
4035 ret = GetLastError ();
4036 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4037 return ret;
4040 hHeap = GetProcessHeap ();
4041 if (hHeap == NULL)
4043 ERR ("GetProcessHeap failed\n");
4044 return ERROR_OUTOFMEMORY;
4047 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4048 if (pKeyNameW == NULL)
4050 ERR ("Failed to allocate %li bytes from process heap\n",
4051 (LONG) len * sizeof (WCHAR));
4052 return ERROR_OUTOFMEMORY;
4055 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4057 ret = GetLastError ();
4058 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4059 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4060 WARN ("HeapFree failed with code %li\n", GetLastError ());
4061 return ret;
4064 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4065 pcbEnumValues, pnEnumValues);
4066 if (ret != ERROR_SUCCESS)
4068 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4069 WARN ("HeapFree failed with code %li\n", GetLastError ());
4070 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4071 return ret;
4074 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4076 ret = GetLastError ();
4077 ERR ("HeapFree failed with code %li\n", ret);
4078 return ret;
4081 if (*pnEnumValues == 0) /* empty key */
4082 return ERROR_SUCCESS;
4084 dwBufSize = 0;
4085 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4087 PPRINTER_ENUM_VALUESW ppev =
4088 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4090 if (dwBufSize < ppev->cbValueName)
4091 dwBufSize = ppev->cbValueName;
4093 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4094 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4095 dwBufSize = ppev->cbData;
4098 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4100 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4101 if (pBuffer == NULL)
4103 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4104 return ERROR_OUTOFMEMORY;
4107 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4109 PPRINTER_ENUM_VALUESW ppev =
4110 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4112 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4113 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4114 NULL);
4115 if (len == 0)
4117 ret = GetLastError ();
4118 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4119 if (HeapFree (hHeap, 0, pBuffer) == 0)
4120 WARN ("HeapFree failed with code %li\n", GetLastError ());
4121 return ret;
4124 memcpy (ppev->pValueName, pBuffer, len);
4126 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4128 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4129 ppev->dwType != REG_MULTI_SZ)
4130 continue;
4132 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4133 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4134 if (len == 0)
4136 ret = GetLastError ();
4137 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4138 if (HeapFree (hHeap, 0, pBuffer) == 0)
4139 WARN ("HeapFree failed with code %li\n", GetLastError ());
4140 return ret;
4143 memcpy (ppev->pData, pBuffer, len);
4145 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4146 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4149 if (HeapFree (hHeap, 0, pBuffer) == 0)
4151 ret = GetLastError ();
4152 ERR ("HeapFree failed with code %li\n", ret);
4153 return ret;
4156 return ERROR_SUCCESS;
4159 /******************************************************************************
4160 * AbortPrinter (WINSPOOL.@)
4162 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4164 FIXME("(%p), stub!\n", hPrinter);
4165 return TRUE;
4168 /******************************************************************************
4169 * AddPortA (WINSPOOL.@)
4171 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4173 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4174 return FALSE;
4177 /******************************************************************************
4178 * AddPortW (WINSPOOL.@)
4180 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4182 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4183 return FALSE;
4186 /******************************************************************************
4187 * AddPortExA (WINSPOOL.@)
4189 * Adds a print spooler port without presenting a user interface.
4191 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4193 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4194 lpBuffer, debugstr_a(lpMonitorName));
4195 return FALSE;
4198 /******************************************************************************
4199 * AddPortExW (WINSPOOL.@)
4201 * See AddPortExW.
4203 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4205 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4206 lpBuffer, debugstr_w(lpMonitorName));
4207 return FALSE;
4210 /******************************************************************************
4211 * AddPrinterConnectionA (WINSPOOL.@)
4213 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4215 FIXME("%s\n", debugstr_a(pName));
4216 return FALSE;
4219 /******************************************************************************
4220 * AddPrinterConnectionW (WINSPOOL.@)
4222 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4224 FIXME("%s\n", debugstr_w(pName));
4225 return FALSE;
4228 /******************************************************************************
4229 * AddPrinterDriverExW (WINSPOOL.@)
4231 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4232 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4234 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4235 Level, pDriverInfo, dwFileCopyFlags);
4236 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4237 return FALSE;
4240 /******************************************************************************
4241 * AddPrinterDriverExA (WINSPOOL.@)
4243 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4244 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4246 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4247 Level, pDriverInfo, dwFileCopyFlags);
4248 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4249 return FALSE;
4252 /******************************************************************************
4253 * ConfigurePortA (WINSPOOL.@)
4255 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4257 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4258 return FALSE;
4261 /******************************************************************************
4262 * ConfigurePortW (WINSPOOL.@)
4264 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4266 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4267 return FALSE;
4270 /******************************************************************************
4271 * ConnectToPrinterDlg (WINSPOOL.@)
4273 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4275 FIXME("%p %lx\n", hWnd, Flags);
4276 return NULL;
4279 /******************************************************************************
4280 * DeletePrinterConnectionA (WINSPOOL.@)
4282 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4284 FIXME("%s\n", debugstr_a(pName));
4285 return TRUE;
4288 /******************************************************************************
4289 * DeletePrinterConnectionW (WINSPOOL.@)
4291 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4293 FIXME("%s\n", debugstr_w(pName));
4294 return TRUE;
4297 /******************************************************************************
4298 * DeletePrinterDriverExW (WINSPOOL.@)
4300 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4301 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4303 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4304 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4305 return TRUE;
4308 /******************************************************************************
4309 * DeletePrinterDriverExA (WINSPOOL.@)
4311 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4312 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4314 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4315 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4316 return TRUE;
4319 /******************************************************************************
4320 * DeletePrinterDataExW (WINSPOOL.@)
4322 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4323 LPCWSTR pValueName)
4325 FIXME("%p %s %s\n", hPrinter,
4326 debugstr_w(pKeyName), debugstr_w(pValueName));
4327 return ERROR_INVALID_PARAMETER;
4330 /******************************************************************************
4331 * DeletePrinterDataExA (WINSPOOL.@)
4333 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4334 LPCSTR pValueName)
4336 FIXME("%p %s %s\n", hPrinter,
4337 debugstr_a(pKeyName), debugstr_a(pValueName));
4338 return ERROR_INVALID_PARAMETER;
4341 /******************************************************************************
4342 * DeletePrintProcessorA (WINSPOOL.@)
4344 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4346 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4347 debugstr_a(pPrintProcessorName));
4348 return TRUE;
4351 /******************************************************************************
4352 * DeletePrintProcessorW (WINSPOOL.@)
4354 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4356 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4357 debugstr_w(pPrintProcessorName));
4358 return TRUE;
4361 /******************************************************************************
4362 * DeletePrintProvidorA (WINSPOOL.@)
4364 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4366 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4367 debugstr_a(pPrintProviderName));
4368 return TRUE;
4371 /******************************************************************************
4372 * DeletePrintProvidorW (WINSPOOL.@)
4374 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4376 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4377 debugstr_w(pPrintProviderName));
4378 return TRUE;
4381 /******************************************************************************
4382 * EnumFormsA (WINSPOOL.@)
4384 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4385 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4387 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4388 return FALSE;
4391 /******************************************************************************
4392 * EnumFormsW (WINSPOOL.@)
4394 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4395 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4397 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4398 return FALSE;
4401 /*****************************************************************************
4402 * EnumMonitorsA [WINSPOOL.@]
4405 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4406 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4408 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4409 cbBuf, pcbNeeded, pcReturned);
4410 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4411 return 0;
4414 /*****************************************************************************
4415 * EnumMonitorsW [WINSPOOL.@]
4418 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4419 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4421 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4422 cbBuf, pcbNeeded, pcReturned);
4423 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4424 return 0;
4427 /******************************************************************************
4428 * XcvDataW (WINSPOOL.@)
4430 * Notes:
4431 * There doesn't seem to be an A version...
4433 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4434 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4435 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4437 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4438 pInputData, cbInputData, pOutputData,
4439 cbOutputData, pcbOutputNeeded, pdwStatus);
4440 return FALSE;
4443 /*****************************************************************************
4444 * EnumPrinterDataA [WINSPOOL.@]
4447 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4448 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4449 DWORD cbData, LPDWORD pcbData )
4451 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4452 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4453 return ERROR_NO_MORE_ITEMS;
4456 /*****************************************************************************
4457 * EnumPrinterDataW [WINSPOOL.@]
4460 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4461 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4462 DWORD cbData, LPDWORD pcbData )
4464 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4465 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4466 return ERROR_NO_MORE_ITEMS;
4469 /*****************************************************************************
4470 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4473 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4474 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4475 LPDWORD pcbNeeded, LPDWORD pcReturned)
4477 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4478 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4479 pcbNeeded, pcReturned);
4480 return FALSE;
4483 /*****************************************************************************
4484 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4487 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4488 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4489 LPDWORD pcbNeeded, LPDWORD pcReturned)
4491 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4492 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4493 pcbNeeded, pcReturned);
4494 return FALSE;
4497 /*****************************************************************************
4498 * EnumPrintProcessorsA [WINSPOOL.@]
4501 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4502 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4504 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4505 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
4506 return FALSE;
4509 /*****************************************************************************
4510 * EnumPrintProcessorsW [WINSPOOL.@]
4513 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4514 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4516 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4517 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
4518 cbBuf, pcbNeeded, pcbReturned);
4519 return FALSE;
4522 /*****************************************************************************
4523 * ExtDeviceMode [WINSPOOL.@]
4526 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
4527 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
4528 DWORD fMode)
4530 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
4531 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
4532 debugstr_a(pProfile), fMode);
4533 return -1;
4536 /*****************************************************************************
4537 * FindClosePrinterChangeNotification [WINSPOOL.@]
4540 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
4542 FIXME("Stub: %p\n", hChange);
4543 return TRUE;
4546 /*****************************************************************************
4547 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4550 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
4551 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
4553 FIXME("Stub: %p %lx %lx %p\n",
4554 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
4555 return INVALID_HANDLE_VALUE;
4558 /*****************************************************************************
4559 * FindNextPrinterChangeNotification [WINSPOOL.@]
4562 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
4563 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
4565 FIXME("Stub: %p %p %p %p\n",
4566 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
4567 return FALSE;
4570 /*****************************************************************************
4571 * FreePrinterNotifyInfo [WINSPOOL.@]
4574 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
4576 FIXME("Stub: %p\n", pPrinterNotifyInfo);
4577 return TRUE;
4580 /*****************************************************************************
4581 * GetJobA [WINSPOOL.@]
4584 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4585 DWORD cbBuf, LPDWORD pcbNeeded)
4587 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4588 cbBuf, pcbNeeded);
4589 return FALSE;
4592 /*****************************************************************************
4593 * GetJobW [WINSPOOL.@]
4596 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4597 DWORD cbBuf, LPDWORD pcbNeeded)
4599 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob,
4600 cbBuf, pcbNeeded);
4601 return FALSE;
4604 /*****************************************************************************
4605 * ScheduleJob [WINSPOOL.@]
4608 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
4610 opened_printer_t *printer;
4611 BOOL ret = FALSE;
4612 struct list *cursor, *cursor2;
4614 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
4615 EnterCriticalSection(&printer_handles_cs);
4616 printer = get_opened_printer(hPrinter);
4617 if(!printer)
4618 goto end;
4620 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->jobs)
4622 job_t *job = LIST_ENTRY(cursor, job_t, entry);
4623 HANDLE hf;
4625 if(job->job_id != dwJobID) continue;
4627 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
4628 if(hf != INVALID_HANDLE_VALUE)
4630 FIXME("need to schedule job %ld filename %s\n", job->job_id, debugstr_w(job->filename));
4631 CloseHandle(hf);
4632 DeleteFileW(job->filename);
4634 list_remove(cursor);
4635 HeapFree(GetProcessHeap(), 0, job->filename);
4636 HeapFree(GetProcessHeap(), 0, job);
4637 ret = TRUE;
4638 break;
4640 end:
4641 LeaveCriticalSection(&printer_handles_cs);
4642 return ret;