printing: Don't limit the printer name length to CCHDEVICENAME characters.
[wine.git] / dlls / winspool.drv / info.c
blob9d6e1c0759a26e2a45aa0f14a0a9c071fe9ad6af
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
9 * Copyright 2005, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
43 # endif
44 #endif
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winuser.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "wingdi.h"
55 #include "winspool.h"
56 #include "winternl.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
61 #include "heap.h"
62 #include "winnls.h"
64 #include "wspool.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
68 static CRITICAL_SECTION printer_handles_cs;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
71 0, 0, &printer_handles_cs,
72 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
77 typedef struct {
78 DWORD job_id;
79 HANDLE hf;
80 } started_doc_t;
82 typedef struct {
83 struct list jobs;
84 LONG ref;
85 } jobqueue_t;
87 typedef struct {
88 LPWSTR name;
89 jobqueue_t *queue;
90 started_doc_t *doc;
91 } opened_printer_t;
93 typedef struct {
94 struct list entry;
95 DWORD job_id;
96 WCHAR *filename;
97 WCHAR *document_title;
98 } job_t;
101 typedef struct {
102 LPCWSTR envname;
103 LPCWSTR subdir;
104 DWORD driverversion;
105 LPCWSTR versionregpath;
106 LPCWSTR versionsubdir;
107 } printenv_t;
109 /* ############################### */
111 static opened_printer_t **printer_handles;
112 static int nb_printer_handles;
113 static LONG next_job_id = 1;
115 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
116 WORD fwCapability, LPSTR lpszOutput,
117 LPDEVMODEA lpdm );
118 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
119 LPSTR lpszDevice, LPSTR lpszPort,
120 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
121 DWORD fwMode );
123 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
124 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
125 'c','o','n','t','r','o','l','\\',
126 'P','r','i','n','t','\\',
127 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
128 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
130 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'C','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'M','o','n','i','t','o','r','s',0};
136 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
137 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
138 'C','o','n','t','r','o','l','\\',
139 'P','r','i','n','t','\\',
140 'P','r','i','n','t','e','r','s',0};
142 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
144 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
145 'M','i','c','r','o','s','o','f','t','\\',
146 'W','i','n','d','o','w','s',' ','N','T','\\',
147 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
148 'W','i','n','d','o','w','s',0};
150 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'D','e','v','i','c','e','s',0};
156 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
157 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
158 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
159 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
160 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
161 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
162 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
164 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
165 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
167 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
168 'i','o','n',' ','F','i','l','e',0};
169 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
170 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
171 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
172 'M','o','d','e',0};
173 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
174 'i','l','e','s',0};
175 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
176 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
177 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
178 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
179 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
180 static const WCHAR NameW[] = {'N','a','m','e',0};
181 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
182 static const WCHAR PortW[] = {'P','o','r','t',0};
183 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
184 's','s','o','r',0};
185 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
186 'v','e','r',0};
187 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
188 'v','e','r','D','a','t','a',0};
189 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
190 'i','l','e',0};
191 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
192 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
193 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
194 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
195 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
196 static const WCHAR emptyStringW[] = {0};
198 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
200 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
201 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
202 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
204 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
205 'D','o','c','u','m','e','n','t',0};
207 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
208 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
209 DWORD Level, LPBYTE pDriverInfo,
210 DWORD cbBuf, LPDWORD pcbNeeded,
211 BOOL unicode);
212 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
213 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
215 /******************************************************************
216 * validate the user-supplied printing-environment [internal]
218 * PARAMS
219 * env [I] PTR to Environment-String or NULL
221 * RETURNS
222 * Failure: NULL
223 * Success: PTR to printenv_t
225 * NOTES
226 * An empty string is handled the same way as NULL.
227 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
231 static const printenv_t * validate_envW(LPCWSTR env)
233 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
234 3, Version3_RegPathW, Version3_SubdirW};
235 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
236 0, emptyStringW, emptyStringW};
237 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
239 const printenv_t *result = NULL;
240 unsigned int i;
242 TRACE("testing %s\n", debugstr_w(env));
243 if (env && env[0])
245 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
247 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
249 result = all_printenv[i];
250 break;
254 if (result == NULL) {
255 FIXME("unsupported Environment: %s\n", debugstr_w(env));
256 SetLastError(ERROR_INVALID_ENVIRONMENT);
258 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
260 else
262 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
264 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
266 return result;
270 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
271 if passed a NULL string. This returns NULLs to the result.
273 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
275 if ( (src) )
277 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
278 return usBufferPtr->Buffer;
280 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
281 return NULL;
284 static LPWSTR strdupW(LPCWSTR p)
286 LPWSTR ret;
287 DWORD len;
289 if(!p) return NULL;
290 len = (strlenW(p) + 1) * sizeof(WCHAR);
291 ret = HeapAlloc(GetProcessHeap(), 0, len);
292 memcpy(ret, p, len);
293 return ret;
296 static void
297 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
298 char qbuf[200];
300 /* If forcing, or no profile string entry for device yet, set the entry
302 * The always change entry if not WINEPS yet is discussable.
304 if (force ||
305 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
306 !strcmp(qbuf,"*") ||
307 !strstr(qbuf,"WINEPS.DRV")
309 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
310 HKEY hkey;
312 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
313 WriteProfileStringA("windows","device",buf);
314 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
315 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
316 RegCloseKey(hkey);
318 HeapFree(GetProcessHeap(),0,buf);
322 #ifdef HAVE_CUPS_CUPS_H
323 static typeof(cupsGetDests) *pcupsGetDests;
324 static typeof(cupsGetPPD) *pcupsGetPPD;
325 static typeof(cupsPrintFile) *pcupsPrintFile;
326 static void *cupshandle;
328 static BOOL CUPS_LoadPrinters(void)
330 int i, nrofdests;
331 BOOL hadprinter = FALSE;
332 cups_dest_t *dests;
333 PRINTER_INFO_2A pinfo2a;
334 char *port,*devline;
335 HKEY hkeyPrinter, hkeyPrinters, hkey;
337 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
338 if (!cupshandle)
339 return FALSE;
340 TRACE("loaded %s\n", SONAME_LIBCUPS);
342 #define DYNCUPS(x) \
343 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
344 if (!p##x) return FALSE;
346 DYNCUPS(cupsGetPPD);
347 DYNCUPS(cupsGetDests);
348 DYNCUPS(cupsPrintFile);
349 #undef DYNCUPS
351 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
352 ERROR_SUCCESS) {
353 ERR("Can't create Printers key\n");
354 return FALSE;
357 nrofdests = pcupsGetDests(&dests);
358 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
359 for (i=0;i<nrofdests;i++) {
360 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
361 sprintf(port,"LPR:%s",dests[i].name);
362 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
363 sprintf(devline,"WINEPS.DRV,%s",port);
364 WriteProfileStringA("devices",dests[i].name,devline);
365 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
366 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
367 RegCloseKey(hkey);
369 HeapFree(GetProcessHeap(),0,devline);
371 TRACE("Printer %d: %s\n", i, dests[i].name);
372 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
373 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
374 and continue */
375 TRACE("Printer already exists\n");
376 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
377 RegCloseKey(hkeyPrinter);
378 } else {
379 memset(&pinfo2a,0,sizeof(pinfo2a));
380 pinfo2a.pPrinterName = dests[i].name;
381 pinfo2a.pDatatype = "RAW";
382 pinfo2a.pPrintProcessor = "WinPrint";
383 pinfo2a.pDriverName = "PS Driver";
384 pinfo2a.pComment = "WINEPS Printer using CUPS";
385 pinfo2a.pLocation = "<physical location of printer>";
386 pinfo2a.pPortName = port;
387 pinfo2a.pParameters = "<parameters?>";
388 pinfo2a.pShareName = "<share name?>";
389 pinfo2a.pSepFile = "<sep file?>";
391 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
392 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
393 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
396 HeapFree(GetProcessHeap(),0,port);
398 hadprinter = TRUE;
399 if (dests[i].is_default)
400 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
402 RegCloseKey(hkeyPrinters);
403 return hadprinter;
405 #endif
407 static BOOL
408 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
409 PRINTER_INFO_2A pinfo2a;
410 char *e,*s,*name,*prettyname,*devname;
411 BOOL ret = FALSE, set_default = FALSE;
412 char *port,*devline,*env_default;
413 HKEY hkeyPrinter, hkeyPrinters, hkey;
415 while (isspace(*pent)) pent++;
416 s = strchr(pent,':');
417 if(s) *s='\0';
418 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
419 strcpy(name,pent);
420 if(s) {
421 *s=':';
422 pent = s;
423 } else
424 pent = "";
426 TRACE("name=%s entry=%s\n",name, pent);
428 if(ispunct(*name)) { /* a tc entry, not a real printer */
429 TRACE("skipping tc entry\n");
430 goto end;
433 if(strstr(pent,":server")) { /* server only version so skip */
434 TRACE("skipping server entry\n");
435 goto end;
438 /* Determine whether this is a postscript printer. */
440 ret = TRUE;
441 env_default = getenv("PRINTER");
442 prettyname = name;
443 /* Get longest name, usually the one at the right for later display. */
444 while((s=strchr(prettyname,'|'))) {
445 *s = '\0';
446 e = s;
447 while(isspace(*--e)) *e = '\0';
448 TRACE("\t%s\n", debugstr_a(prettyname));
449 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
450 for(prettyname = s+1; isspace(*prettyname); prettyname++)
453 e = prettyname + strlen(prettyname);
454 while(isspace(*--e)) *e = '\0';
455 TRACE("\t%s\n", debugstr_a(prettyname));
456 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
458 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
459 * if it is too long, we use it as comment below. */
460 devname = prettyname;
461 if (strlen(devname)>=CCHDEVICENAME-1)
462 devname = name;
463 if (strlen(devname)>=CCHDEVICENAME-1) {
464 ret = FALSE;
465 goto end;
468 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
469 sprintf(port,"LPR:%s",name);
471 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
472 sprintf(devline,"WINEPS.DRV,%s",port);
473 WriteProfileStringA("devices",devname,devline);
474 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
475 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
476 RegCloseKey(hkey);
478 HeapFree(GetProcessHeap(),0,devline);
480 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
481 ERROR_SUCCESS) {
482 ERR("Can't create Printers key\n");
483 ret = FALSE;
484 goto end;
486 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
487 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
488 and continue */
489 TRACE("Printer already exists\n");
490 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
491 RegCloseKey(hkeyPrinter);
492 } else {
493 memset(&pinfo2a,0,sizeof(pinfo2a));
494 pinfo2a.pPrinterName = devname;
495 pinfo2a.pDatatype = "RAW";
496 pinfo2a.pPrintProcessor = "WinPrint";
497 pinfo2a.pDriverName = "PS Driver";
498 pinfo2a.pComment = "WINEPS Printer using LPR";
499 pinfo2a.pLocation = prettyname;
500 pinfo2a.pPortName = port;
501 pinfo2a.pParameters = "<parameters?>";
502 pinfo2a.pShareName = "<share name?>";
503 pinfo2a.pSepFile = "<sep file?>";
505 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
506 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
507 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
510 RegCloseKey(hkeyPrinters);
512 if (isfirst || set_default)
513 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
515 HeapFree(GetProcessHeap(), 0, port);
516 end:
517 HeapFree(GetProcessHeap(), 0, name);
518 return ret;
521 static BOOL
522 PRINTCAP_LoadPrinters(void) {
523 BOOL hadprinter = FALSE;
524 char buf[200];
525 FILE *f;
526 char *pent = NULL;
527 BOOL had_bash = FALSE;
529 f = fopen("/etc/printcap","r");
530 if (!f)
531 return FALSE;
533 while(fgets(buf,sizeof(buf),f)) {
534 char *start, *end;
536 end=strchr(buf,'\n');
537 if (end) *end='\0';
539 start = buf;
540 while(isspace(*start)) start++;
541 if(*start == '#' || *start == '\0')
542 continue;
544 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
545 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
546 HeapFree(GetProcessHeap(),0,pent);
547 pent = NULL;
550 if (end && *--end == '\\') {
551 *end = '\0';
552 had_bash = TRUE;
553 } else
554 had_bash = FALSE;
556 if (pent) {
557 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
558 strcat(pent,start);
559 } else {
560 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
561 strcpy(pent,start);
565 if(pent) {
566 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
567 HeapFree(GetProcessHeap(),0,pent);
569 fclose(f);
570 return hadprinter;
573 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
575 if (value)
576 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
577 lstrlenW(value) * sizeof(WCHAR));
578 else
579 return ERROR_FILE_NOT_FOUND;
582 void WINSPOOL_LoadSystemPrinters(void)
584 HKEY hkey, hkeyPrinters;
585 DRIVER_INFO_3A di3a;
586 HANDLE hprn;
587 DWORD needed, num, i;
588 WCHAR PrinterName[256];
589 BOOL done = FALSE;
591 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
592 di3a.pName = "PS Driver";
593 di3a.pEnvironment = NULL; /* NULL means auto */
594 di3a.pDriverPath = "wineps16";
595 di3a.pDataFile = "<datafile?>";
596 di3a.pConfigFile = "wineps16";
597 di3a.pHelpFile = "<helpfile?>";
598 di3a.pDependentFiles = "<dependend files?>";
599 di3a.pMonitorName = "<monitor name?>";
600 di3a.pDefaultDataType = "RAW";
602 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
603 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
604 return;
607 /* This ensures that all printer entries have a valid Name value. If causes
608 problems later if they don't. If one is found to be missed we create one
609 and set it equal to the name of the key */
610 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
611 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
612 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
613 for(i = 0; i < num; i++) {
614 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
615 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
616 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
617 set_reg_szW(hkey, NameW, PrinterName);
619 RegCloseKey(hkey);
624 RegCloseKey(hkeyPrinters);
627 /* We want to avoid calling AddPrinter on printers as much as
628 possible, because on cups printers this will (eventually) lead
629 to a call to cupsGetPPD which takes forever, even with non-cups
630 printers AddPrinter takes a while. So we'll tag all printers that
631 were automatically added last time around, if they still exist
632 we'll leave them be otherwise we'll delete them. */
633 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
634 if(needed) {
635 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
636 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
637 for(i = 0; i < num; i++) {
638 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
639 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
640 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
641 DWORD dw = 1;
642 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
643 RegCloseKey(hkey);
645 ClosePrinter(hprn);
650 HeapFree(GetProcessHeap(), 0, pi);
654 #ifdef HAVE_CUPS_CUPS_H
655 done = CUPS_LoadPrinters();
656 #endif
658 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
659 /* Check for [ppd] section in config file before parsing /etc/printcap */
660 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
661 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
662 &hkey) == ERROR_SUCCESS) {
663 RegCloseKey(hkey);
664 PRINTCAP_LoadPrinters();
668 /* Now enumerate the list again and delete any printers that a still tagged */
669 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
670 if(needed) {
671 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
672 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
673 for(i = 0; i < num; i++) {
674 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
675 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
676 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
677 DWORD dw, type, size = sizeof(dw);
678 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
679 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
680 DeletePrinter(hprn);
682 RegCloseKey(hkey);
684 ClosePrinter(hprn);
689 HeapFree(GetProcessHeap(), 0, pi);
692 return;
696 /*****************************************************************************
697 * enumerate the local monitors (INTERNAL)
699 * returns the needed size (in bytes) for pMonitors
700 * and *lpreturned is set to number of entries returned in pMonitors
703 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
705 HKEY hroot = NULL;
706 HKEY hentry = NULL;
707 LPWSTR ptr;
708 LPMONITOR_INFO_2W mi;
709 WCHAR buffer[MAX_PATH];
710 WCHAR dllname[MAX_PATH];
711 DWORD dllsize;
712 DWORD len;
713 DWORD index = 0;
714 DWORD needed = 0;
715 DWORD numentries;
716 DWORD entrysize;
718 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
720 numentries = *lpreturned; /* this is 0, when we scan the registry */
721 len = entrysize * numentries;
722 ptr = (LPWSTR) &pMonitors[len];
724 numentries = 0;
725 len = sizeof(buffer);
726 buffer[0] = '\0';
728 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
729 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
730 /* Scan all Monitor-Registry-Keys */
731 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
732 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
733 dllsize = sizeof(dllname);
734 dllname[0] = '\0';
736 /* The Monitor must have a Driver-DLL */
737 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
738 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
739 /* We found a valid DLL for this Monitor. */
740 TRACE("using Driver: %s\n", debugstr_w(dllname));
742 RegCloseKey(hentry);
745 /* Windows returns only Port-Monitors here, but to simplify our code,
746 we do no filtering for Language-Monitors */
747 if (dllname[0]) {
748 numentries++;
749 needed += entrysize;
750 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
751 if (level > 1) {
752 /* we install and return only monitors for "Windows NT x86" */
753 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
754 needed += dllsize;
757 /* required size is calculated. Now fill the user-buffer */
758 if (pMonitors && (cbBuf >= needed)){
759 mi = (LPMONITOR_INFO_2W) pMonitors;
760 pMonitors += entrysize;
762 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
763 mi->pName = ptr;
764 lstrcpyW(ptr, buffer); /* Name of the Monitor */
765 ptr += (len+1); /* len is lstrlenW(monitorname) */
766 if (level > 1) {
767 mi->pEnvironment = ptr;
768 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
769 ptr += (lstrlenW(envname_x86W)+1);
771 mi->pDLLName = ptr;
772 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
773 ptr += (dllsize / sizeof(WCHAR));
777 index++;
778 len = sizeof(buffer);
779 buffer[0] = '\0';
781 RegCloseKey(hroot);
783 *lpreturned = numentries;
784 TRACE("need %ld byte for %ld entries\n", needed, numentries);
785 return needed;
788 /******************************************************************
789 * get_opened_printer_entry
790 * Get the first place empty in the opened printer table
792 * ToDo:
793 * - pDefault is ignored
795 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
797 UINT_PTR handle = nb_printer_handles, i;
798 jobqueue_t *queue = NULL;
799 opened_printer_t *printer = NULL;
801 EnterCriticalSection(&printer_handles_cs);
803 for (i = 0; i < nb_printer_handles; i++)
805 if (!printer_handles[i])
807 if(handle == nb_printer_handles)
808 handle = i;
810 else
812 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
813 queue = printer_handles[i]->queue;
817 if (handle >= nb_printer_handles)
819 opened_printer_t **new_array;
820 if (printer_handles)
821 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
822 (nb_printer_handles + 16) * sizeof(*new_array) );
823 else
824 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
825 (nb_printer_handles + 16) * sizeof(*new_array) );
827 if (!new_array)
829 handle = 0;
830 goto end;
832 printer_handles = new_array;
833 nb_printer_handles += 16;
836 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
838 handle = 0;
839 goto end;
842 if(name) {
843 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
844 if (!printer->name) {
845 handle = 0;
846 goto end;
848 strcpyW(printer->name, name);
851 if(queue)
852 printer->queue = queue;
853 else
855 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
856 if (!printer->queue) {
857 handle = 0;
858 goto end;
860 list_init(&printer->queue->jobs);
861 printer->queue->ref = 0;
863 InterlockedIncrement(&printer->queue->ref);
865 printer_handles[handle] = printer;
866 handle++;
867 end:
868 LeaveCriticalSection(&printer_handles_cs);
869 if (!handle && printer) {
870 /* Something Failed: Free the Buffers */
871 HeapFree(GetProcessHeap(), 0, printer->name);
872 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
873 HeapFree(GetProcessHeap(), 0, printer);
876 return (HANDLE)handle;
879 /******************************************************************
880 * get_opened_printer
881 * Get the pointer to the opened printer referred by the handle
883 static opened_printer_t *get_opened_printer(HANDLE hprn)
885 UINT_PTR idx = (UINT_PTR)hprn;
886 opened_printer_t *ret = NULL;
888 EnterCriticalSection(&printer_handles_cs);
890 if ((idx <= 0) || (idx > nb_printer_handles))
891 goto end;
893 ret = printer_handles[idx - 1];
894 end:
895 LeaveCriticalSection(&printer_handles_cs);
896 return ret;
899 /******************************************************************
900 * get_opened_printer_name
901 * Get the pointer to the opened printer name referred by the handle
903 static LPCWSTR get_opened_printer_name(HANDLE hprn)
905 opened_printer_t *printer = get_opened_printer(hprn);
906 if(!printer) return NULL;
907 return printer->name;
910 /******************************************************************
911 * WINSPOOL_GetOpenedPrinterRegKey
914 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
916 LPCWSTR name = get_opened_printer_name(hPrinter);
917 DWORD ret;
918 HKEY hkeyPrinters;
920 if(!name) return ERROR_INVALID_HANDLE;
922 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
923 ERROR_SUCCESS)
924 return ret;
926 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
928 ERR("Can't find opened printer %s in registry\n",
929 debugstr_w(name));
930 RegCloseKey(hkeyPrinters);
931 return ERROR_INVALID_PRINTER_NAME; /* ? */
933 RegCloseKey(hkeyPrinters);
934 return ERROR_SUCCESS;
937 /******************************************************************
938 * get_job
940 * Get the pointer to the specified job.
941 * Should hold the printer_handles_cs before calling.
943 static job_t *get_job(HANDLE hprn, DWORD JobId)
945 opened_printer_t *printer = get_opened_printer(hprn);
946 job_t *job;
948 if(!printer) return NULL;
949 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
951 if(job->job_id == JobId)
952 return job;
954 return NULL;
957 /***********************************************************
958 * DEVMODEcpyAtoW
960 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
962 BOOL Formname;
963 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
964 DWORD size;
966 Formname = (dmA->dmSize > off_formname);
967 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
968 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
969 dmW->dmDeviceName, CCHDEVICENAME);
970 if(!Formname) {
971 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
972 dmA->dmSize - CCHDEVICENAME);
973 } else {
974 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
975 off_formname - CCHDEVICENAME);
976 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
977 dmW->dmFormName, CCHFORMNAME);
978 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
979 (off_formname + CCHFORMNAME));
981 dmW->dmSize = size;
982 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
983 dmA->dmDriverExtra);
984 return dmW;
987 /***********************************************************
988 * DEVMODEdupWtoA
989 * Creates an ascii copy of supplied devmode on heap
991 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
993 LPDEVMODEA dmA;
994 DWORD size;
995 BOOL Formname;
996 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
998 if(!dmW) return NULL;
999 Formname = (dmW->dmSize > off_formname);
1000 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1001 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1002 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1003 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1004 if(!Formname) {
1005 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1006 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1007 } else {
1008 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1009 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1010 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1011 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1012 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1013 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1015 dmA->dmSize = size;
1016 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1017 dmW->dmDriverExtra);
1018 return dmA;
1021 /***********************************************************
1022 * PRINTER_INFO_2AtoW
1023 * Creates a unicode copy of PRINTER_INFO_2A on heap
1025 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1027 LPPRINTER_INFO_2W piW;
1028 UNICODE_STRING usBuffer;
1030 if(!piA) return NULL;
1031 piW = HeapAlloc(heap, 0, sizeof(*piW));
1032 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1034 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1035 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1036 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1037 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1038 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1039 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1040 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1041 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1042 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1043 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1044 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1045 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1046 return piW;
1049 /***********************************************************
1050 * FREE_PRINTER_INFO_2W
1051 * Free PRINTER_INFO_2W and all strings
1053 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1055 if(!piW) return;
1057 HeapFree(heap,0,piW->pServerName);
1058 HeapFree(heap,0,piW->pPrinterName);
1059 HeapFree(heap,0,piW->pShareName);
1060 HeapFree(heap,0,piW->pPortName);
1061 HeapFree(heap,0,piW->pDriverName);
1062 HeapFree(heap,0,piW->pComment);
1063 HeapFree(heap,0,piW->pLocation);
1064 HeapFree(heap,0,piW->pDevMode);
1065 HeapFree(heap,0,piW->pSepFile);
1066 HeapFree(heap,0,piW->pPrintProcessor);
1067 HeapFree(heap,0,piW->pDatatype);
1068 HeapFree(heap,0,piW->pParameters);
1069 HeapFree(heap,0,piW);
1070 return;
1073 /******************************************************************
1074 * DeviceCapabilities [WINSPOOL.@]
1075 * DeviceCapabilitiesA [WINSPOOL.@]
1078 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1079 LPSTR pOutput, LPDEVMODEA lpdm)
1081 INT ret;
1083 if (!GDI_CallDeviceCapabilities16)
1085 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1086 (LPCSTR)104 );
1087 if (!GDI_CallDeviceCapabilities16) return -1;
1089 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1091 /* If DC_PAPERSIZE map POINT16s to POINTs */
1092 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1093 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1094 POINT *pt = (POINT *)pOutput;
1095 INT i;
1096 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1097 for(i = 0; i < ret; i++, pt++)
1099 pt->x = tmp[i].x;
1100 pt->y = tmp[i].y;
1102 HeapFree( GetProcessHeap(), 0, tmp );
1104 return ret;
1108 /*****************************************************************************
1109 * DeviceCapabilitiesW [WINSPOOL.@]
1111 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1114 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1115 WORD fwCapability, LPWSTR pOutput,
1116 const DEVMODEW *pDevMode)
1118 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1119 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1120 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1121 INT ret;
1123 if(pOutput && (fwCapability == DC_BINNAMES ||
1124 fwCapability == DC_FILEDEPENDENCIES ||
1125 fwCapability == DC_PAPERNAMES)) {
1126 /* These need A -> W translation */
1127 INT size = 0, i;
1128 LPSTR pOutputA;
1129 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1130 dmA);
1131 if(ret == -1)
1132 return ret;
1133 switch(fwCapability) {
1134 case DC_BINNAMES:
1135 size = 24;
1136 break;
1137 case DC_PAPERNAMES:
1138 case DC_FILEDEPENDENCIES:
1139 size = 64;
1140 break;
1142 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1143 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1144 dmA);
1145 for(i = 0; i < ret; i++)
1146 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1147 pOutput + (i * size), size);
1148 HeapFree(GetProcessHeap(), 0, pOutputA);
1149 } else {
1150 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1151 (LPSTR)pOutput, dmA);
1153 HeapFree(GetProcessHeap(),0,pPortA);
1154 HeapFree(GetProcessHeap(),0,pDeviceA);
1155 HeapFree(GetProcessHeap(),0,dmA);
1156 return ret;
1159 /******************************************************************
1160 * DocumentPropertiesA [WINSPOOL.@]
1162 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1164 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1165 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1166 LPDEVMODEA pDevModeInput,DWORD fMode )
1168 LPSTR lpName = pDeviceName;
1169 LONG ret;
1171 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1172 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1175 if(!pDeviceName) {
1176 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1177 if(!lpNameW) {
1178 ERR("no name from hPrinter?\n");
1179 SetLastError(ERROR_INVALID_HANDLE);
1180 return -1;
1182 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1185 if (!GDI_CallExtDeviceMode16)
1187 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1188 (LPCSTR)102 );
1189 if (!GDI_CallExtDeviceMode16) {
1190 ERR("No CallExtDeviceMode16?\n");
1191 return -1;
1194 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1195 pDevModeInput, NULL, fMode);
1197 if(!pDeviceName)
1198 HeapFree(GetProcessHeap(),0,lpName);
1199 return ret;
1203 /*****************************************************************************
1204 * DocumentPropertiesW (WINSPOOL.@)
1206 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1208 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1209 LPWSTR pDeviceName,
1210 LPDEVMODEW pDevModeOutput,
1211 LPDEVMODEW pDevModeInput, DWORD fMode)
1214 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1215 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1216 LPDEVMODEA pDevModeOutputA = NULL;
1217 LONG ret;
1219 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1220 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1221 fMode);
1222 if(pDevModeOutput) {
1223 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1224 if(ret < 0) return ret;
1225 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1227 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1228 pDevModeInputA, fMode);
1229 if(pDevModeOutput) {
1230 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1231 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1233 if(fMode == 0 && ret > 0)
1234 ret += (CCHDEVICENAME + CCHFORMNAME);
1235 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1236 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1237 return ret;
1240 /******************************************************************
1241 * OpenPrinterA [WINSPOOL.@]
1243 * See OpenPrinterW.
1246 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1247 LPPRINTER_DEFAULTSA pDefault)
1249 UNICODE_STRING lpPrinterNameW;
1250 UNICODE_STRING usBuffer;
1251 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1252 PWSTR pwstrPrinterNameW;
1253 BOOL ret;
1255 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1257 if(pDefault) {
1258 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1259 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1260 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1261 pDefaultW = &DefaultW;
1263 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1264 if(pDefault) {
1265 RtlFreeUnicodeString(&usBuffer);
1266 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1268 RtlFreeUnicodeString(&lpPrinterNameW);
1269 return ret;
1272 /******************************************************************
1273 * OpenPrinterW [WINSPOOL.@]
1275 * Open a Printer / Printserver or a Printer-Object
1277 * PARAMS
1278 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1279 * phPrinter [O] The resulting Handle is stored here
1280 * pDefault [I] PTR to Default Printer Settings or NULL
1282 * RETURNS
1283 * Success: TRUE
1284 * Failure: FALSE
1286 * NOTES
1287 * lpPrinterName is one of:
1288 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1289 *| Printer: "PrinterName"
1290 *| Printer-Object: "PrinterName,Job xxx"
1291 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1292 *| XcvPort: "Servername,XcvPort PortName"
1294 * BUGS
1295 *| Printer-Object not supported
1296 *| XcvMonitor not supported
1297 *| XcvPort not supported
1298 *| pDefaults is ignored
1301 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1303 HKEY hkeyPrinters = NULL;
1304 HKEY hkeyPrinter = NULL;
1306 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1307 if (pDefault) {
1308 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08lx\n",
1309 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1312 if(lpPrinterName != NULL)
1314 /* Check any Printer exists */
1315 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1316 ERR("Can't create Printers key\n");
1317 SetLastError(ERROR_FILE_NOT_FOUND);
1318 return FALSE;
1320 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1321 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1323 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1324 RegCloseKey(hkeyPrinters);
1325 SetLastError(ERROR_INVALID_PRINTER_NAME);
1326 return FALSE;
1328 RegCloseKey(hkeyPrinter);
1329 RegCloseKey(hkeyPrinters);
1331 if(!phPrinter) {
1332 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1333 SetLastError(ERROR_INVALID_PARAMETER);
1334 return FALSE;
1337 /* Get the unique handle of the printer or Printserver */
1338 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1339 return (*phPrinter != 0);
1342 /******************************************************************
1343 * AddMonitorA [WINSPOOL.@]
1345 * See AddMonitorW.
1348 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1350 LPWSTR nameW = NULL;
1351 INT len;
1352 BOOL res;
1353 LPMONITOR_INFO_2A mi2a;
1354 MONITOR_INFO_2W mi2w;
1356 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1357 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1358 mi2a ? debugstr_a(mi2a->pName) : NULL,
1359 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1360 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1362 if (Level != 2) {
1363 SetLastError(ERROR_INVALID_LEVEL);
1364 return FALSE;
1367 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1368 if (mi2a == NULL) {
1369 return FALSE;
1372 if (pName) {
1373 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1374 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1375 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1378 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1379 if (mi2a->pName) {
1380 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1381 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1382 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1384 if (mi2a->pEnvironment) {
1385 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1386 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1387 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1389 if (mi2a->pDLLName) {
1390 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1391 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1392 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1395 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1397 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1398 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1399 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1401 HeapFree(GetProcessHeap(), 0, nameW);
1402 return (res);
1405 /******************************************************************************
1406 * AddMonitorW [WINSPOOL.@]
1408 * Install a Printmonitor
1410 * PARAMS
1411 * pName [I] Servername or NULL (local Computer)
1412 * Level [I] Structure-Level (Must be 2)
1413 * pMonitors [I] PTR to MONITOR_INFO_2
1415 * RETURNS
1416 * Success: TRUE
1417 * Failure: FALSE
1419 * NOTES
1420 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1423 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1425 LPMONITOR_INFO_2W mi2w;
1426 HKEY hroot = NULL;
1427 HKEY hentry = NULL;
1428 HMODULE hdll = NULL;
1429 DWORD disposition;
1430 BOOL res = FALSE;
1432 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1433 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1434 mi2w ? debugstr_w(mi2w->pName) : NULL,
1435 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1436 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1438 if (Level != 2) {
1439 SetLastError(ERROR_INVALID_LEVEL);
1440 return FALSE;
1443 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1444 if (mi2w == NULL) {
1445 return FALSE;
1448 if (pName && (pName[0])) {
1449 FIXME("for server %s not implemented\n", debugstr_w(pName));
1450 SetLastError(ERROR_ACCESS_DENIED);
1451 return FALSE;
1455 if (!mi2w->pName || (! mi2w->pName[0])) {
1456 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1457 SetLastError(ERROR_INVALID_PARAMETER);
1458 return FALSE;
1460 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1461 WARN("Environment %s requested (we support only %s)\n",
1462 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1463 SetLastError(ERROR_INVALID_ENVIRONMENT);
1464 return FALSE;
1467 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1468 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1469 SetLastError(ERROR_INVALID_PARAMETER);
1470 return FALSE;
1473 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1474 return FALSE;
1476 FreeLibrary(hdll);
1478 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1479 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1480 return FALSE;
1483 if(RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1484 KEY_WRITE, NULL, &hentry, &disposition) == ERROR_SUCCESS) {
1486 if (disposition == REG_OPENED_EXISTING_KEY) {
1487 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1488 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1489 9x: ERROR_ALREADY_EXISTS (183) */
1490 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1492 else
1494 INT len;
1495 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1496 res = (RegSetValueExW(hentry, DriverW, 0,
1497 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1499 RegCloseKey(hentry);
1502 RegCloseKey(hroot);
1503 return (res);
1506 /******************************************************************
1507 * DeletePrinterDriverA [WINSPOOL.@]
1510 BOOL WINAPI
1511 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1513 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1514 debugstr_a(pDriverName));
1515 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1516 return FALSE;
1519 /******************************************************************
1520 * DeletePrinterDriverW [WINSPOOL.@]
1523 BOOL WINAPI
1524 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1526 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1527 debugstr_w(pDriverName));
1528 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1529 return FALSE;
1532 /******************************************************************
1533 * DeleteMonitorA [WINSPOOL.@]
1535 * See DeleteMonitorW.
1538 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1540 LPWSTR nameW = NULL;
1541 LPWSTR EnvironmentW = NULL;
1542 LPWSTR MonitorNameW = NULL;
1543 BOOL res;
1544 INT len;
1546 if (pName) {
1547 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1548 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1549 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1552 if (pEnvironment) {
1553 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1554 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1555 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1557 if (pMonitorName) {
1558 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1559 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1560 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1563 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1565 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1566 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1567 HeapFree(GetProcessHeap(), 0, nameW);
1568 return (res);
1571 /******************************************************************
1572 * DeleteMonitorW [WINSPOOL.@]
1574 * Delete a specific Printmonitor from a Printing-Environment
1576 * PARAMS
1577 * pName [I] Servername or NULL (local Computer)
1578 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1579 * pMonitorName [I] Name of the Monitor, that should be deleted
1581 * RETURNS
1582 * Success: TRUE
1583 * Failure: FALSE
1585 * NOTES
1586 * pEnvironment is ignored in Windows for the local Computer.
1590 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1592 HKEY hroot = NULL;
1594 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1595 debugstr_w(pMonitorName));
1597 if (pName && (pName[0])) {
1598 FIXME("for server %s not implemented\n", debugstr_w(pName));
1599 SetLastError(ERROR_ACCESS_DENIED);
1600 return FALSE;
1603 /* pEnvironment is ignored in Windows for the local Computer */
1605 if (!pMonitorName || !pMonitorName[0]) {
1606 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1607 SetLastError(ERROR_INVALID_PARAMETER);
1608 return FALSE;
1611 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1612 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1613 return FALSE;
1616 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1617 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1618 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1619 RegCloseKey(hroot);
1620 return TRUE;
1623 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1624 RegCloseKey(hroot);
1626 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1627 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1628 return (FALSE);
1631 /******************************************************************
1632 * DeletePortA [WINSPOOL.@]
1634 * See DeletePortW.
1637 BOOL WINAPI
1638 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1640 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1641 debugstr_a(pPortName));
1642 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1643 return FALSE;
1646 /******************************************************************
1647 * DeletePortW [WINSPOOL.@]
1649 * Delete a specific Port
1651 * PARAMS
1652 * pName [I] Servername or NULL (local Computer)
1653 * hWnd [I] Handle to parent Window for the Dialog-Box
1654 * pPortName [I] Name of the Port, that should be deleted
1656 * RETURNS
1657 * Success: TRUE
1658 * Failure: FALSE
1660 * BUGS
1661 * only a Stub
1664 BOOL WINAPI
1665 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1667 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1668 debugstr_w(pPortName));
1669 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1670 return FALSE;
1673 /******************************************************************************
1674 * SetPrinterW [WINSPOOL.@]
1676 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1678 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1679 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1680 return FALSE;
1683 /******************************************************************************
1684 * WritePrinter [WINSPOOL.@]
1686 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1688 opened_printer_t *printer;
1689 BOOL ret = FALSE;
1691 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1693 EnterCriticalSection(&printer_handles_cs);
1694 printer = get_opened_printer(hPrinter);
1695 if(!printer)
1697 SetLastError(ERROR_INVALID_HANDLE);
1698 goto end;
1701 if(!printer->doc)
1703 SetLastError(ERROR_SPL_NO_STARTDOC);
1704 goto end;
1707 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1708 end:
1709 LeaveCriticalSection(&printer_handles_cs);
1710 return ret;
1713 /*****************************************************************************
1714 * AddFormA [WINSPOOL.@]
1716 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1718 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1719 return 1;
1722 /*****************************************************************************
1723 * AddFormW [WINSPOOL.@]
1725 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1727 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1728 return 1;
1731 /*****************************************************************************
1732 * AddJobA [WINSPOOL.@]
1734 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1736 BOOL ret;
1737 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1738 DWORD needed;
1740 if(Level != 1) {
1741 SetLastError(ERROR_INVALID_LEVEL);
1742 return FALSE;
1745 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1747 if(ret) {
1748 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1749 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1750 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1751 if(*pcbNeeded > cbBuf) {
1752 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1753 ret = FALSE;
1754 } else {
1755 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1756 addjobA->JobId = addjobW->JobId;
1757 addjobA->Path = (char *)(addjobA + 1);
1758 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1761 return ret;
1764 /*****************************************************************************
1765 * AddJobW [WINSPOOL.@]
1767 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1769 opened_printer_t *printer;
1770 job_t *job;
1771 BOOL ret = FALSE;
1772 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1773 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1774 WCHAR path[MAX_PATH], filename[MAX_PATH];
1775 DWORD len;
1776 ADDJOB_INFO_1W *addjob;
1778 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1780 EnterCriticalSection(&printer_handles_cs);
1782 printer = get_opened_printer(hPrinter);
1784 if(!printer) {
1785 SetLastError(ERROR_INVALID_HANDLE);
1786 goto end;
1789 if(Level != 1) {
1790 SetLastError(ERROR_INVALID_LEVEL);
1791 goto end;
1794 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1795 if(!job)
1796 goto end;
1798 job->job_id = InterlockedIncrement(&next_job_id);
1800 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1801 if(path[len - 1] != '\\')
1802 path[len++] = '\\';
1803 memcpy(path + len, spool_path, sizeof(spool_path));
1804 sprintfW(filename, fmtW, path, job->job_id);
1806 len = strlenW(filename);
1807 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1808 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1809 job->document_title = strdupW(default_doc_title);
1810 list_add_tail(&printer->queue->jobs, &job->entry);
1812 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1813 if(*pcbNeeded <= cbBuf) {
1814 addjob = (ADDJOB_INFO_1W*)pData;
1815 addjob->JobId = job->job_id;
1816 addjob->Path = (WCHAR *)(addjob + 1);
1817 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1818 ret = TRUE;
1819 } else
1820 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1822 end:
1823 LeaveCriticalSection(&printer_handles_cs);
1824 return ret;
1827 /*****************************************************************************
1828 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1830 * Return the PATH for the Print-Processors
1832 * See GetPrintProcessorDirectoryW.
1836 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1837 DWORD level, LPBYTE Info,
1838 DWORD cbBuf, LPDWORD pcbNeeded)
1840 LPWSTR serverW = NULL;
1841 LPWSTR envW = NULL;
1842 BOOL ret;
1843 INT len;
1845 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
1846 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
1849 if (server) {
1850 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
1851 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1852 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
1855 if (env) {
1856 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
1857 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1858 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
1861 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
1862 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
1864 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
1865 cbBuf, pcbNeeded);
1867 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
1868 cbBuf, NULL, NULL) > 0;
1871 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
1872 HeapFree(GetProcessHeap(), 0, envW);
1873 HeapFree(GetProcessHeap(), 0, serverW);
1874 return ret;
1877 /*****************************************************************************
1878 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1880 * Return the PATH for the Print-Processors
1882 * PARAMS
1883 * server [I] Servername (NT only) or NULL (local Computer)
1884 * env [I] Printing-Environment (see below) or NULL (Default)
1885 * level [I] Structure-Level (must be 1)
1886 * Info [O] PTR to Buffer that receives the Result
1887 * cbBuf [I] Size of Buffer at "Info"
1888 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1889 * required for the Buffer at "Info"
1891 * RETURNS
1892 * Success: TRUE and in pcbNeeded the Bytes used in Info
1893 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
1894 * if cbBuf is too small
1896 * Native Values returned in Info on Success:
1897 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
1898 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
1899 *| win9x(Windows 4.0): "%winsysdir%"
1901 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1903 * BUGS
1904 * Only NULL or "" is supported for server
1907 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1908 DWORD level, LPBYTE Info,
1909 DWORD cbBuf, LPDWORD pcbNeeded)
1911 DWORD needed;
1912 const printenv_t * env_t;
1914 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server),
1915 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
1917 if(server != NULL && server[0]) {
1918 FIXME("server not supported: %s\n", debugstr_w(server));
1919 SetLastError(ERROR_INVALID_PARAMETER);
1920 return FALSE;
1923 env_t = validate_envW(env);
1924 if(!env_t) return FALSE; /* environment invalid or unsupported */
1926 if(level != 1) {
1927 WARN("(Level: %ld) is ignored in win9x\n", level);
1928 SetLastError(ERROR_INVALID_LEVEL);
1929 return FALSE;
1932 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1933 needed = GetSystemDirectoryW(NULL, 0);
1934 /* add the Size for the Subdirectories */
1935 needed += lstrlenW(spoolprtprocsW);
1936 needed += lstrlenW(env_t->subdir);
1937 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1939 if(pcbNeeded) *pcbNeeded = needed;
1940 TRACE ("required: 0x%lx/%ld\n", needed, needed);
1941 if (needed > cbBuf) {
1942 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1943 return FALSE;
1945 if(pcbNeeded == NULL) {
1946 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
1947 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
1948 SetLastError(RPC_X_NULL_REF_POINTER);
1949 return FALSE;
1951 if(Info == NULL) {
1952 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
1953 SetLastError(RPC_X_NULL_REF_POINTER);
1954 return FALSE;
1957 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
1958 /* add the Subdirectories */
1959 lstrcatW((LPWSTR) Info, spoolprtprocsW);
1960 lstrcatW((LPWSTR) Info, env_t->subdir);
1961 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
1962 return TRUE;
1965 /*****************************************************************************
1966 * WINSPOOL_OpenDriverReg [internal]
1968 * opens the registry for the printer drivers depending on the given input
1969 * variable pEnvironment
1971 * RETURNS:
1972 * the opened hkey on success
1973 * NULL on error
1975 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1977 HKEY retval = NULL;
1978 LPWSTR buffer;
1979 const printenv_t * env;
1981 TRACE("(%s, %d)\n",
1982 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
1984 if (!pEnvironment || unicode) {
1985 /* pEnvironment was NULL or an Unicode-String: use it direct */
1986 env = validate_envW(pEnvironment);
1988 else
1990 /* pEnvironment was an ANSI-String: convert to unicode first */
1991 LPWSTR buffer;
1992 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1993 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1994 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1995 env = validate_envW(buffer);
1996 HeapFree(GetProcessHeap(), 0, buffer);
1998 if (!env) return NULL;
2000 buffer = HeapAlloc( GetProcessHeap(), 0,
2001 (strlenW(DriversW) + strlenW(env->envname) +
2002 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2003 if(buffer) {
2004 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2005 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2006 HeapFree(GetProcessHeap(), 0, buffer);
2008 return retval;
2011 /*****************************************************************************
2012 * AddPrinterW [WINSPOOL.@]
2014 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2016 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2017 LPDEVMODEA dmA;
2018 LPDEVMODEW dmW;
2019 HANDLE retval;
2020 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2021 LONG size;
2023 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2025 if(pName != NULL) {
2026 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2027 SetLastError(ERROR_INVALID_PARAMETER);
2028 return 0;
2030 if(Level != 2) {
2031 ERR("Level = %ld, unsupported!\n", Level);
2032 SetLastError(ERROR_INVALID_LEVEL);
2033 return 0;
2035 if(!pPrinter) {
2036 SetLastError(ERROR_INVALID_PARAMETER);
2037 return 0;
2039 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2040 ERROR_SUCCESS) {
2041 ERR("Can't create Printers key\n");
2042 return 0;
2044 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2045 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2046 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2047 RegCloseKey(hkeyPrinter);
2048 RegCloseKey(hkeyPrinters);
2049 return 0;
2051 RegCloseKey(hkeyPrinter);
2053 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2054 if(!hkeyDrivers) {
2055 ERR("Can't create Drivers key\n");
2056 RegCloseKey(hkeyPrinters);
2057 return 0;
2059 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2060 ERROR_SUCCESS) {
2061 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2062 RegCloseKey(hkeyPrinters);
2063 RegCloseKey(hkeyDrivers);
2064 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2065 return 0;
2067 RegCloseKey(hkeyDriver);
2068 RegCloseKey(hkeyDrivers);
2070 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2071 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2072 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2073 RegCloseKey(hkeyPrinters);
2074 return 0;
2077 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2078 ERROR_SUCCESS) {
2079 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2080 SetLastError(ERROR_INVALID_PRINTER_NAME);
2081 RegCloseKey(hkeyPrinters);
2082 return 0;
2084 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2085 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2086 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2088 /* See if we can load the driver. We may need the devmode structure anyway
2090 * FIXME:
2091 * Note that DocumentPropertiesW will briefly try to open the printer we
2092 * just create to find a DEVMODEA struct (it will use the WINEPS default
2093 * one in case it is not there, so we are ok).
2095 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2097 if(size < 0) {
2098 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2099 size = sizeof(DEVMODEW);
2101 if(pi->pDevMode)
2102 dmW = pi->pDevMode;
2103 else
2105 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2106 ZeroMemory(dmW,size);
2107 dmW->dmSize = size;
2108 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2110 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2111 HeapFree(GetProcessHeap(),0,dmW);
2112 dmW=NULL;
2114 else
2116 /* set devmode to printer name */
2117 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2121 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2122 and we support these drivers. NT writes DEVMODEW so somehow
2123 we'll need to distinguish between these when we support NT
2124 drivers */
2125 if (dmW)
2127 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2128 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2129 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2130 HeapFree(GetProcessHeap(), 0, dmA);
2131 if(!pi->pDevMode)
2132 HeapFree(GetProcessHeap(), 0, dmW);
2134 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2135 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2136 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2137 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2139 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2140 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2141 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2142 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2143 (LPBYTE)&pi->Priority, sizeof(DWORD));
2144 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2145 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2146 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2147 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2148 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2149 (LPBYTE)&pi->Status, sizeof(DWORD));
2150 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2151 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2153 RegCloseKey(hkeyPrinter);
2154 RegCloseKey(hkeyPrinters);
2155 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2156 ERR("OpenPrinter failing\n");
2157 return 0;
2159 return retval;
2162 /*****************************************************************************
2163 * AddPrinterA [WINSPOOL.@]
2165 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2167 UNICODE_STRING pNameW;
2168 PWSTR pwstrNameW;
2169 PRINTER_INFO_2W *piW;
2170 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2171 HANDLE ret;
2173 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2174 if(Level != 2) {
2175 ERR("Level = %ld, unsupported!\n", Level);
2176 SetLastError(ERROR_INVALID_LEVEL);
2177 return 0;
2179 pwstrNameW = asciitounicode(&pNameW,pName);
2180 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2182 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2184 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2185 RtlFreeUnicodeString(&pNameW);
2186 return ret;
2190 /*****************************************************************************
2191 * ClosePrinter [WINSPOOL.@]
2193 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2195 UINT_PTR i = (UINT_PTR)hPrinter;
2196 opened_printer_t *printer = NULL;
2197 BOOL ret = FALSE;
2199 TRACE("Handle %p\n", hPrinter);
2201 EnterCriticalSection(&printer_handles_cs);
2203 if ((i > 0) && (i <= nb_printer_handles))
2204 printer = printer_handles[i - 1];
2206 if(printer)
2208 struct list *cursor, *cursor2;
2210 if(printer->doc)
2211 EndDocPrinter(hPrinter);
2213 if(InterlockedDecrement(&printer->queue->ref) == 0)
2215 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2217 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2218 ScheduleJob(hPrinter, job->job_id);
2220 HeapFree(GetProcessHeap(), 0, printer->queue);
2222 HeapFree(GetProcessHeap(), 0, printer->name);
2223 HeapFree(GetProcessHeap(), 0, printer);
2224 printer_handles[i - 1] = NULL;
2225 ret = TRUE;
2227 LeaveCriticalSection(&printer_handles_cs);
2228 return ret;
2231 /*****************************************************************************
2232 * DeleteFormA [WINSPOOL.@]
2234 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2236 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2237 return 1;
2240 /*****************************************************************************
2241 * DeleteFormW [WINSPOOL.@]
2243 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2245 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2246 return 1;
2249 /*****************************************************************************
2250 * WINSPOOL_SHRegDeleteKey
2252 * Recursively delete subkeys.
2253 * Cut & paste from shlwapi.
2256 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2258 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2259 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2260 HKEY hSubKey = 0;
2262 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2263 if(!dwRet)
2265 /* Find how many subkeys there are */
2266 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2267 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2268 if(!dwRet)
2270 dwMaxSubkeyLen++;
2271 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2272 /* Name too big: alloc a buffer for it */
2273 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2275 if(!lpszName)
2276 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2277 else
2279 /* Recursively delete all the subkeys */
2280 for(i = 0; i < dwKeyCount && !dwRet; i++)
2282 dwSize = dwMaxSubkeyLen;
2283 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2284 if(!dwRet)
2285 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2288 if (lpszName != szNameBuf)
2289 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2293 RegCloseKey(hSubKey);
2294 if(!dwRet)
2295 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2297 return dwRet;
2300 /*****************************************************************************
2301 * DeletePrinter [WINSPOOL.@]
2303 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2305 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2306 HKEY hkeyPrinters, hkey;
2308 if(!lpNameW) {
2309 SetLastError(ERROR_INVALID_HANDLE);
2310 return FALSE;
2312 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2313 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2314 RegCloseKey(hkeyPrinters);
2316 WriteProfileStringW(devicesW, lpNameW, NULL);
2317 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2318 RegDeleteValueW(hkey, lpNameW);
2319 RegCloseKey(hkey);
2321 return TRUE;
2324 /*****************************************************************************
2325 * SetPrinterA [WINSPOOL.@]
2327 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2328 DWORD Command)
2330 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2331 return FALSE;
2334 /*****************************************************************************
2335 * SetJobA [WINSPOOL.@]
2337 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2338 LPBYTE pJob, DWORD Command)
2340 BOOL ret;
2341 LPBYTE JobW;
2342 UNICODE_STRING usBuffer;
2344 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2346 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2347 are all ignored by SetJob, so we don't bother copying them */
2348 switch(Level)
2350 case 0:
2351 JobW = NULL;
2352 break;
2353 case 1:
2355 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2356 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2358 JobW = (LPBYTE)info1W;
2359 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2360 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2361 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2362 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2363 info1W->Status = info1A->Status;
2364 info1W->Priority = info1A->Priority;
2365 info1W->Position = info1A->Position;
2366 info1W->PagesPrinted = info1A->PagesPrinted;
2367 break;
2369 case 2:
2371 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2372 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2374 JobW = (LPBYTE)info2W;
2375 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2376 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2377 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2378 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2379 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2380 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2381 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2382 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2383 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2384 info2W->Status = info2A->Status;
2385 info2W->Priority = info2A->Priority;
2386 info2W->Position = info2A->Position;
2387 info2W->StartTime = info2A->StartTime;
2388 info2W->UntilTime = info2A->UntilTime;
2389 info2W->PagesPrinted = info2A->PagesPrinted;
2390 break;
2392 case 3:
2393 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2394 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2395 break;
2396 default:
2397 SetLastError(ERROR_INVALID_LEVEL);
2398 return FALSE;
2401 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2403 switch(Level)
2405 case 1:
2407 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2408 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2409 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2410 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2411 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2412 break;
2414 case 2:
2416 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2417 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2418 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2419 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2420 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2421 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2422 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2423 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2424 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2425 break;
2428 HeapFree(GetProcessHeap(), 0, JobW);
2430 return ret;
2433 /*****************************************************************************
2434 * SetJobW [WINSPOOL.@]
2436 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2437 LPBYTE pJob, DWORD Command)
2439 BOOL ret = FALSE;
2440 job_t *job;
2442 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2443 FIXME("Ignoring everything other than document title\n");
2445 EnterCriticalSection(&printer_handles_cs);
2446 job = get_job(hPrinter, JobId);
2447 if(!job)
2448 goto end;
2450 switch(Level)
2452 case 0:
2453 break;
2454 case 1:
2456 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2457 HeapFree(GetProcessHeap(), 0, job->document_title);
2458 job->document_title = strdupW(info1->pDocument);
2459 break;
2461 case 2:
2463 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2464 HeapFree(GetProcessHeap(), 0, job->document_title);
2465 job->document_title = strdupW(info2->pDocument);
2466 break;
2468 case 3:
2469 break;
2470 default:
2471 SetLastError(ERROR_INVALID_LEVEL);
2472 goto end;
2474 ret = TRUE;
2475 end:
2476 LeaveCriticalSection(&printer_handles_cs);
2477 return ret;
2480 /*****************************************************************************
2481 * EndDocPrinter [WINSPOOL.@]
2483 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2485 opened_printer_t *printer;
2486 BOOL ret = FALSE;
2487 TRACE("(%p)\n", hPrinter);
2489 EnterCriticalSection(&printer_handles_cs);
2491 printer = get_opened_printer(hPrinter);
2492 if(!printer)
2494 SetLastError(ERROR_INVALID_HANDLE);
2495 goto end;
2498 if(!printer->doc)
2500 SetLastError(ERROR_SPL_NO_STARTDOC);
2501 goto end;
2504 CloseHandle(printer->doc->hf);
2505 ScheduleJob(hPrinter, printer->doc->job_id);
2506 HeapFree(GetProcessHeap(), 0, printer->doc);
2507 printer->doc = NULL;
2508 ret = TRUE;
2509 end:
2510 LeaveCriticalSection(&printer_handles_cs);
2511 return ret;
2514 /*****************************************************************************
2515 * EndPagePrinter [WINSPOOL.@]
2517 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2519 FIXME("(%p): stub\n", hPrinter);
2520 return TRUE;
2523 /*****************************************************************************
2524 * StartDocPrinterA [WINSPOOL.@]
2526 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2528 UNICODE_STRING usBuffer;
2529 DOC_INFO_2W doc2W;
2530 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2531 DWORD ret;
2533 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2534 or one (DOC_INFO_3) extra DWORDs */
2536 switch(Level) {
2537 case 2:
2538 doc2W.JobId = doc2->JobId;
2539 /* fall through */
2540 case 3:
2541 doc2W.dwMode = doc2->dwMode;
2542 /* fall through */
2543 case 1:
2544 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2545 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2546 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2547 break;
2549 default:
2550 SetLastError(ERROR_INVALID_LEVEL);
2551 return FALSE;
2554 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2556 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2557 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2558 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2560 return ret;
2563 /*****************************************************************************
2564 * StartDocPrinterW [WINSPOOL.@]
2566 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2568 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2569 opened_printer_t *printer;
2570 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2571 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2572 JOB_INFO_1W job_info;
2573 DWORD needed, ret = 0;
2574 HANDLE hf;
2575 WCHAR *filename;
2577 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2578 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2579 debugstr_w(doc->pDatatype));
2581 if(Level < 1 || Level > 3)
2583 SetLastError(ERROR_INVALID_LEVEL);
2584 return 0;
2587 EnterCriticalSection(&printer_handles_cs);
2588 printer = get_opened_printer(hPrinter);
2589 if(!printer)
2591 SetLastError(ERROR_INVALID_HANDLE);
2592 goto end;
2595 if(printer->doc)
2597 SetLastError(ERROR_INVALID_PRINTER_STATE);
2598 goto end;
2601 /* Even if we're printing to a file we still add a print job, we'll
2602 just ignore the spool file name */
2604 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2606 ERR("AddJob failed gle %08lx\n", GetLastError());
2607 goto end;
2610 if(doc->pOutputFile)
2611 filename = doc->pOutputFile;
2612 else
2613 filename = addjob->Path;
2615 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2616 if(hf == INVALID_HANDLE_VALUE)
2617 goto end;
2619 memset(&job_info, 0, sizeof(job_info));
2620 job_info.pDocument = doc->pDocName;
2621 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2623 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2624 printer->doc->hf = hf;
2625 ret = printer->doc->job_id = addjob->JobId;
2626 end:
2627 LeaveCriticalSection(&printer_handles_cs);
2629 return ret;
2632 /*****************************************************************************
2633 * StartPagePrinter [WINSPOOL.@]
2635 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2637 FIXME("(%p): stub\n", hPrinter);
2638 return TRUE;
2641 /*****************************************************************************
2642 * GetFormA [WINSPOOL.@]
2644 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2645 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2647 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2648 Level,pForm,cbBuf,pcbNeeded);
2649 return FALSE;
2652 /*****************************************************************************
2653 * GetFormW [WINSPOOL.@]
2655 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2656 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2658 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2659 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2660 return FALSE;
2663 /*****************************************************************************
2664 * SetFormA [WINSPOOL.@]
2666 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2667 LPBYTE pForm)
2669 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2670 return FALSE;
2673 /*****************************************************************************
2674 * SetFormW [WINSPOOL.@]
2676 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2677 LPBYTE pForm)
2679 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2680 return FALSE;
2683 /*****************************************************************************
2684 * ReadPrinter [WINSPOOL.@]
2686 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2687 LPDWORD pNoBytesRead)
2689 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2690 return FALSE;
2693 /*****************************************************************************
2694 * ResetPrinterA [WINSPOOL.@]
2696 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2698 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2699 return FALSE;
2702 /*****************************************************************************
2703 * ResetPrinterW [WINSPOOL.@]
2705 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2707 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2708 return FALSE;
2711 /*****************************************************************************
2712 * WINSPOOL_GetDWORDFromReg
2714 * Return DWORD associated with ValueName from hkey.
2716 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2718 DWORD sz = sizeof(DWORD), type, value = 0;
2719 LONG ret;
2721 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2723 if(ret != ERROR_SUCCESS) {
2724 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2725 return 0;
2727 if(type != REG_DWORD) {
2728 ERR("Got type %ld\n", type);
2729 return 0;
2731 return value;
2734 /*****************************************************************************
2735 * WINSPOOL_GetStringFromReg
2737 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2738 * String is stored either as unicode or ascii.
2739 * Bit of a hack here to get the ValueName if we want ascii.
2741 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2742 DWORD buflen, DWORD *needed,
2743 BOOL unicode)
2745 DWORD sz = buflen, type;
2746 LONG ret;
2748 if(unicode)
2749 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2750 else {
2751 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2752 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2753 HeapFree(GetProcessHeap(),0,ValueNameA);
2755 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2756 WARN("Got ret = %ld\n", ret);
2757 *needed = 0;
2758 return FALSE;
2760 /* add space for terminating '\0' */
2761 sz += unicode ? sizeof(WCHAR) : 1;
2762 *needed = sz;
2764 if (ptr)
2765 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2767 return TRUE;
2770 /*****************************************************************************
2771 * WINSPOOL_GetDefaultDevMode
2773 * Get a default DevMode values for wineps.
2774 * FIXME - use ppd.
2777 static void WINSPOOL_GetDefaultDevMode(
2778 LPBYTE ptr,
2779 DWORD buflen, DWORD *needed,
2780 BOOL unicode)
2782 DEVMODEA dm;
2783 static const char szwps[] = "wineps.drv";
2785 /* fill default DEVMODE - should be read from ppd... */
2786 ZeroMemory( &dm, sizeof(dm) );
2787 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2788 dm.dmSpecVersion = DM_SPECVERSION;
2789 dm.dmDriverVersion = 1;
2790 dm.dmSize = sizeof(DEVMODEA);
2791 dm.dmDriverExtra = 0;
2792 dm.dmFields =
2793 DM_ORIENTATION | DM_PAPERSIZE |
2794 DM_PAPERLENGTH | DM_PAPERWIDTH |
2795 DM_SCALE |
2796 DM_COPIES |
2797 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2798 DM_YRESOLUTION | DM_TTOPTION;
2800 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2801 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2802 dm.u1.s1.dmPaperLength = 2970;
2803 dm.u1.s1.dmPaperWidth = 2100;
2805 dm.dmScale = 100;
2806 dm.dmCopies = 1;
2807 dm.dmDefaultSource = DMBIN_AUTO;
2808 dm.dmPrintQuality = DMRES_MEDIUM;
2809 /* dm.dmColor */
2810 /* dm.dmDuplex */
2811 dm.dmYResolution = 300; /* 300dpi */
2812 dm.dmTTOption = DMTT_BITMAP;
2813 /* dm.dmCollate */
2814 /* dm.dmFormName */
2815 /* dm.dmLogPixels */
2816 /* dm.dmBitsPerPel */
2817 /* dm.dmPelsWidth */
2818 /* dm.dmPelsHeight */
2819 /* dm.dmDisplayFlags */
2820 /* dm.dmDisplayFrequency */
2821 /* dm.dmICMMethod */
2822 /* dm.dmICMIntent */
2823 /* dm.dmMediaType */
2824 /* dm.dmDitherType */
2825 /* dm.dmReserved1 */
2826 /* dm.dmReserved2 */
2827 /* dm.dmPanningWidth */
2828 /* dm.dmPanningHeight */
2830 if(unicode) {
2831 if(buflen >= sizeof(DEVMODEW)) {
2832 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2833 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2834 HeapFree(GetProcessHeap(),0,pdmW);
2836 *needed = sizeof(DEVMODEW);
2838 else
2840 if(buflen >= sizeof(DEVMODEA)) {
2841 memcpy(ptr, &dm, sizeof(DEVMODEA));
2843 *needed = sizeof(DEVMODEA);
2847 /*****************************************************************************
2848 * WINSPOOL_GetDevModeFromReg
2850 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2851 * DevMode is stored either as unicode or ascii.
2853 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2854 LPBYTE ptr,
2855 DWORD buflen, DWORD *needed,
2856 BOOL unicode)
2858 DWORD sz = buflen, type;
2859 LONG ret;
2861 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2862 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2863 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2864 if (sz < sizeof(DEVMODEA))
2866 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2867 return FALSE;
2869 /* ensures that dmSize is not erratically bogus if registry is invalid */
2870 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2871 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2872 if(unicode) {
2873 sz += (CCHDEVICENAME + CCHFORMNAME);
2874 if(buflen >= sz) {
2875 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2876 memcpy(ptr, dmW, sz);
2877 HeapFree(GetProcessHeap(),0,dmW);
2880 *needed = sz;
2881 return TRUE;
2884 /*********************************************************************
2885 * WINSPOOL_GetPrinter_2
2887 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2888 * The strings are either stored as unicode or ascii.
2890 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2891 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2892 BOOL unicode)
2894 DWORD size, left = cbBuf;
2895 BOOL space = (cbBuf > 0);
2896 LPBYTE ptr = buf;
2898 *pcbNeeded = 0;
2900 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2901 unicode)) {
2902 if(space && size <= left) {
2903 pi2->pPrinterName = (LPWSTR)ptr;
2904 ptr += size;
2905 left -= size;
2906 } else
2907 space = FALSE;
2908 *pcbNeeded += size;
2910 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2911 unicode)) {
2912 if(space && size <= left) {
2913 pi2->pShareName = (LPWSTR)ptr;
2914 ptr += size;
2915 left -= size;
2916 } else
2917 space = FALSE;
2918 *pcbNeeded += size;
2920 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2921 unicode)) {
2922 if(space && size <= left) {
2923 pi2->pPortName = (LPWSTR)ptr;
2924 ptr += size;
2925 left -= size;
2926 } else
2927 space = FALSE;
2928 *pcbNeeded += size;
2930 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2931 &size, unicode)) {
2932 if(space && size <= left) {
2933 pi2->pDriverName = (LPWSTR)ptr;
2934 ptr += size;
2935 left -= size;
2936 } else
2937 space = FALSE;
2938 *pcbNeeded += size;
2940 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2941 unicode)) {
2942 if(space && size <= left) {
2943 pi2->pComment = (LPWSTR)ptr;
2944 ptr += size;
2945 left -= size;
2946 } else
2947 space = FALSE;
2948 *pcbNeeded += size;
2950 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2951 unicode)) {
2952 if(space && size <= left) {
2953 pi2->pLocation = (LPWSTR)ptr;
2954 ptr += size;
2955 left -= size;
2956 } else
2957 space = FALSE;
2958 *pcbNeeded += size;
2960 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2961 &size, unicode)) {
2962 if(space && size <= left) {
2963 pi2->pDevMode = (LPDEVMODEW)ptr;
2964 ptr += size;
2965 left -= size;
2966 } else
2967 space = FALSE;
2968 *pcbNeeded += size;
2970 else
2972 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2973 if(space && size <= left) {
2974 pi2->pDevMode = (LPDEVMODEW)ptr;
2975 ptr += size;
2976 left -= size;
2977 } else
2978 space = FALSE;
2979 *pcbNeeded += size;
2981 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2982 &size, unicode)) {
2983 if(space && size <= left) {
2984 pi2->pSepFile = (LPWSTR)ptr;
2985 ptr += size;
2986 left -= size;
2987 } else
2988 space = FALSE;
2989 *pcbNeeded += size;
2991 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2992 &size, unicode)) {
2993 if(space && size <= left) {
2994 pi2->pPrintProcessor = (LPWSTR)ptr;
2995 ptr += size;
2996 left -= size;
2997 } else
2998 space = FALSE;
2999 *pcbNeeded += size;
3001 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3002 &size, unicode)) {
3003 if(space && size <= left) {
3004 pi2->pDatatype = (LPWSTR)ptr;
3005 ptr += size;
3006 left -= size;
3007 } else
3008 space = FALSE;
3009 *pcbNeeded += size;
3011 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3012 &size, unicode)) {
3013 if(space && size <= left) {
3014 pi2->pParameters = (LPWSTR)ptr;
3015 ptr += size;
3016 left -= size;
3017 } else
3018 space = FALSE;
3019 *pcbNeeded += size;
3021 if(pi2) {
3022 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3023 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3024 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3025 "Default Priority");
3026 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3027 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3030 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3031 memset(pi2, 0, sizeof(*pi2));
3033 return space;
3036 /*********************************************************************
3037 * WINSPOOL_GetPrinter_4
3039 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3041 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3042 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3043 BOOL unicode)
3045 DWORD size, left = cbBuf;
3046 BOOL space = (cbBuf > 0);
3047 LPBYTE ptr = buf;
3049 *pcbNeeded = 0;
3051 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3052 unicode)) {
3053 if(space && size <= left) {
3054 pi4->pPrinterName = (LPWSTR)ptr;
3055 ptr += size;
3056 left -= size;
3057 } else
3058 space = FALSE;
3059 *pcbNeeded += size;
3061 if(pi4) {
3062 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3065 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3066 memset(pi4, 0, sizeof(*pi4));
3068 return space;
3071 /*********************************************************************
3072 * WINSPOOL_GetPrinter_5
3074 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3076 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3077 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3078 BOOL unicode)
3080 DWORD size, left = cbBuf;
3081 BOOL space = (cbBuf > 0);
3082 LPBYTE ptr = buf;
3084 *pcbNeeded = 0;
3086 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3087 unicode)) {
3088 if(space && size <= left) {
3089 pi5->pPrinterName = (LPWSTR)ptr;
3090 ptr += size;
3091 left -= size;
3092 } else
3093 space = FALSE;
3094 *pcbNeeded += size;
3096 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3097 unicode)) {
3098 if(space && size <= left) {
3099 pi5->pPortName = (LPWSTR)ptr;
3100 ptr += size;
3101 left -= size;
3102 } else
3103 space = FALSE;
3104 *pcbNeeded += size;
3106 if(pi5) {
3107 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3108 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3109 "dnsTimeout");
3110 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3111 "txTimeout");
3114 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3115 memset(pi5, 0, sizeof(*pi5));
3117 return space;
3120 /*****************************************************************************
3121 * WINSPOOL_GetPrinter
3123 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3124 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3125 * just a collection of pointers to strings.
3127 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3128 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3130 LPCWSTR name;
3131 DWORD size, needed = 0;
3132 LPBYTE ptr = NULL;
3133 HKEY hkeyPrinter, hkeyPrinters;
3134 BOOL ret;
3136 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3138 if (!(name = get_opened_printer_name(hPrinter))) {
3139 SetLastError(ERROR_INVALID_HANDLE);
3140 return FALSE;
3143 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3144 ERROR_SUCCESS) {
3145 ERR("Can't create Printers key\n");
3146 return FALSE;
3148 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3150 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3151 RegCloseKey(hkeyPrinters);
3152 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3153 return FALSE;
3156 switch(Level) {
3157 case 2:
3159 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3161 size = sizeof(PRINTER_INFO_2W);
3162 if(size <= cbBuf) {
3163 ptr = pPrinter + size;
3164 cbBuf -= size;
3165 memset(pPrinter, 0, size);
3166 } else {
3167 pi2 = NULL;
3168 cbBuf = 0;
3170 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3171 unicode);
3172 needed += size;
3173 break;
3176 case 4:
3178 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3180 size = sizeof(PRINTER_INFO_4W);
3181 if(size <= cbBuf) {
3182 ptr = pPrinter + size;
3183 cbBuf -= size;
3184 memset(pPrinter, 0, size);
3185 } else {
3186 pi4 = NULL;
3187 cbBuf = 0;
3189 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3190 unicode);
3191 needed += size;
3192 break;
3196 case 5:
3198 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3200 size = sizeof(PRINTER_INFO_5W);
3201 if(size <= cbBuf) {
3202 ptr = pPrinter + size;
3203 cbBuf -= size;
3204 memset(pPrinter, 0, size);
3205 } else {
3206 pi5 = NULL;
3207 cbBuf = 0;
3210 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3211 unicode);
3212 needed += size;
3213 break;
3216 default:
3217 FIXME("Unimplemented level %ld\n", Level);
3218 SetLastError(ERROR_INVALID_LEVEL);
3219 RegCloseKey(hkeyPrinters);
3220 RegCloseKey(hkeyPrinter);
3221 return FALSE;
3224 RegCloseKey(hkeyPrinter);
3225 RegCloseKey(hkeyPrinters);
3227 TRACE("returning %d needed = %ld\n", ret, needed);
3228 if(pcbNeeded) *pcbNeeded = needed;
3229 if(!ret)
3230 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3231 return ret;
3234 /*****************************************************************************
3235 * GetPrinterW [WINSPOOL.@]
3237 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3238 DWORD cbBuf, LPDWORD pcbNeeded)
3240 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3241 TRUE);
3244 /*****************************************************************************
3245 * GetPrinterA [WINSPOOL.@]
3247 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3248 DWORD cbBuf, LPDWORD pcbNeeded)
3250 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3251 FALSE);
3254 /*****************************************************************************
3255 * WINSPOOL_EnumPrinters
3257 * Implementation of EnumPrintersA|W
3259 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3260 DWORD dwLevel, LPBYTE lpbPrinters,
3261 DWORD cbBuf, LPDWORD lpdwNeeded,
3262 LPDWORD lpdwReturned, BOOL unicode)
3265 HKEY hkeyPrinters, hkeyPrinter;
3266 WCHAR PrinterName[255];
3267 DWORD needed = 0, number = 0;
3268 DWORD used, i, left;
3269 PBYTE pi, buf;
3271 if(lpbPrinters)
3272 memset(lpbPrinters, 0, cbBuf);
3273 if(lpdwReturned)
3274 *lpdwReturned = 0;
3275 if(lpdwNeeded)
3276 *lpdwNeeded = 0;
3278 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3279 if(dwType == PRINTER_ENUM_DEFAULT)
3280 return TRUE;
3282 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3283 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3284 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3285 if(!dwType) return TRUE;
3288 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3289 FIXME("dwType = %08lx\n", dwType);
3290 SetLastError(ERROR_INVALID_FLAGS);
3291 return FALSE;
3294 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3295 ERROR_SUCCESS) {
3296 ERR("Can't create Printers key\n");
3297 return FALSE;
3300 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3301 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3302 RegCloseKey(hkeyPrinters);
3303 ERR("Can't query Printers key\n");
3304 return FALSE;
3306 TRACE("Found %ld printers\n", number);
3308 switch(dwLevel) {
3309 case 1:
3310 RegCloseKey(hkeyPrinters);
3311 if (lpdwReturned)
3312 *lpdwReturned = number;
3313 return TRUE;
3315 case 2:
3316 used = number * sizeof(PRINTER_INFO_2W);
3317 break;
3318 case 4:
3319 used = number * sizeof(PRINTER_INFO_4W);
3320 break;
3321 case 5:
3322 used = number * sizeof(PRINTER_INFO_5W);
3323 break;
3325 default:
3326 SetLastError(ERROR_INVALID_LEVEL);
3327 RegCloseKey(hkeyPrinters);
3328 return FALSE;
3330 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3332 for(i = 0; i < number; i++) {
3333 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3334 ERROR_SUCCESS) {
3335 ERR("Can't enum key number %ld\n", i);
3336 RegCloseKey(hkeyPrinters);
3337 return FALSE;
3339 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3340 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3341 ERROR_SUCCESS) {
3342 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3343 RegCloseKey(hkeyPrinters);
3344 return FALSE;
3347 if(cbBuf > used) {
3348 buf = lpbPrinters + used;
3349 left = cbBuf - used;
3350 } else {
3351 buf = NULL;
3352 left = 0;
3355 switch(dwLevel) {
3356 case 2:
3357 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3358 left, &needed, unicode);
3359 used += needed;
3360 if(pi) pi += sizeof(PRINTER_INFO_2W);
3361 break;
3362 case 4:
3363 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3364 left, &needed, unicode);
3365 used += needed;
3366 if(pi) pi += sizeof(PRINTER_INFO_4W);
3367 break;
3368 case 5:
3369 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3370 left, &needed, unicode);
3371 used += needed;
3372 if(pi) pi += sizeof(PRINTER_INFO_5W);
3373 break;
3374 default:
3375 ERR("Shouldn't be here!\n");
3376 RegCloseKey(hkeyPrinter);
3377 RegCloseKey(hkeyPrinters);
3378 return FALSE;
3380 RegCloseKey(hkeyPrinter);
3382 RegCloseKey(hkeyPrinters);
3384 if(lpdwNeeded)
3385 *lpdwNeeded = used;
3387 if(used > cbBuf) {
3388 if(lpbPrinters)
3389 memset(lpbPrinters, 0, cbBuf);
3390 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3391 return FALSE;
3393 if(lpdwReturned)
3394 *lpdwReturned = number;
3395 SetLastError(ERROR_SUCCESS);
3396 return TRUE;
3400 /******************************************************************
3401 * EnumPrintersW [WINSPOOL.@]
3403 * Enumerates the available printers, print servers and print
3404 * providers, depending on the specified flags, name and level.
3406 * RETURNS:
3408 * If level is set to 1:
3409 * Not implemented yet!
3410 * Returns TRUE with an empty list.
3412 * If level is set to 2:
3413 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3414 * Returns an array of PRINTER_INFO_2 data structures in the
3415 * lpbPrinters buffer. Note that according to MSDN also an
3416 * OpenPrinter should be performed on every remote printer.
3418 * If level is set to 4 (officially WinNT only):
3419 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3420 * Fast: Only the registry is queried to retrieve printer names,
3421 * no connection to the driver is made.
3422 * Returns an array of PRINTER_INFO_4 data structures in the
3423 * lpbPrinters buffer.
3425 * If level is set to 5 (officially WinNT4/Win9x only):
3426 * Fast: Only the registry is queried to retrieve printer names,
3427 * no connection to the driver is made.
3428 * Returns an array of PRINTER_INFO_5 data structures in the
3429 * lpbPrinters buffer.
3431 * If level set to 3 or 6+:
3432 * returns zero (failure!)
3434 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3435 * for information.
3437 * BUGS:
3438 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3439 * - Only levels 2, 4 and 5 are implemented at the moment.
3440 * - 16-bit printer drivers are not enumerated.
3441 * - Returned amount of bytes used/needed does not match the real Windoze
3442 * implementation (as in this implementation, all strings are part
3443 * of the buffer, whereas Win32 keeps them somewhere else)
3444 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3446 * NOTE:
3447 * - In a regular Wine installation, no registry settings for printers
3448 * exist, which makes this function return an empty list.
3450 BOOL WINAPI EnumPrintersW(
3451 DWORD dwType, /* [in] Types of print objects to enumerate */
3452 LPWSTR lpszName, /* [in] name of objects to enumerate */
3453 DWORD dwLevel, /* [in] type of printer info structure */
3454 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3455 DWORD cbBuf, /* [in] max size of buffer in bytes */
3456 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3457 LPDWORD lpdwReturned /* [out] number of entries returned */
3460 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3461 lpdwNeeded, lpdwReturned, TRUE);
3464 /******************************************************************
3465 * EnumPrintersA [WINSPOOL.@]
3468 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3469 DWORD dwLevel, LPBYTE lpbPrinters,
3470 DWORD cbBuf, LPDWORD lpdwNeeded,
3471 LPDWORD lpdwReturned)
3473 BOOL ret;
3474 UNICODE_STRING lpszNameW;
3475 PWSTR pwstrNameW;
3477 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3478 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3479 lpdwNeeded, lpdwReturned, FALSE);
3480 RtlFreeUnicodeString(&lpszNameW);
3481 return ret;
3484 /*****************************************************************************
3485 * WINSPOOL_GetDriverInfoFromReg [internal]
3487 * Enters the information from the registry into the DRIVER_INFO struct
3489 * RETURNS
3490 * zero if the printer driver does not exist in the registry
3491 * (only if Level > 1) otherwise nonzero
3493 static BOOL WINSPOOL_GetDriverInfoFromReg(
3494 HKEY hkeyDrivers,
3495 LPWSTR DriverName,
3496 LPWSTR pEnvironment,
3497 DWORD Level,
3498 LPBYTE ptr, /* DRIVER_INFO */
3499 LPBYTE pDriverStrings, /* strings buffer */
3500 DWORD cbBuf, /* size of string buffer */
3501 LPDWORD pcbNeeded, /* space needed for str. */
3502 BOOL unicode) /* type of strings */
3504 DWORD size, tmp;
3505 HKEY hkeyDriver;
3506 LPBYTE strPtr = pDriverStrings;
3508 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3509 debugstr_w(DriverName), debugstr_w(pEnvironment),
3510 Level, ptr, pDriverStrings, cbBuf, unicode);
3512 if(unicode) {
3513 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3514 if (*pcbNeeded <= cbBuf)
3515 strcpyW((LPWSTR)strPtr, DriverName);
3516 } else {
3517 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3518 NULL, NULL);
3519 if(*pcbNeeded <= cbBuf)
3520 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3521 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3523 if(Level == 1) {
3524 if(ptr)
3525 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3526 return TRUE;
3527 } else {
3528 if(ptr)
3529 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3530 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3533 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3534 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3535 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3536 return FALSE;
3539 if(ptr)
3540 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3542 if(!pEnvironment)
3543 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3544 if(unicode)
3545 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3546 else
3547 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3548 NULL, NULL);
3549 *pcbNeeded += size;
3550 if(*pcbNeeded <= cbBuf) {
3551 if(unicode)
3552 strcpyW((LPWSTR)strPtr, pEnvironment);
3553 else
3554 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3555 (LPSTR)strPtr, size, NULL, NULL);
3556 if(ptr)
3557 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3558 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3561 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3562 unicode)) {
3563 *pcbNeeded += size;
3564 if(*pcbNeeded <= cbBuf)
3565 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3566 unicode);
3567 if(ptr)
3568 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3569 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3572 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3573 unicode)) {
3574 *pcbNeeded += size;
3575 if(*pcbNeeded <= cbBuf)
3576 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3577 &tmp, unicode);
3578 if(ptr)
3579 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3580 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3583 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3584 0, &size, unicode)) {
3585 *pcbNeeded += size;
3586 if(*pcbNeeded <= cbBuf)
3587 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3588 size, &tmp, unicode);
3589 if(ptr)
3590 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3591 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3594 if(Level == 2 ) {
3595 RegCloseKey(hkeyDriver);
3596 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3597 return TRUE;
3600 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3601 unicode)) {
3602 *pcbNeeded += size;
3603 if(*pcbNeeded <= cbBuf)
3604 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3605 size, &tmp, unicode);
3606 if(ptr)
3607 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3608 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3611 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3612 &size, unicode)) {
3613 *pcbNeeded += size;
3614 if(*pcbNeeded <= cbBuf)
3615 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3616 size, &tmp, unicode);
3617 if(ptr)
3618 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3619 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3622 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3623 unicode)) {
3624 *pcbNeeded += size;
3625 if(*pcbNeeded <= cbBuf)
3626 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3627 size, &tmp, unicode);
3628 if(ptr)
3629 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3630 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3633 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3634 unicode)) {
3635 *pcbNeeded += size;
3636 if(*pcbNeeded <= cbBuf)
3637 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3638 size, &tmp, unicode);
3639 if(ptr)
3640 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3641 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3644 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3645 RegCloseKey(hkeyDriver);
3646 return TRUE;
3649 /*****************************************************************************
3650 * WINSPOOL_GetPrinterDriver
3652 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3653 DWORD Level, LPBYTE pDriverInfo,
3654 DWORD cbBuf, LPDWORD pcbNeeded,
3655 BOOL unicode)
3657 LPCWSTR name;
3658 WCHAR DriverName[100];
3659 DWORD ret, type, size, needed = 0;
3660 LPBYTE ptr = NULL;
3661 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3663 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3664 Level,pDriverInfo,cbBuf, pcbNeeded);
3666 ZeroMemory(pDriverInfo, cbBuf);
3668 if (!(name = get_opened_printer_name(hPrinter))) {
3669 SetLastError(ERROR_INVALID_HANDLE);
3670 return FALSE;
3672 if(Level < 1 || Level > 6) {
3673 SetLastError(ERROR_INVALID_LEVEL);
3674 return FALSE;
3676 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3677 ERROR_SUCCESS) {
3678 ERR("Can't create Printers key\n");
3679 return FALSE;
3681 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3682 != ERROR_SUCCESS) {
3683 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3684 RegCloseKey(hkeyPrinters);
3685 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3686 return FALSE;
3688 size = sizeof(DriverName);
3689 DriverName[0] = 0;
3690 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3691 (LPBYTE)DriverName, &size);
3692 RegCloseKey(hkeyPrinter);
3693 RegCloseKey(hkeyPrinters);
3694 if(ret != ERROR_SUCCESS) {
3695 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3696 return FALSE;
3699 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3700 if(!hkeyDrivers) {
3701 ERR("Can't create Drivers key\n");
3702 return FALSE;
3705 switch(Level) {
3706 case 1:
3707 size = sizeof(DRIVER_INFO_1W);
3708 break;
3709 case 2:
3710 size = sizeof(DRIVER_INFO_2W);
3711 break;
3712 case 3:
3713 size = sizeof(DRIVER_INFO_3W);
3714 break;
3715 case 4:
3716 size = sizeof(DRIVER_INFO_4W);
3717 break;
3718 case 5:
3719 size = sizeof(DRIVER_INFO_5W);
3720 break;
3721 case 6:
3722 size = sizeof(DRIVER_INFO_6W);
3723 break;
3724 default:
3725 ERR("Invalid level\n");
3726 return FALSE;
3729 if(size <= cbBuf)
3730 ptr = pDriverInfo + size;
3732 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3733 pEnvironment, Level, pDriverInfo,
3734 (cbBuf < size) ? NULL : ptr,
3735 (cbBuf < size) ? 0 : cbBuf - size,
3736 &needed, unicode)) {
3737 RegCloseKey(hkeyDrivers);
3738 return FALSE;
3741 RegCloseKey(hkeyDrivers);
3743 if(pcbNeeded) *pcbNeeded = size + needed;
3744 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3745 if(cbBuf >= needed) return TRUE;
3746 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3747 return FALSE;
3750 /*****************************************************************************
3751 * GetPrinterDriverA [WINSPOOL.@]
3753 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3754 DWORD Level, LPBYTE pDriverInfo,
3755 DWORD cbBuf, LPDWORD pcbNeeded)
3757 BOOL ret;
3758 UNICODE_STRING pEnvW;
3759 PWSTR pwstrEnvW;
3761 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3762 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3763 cbBuf, pcbNeeded, FALSE);
3764 RtlFreeUnicodeString(&pEnvW);
3765 return ret;
3767 /*****************************************************************************
3768 * GetPrinterDriverW [WINSPOOL.@]
3770 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3771 DWORD Level, LPBYTE pDriverInfo,
3772 DWORD cbBuf, LPDWORD pcbNeeded)
3774 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3775 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3778 /*****************************************************************************
3779 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3781 * Return the PATH for the Printer-Drivers (UNICODE)
3783 * PARAMS
3784 * pName [I] Servername (NT only) or NULL (local Computer)
3785 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3786 * Level [I] Structure-Level (must be 1)
3787 * pDriverDirectory [O] PTR to Buffer that receives the Result
3788 * cbBuf [I] Size of Buffer at pDriverDirectory
3789 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3790 * required for pDriverDirectory
3792 * RETURNS
3793 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3794 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3795 * if cbBuf is too small
3797 * Native Values returned in pDriverDirectory on Success:
3798 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3799 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3800 *| win9x(Windows 4.0): "%winsysdir%"
3802 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3804 * FIXME
3805 *- Only NULL or "" is supported for pName
3808 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3809 DWORD Level, LPBYTE pDriverDirectory,
3810 DWORD cbBuf, LPDWORD pcbNeeded)
3812 DWORD needed;
3813 const printenv_t * env;
3815 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3816 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3817 if(pName != NULL && pName[0]) {
3818 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3819 SetLastError(ERROR_INVALID_PARAMETER);
3820 return FALSE;
3823 env = validate_envW(pEnvironment);
3824 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3826 if(Level != 1) {
3827 WARN("(Level: %ld) is ignored in win9x\n", Level);
3828 SetLastError(ERROR_INVALID_LEVEL);
3829 return FALSE;
3832 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3833 needed = GetSystemDirectoryW(NULL, 0);
3834 /* add the Size for the Subdirectories */
3835 needed += lstrlenW(spooldriversW);
3836 needed += lstrlenW(env->subdir);
3837 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3839 if(pcbNeeded)
3840 *pcbNeeded = needed;
3841 TRACE("required: 0x%lx/%ld\n", needed, needed);
3842 if(needed > cbBuf) {
3843 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3844 return FALSE;
3846 if(pcbNeeded == NULL) {
3847 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3848 SetLastError(RPC_X_NULL_REF_POINTER);
3849 return FALSE;
3851 if(pDriverDirectory == NULL) {
3852 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3853 SetLastError(ERROR_INVALID_USER_BUFFER);
3854 return FALSE;
3857 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3858 /* add the Subdirectories */
3859 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3860 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3861 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3862 return TRUE;
3866 /*****************************************************************************
3867 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3869 * Return the PATH for the Printer-Drivers (ANSI)
3871 * See GetPrinterDriverDirectoryW.
3873 * NOTES
3874 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3877 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3878 DWORD Level, LPBYTE pDriverDirectory,
3879 DWORD cbBuf, LPDWORD pcbNeeded)
3881 UNICODE_STRING nameW, environmentW;
3882 BOOL ret;
3883 DWORD pcbNeededW;
3884 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3885 WCHAR *driverDirectoryW = NULL;
3887 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3888 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3890 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3892 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3893 else nameW.Buffer = NULL;
3894 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3895 else environmentW.Buffer = NULL;
3897 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3898 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3899 if (ret) {
3900 DWORD needed;
3901 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3902 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3903 if(pcbNeeded)
3904 *pcbNeeded = needed;
3905 ret = (needed <= cbBuf) ? TRUE : FALSE;
3906 } else
3907 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3909 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3911 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3912 RtlFreeUnicodeString(&environmentW);
3913 RtlFreeUnicodeString(&nameW);
3915 return ret;
3918 /*****************************************************************************
3919 * AddPrinterDriverA [WINSPOOL.@]
3921 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3923 DRIVER_INFO_3A di3;
3924 HKEY hkeyDrivers, hkeyName;
3926 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3928 if(level != 2 && level != 3) {
3929 SetLastError(ERROR_INVALID_LEVEL);
3930 return FALSE;
3932 if(pName != NULL) {
3933 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3934 SetLastError(ERROR_INVALID_PARAMETER);
3935 return FALSE;
3937 if(!pDriverInfo) {
3938 WARN("pDriverInfo == NULL\n");
3939 SetLastError(ERROR_INVALID_PARAMETER);
3940 return FALSE;
3943 if(level == 3)
3944 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3945 else {
3946 memset(&di3, 0, sizeof(di3));
3947 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3950 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3951 !di3.pDataFile) {
3952 SetLastError(ERROR_INVALID_PARAMETER);
3953 return FALSE;
3955 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3956 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3957 if(!di3.pHelpFile) di3.pHelpFile = "";
3958 if(!di3.pMonitorName) di3.pMonitorName = "";
3960 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3962 if(!hkeyDrivers) {
3963 ERR("Can't create Drivers key\n");
3964 return FALSE;
3967 if(level == 2) { /* apparently can't overwrite with level2 */
3968 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3969 RegCloseKey(hkeyName);
3970 RegCloseKey(hkeyDrivers);
3971 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3972 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3973 return FALSE;
3976 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3977 RegCloseKey(hkeyDrivers);
3978 ERR("Can't create Name key\n");
3979 return FALSE;
3981 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3983 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3984 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3985 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3986 sizeof(DWORD));
3987 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3988 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3989 (LPBYTE) di3.pDependentFiles, 0);
3990 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3991 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3992 RegCloseKey(hkeyName);
3993 RegCloseKey(hkeyDrivers);
3995 return TRUE;
3998 /*****************************************************************************
3999 * AddPrinterDriverW [WINSPOOL.@]
4001 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4002 LPBYTE pDriverInfo)
4004 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
4005 level,pDriverInfo);
4006 return FALSE;
4009 /*****************************************************************************
4010 * AddPrintProcessorA [WINSPOOL.@]
4012 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4013 LPSTR pPrintProcessorName)
4015 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4016 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4017 return FALSE;
4020 /*****************************************************************************
4021 * AddPrintProcessorW [WINSPOOL.@]
4023 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4024 LPWSTR pPrintProcessorName)
4026 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4027 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4028 return FALSE;
4031 /*****************************************************************************
4032 * AddPrintProvidorA [WINSPOOL.@]
4034 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4036 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4037 return FALSE;
4040 /*****************************************************************************
4041 * AddPrintProvidorW [WINSPOOL.@]
4043 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4045 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4046 return FALSE;
4049 /*****************************************************************************
4050 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4052 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4053 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4055 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4056 pDevModeOutput, pDevModeInput);
4057 return 0;
4060 /*****************************************************************************
4061 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4063 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4064 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4066 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4067 pDevModeOutput, pDevModeInput);
4068 return 0;
4071 /*****************************************************************************
4072 * PrinterProperties [WINSPOOL.@]
4074 * Displays a dialog to set the properties of the printer.
4076 * RETURNS
4077 * nonzero on success or zero on failure
4079 * BUGS
4080 * implemented as stub only
4082 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4083 HANDLE hPrinter /* [in] handle to printer object */
4085 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4086 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4087 return FALSE;
4090 /*****************************************************************************
4091 * EnumJobsA [WINSPOOL.@]
4094 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4095 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4096 LPDWORD pcReturned)
4098 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4099 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4101 if(pcbNeeded) *pcbNeeded = 0;
4102 if(pcReturned) *pcReturned = 0;
4103 return FALSE;
4107 /*****************************************************************************
4108 * EnumJobsW [WINSPOOL.@]
4111 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4112 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4113 LPDWORD pcReturned)
4115 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4116 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4118 if(pcbNeeded) *pcbNeeded = 0;
4119 if(pcReturned) *pcReturned = 0;
4120 return FALSE;
4123 /*****************************************************************************
4124 * WINSPOOL_EnumPrinterDrivers [internal]
4126 * Delivers information about all printer drivers installed on the
4127 * localhost or a given server
4129 * RETURNS
4130 * nonzero on success or zero on failure. If the buffer for the returned
4131 * information is too small the function will return an error
4133 * BUGS
4134 * - only implemented for localhost, foreign hosts will return an error
4136 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4137 DWORD Level, LPBYTE pDriverInfo,
4138 DWORD cbBuf, LPDWORD pcbNeeded,
4139 LPDWORD pcReturned, BOOL unicode)
4141 { HKEY hkeyDrivers;
4142 DWORD i, needed, number = 0, size = 0;
4143 WCHAR DriverNameW[255];
4144 PBYTE ptr;
4146 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4147 debugstr_w(pName), debugstr_w(pEnvironment),
4148 Level, pDriverInfo, cbBuf, unicode);
4150 /* check for local drivers */
4151 if((pName) && (pName[0])) {
4152 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4153 SetLastError(ERROR_ACCESS_DENIED);
4154 return FALSE;
4157 /* check input parameter */
4158 if((Level < 1) || (Level > 3)) {
4159 ERR("unsupported level %ld\n", Level);
4160 SetLastError(ERROR_INVALID_LEVEL);
4161 return FALSE;
4164 /* initialize return values */
4165 if(pDriverInfo)
4166 memset( pDriverInfo, 0, cbBuf);
4167 *pcbNeeded = 0;
4168 *pcReturned = 0;
4170 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4171 if(!hkeyDrivers) {
4172 ERR("Can't open Drivers key\n");
4173 return FALSE;
4176 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4177 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4178 RegCloseKey(hkeyDrivers);
4179 ERR("Can't query Drivers key\n");
4180 return FALSE;
4182 TRACE("Found %ld Drivers\n", number);
4184 /* get size of single struct
4185 * unicode and ascii structure have the same size
4187 switch (Level) {
4188 case 1:
4189 size = sizeof(DRIVER_INFO_1A);
4190 break;
4191 case 2:
4192 size = sizeof(DRIVER_INFO_2A);
4193 break;
4194 case 3:
4195 size = sizeof(DRIVER_INFO_3A);
4196 break;
4199 /* calculate required buffer size */
4200 *pcbNeeded = size * number;
4202 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4203 i < number;
4204 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4205 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4206 != ERROR_SUCCESS) {
4207 ERR("Can't enum key number %ld\n", i);
4208 RegCloseKey(hkeyDrivers);
4209 return FALSE;
4211 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4212 pEnvironment, Level, ptr,
4213 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4214 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4215 &needed, unicode)) {
4216 RegCloseKey(hkeyDrivers);
4217 return FALSE;
4219 (*pcbNeeded) += needed;
4222 RegCloseKey(hkeyDrivers);
4224 if(cbBuf < *pcbNeeded){
4225 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4226 return FALSE;
4229 *pcReturned = number;
4230 return TRUE;
4233 /*****************************************************************************
4234 * EnumPrinterDriversW [WINSPOOL.@]
4236 * see function EnumPrinterDrivers for RETURNS, BUGS
4238 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4239 LPBYTE pDriverInfo, DWORD cbBuf,
4240 LPDWORD pcbNeeded, LPDWORD pcReturned)
4242 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4243 cbBuf, pcbNeeded, pcReturned, TRUE);
4246 /*****************************************************************************
4247 * EnumPrinterDriversA [WINSPOOL.@]
4249 * see function EnumPrinterDrivers for RETURNS, BUGS
4251 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4252 LPBYTE pDriverInfo, DWORD cbBuf,
4253 LPDWORD pcbNeeded, LPDWORD pcReturned)
4254 { BOOL ret;
4255 UNICODE_STRING pNameW, pEnvironmentW;
4256 PWSTR pwstrNameW, pwstrEnvironmentW;
4258 pwstrNameW = asciitounicode(&pNameW, pName);
4259 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4261 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4262 Level, pDriverInfo, cbBuf, pcbNeeded,
4263 pcReturned, FALSE);
4264 RtlFreeUnicodeString(&pNameW);
4265 RtlFreeUnicodeString(&pEnvironmentW);
4267 return ret;
4270 static CHAR PortMonitor[] = "Wine Port Monitor";
4271 static CHAR PortDescription[] = "Wine Port";
4273 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4275 HANDLE handle;
4277 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4278 NULL, OPEN_EXISTING, 0, NULL );
4279 if (handle == INVALID_HANDLE_VALUE)
4280 return FALSE;
4281 TRACE("Checking %s exists\n", name );
4282 CloseHandle( handle );
4283 return TRUE;
4286 static DWORD WINSPOOL_CountSerialPorts(void)
4288 CHAR name[6];
4289 DWORD n = 0, i;
4291 for (i=0; i<4; i++)
4293 strcpy( name, "COMx:" );
4294 name[3] = '1' + i;
4295 if (WINSPOOL_ComPortExists( name ))
4296 n++;
4299 return n;
4302 /******************************************************************************
4303 * EnumPortsA (WINSPOOL.@)
4305 * See EnumPortsW.
4307 * BUGS
4308 * ANSI-Version did not call the UNICODE-Version
4311 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4312 LPDWORD bufneeded,LPDWORD bufreturned)
4314 CHAR portname[10];
4315 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4316 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4317 HKEY hkey_printer;
4318 BOOL retval = TRUE;
4320 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4321 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4323 switch( level )
4325 case 1:
4326 info_size = sizeof (PORT_INFO_1A);
4327 break;
4328 case 2:
4329 info_size = sizeof (PORT_INFO_2A);
4330 break;
4331 default:
4332 SetLastError(ERROR_INVALID_LEVEL);
4333 return FALSE;
4336 /* see how many exist */
4338 hkey_printer = 0;
4339 serial_count = WINSPOOL_CountSerialPorts();
4340 printer_count = 0;
4342 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4343 if ( r == ERROR_SUCCESS )
4345 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4346 &printer_count, NULL, NULL, NULL, NULL);
4348 count = serial_count + printer_count;
4350 /* then fill in the structure info structure once
4351 we know the offset to the first string */
4353 memset( buffer, 0, bufsize );
4354 n = 0;
4355 ofs = info_size*count;
4356 for ( i=0; i<count; i++)
4358 DWORD vallen = sizeof(portname) - 1;
4360 /* get the serial port values, then the printer values */
4361 if ( i < serial_count )
4363 strcpy( portname, "COMx:" );
4364 portname[3] = '1' + i;
4365 if (!WINSPOOL_ComPortExists( portname ))
4366 continue;
4368 TRACE("Found %s\n", portname );
4369 vallen = strlen( portname );
4371 else
4373 r = RegEnumValueA( hkey_printer, i-serial_count,
4374 portname, &vallen, NULL, NULL, NULL, 0 );
4375 if ( r )
4376 continue;
4379 /* add a colon if necessary, and make it upper case */
4380 CharUpperBuffA(portname,vallen);
4381 if (strcasecmp(portname,"nul")!=0)
4382 if (vallen && (portname[vallen-1] != ':') )
4383 lstrcatA(portname,":");
4385 /* add the port info structure if we can fit it */
4386 if ( info_size*(n+1) < bufsize )
4388 if ( level == 1)
4390 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4391 info->pName = (LPSTR) &buffer[ofs];
4393 else if ( level == 2)
4395 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4396 info->pPortName = (LPSTR) &buffer[ofs];
4397 /* FIXME: fill in more stuff here */
4398 info->pMonitorName = PortMonitor;
4399 info->pDescription = PortDescription;
4400 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4403 /* add the name of the port if we can fit it */
4404 if ( ofs < bufsize )
4405 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4407 n++;
4409 else
4410 retval = FALSE;
4411 ofs += lstrlenA(portname)+1;
4414 RegCloseKey(hkey_printer);
4416 if(bufneeded)
4417 *bufneeded = ofs;
4419 if(bufreturned)
4420 *bufreturned = n;
4422 return retval;
4425 /******************************************************************************
4426 * EnumPortsW (WINSPOOL.@)
4428 * Enumerate available Ports
4430 * PARAMS
4431 * name [I] Servername or NULL (local Computer)
4432 * level [I] Structure-Level (1 or 2)
4433 * buffer [O] PTR to Buffer that receives the Result
4434 * bufsize [I] Size of Buffer at buffer
4435 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4436 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4438 * RETURNS
4439 * Success: TRUE
4440 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4442 * BUGS
4443 * UNICODE-Version is a stub
4446 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4447 LPDWORD bufneeded,LPDWORD bufreturned)
4449 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4450 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4451 return FALSE;
4454 /******************************************************************************
4455 * GetDefaultPrinterW (WINSPOOL.@)
4457 * FIXME
4458 * This function must read the value from data 'device' of key
4459 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4461 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4463 BOOL retval = TRUE;
4464 DWORD insize, len;
4465 WCHAR *buffer, *ptr;
4467 if (!namesize)
4469 SetLastError(ERROR_INVALID_PARAMETER);
4470 return FALSE;
4473 /* make the buffer big enough for the stuff from the profile/registry,
4474 * the content must fit into the local buffer to compute the correct
4475 * size even if the extern buffer is too small or not given.
4476 * (20 for ,driver,port) */
4477 insize = *namesize;
4478 len = max(100, (insize + 20));
4479 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4481 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4483 SetLastError (ERROR_FILE_NOT_FOUND);
4484 retval = FALSE;
4485 goto end;
4487 TRACE("%s\n", debugstr_w(buffer));
4489 if ((ptr = strchrW(buffer, ',')) == NULL)
4491 SetLastError(ERROR_INVALID_NAME);
4492 retval = FALSE;
4493 goto end;
4496 *ptr = 0;
4497 *namesize = strlenW(buffer) + 1;
4498 if(!name || (*namesize > insize))
4500 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4501 retval = FALSE;
4502 goto end;
4504 strcpyW(name, buffer);
4506 end:
4507 HeapFree( GetProcessHeap(), 0, buffer);
4508 return retval;
4512 /******************************************************************************
4513 * GetDefaultPrinterA (WINSPOOL.@)
4515 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4517 BOOL retval = TRUE;
4518 DWORD insize = 0;
4519 WCHAR *bufferW = NULL;
4521 if (!namesize)
4523 SetLastError(ERROR_INVALID_PARAMETER);
4524 return FALSE;
4527 if(name && *namesize) {
4528 insize = *namesize;
4529 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4532 if(!GetDefaultPrinterW( bufferW, namesize)) {
4533 retval = FALSE;
4534 goto end;
4537 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4538 NULL, NULL);
4539 if (!*namesize)
4541 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4542 retval = FALSE;
4544 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4546 end:
4547 HeapFree( GetProcessHeap(), 0, bufferW);
4548 return retval;
4552 /******************************************************************************
4553 * SetDefaultPrinterW (WINSPOOL.204)
4555 * Set the Name of the Default Printer
4557 * PARAMS
4558 * pszPrinter [I] Name of the Printer or NULL
4560 * RETURNS
4561 * Success: True
4562 * Failure: FALSE
4564 * NOTES
4565 * When the Parameter is NULL or points to an Empty String and
4566 * a Default Printer was already present, then this Function changes nothing.
4567 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4568 * the First enumerated local Printer is used.
4571 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4574 TRACE("(%s)\n", debugstr_w(pszPrinter));
4576 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4577 return FALSE;
4580 /******************************************************************************
4581 * SetDefaultPrinterA (WINSPOOL.202)
4583 * See SetDefaultPrinterW.
4586 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4589 TRACE("(%s)\n", debugstr_a(pszPrinter));
4591 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4592 return FALSE;
4596 /******************************************************************************
4597 * SetPrinterDataExA (WINSPOOL.@)
4599 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4600 LPCSTR pValueName, DWORD Type,
4601 LPBYTE pData, DWORD cbData)
4603 HKEY hkeyPrinter, hkeySubkey;
4604 DWORD ret;
4606 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4607 debugstr_a(pValueName), Type, pData, cbData);
4609 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4610 != ERROR_SUCCESS)
4611 return ret;
4613 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4614 != ERROR_SUCCESS) {
4615 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4616 RegCloseKey(hkeyPrinter);
4617 return ret;
4619 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4620 RegCloseKey(hkeySubkey);
4621 RegCloseKey(hkeyPrinter);
4622 return ret;
4625 /******************************************************************************
4626 * SetPrinterDataExW (WINSPOOL.@)
4628 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4629 LPCWSTR pValueName, DWORD Type,
4630 LPBYTE pData, DWORD cbData)
4632 HKEY hkeyPrinter, hkeySubkey;
4633 DWORD ret;
4635 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4636 debugstr_w(pValueName), Type, pData, cbData);
4638 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4639 != ERROR_SUCCESS)
4640 return ret;
4642 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4643 != ERROR_SUCCESS) {
4644 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4645 RegCloseKey(hkeyPrinter);
4646 return ret;
4648 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4649 RegCloseKey(hkeySubkey);
4650 RegCloseKey(hkeyPrinter);
4651 return ret;
4654 /******************************************************************************
4655 * SetPrinterDataA (WINSPOOL.@)
4657 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4658 LPBYTE pData, DWORD cbData)
4660 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4661 pData, cbData);
4664 /******************************************************************************
4665 * SetPrinterDataW (WINSPOOL.@)
4667 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4668 LPBYTE pData, DWORD cbData)
4670 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4671 pData, cbData);
4674 /******************************************************************************
4675 * GetPrinterDataExA (WINSPOOL.@)
4677 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4678 LPCSTR pValueName, LPDWORD pType,
4679 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4681 HKEY hkeyPrinter, hkeySubkey;
4682 DWORD ret;
4684 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4685 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4686 pcbNeeded);
4688 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4689 != ERROR_SUCCESS)
4690 return ret;
4692 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4693 != ERROR_SUCCESS) {
4694 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4695 RegCloseKey(hkeyPrinter);
4696 return ret;
4698 *pcbNeeded = nSize;
4699 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4700 RegCloseKey(hkeySubkey);
4701 RegCloseKey(hkeyPrinter);
4702 return ret;
4705 /******************************************************************************
4706 * GetPrinterDataExW (WINSPOOL.@)
4708 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4709 LPCWSTR pValueName, LPDWORD pType,
4710 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4712 HKEY hkeyPrinter, hkeySubkey;
4713 DWORD ret;
4715 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4716 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4717 pcbNeeded);
4719 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4720 != ERROR_SUCCESS)
4721 return ret;
4723 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4724 != ERROR_SUCCESS) {
4725 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4726 RegCloseKey(hkeyPrinter);
4727 return ret;
4729 *pcbNeeded = nSize;
4730 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4731 RegCloseKey(hkeySubkey);
4732 RegCloseKey(hkeyPrinter);
4733 return ret;
4736 /******************************************************************************
4737 * GetPrinterDataA (WINSPOOL.@)
4739 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4740 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4742 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4743 pData, nSize, pcbNeeded);
4746 /******************************************************************************
4747 * GetPrinterDataW (WINSPOOL.@)
4749 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4750 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4752 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4753 pData, nSize, pcbNeeded);
4756 /*******************************************************************************
4757 * EnumPrinterDataExW [WINSPOOL.@]
4759 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4760 LPBYTE pEnumValues, DWORD cbEnumValues,
4761 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4763 HKEY hkPrinter, hkSubKey;
4764 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4765 cbValueNameLen, cbMaxValueLen, cbValueLen,
4766 cbBufSize, dwType;
4767 LPWSTR lpValueName;
4768 HANDLE hHeap;
4769 PBYTE lpValue;
4770 PPRINTER_ENUM_VALUESW ppev;
4772 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4774 if (pKeyName == NULL || *pKeyName == 0)
4775 return ERROR_INVALID_PARAMETER;
4777 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4778 if (ret != ERROR_SUCCESS)
4780 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4781 hPrinter, ret);
4782 return ret;
4785 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4786 if (ret != ERROR_SUCCESS)
4788 r = RegCloseKey (hkPrinter);
4789 if (r != ERROR_SUCCESS)
4790 WARN ("RegCloseKey returned %li\n", r);
4791 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4792 debugstr_w (pKeyName), ret);
4793 return ret;
4796 ret = RegCloseKey (hkPrinter);
4797 if (ret != ERROR_SUCCESS)
4799 ERR ("RegCloseKey returned %li\n", ret);
4800 r = RegCloseKey (hkSubKey);
4801 if (r != ERROR_SUCCESS)
4802 WARN ("RegCloseKey returned %li\n", r);
4803 return ret;
4806 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4807 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4808 if (ret != ERROR_SUCCESS)
4810 r = RegCloseKey (hkSubKey);
4811 if (r != ERROR_SUCCESS)
4812 WARN ("RegCloseKey returned %li\n", r);
4813 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4814 return ret;
4817 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4818 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4820 if (cValues == 0) /* empty key */
4822 r = RegCloseKey (hkSubKey);
4823 if (r != ERROR_SUCCESS)
4824 WARN ("RegCloseKey returned %li\n", r);
4825 *pcbEnumValues = *pnEnumValues = 0;
4826 return ERROR_SUCCESS;
4829 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4831 hHeap = GetProcessHeap ();
4832 if (hHeap == NULL)
4834 ERR ("GetProcessHeap failed\n");
4835 r = RegCloseKey (hkSubKey);
4836 if (r != ERROR_SUCCESS)
4837 WARN ("RegCloseKey returned %li\n", r);
4838 return ERROR_OUTOFMEMORY;
4841 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4842 if (lpValueName == NULL)
4844 ERR ("Failed to allocate %li bytes from process heap\n",
4845 cbMaxValueNameLen * sizeof (WCHAR));
4846 r = RegCloseKey (hkSubKey);
4847 if (r != ERROR_SUCCESS)
4848 WARN ("RegCloseKey returned %li\n", r);
4849 return ERROR_OUTOFMEMORY;
4852 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4853 if (lpValue == NULL)
4855 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4856 if (HeapFree (hHeap, 0, lpValueName) == 0)
4857 WARN ("HeapFree failed with code %li\n", GetLastError ());
4858 r = RegCloseKey (hkSubKey);
4859 if (r != ERROR_SUCCESS)
4860 WARN ("RegCloseKey returned %li\n", r);
4861 return ERROR_OUTOFMEMORY;
4864 TRACE ("pass 1: calculating buffer required for all names and values\n");
4866 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4868 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4870 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4872 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4873 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4874 NULL, NULL, lpValue, &cbValueLen);
4875 if (ret != ERROR_SUCCESS)
4877 if (HeapFree (hHeap, 0, lpValue) == 0)
4878 WARN ("HeapFree failed with code %li\n", GetLastError ());
4879 if (HeapFree (hHeap, 0, lpValueName) == 0)
4880 WARN ("HeapFree failed with code %li\n", GetLastError ());
4881 r = RegCloseKey (hkSubKey);
4882 if (r != ERROR_SUCCESS)
4883 WARN ("RegCloseKey returned %li\n", r);
4884 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4885 return ret;
4888 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4889 debugstr_w (lpValueName), dwIndex,
4890 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4892 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4893 cbBufSize += cbValueLen;
4896 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4898 *pcbEnumValues = cbBufSize;
4899 *pnEnumValues = cValues;
4901 if (cbEnumValues < cbBufSize) /* buffer too small */
4903 if (HeapFree (hHeap, 0, lpValue) == 0)
4904 WARN ("HeapFree failed with code %li\n", GetLastError ());
4905 if (HeapFree (hHeap, 0, lpValueName) == 0)
4906 WARN ("HeapFree failed with code %li\n", GetLastError ());
4907 r = RegCloseKey (hkSubKey);
4908 if (r != ERROR_SUCCESS)
4909 WARN ("RegCloseKey returned %li\n", r);
4910 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4911 return ERROR_MORE_DATA;
4914 TRACE ("pass 2: copying all names and values to buffer\n");
4916 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4917 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4919 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4921 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4922 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4923 NULL, &dwType, lpValue, &cbValueLen);
4924 if (ret != ERROR_SUCCESS)
4926 if (HeapFree (hHeap, 0, lpValue) == 0)
4927 WARN ("HeapFree failed with code %li\n", GetLastError ());
4928 if (HeapFree (hHeap, 0, lpValueName) == 0)
4929 WARN ("HeapFree failed with code %li\n", GetLastError ());
4930 r = RegCloseKey (hkSubKey);
4931 if (r != ERROR_SUCCESS)
4932 WARN ("RegCloseKey returned %li\n", r);
4933 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4934 return ret;
4937 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4938 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4939 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4940 pEnumValues += cbValueNameLen;
4942 /* return # of *bytes* (including trailing \0), not # of chars */
4943 ppev[dwIndex].cbValueName = cbValueNameLen;
4945 ppev[dwIndex].dwType = dwType;
4947 memcpy (pEnumValues, lpValue, cbValueLen);
4948 ppev[dwIndex].pData = pEnumValues;
4949 pEnumValues += cbValueLen;
4951 ppev[dwIndex].cbData = cbValueLen;
4953 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4954 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4957 if (HeapFree (hHeap, 0, lpValue) == 0)
4959 ret = GetLastError ();
4960 ERR ("HeapFree failed with code %li\n", ret);
4961 if (HeapFree (hHeap, 0, lpValueName) == 0)
4962 WARN ("HeapFree failed with code %li\n", GetLastError ());
4963 r = RegCloseKey (hkSubKey);
4964 if (r != ERROR_SUCCESS)
4965 WARN ("RegCloseKey returned %li\n", r);
4966 return ret;
4969 if (HeapFree (hHeap, 0, lpValueName) == 0)
4971 ret = GetLastError ();
4972 ERR ("HeapFree failed with code %li\n", ret);
4973 r = RegCloseKey (hkSubKey);
4974 if (r != ERROR_SUCCESS)
4975 WARN ("RegCloseKey returned %li\n", r);
4976 return ret;
4979 ret = RegCloseKey (hkSubKey);
4980 if (ret != ERROR_SUCCESS)
4982 ERR ("RegCloseKey returned %li\n", ret);
4983 return ret;
4986 return ERROR_SUCCESS;
4989 /*******************************************************************************
4990 * EnumPrinterDataExA [WINSPOOL.@]
4992 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4993 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4994 * what Windows 2000 SP1 does.
4997 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4998 LPBYTE pEnumValues, DWORD cbEnumValues,
4999 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5001 INT len;
5002 LPWSTR pKeyNameW;
5003 DWORD ret, dwIndex, dwBufSize;
5004 HANDLE hHeap;
5005 LPSTR pBuffer;
5007 TRACE ("%p %s\n", hPrinter, pKeyName);
5009 if (pKeyName == NULL || *pKeyName == 0)
5010 return ERROR_INVALID_PARAMETER;
5012 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5013 if (len == 0)
5015 ret = GetLastError ();
5016 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5017 return ret;
5020 hHeap = GetProcessHeap ();
5021 if (hHeap == NULL)
5023 ERR ("GetProcessHeap failed\n");
5024 return ERROR_OUTOFMEMORY;
5027 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5028 if (pKeyNameW == NULL)
5030 ERR ("Failed to allocate %li bytes from process heap\n",
5031 (LONG) len * sizeof (WCHAR));
5032 return ERROR_OUTOFMEMORY;
5035 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5037 ret = GetLastError ();
5038 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5039 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5040 WARN ("HeapFree failed with code %li\n", GetLastError ());
5041 return ret;
5044 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5045 pcbEnumValues, pnEnumValues);
5046 if (ret != ERROR_SUCCESS)
5048 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5049 WARN ("HeapFree failed with code %li\n", GetLastError ());
5050 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5051 return ret;
5054 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5056 ret = GetLastError ();
5057 ERR ("HeapFree failed with code %li\n", ret);
5058 return ret;
5061 if (*pnEnumValues == 0) /* empty key */
5062 return ERROR_SUCCESS;
5064 dwBufSize = 0;
5065 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5067 PPRINTER_ENUM_VALUESW ppev =
5068 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5070 if (dwBufSize < ppev->cbValueName)
5071 dwBufSize = ppev->cbValueName;
5073 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5074 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5075 dwBufSize = ppev->cbData;
5078 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5080 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5081 if (pBuffer == NULL)
5083 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5084 return ERROR_OUTOFMEMORY;
5087 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5089 PPRINTER_ENUM_VALUESW ppev =
5090 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5092 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5093 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5094 NULL);
5095 if (len == 0)
5097 ret = GetLastError ();
5098 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5099 if (HeapFree (hHeap, 0, pBuffer) == 0)
5100 WARN ("HeapFree failed with code %li\n", GetLastError ());
5101 return ret;
5104 memcpy (ppev->pValueName, pBuffer, len);
5106 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5108 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5109 ppev->dwType != REG_MULTI_SZ)
5110 continue;
5112 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5113 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5114 if (len == 0)
5116 ret = GetLastError ();
5117 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5118 if (HeapFree (hHeap, 0, pBuffer) == 0)
5119 WARN ("HeapFree failed with code %li\n", GetLastError ());
5120 return ret;
5123 memcpy (ppev->pData, pBuffer, len);
5125 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5126 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5129 if (HeapFree (hHeap, 0, pBuffer) == 0)
5131 ret = GetLastError ();
5132 ERR ("HeapFree failed with code %li\n", ret);
5133 return ret;
5136 return ERROR_SUCCESS;
5139 /******************************************************************************
5140 * AbortPrinter (WINSPOOL.@)
5142 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5144 FIXME("(%p), stub!\n", hPrinter);
5145 return TRUE;
5148 /******************************************************************************
5149 * AddPortA (WINSPOOL.@)
5151 * See AddPortW.
5154 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5156 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5157 return FALSE;
5160 /******************************************************************************
5161 * AddPortW (WINSPOOL.@)
5163 * Add a Port for a specific Monitor
5165 * PARAMS
5166 * pName [I] Servername or NULL (local Computer)
5167 * hWnd [I] Handle to parent Window for the Dialog-Box
5168 * pMonitorName [I] Name of the Monitor that manage the Port
5170 * RETURNS
5171 * Success: TRUE
5172 * Failure: FALSE
5174 * BUGS
5175 * only a Stub
5178 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5180 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5181 return FALSE;
5184 /******************************************************************************
5185 * AddPortExA (WINSPOOL.@)
5187 * See AddPortExW.
5190 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5192 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5193 lpBuffer, debugstr_a(lpMonitorName));
5194 return FALSE;
5197 /******************************************************************************
5198 * AddPortExW (WINSPOOL.@)
5200 * Add a Port for a specific Monitor, without presenting a user interface
5202 * PARAMS
5203 * hMonitor [I] Handle from InitializePrintMonitor2()
5204 * pName [I] Servername or NULL (local Computer)
5205 * Level [I] Structure-Level (1 or 2) for lpBuffer
5206 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5207 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5209 * RETURNS
5210 * Success: TRUE
5211 * Failure: FALSE
5213 * BUGS
5214 * only a Stub
5217 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5219 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5220 lpBuffer, debugstr_w(lpMonitorName));
5221 return FALSE;
5224 /******************************************************************************
5225 * AddPrinterConnectionA (WINSPOOL.@)
5227 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5229 FIXME("%s\n", debugstr_a(pName));
5230 return FALSE;
5233 /******************************************************************************
5234 * AddPrinterConnectionW (WINSPOOL.@)
5236 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5238 FIXME("%s\n", debugstr_w(pName));
5239 return FALSE;
5242 /******************************************************************************
5243 * AddPrinterDriverExW (WINSPOOL.@)
5245 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5246 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5248 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5249 Level, pDriverInfo, dwFileCopyFlags);
5250 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5251 return FALSE;
5254 /******************************************************************************
5255 * AddPrinterDriverExA (WINSPOOL.@)
5257 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5258 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5260 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5261 Level, pDriverInfo, dwFileCopyFlags);
5262 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5263 return FALSE;
5266 /******************************************************************************
5267 * ConfigurePortA (WINSPOOL.@)
5269 * See ConfigurePortW.
5272 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5274 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5275 return FALSE;
5278 /******************************************************************************
5279 * ConfigurePortW (WINSPOOL.@)
5281 * Display the Configuration-Dialog for a specific Port
5283 * PARAMS
5284 * pName [I] Servername or NULL (local Computer)
5285 * hWnd [I] Handle to parent Window for the Dialog-Box
5286 * pPortName [I] Name of the Port, that should be configured
5288 * RETURNS
5289 * Success: TRUE
5290 * Failure: FALSE
5292 * BUGS
5293 * only a Stub
5296 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5298 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5299 return FALSE;
5302 /******************************************************************************
5303 * ConnectToPrinterDlg (WINSPOOL.@)
5305 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5307 FIXME("%p %lx\n", hWnd, Flags);
5308 return NULL;
5311 /******************************************************************************
5312 * DeletePrinterConnectionA (WINSPOOL.@)
5314 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5316 FIXME("%s\n", debugstr_a(pName));
5317 return TRUE;
5320 /******************************************************************************
5321 * DeletePrinterConnectionW (WINSPOOL.@)
5323 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5325 FIXME("%s\n", debugstr_w(pName));
5326 return TRUE;
5329 /******************************************************************************
5330 * DeletePrinterDriverExW (WINSPOOL.@)
5332 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5333 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5335 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5336 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5337 return TRUE;
5340 /******************************************************************************
5341 * DeletePrinterDriverExA (WINSPOOL.@)
5343 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5344 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5346 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5347 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5348 return TRUE;
5351 /******************************************************************************
5352 * DeletePrinterDataExW (WINSPOOL.@)
5354 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5355 LPCWSTR pValueName)
5357 FIXME("%p %s %s\n", hPrinter,
5358 debugstr_w(pKeyName), debugstr_w(pValueName));
5359 return ERROR_INVALID_PARAMETER;
5362 /******************************************************************************
5363 * DeletePrinterDataExA (WINSPOOL.@)
5365 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5366 LPCSTR pValueName)
5368 FIXME("%p %s %s\n", hPrinter,
5369 debugstr_a(pKeyName), debugstr_a(pValueName));
5370 return ERROR_INVALID_PARAMETER;
5373 /******************************************************************************
5374 * DeletePrintProcessorA (WINSPOOL.@)
5376 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5378 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5379 debugstr_a(pPrintProcessorName));
5380 return TRUE;
5383 /******************************************************************************
5384 * DeletePrintProcessorW (WINSPOOL.@)
5386 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5388 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5389 debugstr_w(pPrintProcessorName));
5390 return TRUE;
5393 /******************************************************************************
5394 * DeletePrintProvidorA (WINSPOOL.@)
5396 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5398 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5399 debugstr_a(pPrintProviderName));
5400 return TRUE;
5403 /******************************************************************************
5404 * DeletePrintProvidorW (WINSPOOL.@)
5406 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5408 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5409 debugstr_w(pPrintProviderName));
5410 return TRUE;
5413 /******************************************************************************
5414 * EnumFormsA (WINSPOOL.@)
5416 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5417 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5419 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5420 return FALSE;
5423 /******************************************************************************
5424 * EnumFormsW (WINSPOOL.@)
5426 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5427 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5429 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5430 return FALSE;
5433 /*****************************************************************************
5434 * EnumMonitorsA [WINSPOOL.@]
5436 * See EnumMonitorsW.
5439 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5440 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5442 BOOL res;
5443 LPBYTE bufferW = NULL;
5444 LPWSTR nameW = NULL;
5445 DWORD needed = 0;
5446 DWORD numentries = 0;
5447 INT len;
5449 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5450 cbBuf, pcbNeeded, pcReturned);
5452 /* convert servername to unicode */
5453 if (pName) {
5454 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5455 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5456 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5458 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5459 needed = cbBuf * sizeof(WCHAR);
5460 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5461 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5463 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5464 if (pcbNeeded) needed = *pcbNeeded;
5465 /* HeapReAlloc return NULL, when bufferW was NULL */
5466 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5467 HeapAlloc(GetProcessHeap(), 0, needed);
5469 /* Try again with the large Buffer */
5470 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5472 numentries = pcReturned ? *pcReturned : 0;
5473 needed = 0;
5475 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5476 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5478 if (res) {
5479 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5480 DWORD entrysize = 0;
5481 DWORD index;
5482 LPSTR ptr;
5483 LPMONITOR_INFO_2W mi2w;
5484 LPMONITOR_INFO_2A mi2a;
5486 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5487 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5489 /* First pass: calculate the size for all Entries */
5490 mi2w = (LPMONITOR_INFO_2W) bufferW;
5491 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5492 index = 0;
5493 while (index < numentries) {
5494 index++;
5495 needed += entrysize; /* MONITOR_INFO_?A */
5496 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5498 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5499 NULL, 0, NULL, NULL);
5500 if (Level > 1) {
5501 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5502 NULL, 0, NULL, NULL);
5503 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5504 NULL, 0, NULL, NULL);
5506 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5507 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5508 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5511 /* check for errors and quit on failure */
5512 if (cbBuf < needed) {
5513 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5514 res = FALSE;
5515 goto emA_cleanup;
5517 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5518 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5519 cbBuf -= len ; /* free Bytes in the user-Buffer */
5520 mi2w = (LPMONITOR_INFO_2W) bufferW;
5521 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5522 index = 0;
5523 /* Second Pass: Fill the User Buffer (if we have one) */
5524 while ((index < numentries) && pMonitors) {
5525 index++;
5526 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5527 mi2a->pName = ptr;
5528 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5529 ptr, cbBuf , NULL, NULL);
5530 ptr += len;
5531 cbBuf -= len;
5532 if (Level > 1) {
5533 mi2a->pEnvironment = ptr;
5534 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5535 ptr, cbBuf, NULL, NULL);
5536 ptr += len;
5537 cbBuf -= len;
5539 mi2a->pDLLName = ptr;
5540 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5541 ptr, cbBuf, NULL, NULL);
5542 ptr += len;
5543 cbBuf -= len;
5545 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5546 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5547 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5550 emA_cleanup:
5551 if (pcbNeeded) *pcbNeeded = needed;
5552 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5554 HeapFree(GetProcessHeap(), 0, nameW);
5555 HeapFree(GetProcessHeap(), 0, bufferW);
5557 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5558 (res), GetLastError(), needed, numentries);
5560 return (res);
5564 /*****************************************************************************
5565 * EnumMonitorsW [WINSPOOL.@]
5567 * Enumerate available Port-Monitors
5569 * PARAMS
5570 * pName [I] Servername or NULL (local Computer)
5571 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5572 * pMonitors [O] PTR to Buffer that receives the Result
5573 * cbBuf [I] Size of Buffer at pMonitors
5574 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5575 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5577 * RETURNS
5578 * Success: TRUE
5579 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5581 * NOTES
5582 * Windows reads the Registry once and cache the Results.
5584 *| Language-Monitors are also installed in the same Registry-Location but
5585 *| they are filtered in Windows (not returned by EnumMonitors).
5586 *| We do no filtering to simplify our Code.
5589 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5590 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5592 DWORD needed = 0;
5593 DWORD numentries = 0;
5594 BOOL res = FALSE;
5596 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5597 cbBuf, pcbNeeded, pcReturned);
5599 if (pName && (lstrlenW(pName))) {
5600 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5601 SetLastError(ERROR_ACCESS_DENIED);
5602 goto emW_cleanup;
5605 /* Level is not checked in win9x */
5606 if (!Level || (Level > 2)) {
5607 WARN("level (%ld) is ignored in win9x\n", Level);
5608 SetLastError(ERROR_INVALID_LEVEL);
5609 goto emW_cleanup;
5611 if (!pcbNeeded) {
5612 SetLastError(RPC_X_NULL_REF_POINTER);
5613 goto emW_cleanup;
5616 /* Scan all Monitor-Keys */
5617 numentries = 0;
5618 needed = get_local_monitors(Level, NULL, 0, &numentries);
5620 /* we calculated the needed buffersize. now do the error-checks */
5621 if (cbBuf < needed) {
5622 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5623 goto emW_cleanup;
5625 else if (!pMonitors || !pcReturned) {
5626 SetLastError(RPC_X_NULL_REF_POINTER);
5627 goto emW_cleanup;
5630 /* fill the Buffer with the Monitor-Keys */
5631 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5632 res = TRUE;
5634 emW_cleanup:
5635 if (pcbNeeded) *pcbNeeded = needed;
5636 if (pcReturned) *pcReturned = numentries;
5638 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5639 res, GetLastError(), needed, numentries);
5641 return (res);
5644 /******************************************************************************
5645 * XcvDataW (WINSPOOL.@)
5647 * Notes:
5648 * There doesn't seem to be an A version...
5650 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5651 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5652 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5654 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5655 pInputData, cbInputData, pOutputData,
5656 cbOutputData, pcbOutputNeeded, pdwStatus);
5657 return FALSE;
5660 /*****************************************************************************
5661 * EnumPrinterDataA [WINSPOOL.@]
5664 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5665 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5666 DWORD cbData, LPDWORD pcbData )
5668 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5669 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5670 return ERROR_NO_MORE_ITEMS;
5673 /*****************************************************************************
5674 * EnumPrinterDataW [WINSPOOL.@]
5677 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5678 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5679 DWORD cbData, LPDWORD pcbData )
5681 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5682 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5683 return ERROR_NO_MORE_ITEMS;
5686 /*****************************************************************************
5687 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5690 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5691 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5692 LPDWORD pcbNeeded, LPDWORD pcReturned)
5694 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5695 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5696 pcbNeeded, pcReturned);
5697 return FALSE;
5700 /*****************************************************************************
5701 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5704 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5705 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5706 LPDWORD pcbNeeded, LPDWORD pcReturned)
5708 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5709 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5710 pcbNeeded, pcReturned);
5711 return FALSE;
5714 /*****************************************************************************
5715 * EnumPrintProcessorsA [WINSPOOL.@]
5718 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5719 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5721 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5722 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5723 return FALSE;
5726 /*****************************************************************************
5727 * EnumPrintProcessorsW [WINSPOOL.@]
5730 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5731 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5733 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5734 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5735 cbBuf, pcbNeeded, pcbReturned);
5736 return FALSE;
5739 /*****************************************************************************
5740 * ExtDeviceMode [WINSPOOL.@]
5743 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5744 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5745 DWORD fMode)
5747 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5748 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5749 debugstr_a(pProfile), fMode);
5750 return -1;
5753 /*****************************************************************************
5754 * FindClosePrinterChangeNotification [WINSPOOL.@]
5757 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5759 FIXME("Stub: %p\n", hChange);
5760 return TRUE;
5763 /*****************************************************************************
5764 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5767 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5768 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5770 FIXME("Stub: %p %lx %lx %p\n",
5771 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5772 return INVALID_HANDLE_VALUE;
5775 /*****************************************************************************
5776 * FindNextPrinterChangeNotification [WINSPOOL.@]
5779 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5780 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5782 FIXME("Stub: %p %p %p %p\n",
5783 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5784 return FALSE;
5787 /*****************************************************************************
5788 * FreePrinterNotifyInfo [WINSPOOL.@]
5791 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5793 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5794 return TRUE;
5797 /*****************************************************************************
5798 * string_to_buf
5800 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5801 * ansi depending on the unicode parameter.
5803 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5805 if(!str)
5807 *size = 0;
5808 return TRUE;
5811 if(unicode)
5813 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5814 if(*size <= cb)
5816 memcpy(ptr, str, *size);
5817 return TRUE;
5819 return FALSE;
5821 else
5823 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5824 if(*size <= cb)
5826 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5827 return TRUE;
5829 return FALSE;
5833 /*****************************************************************************
5834 * get_job_info_1
5836 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5837 LPDWORD pcbNeeded, BOOL unicode)
5839 DWORD size, left = cbBuf;
5840 BOOL space = (cbBuf > 0);
5841 LPBYTE ptr = buf;
5843 *pcbNeeded = 0;
5845 if(space)
5847 ji1->JobId = job->job_id;
5850 string_to_buf(job->document_title, ptr, left, &size, unicode);
5851 if(space && size <= left)
5853 ji1->pDocument = (LPWSTR)ptr;
5854 ptr += size;
5855 left -= size;
5857 else
5858 space = FALSE;
5859 *pcbNeeded += size;
5861 return space;
5864 /*****************************************************************************
5865 * get_job_info_2
5867 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5868 LPDWORD pcbNeeded, BOOL unicode)
5870 DWORD size, left = cbBuf;
5871 BOOL space = (cbBuf > 0);
5872 LPBYTE ptr = buf;
5874 *pcbNeeded = 0;
5876 if(space)
5878 ji2->JobId = job->job_id;
5881 string_to_buf(job->document_title, ptr, left, &size, unicode);
5882 if(space && size <= left)
5884 ji2->pDocument = (LPWSTR)ptr;
5885 ptr += size;
5886 left -= size;
5888 else
5889 space = FALSE;
5890 *pcbNeeded += size;
5892 return space;
5895 /*****************************************************************************
5896 * get_job_info
5898 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5899 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5901 BOOL ret = FALSE;
5902 DWORD needed = 0, size;
5903 job_t *job;
5904 LPBYTE ptr = pJob;
5906 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5908 EnterCriticalSection(&printer_handles_cs);
5909 job = get_job(hPrinter, JobId);
5910 if(!job)
5911 goto end;
5913 switch(Level)
5915 case 1:
5916 size = sizeof(JOB_INFO_1W);
5917 if(cbBuf >= size)
5919 cbBuf -= size;
5920 ptr += size;
5921 memset(pJob, 0, size);
5923 else
5924 cbBuf = 0;
5925 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5926 needed += size;
5927 break;
5929 case 2:
5930 size = sizeof(JOB_INFO_2W);
5931 if(cbBuf >= size)
5933 cbBuf -= size;
5934 ptr += size;
5935 memset(pJob, 0, size);
5937 else
5938 cbBuf = 0;
5939 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5940 needed += size;
5941 break;
5943 case 3:
5944 size = sizeof(JOB_INFO_3);
5945 if(cbBuf >= size)
5947 cbBuf -= size;
5948 memset(pJob, 0, size);
5949 ret = TRUE;
5951 else
5952 cbBuf = 0;
5953 needed = size;
5954 break;
5956 default:
5957 SetLastError(ERROR_INVALID_LEVEL);
5958 goto end;
5960 if(pcbNeeded)
5961 *pcbNeeded = needed;
5962 end:
5963 LeaveCriticalSection(&printer_handles_cs);
5964 return ret;
5967 /*****************************************************************************
5968 * GetJobA [WINSPOOL.@]
5971 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5972 DWORD cbBuf, LPDWORD pcbNeeded)
5974 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5977 /*****************************************************************************
5978 * GetJobW [WINSPOOL.@]
5981 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5982 DWORD cbBuf, LPDWORD pcbNeeded)
5984 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5987 /*****************************************************************************
5988 * schedule_lpr
5990 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5992 char *unixname, *queue, *cmd;
5993 char fmt[] = "lpr -P%s %s";
5994 DWORD len;
5996 if(!(unixname = wine_get_unix_file_name(filename)))
5997 return FALSE;
5999 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6000 queue = HeapAlloc(GetProcessHeap(), 0, len);
6001 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6003 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6004 sprintf(cmd, fmt, queue, unixname);
6006 TRACE("printing with: %s\n", cmd);
6007 system(cmd);
6009 HeapFree(GetProcessHeap(), 0, cmd);
6010 HeapFree(GetProcessHeap(), 0, queue);
6011 HeapFree(GetProcessHeap(), 0, unixname);
6012 return TRUE;
6015 /*****************************************************************************
6016 * schedule_cups
6018 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6020 #if HAVE_CUPS_CUPS_H
6021 if(pcupsPrintFile)
6023 char *unixname, *queue, *doc_titleA;
6024 DWORD len;
6025 BOOL ret;
6027 if(!(unixname = wine_get_unix_file_name(filename)))
6028 return FALSE;
6030 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6031 queue = HeapAlloc(GetProcessHeap(), 0, len);
6032 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6034 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6035 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6036 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6038 TRACE("printing via cups\n");
6039 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6040 HeapFree(GetProcessHeap(), 0, doc_titleA);
6041 HeapFree(GetProcessHeap(), 0, queue);
6042 HeapFree(GetProcessHeap(), 0, unixname);
6043 return ret;
6045 else
6046 #endif
6048 return schedule_lpr(printer_name, filename);
6052 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6054 LPWSTR filename;
6056 switch(msg)
6058 case WM_INITDIALOG:
6059 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6060 return TRUE;
6062 case WM_COMMAND:
6063 if(HIWORD(wparam) == BN_CLICKED)
6065 if(LOWORD(wparam) == IDOK)
6067 HANDLE hf;
6068 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6069 LPWSTR *output;
6071 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6072 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6074 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6076 WCHAR caption[200], message[200];
6077 int mb_ret;
6079 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6080 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6081 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6082 if(mb_ret == IDCANCEL)
6084 HeapFree(GetProcessHeap(), 0, filename);
6085 return TRUE;
6088 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6089 if(hf == INVALID_HANDLE_VALUE)
6091 WCHAR caption[200], message[200];
6093 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6094 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6095 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6096 HeapFree(GetProcessHeap(), 0, filename);
6097 return TRUE;
6099 CloseHandle(hf);
6100 DeleteFileW(filename);
6101 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6102 *output = filename;
6103 EndDialog(hwnd, IDOK);
6104 return TRUE;
6106 if(LOWORD(wparam) == IDCANCEL)
6108 EndDialog(hwnd, IDCANCEL);
6109 return TRUE;
6112 return FALSE;
6114 return FALSE;
6117 /*****************************************************************************
6118 * get_filename
6120 static BOOL get_filename(LPWSTR *filename)
6122 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6123 file_dlg_proc, (LPARAM)filename) == IDOK;
6126 /*****************************************************************************
6127 * schedule_file
6129 static BOOL schedule_file(LPCWSTR filename)
6131 LPWSTR output = NULL;
6133 if(get_filename(&output))
6135 TRACE("copy to %s\n", debugstr_w(output));
6136 CopyFileW(filename, output, FALSE);
6137 HeapFree(GetProcessHeap(), 0, output);
6138 return TRUE;
6140 return FALSE;
6143 /*****************************************************************************
6144 * schedule_pipe
6146 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6148 #ifdef HAVE_FORK
6149 char *unixname, *cmdA;
6150 DWORD len;
6151 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6152 BOOL ret = FALSE;
6153 char buf[1024];
6155 if(!(unixname = wine_get_unix_file_name(filename)))
6156 return FALSE;
6158 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6159 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6160 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6162 TRACE("printing with: %s\n", cmdA);
6164 if((file_fd = open(unixname, O_RDONLY)) == -1)
6165 goto end;
6167 if (pipe(fds))
6169 ERR("pipe() failed!\n");
6170 goto end;
6173 if (fork() == 0)
6175 close(0);
6176 dup2(fds[0], 0);
6177 close(fds[1]);
6179 /* reset signals that we previously set to SIG_IGN */
6180 signal(SIGPIPE, SIG_DFL);
6181 signal(SIGCHLD, SIG_DFL);
6183 system(cmdA);
6184 exit(0);
6187 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6188 write(fds[1], buf, no_read);
6190 ret = TRUE;
6192 end:
6193 if(file_fd != -1) close(file_fd);
6194 if(fds[0] != -1) close(fds[0]);
6195 if(fds[1] != -1) close(fds[1]);
6197 HeapFree(GetProcessHeap(), 0, cmdA);
6198 HeapFree(GetProcessHeap(), 0, unixname);
6199 return ret;
6200 #else
6201 return FALSE;
6202 #endif
6205 /*****************************************************************************
6206 * schedule_unixfile
6208 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6210 int in_fd, out_fd, no_read;
6211 char buf[1024];
6212 BOOL ret = FALSE;
6213 char *unixname, *outputA;
6214 DWORD len;
6216 if(!(unixname = wine_get_unix_file_name(filename)))
6217 return FALSE;
6219 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6220 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6221 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6223 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6224 in_fd = open(unixname, O_RDONLY);
6225 if(out_fd == -1 || in_fd == -1)
6226 goto end;
6228 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6229 write(out_fd, buf, no_read);
6231 ret = TRUE;
6232 end:
6233 if(in_fd != -1) close(in_fd);
6234 if(out_fd != -1) close(out_fd);
6235 HeapFree(GetProcessHeap(), 0, outputA);
6236 HeapFree(GetProcessHeap(), 0, unixname);
6237 return ret;
6240 /*****************************************************************************
6241 * ScheduleJob [WINSPOOL.@]
6244 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6246 opened_printer_t *printer;
6247 BOOL ret = FALSE;
6248 struct list *cursor, *cursor2;
6250 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6251 EnterCriticalSection(&printer_handles_cs);
6252 printer = get_opened_printer(hPrinter);
6253 if(!printer)
6254 goto end;
6256 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6258 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6259 HANDLE hf;
6261 if(job->job_id != dwJobID) continue;
6263 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6264 if(hf != INVALID_HANDLE_VALUE)
6266 PRINTER_INFO_5W *pi5;
6267 DWORD needed;
6268 HKEY hkey;
6269 WCHAR output[1024];
6270 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6271 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6273 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6274 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6275 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6276 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6277 debugstr_w(pi5->pPortName));
6279 output[0] = 0;
6281 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6282 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6284 DWORD type, count = sizeof(output);
6285 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6286 RegCloseKey(hkey);
6288 if(output[0] == '|')
6290 schedule_pipe(output + 1, job->filename);
6292 else if(output[0])
6294 schedule_unixfile(output, job->filename);
6296 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6298 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6300 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6302 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6304 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6306 schedule_file(job->filename);
6308 else
6310 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6312 HeapFree(GetProcessHeap(), 0, pi5);
6313 CloseHandle(hf);
6314 DeleteFileW(job->filename);
6316 list_remove(cursor);
6317 HeapFree(GetProcessHeap(), 0, job->document_title);
6318 HeapFree(GetProcessHeap(), 0, job->filename);
6319 HeapFree(GetProcessHeap(), 0, job);
6320 ret = TRUE;
6321 break;
6323 end:
6324 LeaveCriticalSection(&printer_handles_cs);
6325 return ret;
6328 /*****************************************************************************
6329 * StartDocDlgA [WINSPOOL.@]
6331 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6333 UNICODE_STRING usBuffer;
6334 DOCINFOW docW;
6335 LPWSTR retW;
6336 LPSTR ret = NULL;
6338 docW.cbSize = sizeof(docW);
6339 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6340 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6341 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6342 docW.fwType = doc->fwType;
6344 retW = StartDocDlgW(hPrinter, &docW);
6346 if(retW)
6348 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6349 ret = HeapAlloc(GetProcessHeap(), 0, len);
6350 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6351 HeapFree(GetProcessHeap(), 0, retW);
6354 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6355 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6356 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6358 return ret;
6361 /*****************************************************************************
6362 * StartDocDlgW [WINSPOOL.@]
6364 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6365 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6366 * port is "FILE:". Also returns the full path if passed a relative path.
6368 * The caller should free the returned string from the process heap.
6370 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6372 LPWSTR ret = NULL;
6373 DWORD len, attr;
6375 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6377 PRINTER_INFO_5W *pi5;
6378 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6379 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6380 return NULL;
6381 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6382 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6383 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6385 HeapFree(GetProcessHeap(), 0, pi5);
6386 return NULL;
6388 HeapFree(GetProcessHeap(), 0, pi5);
6391 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6393 LPWSTR name;
6394 get_filename(&name);
6395 if(name)
6397 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6399 HeapFree(GetProcessHeap(), 0, name);
6400 return NULL;
6402 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6403 GetFullPathNameW(name, len, ret, NULL);
6404 HeapFree(GetProcessHeap(), 0, name);
6406 return ret;
6409 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6410 return NULL;
6412 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6413 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6415 attr = GetFileAttributesW(ret);
6416 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6418 HeapFree(GetProcessHeap(), 0, ret);
6419 ret = NULL;
6421 return ret;