wine.inf: We should not override existing associations.
[wine/hacks.git] / dlls / winspool.drv / info.c
blobbf91f9e2c848cc26c2ff78f4b6d9dae109f21594
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 | KEY_QUERY_VALUE, NULL, &hentry,
1485 &disposition) == ERROR_SUCCESS) {
1487 /* Some installers set options for the port before calling AddMonitor.
1488 We query the "Driver" entry to verify that the monitor is installed,
1489 before we return an error.
1490 When a user installs two print monitors at the same time with the
1491 same name but with a different driver DLL and a task switch comes
1492 between RegQueryValueExW and RegSetValueExW, a race condition
1493 is possible but silently ignored. */
1495 DWORD namesize = 0;
1497 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1498 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1499 &namesize) == ERROR_SUCCESS)) {
1500 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1501 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1502 9x: ERROR_ALREADY_EXISTS (183) */
1503 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1505 else
1507 INT len;
1508 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1509 res = (RegSetValueExW(hentry, DriverW, 0,
1510 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1512 RegCloseKey(hentry);
1515 RegCloseKey(hroot);
1516 return (res);
1519 /******************************************************************
1520 * DeletePrinterDriverA [WINSPOOL.@]
1523 BOOL WINAPI
1524 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1526 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1527 debugstr_a(pDriverName));
1528 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1529 return FALSE;
1532 /******************************************************************
1533 * DeletePrinterDriverW [WINSPOOL.@]
1536 BOOL WINAPI
1537 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1539 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1540 debugstr_w(pDriverName));
1541 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1542 return FALSE;
1545 /******************************************************************
1546 * DeleteMonitorA [WINSPOOL.@]
1548 * See DeleteMonitorW.
1551 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1553 LPWSTR nameW = NULL;
1554 LPWSTR EnvironmentW = NULL;
1555 LPWSTR MonitorNameW = NULL;
1556 BOOL res;
1557 INT len;
1559 if (pName) {
1560 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1561 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1562 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1565 if (pEnvironment) {
1566 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1567 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1568 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1570 if (pMonitorName) {
1571 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1572 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1573 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1576 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1578 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1579 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1580 HeapFree(GetProcessHeap(), 0, nameW);
1581 return (res);
1584 /******************************************************************
1585 * DeleteMonitorW [WINSPOOL.@]
1587 * Delete a specific Printmonitor from a Printing-Environment
1589 * PARAMS
1590 * pName [I] Servername or NULL (local Computer)
1591 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1592 * pMonitorName [I] Name of the Monitor, that should be deleted
1594 * RETURNS
1595 * Success: TRUE
1596 * Failure: FALSE
1598 * NOTES
1599 * pEnvironment is ignored in Windows for the local Computer.
1603 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1605 HKEY hroot = NULL;
1607 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1608 debugstr_w(pMonitorName));
1610 if (pName && (pName[0])) {
1611 FIXME("for server %s not implemented\n", debugstr_w(pName));
1612 SetLastError(ERROR_ACCESS_DENIED);
1613 return FALSE;
1616 /* pEnvironment is ignored in Windows for the local Computer */
1618 if (!pMonitorName || !pMonitorName[0]) {
1619 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1620 SetLastError(ERROR_INVALID_PARAMETER);
1621 return FALSE;
1624 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1625 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1626 return FALSE;
1629 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1630 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1631 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1632 RegCloseKey(hroot);
1633 return TRUE;
1636 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1637 RegCloseKey(hroot);
1639 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1640 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1641 return (FALSE);
1644 /******************************************************************
1645 * DeletePortA [WINSPOOL.@]
1647 * See DeletePortW.
1650 BOOL WINAPI
1651 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1653 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1654 debugstr_a(pPortName));
1655 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1656 return FALSE;
1659 /******************************************************************
1660 * DeletePortW [WINSPOOL.@]
1662 * Delete a specific Port
1664 * PARAMS
1665 * pName [I] Servername or NULL (local Computer)
1666 * hWnd [I] Handle to parent Window for the Dialog-Box
1667 * pPortName [I] Name of the Port, that should be deleted
1669 * RETURNS
1670 * Success: TRUE
1671 * Failure: FALSE
1673 * BUGS
1674 * only a Stub
1677 BOOL WINAPI
1678 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1680 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1681 debugstr_w(pPortName));
1682 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1683 return FALSE;
1686 /******************************************************************************
1687 * SetPrinterW [WINSPOOL.@]
1689 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1691 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1692 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1693 return FALSE;
1696 /******************************************************************************
1697 * WritePrinter [WINSPOOL.@]
1699 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1701 opened_printer_t *printer;
1702 BOOL ret = FALSE;
1704 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1706 EnterCriticalSection(&printer_handles_cs);
1707 printer = get_opened_printer(hPrinter);
1708 if(!printer)
1710 SetLastError(ERROR_INVALID_HANDLE);
1711 goto end;
1714 if(!printer->doc)
1716 SetLastError(ERROR_SPL_NO_STARTDOC);
1717 goto end;
1720 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1721 end:
1722 LeaveCriticalSection(&printer_handles_cs);
1723 return ret;
1726 /*****************************************************************************
1727 * AddFormA [WINSPOOL.@]
1729 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1731 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1732 return 1;
1735 /*****************************************************************************
1736 * AddFormW [WINSPOOL.@]
1738 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1740 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1741 return 1;
1744 /*****************************************************************************
1745 * AddJobA [WINSPOOL.@]
1747 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1749 BOOL ret;
1750 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1751 DWORD needed;
1753 if(Level != 1) {
1754 SetLastError(ERROR_INVALID_LEVEL);
1755 return FALSE;
1758 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1760 if(ret) {
1761 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1762 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1763 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1764 if(*pcbNeeded > cbBuf) {
1765 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1766 ret = FALSE;
1767 } else {
1768 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1769 addjobA->JobId = addjobW->JobId;
1770 addjobA->Path = (char *)(addjobA + 1);
1771 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1774 return ret;
1777 /*****************************************************************************
1778 * AddJobW [WINSPOOL.@]
1780 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1782 opened_printer_t *printer;
1783 job_t *job;
1784 BOOL ret = FALSE;
1785 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1786 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1787 WCHAR path[MAX_PATH], filename[MAX_PATH];
1788 DWORD len;
1789 ADDJOB_INFO_1W *addjob;
1791 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1793 EnterCriticalSection(&printer_handles_cs);
1795 printer = get_opened_printer(hPrinter);
1797 if(!printer) {
1798 SetLastError(ERROR_INVALID_HANDLE);
1799 goto end;
1802 if(Level != 1) {
1803 SetLastError(ERROR_INVALID_LEVEL);
1804 goto end;
1807 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1808 if(!job)
1809 goto end;
1811 job->job_id = InterlockedIncrement(&next_job_id);
1813 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1814 if(path[len - 1] != '\\')
1815 path[len++] = '\\';
1816 memcpy(path + len, spool_path, sizeof(spool_path));
1817 sprintfW(filename, fmtW, path, job->job_id);
1819 len = strlenW(filename);
1820 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1821 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1822 job->document_title = strdupW(default_doc_title);
1823 list_add_tail(&printer->queue->jobs, &job->entry);
1825 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1826 if(*pcbNeeded <= cbBuf) {
1827 addjob = (ADDJOB_INFO_1W*)pData;
1828 addjob->JobId = job->job_id;
1829 addjob->Path = (WCHAR *)(addjob + 1);
1830 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1831 ret = TRUE;
1832 } else
1833 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1835 end:
1836 LeaveCriticalSection(&printer_handles_cs);
1837 return ret;
1840 /*****************************************************************************
1841 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1843 * Return the PATH for the Print-Processors
1845 * See GetPrintProcessorDirectoryW.
1849 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1850 DWORD level, LPBYTE Info,
1851 DWORD cbBuf, LPDWORD pcbNeeded)
1853 LPWSTR serverW = NULL;
1854 LPWSTR envW = NULL;
1855 BOOL ret;
1856 INT len;
1858 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
1859 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
1862 if (server) {
1863 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
1864 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1865 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
1868 if (env) {
1869 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
1870 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1871 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
1874 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
1875 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
1877 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
1878 cbBuf, pcbNeeded);
1880 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
1881 cbBuf, NULL, NULL) > 0;
1884 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
1885 HeapFree(GetProcessHeap(), 0, envW);
1886 HeapFree(GetProcessHeap(), 0, serverW);
1887 return ret;
1890 /*****************************************************************************
1891 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1893 * Return the PATH for the Print-Processors
1895 * PARAMS
1896 * server [I] Servername (NT only) or NULL (local Computer)
1897 * env [I] Printing-Environment (see below) or NULL (Default)
1898 * level [I] Structure-Level (must be 1)
1899 * Info [O] PTR to Buffer that receives the Result
1900 * cbBuf [I] Size of Buffer at "Info"
1901 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1902 * required for the Buffer at "Info"
1904 * RETURNS
1905 * Success: TRUE and in pcbNeeded the Bytes used in Info
1906 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
1907 * if cbBuf is too small
1909 * Native Values returned in Info on Success:
1910 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
1911 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
1912 *| win9x(Windows 4.0): "%winsysdir%"
1914 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1916 * BUGS
1917 * Only NULL or "" is supported for server
1920 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1921 DWORD level, LPBYTE Info,
1922 DWORD cbBuf, LPDWORD pcbNeeded)
1924 DWORD needed;
1925 const printenv_t * env_t;
1927 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server),
1928 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
1930 if(server != NULL && server[0]) {
1931 FIXME("server not supported: %s\n", debugstr_w(server));
1932 SetLastError(ERROR_INVALID_PARAMETER);
1933 return FALSE;
1936 env_t = validate_envW(env);
1937 if(!env_t) return FALSE; /* environment invalid or unsupported */
1939 if(level != 1) {
1940 WARN("(Level: %ld) is ignored in win9x\n", level);
1941 SetLastError(ERROR_INVALID_LEVEL);
1942 return FALSE;
1945 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1946 needed = GetSystemDirectoryW(NULL, 0);
1947 /* add the Size for the Subdirectories */
1948 needed += lstrlenW(spoolprtprocsW);
1949 needed += lstrlenW(env_t->subdir);
1950 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1952 if(pcbNeeded) *pcbNeeded = needed;
1953 TRACE ("required: 0x%lx/%ld\n", needed, needed);
1954 if (needed > cbBuf) {
1955 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1956 return FALSE;
1958 if(pcbNeeded == NULL) {
1959 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
1960 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
1961 SetLastError(RPC_X_NULL_REF_POINTER);
1962 return FALSE;
1964 if(Info == NULL) {
1965 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
1966 SetLastError(RPC_X_NULL_REF_POINTER);
1967 return FALSE;
1970 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
1971 /* add the Subdirectories */
1972 lstrcatW((LPWSTR) Info, spoolprtprocsW);
1973 lstrcatW((LPWSTR) Info, env_t->subdir);
1974 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
1975 return TRUE;
1978 /*****************************************************************************
1979 * WINSPOOL_OpenDriverReg [internal]
1981 * opens the registry for the printer drivers depending on the given input
1982 * variable pEnvironment
1984 * RETURNS:
1985 * the opened hkey on success
1986 * NULL on error
1988 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1990 HKEY retval = NULL;
1991 LPWSTR buffer;
1992 const printenv_t * env;
1994 TRACE("(%s, %d)\n",
1995 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
1997 if (!pEnvironment || unicode) {
1998 /* pEnvironment was NULL or an Unicode-String: use it direct */
1999 env = validate_envW(pEnvironment);
2001 else
2003 /* pEnvironment was an ANSI-String: convert to unicode first */
2004 LPWSTR buffer;
2005 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2006 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2007 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2008 env = validate_envW(buffer);
2009 HeapFree(GetProcessHeap(), 0, buffer);
2011 if (!env) return NULL;
2013 buffer = HeapAlloc( GetProcessHeap(), 0,
2014 (strlenW(DriversW) + strlenW(env->envname) +
2015 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2016 if(buffer) {
2017 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2018 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2019 HeapFree(GetProcessHeap(), 0, buffer);
2021 return retval;
2024 /*****************************************************************************
2025 * AddPrinterW [WINSPOOL.@]
2027 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2029 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2030 LPDEVMODEA dmA;
2031 LPDEVMODEW dmW;
2032 HANDLE retval;
2033 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2034 LONG size;
2036 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2038 if(pName != NULL) {
2039 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2040 SetLastError(ERROR_INVALID_PARAMETER);
2041 return 0;
2043 if(Level != 2) {
2044 ERR("Level = %ld, unsupported!\n", Level);
2045 SetLastError(ERROR_INVALID_LEVEL);
2046 return 0;
2048 if(!pPrinter) {
2049 SetLastError(ERROR_INVALID_PARAMETER);
2050 return 0;
2052 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2053 ERROR_SUCCESS) {
2054 ERR("Can't create Printers key\n");
2055 return 0;
2057 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2058 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2059 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2060 RegCloseKey(hkeyPrinter);
2061 RegCloseKey(hkeyPrinters);
2062 return 0;
2064 RegCloseKey(hkeyPrinter);
2066 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2067 if(!hkeyDrivers) {
2068 ERR("Can't create Drivers key\n");
2069 RegCloseKey(hkeyPrinters);
2070 return 0;
2072 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2073 ERROR_SUCCESS) {
2074 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2075 RegCloseKey(hkeyPrinters);
2076 RegCloseKey(hkeyDrivers);
2077 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2078 return 0;
2080 RegCloseKey(hkeyDriver);
2081 RegCloseKey(hkeyDrivers);
2083 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2084 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2085 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2086 RegCloseKey(hkeyPrinters);
2087 return 0;
2090 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2091 ERROR_SUCCESS) {
2092 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2093 SetLastError(ERROR_INVALID_PRINTER_NAME);
2094 RegCloseKey(hkeyPrinters);
2095 return 0;
2097 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2098 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2099 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2101 /* See if we can load the driver. We may need the devmode structure anyway
2103 * FIXME:
2104 * Note that DocumentPropertiesW will briefly try to open the printer we
2105 * just create to find a DEVMODEA struct (it will use the WINEPS default
2106 * one in case it is not there, so we are ok).
2108 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2110 if(size < 0) {
2111 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2112 size = sizeof(DEVMODEW);
2114 if(pi->pDevMode)
2115 dmW = pi->pDevMode;
2116 else
2118 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2119 ZeroMemory(dmW,size);
2120 dmW->dmSize = size;
2121 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2123 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2124 HeapFree(GetProcessHeap(),0,dmW);
2125 dmW=NULL;
2127 else
2129 /* set devmode to printer name */
2130 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2134 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2135 and we support these drivers. NT writes DEVMODEW so somehow
2136 we'll need to distinguish between these when we support NT
2137 drivers */
2138 if (dmW)
2140 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2141 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2142 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2143 HeapFree(GetProcessHeap(), 0, dmA);
2144 if(!pi->pDevMode)
2145 HeapFree(GetProcessHeap(), 0, dmW);
2147 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2148 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2149 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2150 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2152 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2153 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2154 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2155 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2156 (LPBYTE)&pi->Priority, sizeof(DWORD));
2157 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2158 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2159 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2160 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2161 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2162 (LPBYTE)&pi->Status, sizeof(DWORD));
2163 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2164 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2166 RegCloseKey(hkeyPrinter);
2167 RegCloseKey(hkeyPrinters);
2168 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2169 ERR("OpenPrinter failing\n");
2170 return 0;
2172 return retval;
2175 /*****************************************************************************
2176 * AddPrinterA [WINSPOOL.@]
2178 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2180 UNICODE_STRING pNameW;
2181 PWSTR pwstrNameW;
2182 PRINTER_INFO_2W *piW;
2183 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2184 HANDLE ret;
2186 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2187 if(Level != 2) {
2188 ERR("Level = %ld, unsupported!\n", Level);
2189 SetLastError(ERROR_INVALID_LEVEL);
2190 return 0;
2192 pwstrNameW = asciitounicode(&pNameW,pName);
2193 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2195 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2197 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2198 RtlFreeUnicodeString(&pNameW);
2199 return ret;
2203 /*****************************************************************************
2204 * ClosePrinter [WINSPOOL.@]
2206 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2208 UINT_PTR i = (UINT_PTR)hPrinter;
2209 opened_printer_t *printer = NULL;
2210 BOOL ret = FALSE;
2212 TRACE("Handle %p\n", hPrinter);
2214 EnterCriticalSection(&printer_handles_cs);
2216 if ((i > 0) && (i <= nb_printer_handles))
2217 printer = printer_handles[i - 1];
2219 if(printer)
2221 struct list *cursor, *cursor2;
2223 if(printer->doc)
2224 EndDocPrinter(hPrinter);
2226 if(InterlockedDecrement(&printer->queue->ref) == 0)
2228 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2230 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2231 ScheduleJob(hPrinter, job->job_id);
2233 HeapFree(GetProcessHeap(), 0, printer->queue);
2235 HeapFree(GetProcessHeap(), 0, printer->name);
2236 HeapFree(GetProcessHeap(), 0, printer);
2237 printer_handles[i - 1] = NULL;
2238 ret = TRUE;
2240 LeaveCriticalSection(&printer_handles_cs);
2241 return ret;
2244 /*****************************************************************************
2245 * DeleteFormA [WINSPOOL.@]
2247 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2249 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2250 return 1;
2253 /*****************************************************************************
2254 * DeleteFormW [WINSPOOL.@]
2256 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2258 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2259 return 1;
2262 /*****************************************************************************
2263 * WINSPOOL_SHRegDeleteKey
2265 * Recursively delete subkeys.
2266 * Cut & paste from shlwapi.
2269 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2271 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2272 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2273 HKEY hSubKey = 0;
2275 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2276 if(!dwRet)
2278 /* Find how many subkeys there are */
2279 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2280 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2281 if(!dwRet)
2283 dwMaxSubkeyLen++;
2284 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2285 /* Name too big: alloc a buffer for it */
2286 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2288 if(!lpszName)
2289 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2290 else
2292 /* Recursively delete all the subkeys */
2293 for(i = 0; i < dwKeyCount && !dwRet; i++)
2295 dwSize = dwMaxSubkeyLen;
2296 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2297 if(!dwRet)
2298 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2301 if (lpszName != szNameBuf)
2302 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2306 RegCloseKey(hSubKey);
2307 if(!dwRet)
2308 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2310 return dwRet;
2313 /*****************************************************************************
2314 * DeletePrinter [WINSPOOL.@]
2316 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2318 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2319 HKEY hkeyPrinters, hkey;
2321 if(!lpNameW) {
2322 SetLastError(ERROR_INVALID_HANDLE);
2323 return FALSE;
2325 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2326 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2327 RegCloseKey(hkeyPrinters);
2329 WriteProfileStringW(devicesW, lpNameW, NULL);
2330 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2331 RegDeleteValueW(hkey, lpNameW);
2332 RegCloseKey(hkey);
2334 return TRUE;
2337 /*****************************************************************************
2338 * SetPrinterA [WINSPOOL.@]
2340 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2341 DWORD Command)
2343 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2344 return FALSE;
2347 /*****************************************************************************
2348 * SetJobA [WINSPOOL.@]
2350 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2351 LPBYTE pJob, DWORD Command)
2353 BOOL ret;
2354 LPBYTE JobW;
2355 UNICODE_STRING usBuffer;
2357 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2359 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2360 are all ignored by SetJob, so we don't bother copying them */
2361 switch(Level)
2363 case 0:
2364 JobW = NULL;
2365 break;
2366 case 1:
2368 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2369 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2371 JobW = (LPBYTE)info1W;
2372 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2373 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2374 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2375 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2376 info1W->Status = info1A->Status;
2377 info1W->Priority = info1A->Priority;
2378 info1W->Position = info1A->Position;
2379 info1W->PagesPrinted = info1A->PagesPrinted;
2380 break;
2382 case 2:
2384 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2385 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2387 JobW = (LPBYTE)info2W;
2388 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2389 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2390 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2391 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2392 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2393 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2394 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2395 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2396 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2397 info2W->Status = info2A->Status;
2398 info2W->Priority = info2A->Priority;
2399 info2W->Position = info2A->Position;
2400 info2W->StartTime = info2A->StartTime;
2401 info2W->UntilTime = info2A->UntilTime;
2402 info2W->PagesPrinted = info2A->PagesPrinted;
2403 break;
2405 case 3:
2406 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2407 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2408 break;
2409 default:
2410 SetLastError(ERROR_INVALID_LEVEL);
2411 return FALSE;
2414 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2416 switch(Level)
2418 case 1:
2420 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2421 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2422 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2423 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2424 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2425 break;
2427 case 2:
2429 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2430 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2431 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2432 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2433 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2434 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2435 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2436 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2437 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2438 break;
2441 HeapFree(GetProcessHeap(), 0, JobW);
2443 return ret;
2446 /*****************************************************************************
2447 * SetJobW [WINSPOOL.@]
2449 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2450 LPBYTE pJob, DWORD Command)
2452 BOOL ret = FALSE;
2453 job_t *job;
2455 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2456 FIXME("Ignoring everything other than document title\n");
2458 EnterCriticalSection(&printer_handles_cs);
2459 job = get_job(hPrinter, JobId);
2460 if(!job)
2461 goto end;
2463 switch(Level)
2465 case 0:
2466 break;
2467 case 1:
2469 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2470 HeapFree(GetProcessHeap(), 0, job->document_title);
2471 job->document_title = strdupW(info1->pDocument);
2472 break;
2474 case 2:
2476 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2477 HeapFree(GetProcessHeap(), 0, job->document_title);
2478 job->document_title = strdupW(info2->pDocument);
2479 break;
2481 case 3:
2482 break;
2483 default:
2484 SetLastError(ERROR_INVALID_LEVEL);
2485 goto end;
2487 ret = TRUE;
2488 end:
2489 LeaveCriticalSection(&printer_handles_cs);
2490 return ret;
2493 /*****************************************************************************
2494 * EndDocPrinter [WINSPOOL.@]
2496 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2498 opened_printer_t *printer;
2499 BOOL ret = FALSE;
2500 TRACE("(%p)\n", hPrinter);
2502 EnterCriticalSection(&printer_handles_cs);
2504 printer = get_opened_printer(hPrinter);
2505 if(!printer)
2507 SetLastError(ERROR_INVALID_HANDLE);
2508 goto end;
2511 if(!printer->doc)
2513 SetLastError(ERROR_SPL_NO_STARTDOC);
2514 goto end;
2517 CloseHandle(printer->doc->hf);
2518 ScheduleJob(hPrinter, printer->doc->job_id);
2519 HeapFree(GetProcessHeap(), 0, printer->doc);
2520 printer->doc = NULL;
2521 ret = TRUE;
2522 end:
2523 LeaveCriticalSection(&printer_handles_cs);
2524 return ret;
2527 /*****************************************************************************
2528 * EndPagePrinter [WINSPOOL.@]
2530 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2532 FIXME("(%p): stub\n", hPrinter);
2533 return TRUE;
2536 /*****************************************************************************
2537 * StartDocPrinterA [WINSPOOL.@]
2539 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2541 UNICODE_STRING usBuffer;
2542 DOC_INFO_2W doc2W;
2543 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2544 DWORD ret;
2546 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2547 or one (DOC_INFO_3) extra DWORDs */
2549 switch(Level) {
2550 case 2:
2551 doc2W.JobId = doc2->JobId;
2552 /* fall through */
2553 case 3:
2554 doc2W.dwMode = doc2->dwMode;
2555 /* fall through */
2556 case 1:
2557 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2558 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2559 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2560 break;
2562 default:
2563 SetLastError(ERROR_INVALID_LEVEL);
2564 return FALSE;
2567 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2569 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2570 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2571 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2573 return ret;
2576 /*****************************************************************************
2577 * StartDocPrinterW [WINSPOOL.@]
2579 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2581 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2582 opened_printer_t *printer;
2583 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2584 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2585 JOB_INFO_1W job_info;
2586 DWORD needed, ret = 0;
2587 HANDLE hf;
2588 WCHAR *filename;
2590 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2591 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2592 debugstr_w(doc->pDatatype));
2594 if(Level < 1 || Level > 3)
2596 SetLastError(ERROR_INVALID_LEVEL);
2597 return 0;
2600 EnterCriticalSection(&printer_handles_cs);
2601 printer = get_opened_printer(hPrinter);
2602 if(!printer)
2604 SetLastError(ERROR_INVALID_HANDLE);
2605 goto end;
2608 if(printer->doc)
2610 SetLastError(ERROR_INVALID_PRINTER_STATE);
2611 goto end;
2614 /* Even if we're printing to a file we still add a print job, we'll
2615 just ignore the spool file name */
2617 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2619 ERR("AddJob failed gle %08lx\n", GetLastError());
2620 goto end;
2623 if(doc->pOutputFile)
2624 filename = doc->pOutputFile;
2625 else
2626 filename = addjob->Path;
2628 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2629 if(hf == INVALID_HANDLE_VALUE)
2630 goto end;
2632 memset(&job_info, 0, sizeof(job_info));
2633 job_info.pDocument = doc->pDocName;
2634 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2636 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2637 printer->doc->hf = hf;
2638 ret = printer->doc->job_id = addjob->JobId;
2639 end:
2640 LeaveCriticalSection(&printer_handles_cs);
2642 return ret;
2645 /*****************************************************************************
2646 * StartPagePrinter [WINSPOOL.@]
2648 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2650 FIXME("(%p): stub\n", hPrinter);
2651 return TRUE;
2654 /*****************************************************************************
2655 * GetFormA [WINSPOOL.@]
2657 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2658 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2660 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2661 Level,pForm,cbBuf,pcbNeeded);
2662 return FALSE;
2665 /*****************************************************************************
2666 * GetFormW [WINSPOOL.@]
2668 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2669 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2671 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2672 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2673 return FALSE;
2676 /*****************************************************************************
2677 * SetFormA [WINSPOOL.@]
2679 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2680 LPBYTE pForm)
2682 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2683 return FALSE;
2686 /*****************************************************************************
2687 * SetFormW [WINSPOOL.@]
2689 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2690 LPBYTE pForm)
2692 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2693 return FALSE;
2696 /*****************************************************************************
2697 * ReadPrinter [WINSPOOL.@]
2699 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2700 LPDWORD pNoBytesRead)
2702 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2703 return FALSE;
2706 /*****************************************************************************
2707 * ResetPrinterA [WINSPOOL.@]
2709 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2711 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2712 return FALSE;
2715 /*****************************************************************************
2716 * ResetPrinterW [WINSPOOL.@]
2718 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2720 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2721 return FALSE;
2724 /*****************************************************************************
2725 * WINSPOOL_GetDWORDFromReg
2727 * Return DWORD associated with ValueName from hkey.
2729 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2731 DWORD sz = sizeof(DWORD), type, value = 0;
2732 LONG ret;
2734 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2736 if(ret != ERROR_SUCCESS) {
2737 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2738 return 0;
2740 if(type != REG_DWORD) {
2741 ERR("Got type %ld\n", type);
2742 return 0;
2744 return value;
2747 /*****************************************************************************
2748 * WINSPOOL_GetStringFromReg
2750 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2751 * String is stored either as unicode or ascii.
2752 * Bit of a hack here to get the ValueName if we want ascii.
2754 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2755 DWORD buflen, DWORD *needed,
2756 BOOL unicode)
2758 DWORD sz = buflen, type;
2759 LONG ret;
2761 if(unicode)
2762 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2763 else {
2764 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2765 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2766 HeapFree(GetProcessHeap(),0,ValueNameA);
2768 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2769 WARN("Got ret = %ld\n", ret);
2770 *needed = 0;
2771 return FALSE;
2773 /* add space for terminating '\0' */
2774 sz += unicode ? sizeof(WCHAR) : 1;
2775 *needed = sz;
2777 if (ptr)
2778 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2780 return TRUE;
2783 /*****************************************************************************
2784 * WINSPOOL_GetDefaultDevMode
2786 * Get a default DevMode values for wineps.
2787 * FIXME - use ppd.
2790 static void WINSPOOL_GetDefaultDevMode(
2791 LPBYTE ptr,
2792 DWORD buflen, DWORD *needed,
2793 BOOL unicode)
2795 DEVMODEA dm;
2796 static const char szwps[] = "wineps.drv";
2798 /* fill default DEVMODE - should be read from ppd... */
2799 ZeroMemory( &dm, sizeof(dm) );
2800 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2801 dm.dmSpecVersion = DM_SPECVERSION;
2802 dm.dmDriverVersion = 1;
2803 dm.dmSize = sizeof(DEVMODEA);
2804 dm.dmDriverExtra = 0;
2805 dm.dmFields =
2806 DM_ORIENTATION | DM_PAPERSIZE |
2807 DM_PAPERLENGTH | DM_PAPERWIDTH |
2808 DM_SCALE |
2809 DM_COPIES |
2810 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2811 DM_YRESOLUTION | DM_TTOPTION;
2813 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2814 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2815 dm.u1.s1.dmPaperLength = 2970;
2816 dm.u1.s1.dmPaperWidth = 2100;
2818 dm.dmScale = 100;
2819 dm.dmCopies = 1;
2820 dm.dmDefaultSource = DMBIN_AUTO;
2821 dm.dmPrintQuality = DMRES_MEDIUM;
2822 /* dm.dmColor */
2823 /* dm.dmDuplex */
2824 dm.dmYResolution = 300; /* 300dpi */
2825 dm.dmTTOption = DMTT_BITMAP;
2826 /* dm.dmCollate */
2827 /* dm.dmFormName */
2828 /* dm.dmLogPixels */
2829 /* dm.dmBitsPerPel */
2830 /* dm.dmPelsWidth */
2831 /* dm.dmPelsHeight */
2832 /* dm.dmDisplayFlags */
2833 /* dm.dmDisplayFrequency */
2834 /* dm.dmICMMethod */
2835 /* dm.dmICMIntent */
2836 /* dm.dmMediaType */
2837 /* dm.dmDitherType */
2838 /* dm.dmReserved1 */
2839 /* dm.dmReserved2 */
2840 /* dm.dmPanningWidth */
2841 /* dm.dmPanningHeight */
2843 if(unicode) {
2844 if(buflen >= sizeof(DEVMODEW)) {
2845 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2846 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2847 HeapFree(GetProcessHeap(),0,pdmW);
2849 *needed = sizeof(DEVMODEW);
2851 else
2853 if(buflen >= sizeof(DEVMODEA)) {
2854 memcpy(ptr, &dm, sizeof(DEVMODEA));
2856 *needed = sizeof(DEVMODEA);
2860 /*****************************************************************************
2861 * WINSPOOL_GetDevModeFromReg
2863 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2864 * DevMode is stored either as unicode or ascii.
2866 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2867 LPBYTE ptr,
2868 DWORD buflen, DWORD *needed,
2869 BOOL unicode)
2871 DWORD sz = buflen, type;
2872 LONG ret;
2874 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2875 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2876 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2877 if (sz < sizeof(DEVMODEA))
2879 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2880 return FALSE;
2882 /* ensures that dmSize is not erratically bogus if registry is invalid */
2883 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2884 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2885 if(unicode) {
2886 sz += (CCHDEVICENAME + CCHFORMNAME);
2887 if(buflen >= sz) {
2888 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2889 memcpy(ptr, dmW, sz);
2890 HeapFree(GetProcessHeap(),0,dmW);
2893 *needed = sz;
2894 return TRUE;
2897 /*********************************************************************
2898 * WINSPOOL_GetPrinter_2
2900 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2901 * The strings are either stored as unicode or ascii.
2903 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2904 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2905 BOOL unicode)
2907 DWORD size, left = cbBuf;
2908 BOOL space = (cbBuf > 0);
2909 LPBYTE ptr = buf;
2911 *pcbNeeded = 0;
2913 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2914 unicode)) {
2915 if(space && size <= left) {
2916 pi2->pPrinterName = (LPWSTR)ptr;
2917 ptr += size;
2918 left -= size;
2919 } else
2920 space = FALSE;
2921 *pcbNeeded += size;
2923 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2924 unicode)) {
2925 if(space && size <= left) {
2926 pi2->pShareName = (LPWSTR)ptr;
2927 ptr += size;
2928 left -= size;
2929 } else
2930 space = FALSE;
2931 *pcbNeeded += size;
2933 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2934 unicode)) {
2935 if(space && size <= left) {
2936 pi2->pPortName = (LPWSTR)ptr;
2937 ptr += size;
2938 left -= size;
2939 } else
2940 space = FALSE;
2941 *pcbNeeded += size;
2943 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2944 &size, unicode)) {
2945 if(space && size <= left) {
2946 pi2->pDriverName = (LPWSTR)ptr;
2947 ptr += size;
2948 left -= size;
2949 } else
2950 space = FALSE;
2951 *pcbNeeded += size;
2953 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2954 unicode)) {
2955 if(space && size <= left) {
2956 pi2->pComment = (LPWSTR)ptr;
2957 ptr += size;
2958 left -= size;
2959 } else
2960 space = FALSE;
2961 *pcbNeeded += size;
2963 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2964 unicode)) {
2965 if(space && size <= left) {
2966 pi2->pLocation = (LPWSTR)ptr;
2967 ptr += size;
2968 left -= size;
2969 } else
2970 space = FALSE;
2971 *pcbNeeded += size;
2973 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2974 &size, unicode)) {
2975 if(space && size <= left) {
2976 pi2->pDevMode = (LPDEVMODEW)ptr;
2977 ptr += size;
2978 left -= size;
2979 } else
2980 space = FALSE;
2981 *pcbNeeded += size;
2983 else
2985 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2986 if(space && size <= left) {
2987 pi2->pDevMode = (LPDEVMODEW)ptr;
2988 ptr += size;
2989 left -= size;
2990 } else
2991 space = FALSE;
2992 *pcbNeeded += size;
2994 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2995 &size, unicode)) {
2996 if(space && size <= left) {
2997 pi2->pSepFile = (LPWSTR)ptr;
2998 ptr += size;
2999 left -= size;
3000 } else
3001 space = FALSE;
3002 *pcbNeeded += size;
3004 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3005 &size, unicode)) {
3006 if(space && size <= left) {
3007 pi2->pPrintProcessor = (LPWSTR)ptr;
3008 ptr += size;
3009 left -= size;
3010 } else
3011 space = FALSE;
3012 *pcbNeeded += size;
3014 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3015 &size, unicode)) {
3016 if(space && size <= left) {
3017 pi2->pDatatype = (LPWSTR)ptr;
3018 ptr += size;
3019 left -= size;
3020 } else
3021 space = FALSE;
3022 *pcbNeeded += size;
3024 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3025 &size, unicode)) {
3026 if(space && size <= left) {
3027 pi2->pParameters = (LPWSTR)ptr;
3028 ptr += size;
3029 left -= size;
3030 } else
3031 space = FALSE;
3032 *pcbNeeded += size;
3034 if(pi2) {
3035 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3036 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3037 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3038 "Default Priority");
3039 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3040 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3043 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3044 memset(pi2, 0, sizeof(*pi2));
3046 return space;
3049 /*********************************************************************
3050 * WINSPOOL_GetPrinter_4
3052 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3054 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3055 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3056 BOOL unicode)
3058 DWORD size, left = cbBuf;
3059 BOOL space = (cbBuf > 0);
3060 LPBYTE ptr = buf;
3062 *pcbNeeded = 0;
3064 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3065 unicode)) {
3066 if(space && size <= left) {
3067 pi4->pPrinterName = (LPWSTR)ptr;
3068 ptr += size;
3069 left -= size;
3070 } else
3071 space = FALSE;
3072 *pcbNeeded += size;
3074 if(pi4) {
3075 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3078 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3079 memset(pi4, 0, sizeof(*pi4));
3081 return space;
3084 /*********************************************************************
3085 * WINSPOOL_GetPrinter_5
3087 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3089 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3090 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3091 BOOL unicode)
3093 DWORD size, left = cbBuf;
3094 BOOL space = (cbBuf > 0);
3095 LPBYTE ptr = buf;
3097 *pcbNeeded = 0;
3099 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3100 unicode)) {
3101 if(space && size <= left) {
3102 pi5->pPrinterName = (LPWSTR)ptr;
3103 ptr += size;
3104 left -= size;
3105 } else
3106 space = FALSE;
3107 *pcbNeeded += size;
3109 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3110 unicode)) {
3111 if(space && size <= left) {
3112 pi5->pPortName = (LPWSTR)ptr;
3113 ptr += size;
3114 left -= size;
3115 } else
3116 space = FALSE;
3117 *pcbNeeded += size;
3119 if(pi5) {
3120 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3121 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3122 "dnsTimeout");
3123 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3124 "txTimeout");
3127 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3128 memset(pi5, 0, sizeof(*pi5));
3130 return space;
3133 /*****************************************************************************
3134 * WINSPOOL_GetPrinter
3136 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3137 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3138 * just a collection of pointers to strings.
3140 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3141 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3143 LPCWSTR name;
3144 DWORD size, needed = 0;
3145 LPBYTE ptr = NULL;
3146 HKEY hkeyPrinter, hkeyPrinters;
3147 BOOL ret;
3149 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3151 if (!(name = get_opened_printer_name(hPrinter))) {
3152 SetLastError(ERROR_INVALID_HANDLE);
3153 return FALSE;
3156 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3157 ERROR_SUCCESS) {
3158 ERR("Can't create Printers key\n");
3159 return FALSE;
3161 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3163 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3164 RegCloseKey(hkeyPrinters);
3165 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3166 return FALSE;
3169 switch(Level) {
3170 case 2:
3172 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3174 size = sizeof(PRINTER_INFO_2W);
3175 if(size <= cbBuf) {
3176 ptr = pPrinter + size;
3177 cbBuf -= size;
3178 memset(pPrinter, 0, size);
3179 } else {
3180 pi2 = NULL;
3181 cbBuf = 0;
3183 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3184 unicode);
3185 needed += size;
3186 break;
3189 case 4:
3191 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3193 size = sizeof(PRINTER_INFO_4W);
3194 if(size <= cbBuf) {
3195 ptr = pPrinter + size;
3196 cbBuf -= size;
3197 memset(pPrinter, 0, size);
3198 } else {
3199 pi4 = NULL;
3200 cbBuf = 0;
3202 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3203 unicode);
3204 needed += size;
3205 break;
3209 case 5:
3211 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3213 size = sizeof(PRINTER_INFO_5W);
3214 if(size <= cbBuf) {
3215 ptr = pPrinter + size;
3216 cbBuf -= size;
3217 memset(pPrinter, 0, size);
3218 } else {
3219 pi5 = NULL;
3220 cbBuf = 0;
3223 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3224 unicode);
3225 needed += size;
3226 break;
3229 default:
3230 FIXME("Unimplemented level %ld\n", Level);
3231 SetLastError(ERROR_INVALID_LEVEL);
3232 RegCloseKey(hkeyPrinters);
3233 RegCloseKey(hkeyPrinter);
3234 return FALSE;
3237 RegCloseKey(hkeyPrinter);
3238 RegCloseKey(hkeyPrinters);
3240 TRACE("returning %d needed = %ld\n", ret, needed);
3241 if(pcbNeeded) *pcbNeeded = needed;
3242 if(!ret)
3243 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3244 return ret;
3247 /*****************************************************************************
3248 * GetPrinterW [WINSPOOL.@]
3250 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3251 DWORD cbBuf, LPDWORD pcbNeeded)
3253 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3254 TRUE);
3257 /*****************************************************************************
3258 * GetPrinterA [WINSPOOL.@]
3260 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3261 DWORD cbBuf, LPDWORD pcbNeeded)
3263 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3264 FALSE);
3267 /*****************************************************************************
3268 * WINSPOOL_EnumPrinters
3270 * Implementation of EnumPrintersA|W
3272 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3273 DWORD dwLevel, LPBYTE lpbPrinters,
3274 DWORD cbBuf, LPDWORD lpdwNeeded,
3275 LPDWORD lpdwReturned, BOOL unicode)
3278 HKEY hkeyPrinters, hkeyPrinter;
3279 WCHAR PrinterName[255];
3280 DWORD needed = 0, number = 0;
3281 DWORD used, i, left;
3282 PBYTE pi, buf;
3284 if(lpbPrinters)
3285 memset(lpbPrinters, 0, cbBuf);
3286 if(lpdwReturned)
3287 *lpdwReturned = 0;
3288 if(lpdwNeeded)
3289 *lpdwNeeded = 0;
3291 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3292 if(dwType == PRINTER_ENUM_DEFAULT)
3293 return TRUE;
3295 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3296 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3297 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3298 if(!dwType) return TRUE;
3301 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3302 FIXME("dwType = %08lx\n", dwType);
3303 SetLastError(ERROR_INVALID_FLAGS);
3304 return FALSE;
3307 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3308 ERROR_SUCCESS) {
3309 ERR("Can't create Printers key\n");
3310 return FALSE;
3313 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3314 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3315 RegCloseKey(hkeyPrinters);
3316 ERR("Can't query Printers key\n");
3317 return FALSE;
3319 TRACE("Found %ld printers\n", number);
3321 switch(dwLevel) {
3322 case 1:
3323 RegCloseKey(hkeyPrinters);
3324 if (lpdwReturned)
3325 *lpdwReturned = number;
3326 return TRUE;
3328 case 2:
3329 used = number * sizeof(PRINTER_INFO_2W);
3330 break;
3331 case 4:
3332 used = number * sizeof(PRINTER_INFO_4W);
3333 break;
3334 case 5:
3335 used = number * sizeof(PRINTER_INFO_5W);
3336 break;
3338 default:
3339 SetLastError(ERROR_INVALID_LEVEL);
3340 RegCloseKey(hkeyPrinters);
3341 return FALSE;
3343 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3345 for(i = 0; i < number; i++) {
3346 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3347 ERROR_SUCCESS) {
3348 ERR("Can't enum key number %ld\n", i);
3349 RegCloseKey(hkeyPrinters);
3350 return FALSE;
3352 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3353 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3354 ERROR_SUCCESS) {
3355 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3356 RegCloseKey(hkeyPrinters);
3357 return FALSE;
3360 if(cbBuf > used) {
3361 buf = lpbPrinters + used;
3362 left = cbBuf - used;
3363 } else {
3364 buf = NULL;
3365 left = 0;
3368 switch(dwLevel) {
3369 case 2:
3370 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3371 left, &needed, unicode);
3372 used += needed;
3373 if(pi) pi += sizeof(PRINTER_INFO_2W);
3374 break;
3375 case 4:
3376 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3377 left, &needed, unicode);
3378 used += needed;
3379 if(pi) pi += sizeof(PRINTER_INFO_4W);
3380 break;
3381 case 5:
3382 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3383 left, &needed, unicode);
3384 used += needed;
3385 if(pi) pi += sizeof(PRINTER_INFO_5W);
3386 break;
3387 default:
3388 ERR("Shouldn't be here!\n");
3389 RegCloseKey(hkeyPrinter);
3390 RegCloseKey(hkeyPrinters);
3391 return FALSE;
3393 RegCloseKey(hkeyPrinter);
3395 RegCloseKey(hkeyPrinters);
3397 if(lpdwNeeded)
3398 *lpdwNeeded = used;
3400 if(used > cbBuf) {
3401 if(lpbPrinters)
3402 memset(lpbPrinters, 0, cbBuf);
3403 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3404 return FALSE;
3406 if(lpdwReturned)
3407 *lpdwReturned = number;
3408 SetLastError(ERROR_SUCCESS);
3409 return TRUE;
3413 /******************************************************************
3414 * EnumPrintersW [WINSPOOL.@]
3416 * Enumerates the available printers, print servers and print
3417 * providers, depending on the specified flags, name and level.
3419 * RETURNS:
3421 * If level is set to 1:
3422 * Not implemented yet!
3423 * Returns TRUE with an empty list.
3425 * If level is set to 2:
3426 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3427 * Returns an array of PRINTER_INFO_2 data structures in the
3428 * lpbPrinters buffer. Note that according to MSDN also an
3429 * OpenPrinter should be performed on every remote printer.
3431 * If level is set to 4 (officially WinNT only):
3432 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3433 * Fast: Only the registry is queried to retrieve printer names,
3434 * no connection to the driver is made.
3435 * Returns an array of PRINTER_INFO_4 data structures in the
3436 * lpbPrinters buffer.
3438 * If level is set to 5 (officially WinNT4/Win9x only):
3439 * Fast: Only the registry is queried to retrieve printer names,
3440 * no connection to the driver is made.
3441 * Returns an array of PRINTER_INFO_5 data structures in the
3442 * lpbPrinters buffer.
3444 * If level set to 3 or 6+:
3445 * returns zero (failure!)
3447 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3448 * for information.
3450 * BUGS:
3451 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3452 * - Only levels 2, 4 and 5 are implemented at the moment.
3453 * - 16-bit printer drivers are not enumerated.
3454 * - Returned amount of bytes used/needed does not match the real Windoze
3455 * implementation (as in this implementation, all strings are part
3456 * of the buffer, whereas Win32 keeps them somewhere else)
3457 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3459 * NOTE:
3460 * - In a regular Wine installation, no registry settings for printers
3461 * exist, which makes this function return an empty list.
3463 BOOL WINAPI EnumPrintersW(
3464 DWORD dwType, /* [in] Types of print objects to enumerate */
3465 LPWSTR lpszName, /* [in] name of objects to enumerate */
3466 DWORD dwLevel, /* [in] type of printer info structure */
3467 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3468 DWORD cbBuf, /* [in] max size of buffer in bytes */
3469 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3470 LPDWORD lpdwReturned /* [out] number of entries returned */
3473 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3474 lpdwNeeded, lpdwReturned, TRUE);
3477 /******************************************************************
3478 * EnumPrintersA [WINSPOOL.@]
3481 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3482 DWORD dwLevel, LPBYTE lpbPrinters,
3483 DWORD cbBuf, LPDWORD lpdwNeeded,
3484 LPDWORD lpdwReturned)
3486 BOOL ret;
3487 UNICODE_STRING lpszNameW;
3488 PWSTR pwstrNameW;
3490 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3491 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3492 lpdwNeeded, lpdwReturned, FALSE);
3493 RtlFreeUnicodeString(&lpszNameW);
3494 return ret;
3497 /*****************************************************************************
3498 * WINSPOOL_GetDriverInfoFromReg [internal]
3500 * Enters the information from the registry into the DRIVER_INFO struct
3502 * RETURNS
3503 * zero if the printer driver does not exist in the registry
3504 * (only if Level > 1) otherwise nonzero
3506 static BOOL WINSPOOL_GetDriverInfoFromReg(
3507 HKEY hkeyDrivers,
3508 LPWSTR DriverName,
3509 LPWSTR pEnvironment,
3510 DWORD Level,
3511 LPBYTE ptr, /* DRIVER_INFO */
3512 LPBYTE pDriverStrings, /* strings buffer */
3513 DWORD cbBuf, /* size of string buffer */
3514 LPDWORD pcbNeeded, /* space needed for str. */
3515 BOOL unicode) /* type of strings */
3517 DWORD size, tmp;
3518 HKEY hkeyDriver;
3519 LPBYTE strPtr = pDriverStrings;
3521 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3522 debugstr_w(DriverName), debugstr_w(pEnvironment),
3523 Level, ptr, pDriverStrings, cbBuf, unicode);
3525 if(unicode) {
3526 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3527 if (*pcbNeeded <= cbBuf)
3528 strcpyW((LPWSTR)strPtr, DriverName);
3529 } else {
3530 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3531 NULL, NULL);
3532 if(*pcbNeeded <= cbBuf)
3533 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3534 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3536 if(Level == 1) {
3537 if(ptr)
3538 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3539 return TRUE;
3540 } else {
3541 if(ptr)
3542 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3543 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3546 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3547 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3548 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3549 return FALSE;
3552 if(ptr)
3553 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3555 if(!pEnvironment)
3556 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3557 if(unicode)
3558 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3559 else
3560 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3561 NULL, NULL);
3562 *pcbNeeded += size;
3563 if(*pcbNeeded <= cbBuf) {
3564 if(unicode)
3565 strcpyW((LPWSTR)strPtr, pEnvironment);
3566 else
3567 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3568 (LPSTR)strPtr, size, NULL, NULL);
3569 if(ptr)
3570 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3571 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3574 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3575 unicode)) {
3576 *pcbNeeded += size;
3577 if(*pcbNeeded <= cbBuf)
3578 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3579 unicode);
3580 if(ptr)
3581 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3582 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3585 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3586 unicode)) {
3587 *pcbNeeded += size;
3588 if(*pcbNeeded <= cbBuf)
3589 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3590 &tmp, unicode);
3591 if(ptr)
3592 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3593 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3596 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3597 0, &size, unicode)) {
3598 *pcbNeeded += size;
3599 if(*pcbNeeded <= cbBuf)
3600 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3601 size, &tmp, unicode);
3602 if(ptr)
3603 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3604 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3607 if(Level == 2 ) {
3608 RegCloseKey(hkeyDriver);
3609 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3610 return TRUE;
3613 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3614 unicode)) {
3615 *pcbNeeded += size;
3616 if(*pcbNeeded <= cbBuf)
3617 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3618 size, &tmp, unicode);
3619 if(ptr)
3620 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3621 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3624 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3625 &size, unicode)) {
3626 *pcbNeeded += size;
3627 if(*pcbNeeded <= cbBuf)
3628 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3629 size, &tmp, unicode);
3630 if(ptr)
3631 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3632 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3635 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3636 unicode)) {
3637 *pcbNeeded += size;
3638 if(*pcbNeeded <= cbBuf)
3639 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3640 size, &tmp, unicode);
3641 if(ptr)
3642 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3643 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3646 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3647 unicode)) {
3648 *pcbNeeded += size;
3649 if(*pcbNeeded <= cbBuf)
3650 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3651 size, &tmp, unicode);
3652 if(ptr)
3653 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3654 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3657 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3658 RegCloseKey(hkeyDriver);
3659 return TRUE;
3662 /*****************************************************************************
3663 * WINSPOOL_GetPrinterDriver
3665 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3666 DWORD Level, LPBYTE pDriverInfo,
3667 DWORD cbBuf, LPDWORD pcbNeeded,
3668 BOOL unicode)
3670 LPCWSTR name;
3671 WCHAR DriverName[100];
3672 DWORD ret, type, size, needed = 0;
3673 LPBYTE ptr = NULL;
3674 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3676 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3677 Level,pDriverInfo,cbBuf, pcbNeeded);
3679 ZeroMemory(pDriverInfo, cbBuf);
3681 if (!(name = get_opened_printer_name(hPrinter))) {
3682 SetLastError(ERROR_INVALID_HANDLE);
3683 return FALSE;
3685 if(Level < 1 || Level > 6) {
3686 SetLastError(ERROR_INVALID_LEVEL);
3687 return FALSE;
3689 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3690 ERROR_SUCCESS) {
3691 ERR("Can't create Printers key\n");
3692 return FALSE;
3694 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3695 != ERROR_SUCCESS) {
3696 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3697 RegCloseKey(hkeyPrinters);
3698 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3699 return FALSE;
3701 size = sizeof(DriverName);
3702 DriverName[0] = 0;
3703 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3704 (LPBYTE)DriverName, &size);
3705 RegCloseKey(hkeyPrinter);
3706 RegCloseKey(hkeyPrinters);
3707 if(ret != ERROR_SUCCESS) {
3708 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3709 return FALSE;
3712 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3713 if(!hkeyDrivers) {
3714 ERR("Can't create Drivers key\n");
3715 return FALSE;
3718 switch(Level) {
3719 case 1:
3720 size = sizeof(DRIVER_INFO_1W);
3721 break;
3722 case 2:
3723 size = sizeof(DRIVER_INFO_2W);
3724 break;
3725 case 3:
3726 size = sizeof(DRIVER_INFO_3W);
3727 break;
3728 case 4:
3729 size = sizeof(DRIVER_INFO_4W);
3730 break;
3731 case 5:
3732 size = sizeof(DRIVER_INFO_5W);
3733 break;
3734 case 6:
3735 size = sizeof(DRIVER_INFO_6W);
3736 break;
3737 default:
3738 ERR("Invalid level\n");
3739 return FALSE;
3742 if(size <= cbBuf)
3743 ptr = pDriverInfo + size;
3745 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3746 pEnvironment, Level, pDriverInfo,
3747 (cbBuf < size) ? NULL : ptr,
3748 (cbBuf < size) ? 0 : cbBuf - size,
3749 &needed, unicode)) {
3750 RegCloseKey(hkeyDrivers);
3751 return FALSE;
3754 RegCloseKey(hkeyDrivers);
3756 if(pcbNeeded) *pcbNeeded = size + needed;
3757 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3758 if(cbBuf >= needed) return TRUE;
3759 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3760 return FALSE;
3763 /*****************************************************************************
3764 * GetPrinterDriverA [WINSPOOL.@]
3766 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3767 DWORD Level, LPBYTE pDriverInfo,
3768 DWORD cbBuf, LPDWORD pcbNeeded)
3770 BOOL ret;
3771 UNICODE_STRING pEnvW;
3772 PWSTR pwstrEnvW;
3774 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3775 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3776 cbBuf, pcbNeeded, FALSE);
3777 RtlFreeUnicodeString(&pEnvW);
3778 return ret;
3780 /*****************************************************************************
3781 * GetPrinterDriverW [WINSPOOL.@]
3783 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3784 DWORD Level, LPBYTE pDriverInfo,
3785 DWORD cbBuf, LPDWORD pcbNeeded)
3787 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3788 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3791 /*****************************************************************************
3792 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3794 * Return the PATH for the Printer-Drivers (UNICODE)
3796 * PARAMS
3797 * pName [I] Servername (NT only) or NULL (local Computer)
3798 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3799 * Level [I] Structure-Level (must be 1)
3800 * pDriverDirectory [O] PTR to Buffer that receives the Result
3801 * cbBuf [I] Size of Buffer at pDriverDirectory
3802 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3803 * required for pDriverDirectory
3805 * RETURNS
3806 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3807 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3808 * if cbBuf is too small
3810 * Native Values returned in pDriverDirectory on Success:
3811 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3812 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3813 *| win9x(Windows 4.0): "%winsysdir%"
3815 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3817 * FIXME
3818 *- Only NULL or "" is supported for pName
3821 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3822 DWORD Level, LPBYTE pDriverDirectory,
3823 DWORD cbBuf, LPDWORD pcbNeeded)
3825 DWORD needed;
3826 const printenv_t * env;
3828 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3829 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3830 if(pName != NULL && pName[0]) {
3831 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3832 SetLastError(ERROR_INVALID_PARAMETER);
3833 return FALSE;
3836 env = validate_envW(pEnvironment);
3837 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3839 if(Level != 1) {
3840 WARN("(Level: %ld) is ignored in win9x\n", Level);
3841 SetLastError(ERROR_INVALID_LEVEL);
3842 return FALSE;
3845 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3846 needed = GetSystemDirectoryW(NULL, 0);
3847 /* add the Size for the Subdirectories */
3848 needed += lstrlenW(spooldriversW);
3849 needed += lstrlenW(env->subdir);
3850 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3852 if(pcbNeeded)
3853 *pcbNeeded = needed;
3854 TRACE("required: 0x%lx/%ld\n", needed, needed);
3855 if(needed > cbBuf) {
3856 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3857 return FALSE;
3859 if(pcbNeeded == NULL) {
3860 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3861 SetLastError(RPC_X_NULL_REF_POINTER);
3862 return FALSE;
3864 if(pDriverDirectory == NULL) {
3865 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3866 SetLastError(ERROR_INVALID_USER_BUFFER);
3867 return FALSE;
3870 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3871 /* add the Subdirectories */
3872 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3873 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3874 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3875 return TRUE;
3879 /*****************************************************************************
3880 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3882 * Return the PATH for the Printer-Drivers (ANSI)
3884 * See GetPrinterDriverDirectoryW.
3886 * NOTES
3887 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3890 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3891 DWORD Level, LPBYTE pDriverDirectory,
3892 DWORD cbBuf, LPDWORD pcbNeeded)
3894 UNICODE_STRING nameW, environmentW;
3895 BOOL ret;
3896 DWORD pcbNeededW;
3897 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3898 WCHAR *driverDirectoryW = NULL;
3900 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3901 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3903 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3905 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3906 else nameW.Buffer = NULL;
3907 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3908 else environmentW.Buffer = NULL;
3910 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3911 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3912 if (ret) {
3913 DWORD needed;
3914 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3915 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3916 if(pcbNeeded)
3917 *pcbNeeded = needed;
3918 ret = (needed <= cbBuf) ? TRUE : FALSE;
3919 } else
3920 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3922 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3924 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3925 RtlFreeUnicodeString(&environmentW);
3926 RtlFreeUnicodeString(&nameW);
3928 return ret;
3931 /*****************************************************************************
3932 * AddPrinterDriverA [WINSPOOL.@]
3934 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3936 DRIVER_INFO_3A di3;
3937 HKEY hkeyDrivers, hkeyName;
3939 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3941 if(level != 2 && level != 3) {
3942 SetLastError(ERROR_INVALID_LEVEL);
3943 return FALSE;
3945 if ((pName) && (pName[0])) {
3946 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3947 SetLastError(ERROR_INVALID_PARAMETER);
3948 return FALSE;
3950 if(!pDriverInfo) {
3951 WARN("pDriverInfo == NULL\n");
3952 SetLastError(ERROR_INVALID_PARAMETER);
3953 return FALSE;
3956 if(level == 3)
3957 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3958 else {
3959 memset(&di3, 0, sizeof(di3));
3960 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3963 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3964 !di3.pDataFile) {
3965 SetLastError(ERROR_INVALID_PARAMETER);
3966 return FALSE;
3968 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3969 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3970 if(!di3.pHelpFile) di3.pHelpFile = "";
3971 if(!di3.pMonitorName) di3.pMonitorName = "";
3973 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3975 if(!hkeyDrivers) {
3976 ERR("Can't create Drivers key\n");
3977 return FALSE;
3980 if(level == 2) { /* apparently can't overwrite with level2 */
3981 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3982 RegCloseKey(hkeyName);
3983 RegCloseKey(hkeyDrivers);
3984 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3985 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3986 return FALSE;
3989 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3990 RegCloseKey(hkeyDrivers);
3991 ERR("Can't create Name key\n");
3992 return FALSE;
3994 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3996 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3997 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3998 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3999 sizeof(DWORD));
4000 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
4001 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4002 (LPBYTE) di3.pDependentFiles, 0);
4003 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
4004 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
4005 RegCloseKey(hkeyName);
4006 RegCloseKey(hkeyDrivers);
4008 return TRUE;
4011 /*****************************************************************************
4012 * AddPrinterDriverW [WINSPOOL.@]
4014 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4015 LPBYTE pDriverInfo)
4017 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
4018 level,pDriverInfo);
4019 return FALSE;
4022 /*****************************************************************************
4023 * AddPrintProcessorA [WINSPOOL.@]
4025 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4026 LPSTR pPrintProcessorName)
4028 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4029 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4030 return FALSE;
4033 /*****************************************************************************
4034 * AddPrintProcessorW [WINSPOOL.@]
4036 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4037 LPWSTR pPrintProcessorName)
4039 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4040 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4041 return FALSE;
4044 /*****************************************************************************
4045 * AddPrintProvidorA [WINSPOOL.@]
4047 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4049 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4050 return FALSE;
4053 /*****************************************************************************
4054 * AddPrintProvidorW [WINSPOOL.@]
4056 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4058 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4059 return FALSE;
4062 /*****************************************************************************
4063 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4065 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4066 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4068 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4069 pDevModeOutput, pDevModeInput);
4070 return 0;
4073 /*****************************************************************************
4074 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4076 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4077 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4079 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4080 pDevModeOutput, pDevModeInput);
4081 return 0;
4084 /*****************************************************************************
4085 * PrinterProperties [WINSPOOL.@]
4087 * Displays a dialog to set the properties of the printer.
4089 * RETURNS
4090 * nonzero on success or zero on failure
4092 * BUGS
4093 * implemented as stub only
4095 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4096 HANDLE hPrinter /* [in] handle to printer object */
4098 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4099 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4100 return FALSE;
4103 /*****************************************************************************
4104 * EnumJobsA [WINSPOOL.@]
4107 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4108 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4109 LPDWORD pcReturned)
4111 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4112 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4114 if(pcbNeeded) *pcbNeeded = 0;
4115 if(pcReturned) *pcReturned = 0;
4116 return FALSE;
4120 /*****************************************************************************
4121 * EnumJobsW [WINSPOOL.@]
4124 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4125 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4126 LPDWORD pcReturned)
4128 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4129 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4131 if(pcbNeeded) *pcbNeeded = 0;
4132 if(pcReturned) *pcReturned = 0;
4133 return FALSE;
4136 /*****************************************************************************
4137 * WINSPOOL_EnumPrinterDrivers [internal]
4139 * Delivers information about all printer drivers installed on the
4140 * localhost or a given server
4142 * RETURNS
4143 * nonzero on success or zero on failure. If the buffer for the returned
4144 * information is too small the function will return an error
4146 * BUGS
4147 * - only implemented for localhost, foreign hosts will return an error
4149 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4150 DWORD Level, LPBYTE pDriverInfo,
4151 DWORD cbBuf, LPDWORD pcbNeeded,
4152 LPDWORD pcReturned, BOOL unicode)
4154 { HKEY hkeyDrivers;
4155 DWORD i, needed, number = 0, size = 0;
4156 WCHAR DriverNameW[255];
4157 PBYTE ptr;
4159 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4160 debugstr_w(pName), debugstr_w(pEnvironment),
4161 Level, pDriverInfo, cbBuf, unicode);
4163 /* check for local drivers */
4164 if((pName) && (pName[0])) {
4165 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4166 SetLastError(ERROR_ACCESS_DENIED);
4167 return FALSE;
4170 /* check input parameter */
4171 if((Level < 1) || (Level > 3)) {
4172 ERR("unsupported level %ld\n", Level);
4173 SetLastError(ERROR_INVALID_LEVEL);
4174 return FALSE;
4177 /* initialize return values */
4178 if(pDriverInfo)
4179 memset( pDriverInfo, 0, cbBuf);
4180 *pcbNeeded = 0;
4181 *pcReturned = 0;
4183 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4184 if(!hkeyDrivers) {
4185 ERR("Can't open Drivers key\n");
4186 return FALSE;
4189 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4190 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4191 RegCloseKey(hkeyDrivers);
4192 ERR("Can't query Drivers key\n");
4193 return FALSE;
4195 TRACE("Found %ld Drivers\n", number);
4197 /* get size of single struct
4198 * unicode and ascii structure have the same size
4200 switch (Level) {
4201 case 1:
4202 size = sizeof(DRIVER_INFO_1A);
4203 break;
4204 case 2:
4205 size = sizeof(DRIVER_INFO_2A);
4206 break;
4207 case 3:
4208 size = sizeof(DRIVER_INFO_3A);
4209 break;
4212 /* calculate required buffer size */
4213 *pcbNeeded = size * number;
4215 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4216 i < number;
4217 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4218 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4219 != ERROR_SUCCESS) {
4220 ERR("Can't enum key number %ld\n", i);
4221 RegCloseKey(hkeyDrivers);
4222 return FALSE;
4224 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4225 pEnvironment, Level, ptr,
4226 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4227 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4228 &needed, unicode)) {
4229 RegCloseKey(hkeyDrivers);
4230 return FALSE;
4232 (*pcbNeeded) += needed;
4235 RegCloseKey(hkeyDrivers);
4237 if(cbBuf < *pcbNeeded){
4238 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4239 return FALSE;
4242 *pcReturned = number;
4243 return TRUE;
4246 /*****************************************************************************
4247 * EnumPrinterDriversW [WINSPOOL.@]
4249 * see function EnumPrinterDrivers for RETURNS, BUGS
4251 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4252 LPBYTE pDriverInfo, DWORD cbBuf,
4253 LPDWORD pcbNeeded, LPDWORD pcReturned)
4255 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4256 cbBuf, pcbNeeded, pcReturned, TRUE);
4259 /*****************************************************************************
4260 * EnumPrinterDriversA [WINSPOOL.@]
4262 * see function EnumPrinterDrivers for RETURNS, BUGS
4264 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4265 LPBYTE pDriverInfo, DWORD cbBuf,
4266 LPDWORD pcbNeeded, LPDWORD pcReturned)
4267 { BOOL ret;
4268 UNICODE_STRING pNameW, pEnvironmentW;
4269 PWSTR pwstrNameW, pwstrEnvironmentW;
4271 pwstrNameW = asciitounicode(&pNameW, pName);
4272 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4274 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4275 Level, pDriverInfo, cbBuf, pcbNeeded,
4276 pcReturned, FALSE);
4277 RtlFreeUnicodeString(&pNameW);
4278 RtlFreeUnicodeString(&pEnvironmentW);
4280 return ret;
4283 static CHAR PortMonitor[] = "Wine Port Monitor";
4284 static CHAR PortDescription[] = "Wine Port";
4286 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4288 HANDLE handle;
4290 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4291 NULL, OPEN_EXISTING, 0, NULL );
4292 if (handle == INVALID_HANDLE_VALUE)
4293 return FALSE;
4294 TRACE("Checking %s exists\n", name );
4295 CloseHandle( handle );
4296 return TRUE;
4299 static DWORD WINSPOOL_CountSerialPorts(void)
4301 CHAR name[6];
4302 DWORD n = 0, i;
4304 for (i=0; i<4; i++)
4306 strcpy( name, "COMx:" );
4307 name[3] = '1' + i;
4308 if (WINSPOOL_ComPortExists( name ))
4309 n++;
4312 return n;
4315 /******************************************************************************
4316 * EnumPortsA (WINSPOOL.@)
4318 * See EnumPortsW.
4320 * BUGS
4321 * ANSI-Version did not call the UNICODE-Version
4324 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4325 LPDWORD bufneeded,LPDWORD bufreturned)
4327 CHAR portname[10];
4328 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4329 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4330 HKEY hkey_printer;
4331 BOOL retval = TRUE;
4333 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4334 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4336 switch( level )
4338 case 1:
4339 info_size = sizeof (PORT_INFO_1A);
4340 break;
4341 case 2:
4342 info_size = sizeof (PORT_INFO_2A);
4343 break;
4344 default:
4345 SetLastError(ERROR_INVALID_LEVEL);
4346 return FALSE;
4349 /* see how many exist */
4351 hkey_printer = 0;
4352 serial_count = WINSPOOL_CountSerialPorts();
4353 printer_count = 0;
4355 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4356 if ( r == ERROR_SUCCESS )
4358 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4359 &printer_count, NULL, NULL, NULL, NULL);
4361 count = serial_count + printer_count;
4363 /* then fill in the structure info structure once
4364 we know the offset to the first string */
4366 memset( buffer, 0, bufsize );
4367 n = 0;
4368 ofs = info_size*count;
4369 for ( i=0; i<count; i++)
4371 DWORD vallen = sizeof(portname) - 1;
4373 /* get the serial port values, then the printer values */
4374 if ( i < serial_count )
4376 strcpy( portname, "COMx:" );
4377 portname[3] = '1' + i;
4378 if (!WINSPOOL_ComPortExists( portname ))
4379 continue;
4381 TRACE("Found %s\n", portname );
4382 vallen = strlen( portname );
4384 else
4386 r = RegEnumValueA( hkey_printer, i-serial_count,
4387 portname, &vallen, NULL, NULL, NULL, 0 );
4388 if ( r )
4389 continue;
4392 /* add a colon if necessary, and make it upper case */
4393 CharUpperBuffA(portname,vallen);
4394 if (strcasecmp(portname,"nul")!=0)
4395 if (vallen && (portname[vallen-1] != ':') )
4396 lstrcatA(portname,":");
4398 /* add the port info structure if we can fit it */
4399 if ( info_size*(n+1) < bufsize )
4401 if ( level == 1)
4403 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4404 info->pName = (LPSTR) &buffer[ofs];
4406 else if ( level == 2)
4408 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4409 info->pPortName = (LPSTR) &buffer[ofs];
4410 /* FIXME: fill in more stuff here */
4411 info->pMonitorName = PortMonitor;
4412 info->pDescription = PortDescription;
4413 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4416 /* add the name of the port if we can fit it */
4417 if ( ofs < bufsize )
4418 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4420 n++;
4422 else
4423 retval = FALSE;
4424 ofs += lstrlenA(portname)+1;
4427 RegCloseKey(hkey_printer);
4429 if(bufneeded)
4430 *bufneeded = ofs;
4432 if(bufreturned)
4433 *bufreturned = n;
4435 return retval;
4438 /******************************************************************************
4439 * EnumPortsW (WINSPOOL.@)
4441 * Enumerate available Ports
4443 * PARAMS
4444 * name [I] Servername or NULL (local Computer)
4445 * level [I] Structure-Level (1 or 2)
4446 * buffer [O] PTR to Buffer that receives the Result
4447 * bufsize [I] Size of Buffer at buffer
4448 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4449 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4451 * RETURNS
4452 * Success: TRUE
4453 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4455 * BUGS
4456 * UNICODE-Version is a stub
4459 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4460 LPDWORD bufneeded,LPDWORD bufreturned)
4462 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4463 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4464 return FALSE;
4467 /******************************************************************************
4468 * GetDefaultPrinterW (WINSPOOL.@)
4470 * FIXME
4471 * This function must read the value from data 'device' of key
4472 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4474 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4476 BOOL retval = TRUE;
4477 DWORD insize, len;
4478 WCHAR *buffer, *ptr;
4480 if (!namesize)
4482 SetLastError(ERROR_INVALID_PARAMETER);
4483 return FALSE;
4486 /* make the buffer big enough for the stuff from the profile/registry,
4487 * the content must fit into the local buffer to compute the correct
4488 * size even if the extern buffer is too small or not given.
4489 * (20 for ,driver,port) */
4490 insize = *namesize;
4491 len = max(100, (insize + 20));
4492 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4494 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4496 SetLastError (ERROR_FILE_NOT_FOUND);
4497 retval = FALSE;
4498 goto end;
4500 TRACE("%s\n", debugstr_w(buffer));
4502 if ((ptr = strchrW(buffer, ',')) == NULL)
4504 SetLastError(ERROR_INVALID_NAME);
4505 retval = FALSE;
4506 goto end;
4509 *ptr = 0;
4510 *namesize = strlenW(buffer) + 1;
4511 if(!name || (*namesize > insize))
4513 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4514 retval = FALSE;
4515 goto end;
4517 strcpyW(name, buffer);
4519 end:
4520 HeapFree( GetProcessHeap(), 0, buffer);
4521 return retval;
4525 /******************************************************************************
4526 * GetDefaultPrinterA (WINSPOOL.@)
4528 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4530 BOOL retval = TRUE;
4531 DWORD insize = 0;
4532 WCHAR *bufferW = NULL;
4534 if (!namesize)
4536 SetLastError(ERROR_INVALID_PARAMETER);
4537 return FALSE;
4540 if(name && *namesize) {
4541 insize = *namesize;
4542 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4545 if(!GetDefaultPrinterW( bufferW, namesize)) {
4546 retval = FALSE;
4547 goto end;
4550 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4551 NULL, NULL);
4552 if (!*namesize)
4554 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4555 retval = FALSE;
4557 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4559 end:
4560 HeapFree( GetProcessHeap(), 0, bufferW);
4561 return retval;
4565 /******************************************************************************
4566 * SetDefaultPrinterW (WINSPOOL.204)
4568 * Set the Name of the Default Printer
4570 * PARAMS
4571 * pszPrinter [I] Name of the Printer or NULL
4573 * RETURNS
4574 * Success: True
4575 * Failure: FALSE
4577 * NOTES
4578 * When the Parameter is NULL or points to an Empty String and
4579 * a Default Printer was already present, then this Function changes nothing.
4580 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4581 * the First enumerated local Printer is used.
4584 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4587 TRACE("(%s)\n", debugstr_w(pszPrinter));
4589 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4590 return FALSE;
4593 /******************************************************************************
4594 * SetDefaultPrinterA (WINSPOOL.202)
4596 * See SetDefaultPrinterW.
4599 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4602 TRACE("(%s)\n", debugstr_a(pszPrinter));
4604 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4605 return FALSE;
4609 /******************************************************************************
4610 * SetPrinterDataExA (WINSPOOL.@)
4612 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4613 LPCSTR pValueName, DWORD Type,
4614 LPBYTE pData, DWORD cbData)
4616 HKEY hkeyPrinter, hkeySubkey;
4617 DWORD ret;
4619 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4620 debugstr_a(pValueName), Type, pData, cbData);
4622 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4623 != ERROR_SUCCESS)
4624 return ret;
4626 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4627 != ERROR_SUCCESS) {
4628 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4629 RegCloseKey(hkeyPrinter);
4630 return ret;
4632 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4633 RegCloseKey(hkeySubkey);
4634 RegCloseKey(hkeyPrinter);
4635 return ret;
4638 /******************************************************************************
4639 * SetPrinterDataExW (WINSPOOL.@)
4641 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4642 LPCWSTR pValueName, DWORD Type,
4643 LPBYTE pData, DWORD cbData)
4645 HKEY hkeyPrinter, hkeySubkey;
4646 DWORD ret;
4648 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4649 debugstr_w(pValueName), Type, pData, cbData);
4651 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4652 != ERROR_SUCCESS)
4653 return ret;
4655 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4656 != ERROR_SUCCESS) {
4657 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4658 RegCloseKey(hkeyPrinter);
4659 return ret;
4661 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4662 RegCloseKey(hkeySubkey);
4663 RegCloseKey(hkeyPrinter);
4664 return ret;
4667 /******************************************************************************
4668 * SetPrinterDataA (WINSPOOL.@)
4670 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4671 LPBYTE pData, DWORD cbData)
4673 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4674 pData, cbData);
4677 /******************************************************************************
4678 * SetPrinterDataW (WINSPOOL.@)
4680 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4681 LPBYTE pData, DWORD cbData)
4683 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4684 pData, cbData);
4687 /******************************************************************************
4688 * GetPrinterDataExA (WINSPOOL.@)
4690 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4691 LPCSTR pValueName, LPDWORD pType,
4692 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4694 HKEY hkeyPrinter, hkeySubkey;
4695 DWORD ret;
4697 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4698 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4699 pcbNeeded);
4701 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4702 != ERROR_SUCCESS)
4703 return ret;
4705 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4706 != ERROR_SUCCESS) {
4707 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4708 RegCloseKey(hkeyPrinter);
4709 return ret;
4711 *pcbNeeded = nSize;
4712 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4713 RegCloseKey(hkeySubkey);
4714 RegCloseKey(hkeyPrinter);
4715 return ret;
4718 /******************************************************************************
4719 * GetPrinterDataExW (WINSPOOL.@)
4721 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4722 LPCWSTR pValueName, LPDWORD pType,
4723 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4725 HKEY hkeyPrinter, hkeySubkey;
4726 DWORD ret;
4728 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4729 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4730 pcbNeeded);
4732 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4733 != ERROR_SUCCESS)
4734 return ret;
4736 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4737 != ERROR_SUCCESS) {
4738 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4739 RegCloseKey(hkeyPrinter);
4740 return ret;
4742 *pcbNeeded = nSize;
4743 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4744 RegCloseKey(hkeySubkey);
4745 RegCloseKey(hkeyPrinter);
4746 return ret;
4749 /******************************************************************************
4750 * GetPrinterDataA (WINSPOOL.@)
4752 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4753 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4755 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4756 pData, nSize, pcbNeeded);
4759 /******************************************************************************
4760 * GetPrinterDataW (WINSPOOL.@)
4762 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4763 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4765 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4766 pData, nSize, pcbNeeded);
4769 /*******************************************************************************
4770 * EnumPrinterDataExW [WINSPOOL.@]
4772 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4773 LPBYTE pEnumValues, DWORD cbEnumValues,
4774 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4776 HKEY hkPrinter, hkSubKey;
4777 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4778 cbValueNameLen, cbMaxValueLen, cbValueLen,
4779 cbBufSize, dwType;
4780 LPWSTR lpValueName;
4781 HANDLE hHeap;
4782 PBYTE lpValue;
4783 PPRINTER_ENUM_VALUESW ppev;
4785 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4787 if (pKeyName == NULL || *pKeyName == 0)
4788 return ERROR_INVALID_PARAMETER;
4790 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4791 if (ret != ERROR_SUCCESS)
4793 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4794 hPrinter, ret);
4795 return ret;
4798 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4799 if (ret != ERROR_SUCCESS)
4801 r = RegCloseKey (hkPrinter);
4802 if (r != ERROR_SUCCESS)
4803 WARN ("RegCloseKey returned %li\n", r);
4804 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4805 debugstr_w (pKeyName), ret);
4806 return ret;
4809 ret = RegCloseKey (hkPrinter);
4810 if (ret != ERROR_SUCCESS)
4812 ERR ("RegCloseKey returned %li\n", ret);
4813 r = RegCloseKey (hkSubKey);
4814 if (r != ERROR_SUCCESS)
4815 WARN ("RegCloseKey returned %li\n", r);
4816 return ret;
4819 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4820 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4821 if (ret != ERROR_SUCCESS)
4823 r = RegCloseKey (hkSubKey);
4824 if (r != ERROR_SUCCESS)
4825 WARN ("RegCloseKey returned %li\n", r);
4826 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4827 return ret;
4830 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4831 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4833 if (cValues == 0) /* empty key */
4835 r = RegCloseKey (hkSubKey);
4836 if (r != ERROR_SUCCESS)
4837 WARN ("RegCloseKey returned %li\n", r);
4838 *pcbEnumValues = *pnEnumValues = 0;
4839 return ERROR_SUCCESS;
4842 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4844 hHeap = GetProcessHeap ();
4845 if (hHeap == NULL)
4847 ERR ("GetProcessHeap failed\n");
4848 r = RegCloseKey (hkSubKey);
4849 if (r != ERROR_SUCCESS)
4850 WARN ("RegCloseKey returned %li\n", r);
4851 return ERROR_OUTOFMEMORY;
4854 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4855 if (lpValueName == NULL)
4857 ERR ("Failed to allocate %li bytes from process heap\n",
4858 cbMaxValueNameLen * sizeof (WCHAR));
4859 r = RegCloseKey (hkSubKey);
4860 if (r != ERROR_SUCCESS)
4861 WARN ("RegCloseKey returned %li\n", r);
4862 return ERROR_OUTOFMEMORY;
4865 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4866 if (lpValue == NULL)
4868 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4869 if (HeapFree (hHeap, 0, lpValueName) == 0)
4870 WARN ("HeapFree failed with code %li\n", GetLastError ());
4871 r = RegCloseKey (hkSubKey);
4872 if (r != ERROR_SUCCESS)
4873 WARN ("RegCloseKey returned %li\n", r);
4874 return ERROR_OUTOFMEMORY;
4877 TRACE ("pass 1: calculating buffer required for all names and values\n");
4879 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4881 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4883 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4885 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4886 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4887 NULL, NULL, lpValue, &cbValueLen);
4888 if (ret != ERROR_SUCCESS)
4890 if (HeapFree (hHeap, 0, lpValue) == 0)
4891 WARN ("HeapFree failed with code %li\n", GetLastError ());
4892 if (HeapFree (hHeap, 0, lpValueName) == 0)
4893 WARN ("HeapFree failed with code %li\n", GetLastError ());
4894 r = RegCloseKey (hkSubKey);
4895 if (r != ERROR_SUCCESS)
4896 WARN ("RegCloseKey returned %li\n", r);
4897 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4898 return ret;
4901 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4902 debugstr_w (lpValueName), dwIndex,
4903 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4905 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4906 cbBufSize += cbValueLen;
4909 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4911 *pcbEnumValues = cbBufSize;
4912 *pnEnumValues = cValues;
4914 if (cbEnumValues < cbBufSize) /* buffer too small */
4916 if (HeapFree (hHeap, 0, lpValue) == 0)
4917 WARN ("HeapFree failed with code %li\n", GetLastError ());
4918 if (HeapFree (hHeap, 0, lpValueName) == 0)
4919 WARN ("HeapFree failed with code %li\n", GetLastError ());
4920 r = RegCloseKey (hkSubKey);
4921 if (r != ERROR_SUCCESS)
4922 WARN ("RegCloseKey returned %li\n", r);
4923 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4924 return ERROR_MORE_DATA;
4927 TRACE ("pass 2: copying all names and values to buffer\n");
4929 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4930 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4932 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4934 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4935 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4936 NULL, &dwType, lpValue, &cbValueLen);
4937 if (ret != ERROR_SUCCESS)
4939 if (HeapFree (hHeap, 0, lpValue) == 0)
4940 WARN ("HeapFree failed with code %li\n", GetLastError ());
4941 if (HeapFree (hHeap, 0, lpValueName) == 0)
4942 WARN ("HeapFree failed with code %li\n", GetLastError ());
4943 r = RegCloseKey (hkSubKey);
4944 if (r != ERROR_SUCCESS)
4945 WARN ("RegCloseKey returned %li\n", r);
4946 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4947 return ret;
4950 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4951 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4952 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4953 pEnumValues += cbValueNameLen;
4955 /* return # of *bytes* (including trailing \0), not # of chars */
4956 ppev[dwIndex].cbValueName = cbValueNameLen;
4958 ppev[dwIndex].dwType = dwType;
4960 memcpy (pEnumValues, lpValue, cbValueLen);
4961 ppev[dwIndex].pData = pEnumValues;
4962 pEnumValues += cbValueLen;
4964 ppev[dwIndex].cbData = cbValueLen;
4966 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4967 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4970 if (HeapFree (hHeap, 0, lpValue) == 0)
4972 ret = GetLastError ();
4973 ERR ("HeapFree failed with code %li\n", ret);
4974 if (HeapFree (hHeap, 0, lpValueName) == 0)
4975 WARN ("HeapFree failed with code %li\n", GetLastError ());
4976 r = RegCloseKey (hkSubKey);
4977 if (r != ERROR_SUCCESS)
4978 WARN ("RegCloseKey returned %li\n", r);
4979 return ret;
4982 if (HeapFree (hHeap, 0, lpValueName) == 0)
4984 ret = GetLastError ();
4985 ERR ("HeapFree failed with code %li\n", ret);
4986 r = RegCloseKey (hkSubKey);
4987 if (r != ERROR_SUCCESS)
4988 WARN ("RegCloseKey returned %li\n", r);
4989 return ret;
4992 ret = RegCloseKey (hkSubKey);
4993 if (ret != ERROR_SUCCESS)
4995 ERR ("RegCloseKey returned %li\n", ret);
4996 return ret;
4999 return ERROR_SUCCESS;
5002 /*******************************************************************************
5003 * EnumPrinterDataExA [WINSPOOL.@]
5005 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5006 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5007 * what Windows 2000 SP1 does.
5010 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5011 LPBYTE pEnumValues, DWORD cbEnumValues,
5012 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5014 INT len;
5015 LPWSTR pKeyNameW;
5016 DWORD ret, dwIndex, dwBufSize;
5017 HANDLE hHeap;
5018 LPSTR pBuffer;
5020 TRACE ("%p %s\n", hPrinter, pKeyName);
5022 if (pKeyName == NULL || *pKeyName == 0)
5023 return ERROR_INVALID_PARAMETER;
5025 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5026 if (len == 0)
5028 ret = GetLastError ();
5029 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5030 return ret;
5033 hHeap = GetProcessHeap ();
5034 if (hHeap == NULL)
5036 ERR ("GetProcessHeap failed\n");
5037 return ERROR_OUTOFMEMORY;
5040 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5041 if (pKeyNameW == NULL)
5043 ERR ("Failed to allocate %li bytes from process heap\n",
5044 (LONG) len * sizeof (WCHAR));
5045 return ERROR_OUTOFMEMORY;
5048 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5050 ret = GetLastError ();
5051 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5052 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5053 WARN ("HeapFree failed with code %li\n", GetLastError ());
5054 return ret;
5057 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5058 pcbEnumValues, pnEnumValues);
5059 if (ret != ERROR_SUCCESS)
5061 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5062 WARN ("HeapFree failed with code %li\n", GetLastError ());
5063 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5064 return ret;
5067 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5069 ret = GetLastError ();
5070 ERR ("HeapFree failed with code %li\n", ret);
5071 return ret;
5074 if (*pnEnumValues == 0) /* empty key */
5075 return ERROR_SUCCESS;
5077 dwBufSize = 0;
5078 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5080 PPRINTER_ENUM_VALUESW ppev =
5081 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5083 if (dwBufSize < ppev->cbValueName)
5084 dwBufSize = ppev->cbValueName;
5086 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5087 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5088 dwBufSize = ppev->cbData;
5091 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5093 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5094 if (pBuffer == NULL)
5096 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5097 return ERROR_OUTOFMEMORY;
5100 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5102 PPRINTER_ENUM_VALUESW ppev =
5103 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5105 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5106 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5107 NULL);
5108 if (len == 0)
5110 ret = GetLastError ();
5111 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5112 if (HeapFree (hHeap, 0, pBuffer) == 0)
5113 WARN ("HeapFree failed with code %li\n", GetLastError ());
5114 return ret;
5117 memcpy (ppev->pValueName, pBuffer, len);
5119 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5121 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5122 ppev->dwType != REG_MULTI_SZ)
5123 continue;
5125 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5126 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5127 if (len == 0)
5129 ret = GetLastError ();
5130 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5131 if (HeapFree (hHeap, 0, pBuffer) == 0)
5132 WARN ("HeapFree failed with code %li\n", GetLastError ());
5133 return ret;
5136 memcpy (ppev->pData, pBuffer, len);
5138 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5139 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5142 if (HeapFree (hHeap, 0, pBuffer) == 0)
5144 ret = GetLastError ();
5145 ERR ("HeapFree failed with code %li\n", ret);
5146 return ret;
5149 return ERROR_SUCCESS;
5152 /******************************************************************************
5153 * AbortPrinter (WINSPOOL.@)
5155 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5157 FIXME("(%p), stub!\n", hPrinter);
5158 return TRUE;
5161 /******************************************************************************
5162 * AddPortA (WINSPOOL.@)
5164 * See AddPortW.
5167 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5169 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5170 return FALSE;
5173 /******************************************************************************
5174 * AddPortW (WINSPOOL.@)
5176 * Add a Port for a specific Monitor
5178 * PARAMS
5179 * pName [I] Servername or NULL (local Computer)
5180 * hWnd [I] Handle to parent Window for the Dialog-Box
5181 * pMonitorName [I] Name of the Monitor that manage the Port
5183 * RETURNS
5184 * Success: TRUE
5185 * Failure: FALSE
5187 * BUGS
5188 * only a Stub
5191 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5193 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5194 return FALSE;
5197 /******************************************************************************
5198 * AddPortExA (WINSPOOL.@)
5200 * See AddPortExW.
5203 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5205 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5206 lpBuffer, debugstr_a(lpMonitorName));
5207 return FALSE;
5210 /******************************************************************************
5211 * AddPortExW (WINSPOOL.@)
5213 * Add a Port for a specific Monitor, without presenting a user interface
5215 * PARAMS
5216 * hMonitor [I] Handle from InitializePrintMonitor2()
5217 * pName [I] Servername or NULL (local Computer)
5218 * Level [I] Structure-Level (1 or 2) for lpBuffer
5219 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5220 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5222 * RETURNS
5223 * Success: TRUE
5224 * Failure: FALSE
5226 * BUGS
5227 * only a Stub
5230 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5232 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5233 lpBuffer, debugstr_w(lpMonitorName));
5234 return FALSE;
5237 /******************************************************************************
5238 * AddPrinterConnectionA (WINSPOOL.@)
5240 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5242 FIXME("%s\n", debugstr_a(pName));
5243 return FALSE;
5246 /******************************************************************************
5247 * AddPrinterConnectionW (WINSPOOL.@)
5249 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5251 FIXME("%s\n", debugstr_w(pName));
5252 return FALSE;
5255 /******************************************************************************
5256 * AddPrinterDriverExW (WINSPOOL.@)
5258 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5259 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5261 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5262 Level, pDriverInfo, dwFileCopyFlags);
5263 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5264 return FALSE;
5267 /******************************************************************************
5268 * AddPrinterDriverExA (WINSPOOL.@)
5270 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5271 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5273 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5274 Level, pDriverInfo, dwFileCopyFlags);
5275 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5276 return FALSE;
5279 /******************************************************************************
5280 * ConfigurePortA (WINSPOOL.@)
5282 * See ConfigurePortW.
5285 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5287 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5288 return FALSE;
5291 /******************************************************************************
5292 * ConfigurePortW (WINSPOOL.@)
5294 * Display the Configuration-Dialog for a specific Port
5296 * PARAMS
5297 * pName [I] Servername or NULL (local Computer)
5298 * hWnd [I] Handle to parent Window for the Dialog-Box
5299 * pPortName [I] Name of the Port, that should be configured
5301 * RETURNS
5302 * Success: TRUE
5303 * Failure: FALSE
5305 * BUGS
5306 * only a Stub
5309 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5311 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5312 return FALSE;
5315 /******************************************************************************
5316 * ConnectToPrinterDlg (WINSPOOL.@)
5318 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5320 FIXME("%p %lx\n", hWnd, Flags);
5321 return NULL;
5324 /******************************************************************************
5325 * DeletePrinterConnectionA (WINSPOOL.@)
5327 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5329 FIXME("%s\n", debugstr_a(pName));
5330 return TRUE;
5333 /******************************************************************************
5334 * DeletePrinterConnectionW (WINSPOOL.@)
5336 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5338 FIXME("%s\n", debugstr_w(pName));
5339 return TRUE;
5342 /******************************************************************************
5343 * DeletePrinterDriverExW (WINSPOOL.@)
5345 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5346 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5348 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5349 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5350 return TRUE;
5353 /******************************************************************************
5354 * DeletePrinterDriverExA (WINSPOOL.@)
5356 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5357 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5359 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5360 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5361 return TRUE;
5364 /******************************************************************************
5365 * DeletePrinterDataExW (WINSPOOL.@)
5367 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5368 LPCWSTR pValueName)
5370 FIXME("%p %s %s\n", hPrinter,
5371 debugstr_w(pKeyName), debugstr_w(pValueName));
5372 return ERROR_INVALID_PARAMETER;
5375 /******************************************************************************
5376 * DeletePrinterDataExA (WINSPOOL.@)
5378 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5379 LPCSTR pValueName)
5381 FIXME("%p %s %s\n", hPrinter,
5382 debugstr_a(pKeyName), debugstr_a(pValueName));
5383 return ERROR_INVALID_PARAMETER;
5386 /******************************************************************************
5387 * DeletePrintProcessorA (WINSPOOL.@)
5389 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5391 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5392 debugstr_a(pPrintProcessorName));
5393 return TRUE;
5396 /******************************************************************************
5397 * DeletePrintProcessorW (WINSPOOL.@)
5399 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5401 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5402 debugstr_w(pPrintProcessorName));
5403 return TRUE;
5406 /******************************************************************************
5407 * DeletePrintProvidorA (WINSPOOL.@)
5409 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5411 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5412 debugstr_a(pPrintProviderName));
5413 return TRUE;
5416 /******************************************************************************
5417 * DeletePrintProvidorW (WINSPOOL.@)
5419 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5421 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5422 debugstr_w(pPrintProviderName));
5423 return TRUE;
5426 /******************************************************************************
5427 * EnumFormsA (WINSPOOL.@)
5429 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5430 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5432 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5433 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5434 return FALSE;
5437 /******************************************************************************
5438 * EnumFormsW (WINSPOOL.@)
5440 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5441 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5443 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5444 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5445 return FALSE;
5448 /*****************************************************************************
5449 * EnumMonitorsA [WINSPOOL.@]
5451 * See EnumMonitorsW.
5454 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5455 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5457 BOOL res;
5458 LPBYTE bufferW = NULL;
5459 LPWSTR nameW = NULL;
5460 DWORD needed = 0;
5461 DWORD numentries = 0;
5462 INT len;
5464 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5465 cbBuf, pcbNeeded, pcReturned);
5467 /* convert servername to unicode */
5468 if (pName) {
5469 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5470 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5471 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5473 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5474 needed = cbBuf * sizeof(WCHAR);
5475 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5476 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5478 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5479 if (pcbNeeded) needed = *pcbNeeded;
5480 /* HeapReAlloc return NULL, when bufferW was NULL */
5481 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5482 HeapAlloc(GetProcessHeap(), 0, needed);
5484 /* Try again with the large Buffer */
5485 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5487 numentries = pcReturned ? *pcReturned : 0;
5488 needed = 0;
5490 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5491 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5493 if (res) {
5494 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5495 DWORD entrysize = 0;
5496 DWORD index;
5497 LPSTR ptr;
5498 LPMONITOR_INFO_2W mi2w;
5499 LPMONITOR_INFO_2A mi2a;
5501 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5502 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5504 /* First pass: calculate the size for all Entries */
5505 mi2w = (LPMONITOR_INFO_2W) bufferW;
5506 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5507 index = 0;
5508 while (index < numentries) {
5509 index++;
5510 needed += entrysize; /* MONITOR_INFO_?A */
5511 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5513 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5514 NULL, 0, NULL, NULL);
5515 if (Level > 1) {
5516 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5517 NULL, 0, NULL, NULL);
5518 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5519 NULL, 0, NULL, NULL);
5521 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5522 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5523 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5526 /* check for errors and quit on failure */
5527 if (cbBuf < needed) {
5528 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5529 res = FALSE;
5530 goto emA_cleanup;
5532 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5533 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5534 cbBuf -= len ; /* free Bytes in the user-Buffer */
5535 mi2w = (LPMONITOR_INFO_2W) bufferW;
5536 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5537 index = 0;
5538 /* Second Pass: Fill the User Buffer (if we have one) */
5539 while ((index < numentries) && pMonitors) {
5540 index++;
5541 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5542 mi2a->pName = ptr;
5543 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5544 ptr, cbBuf , NULL, NULL);
5545 ptr += len;
5546 cbBuf -= len;
5547 if (Level > 1) {
5548 mi2a->pEnvironment = ptr;
5549 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5550 ptr, cbBuf, NULL, NULL);
5551 ptr += len;
5552 cbBuf -= len;
5554 mi2a->pDLLName = ptr;
5555 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5556 ptr, cbBuf, NULL, NULL);
5557 ptr += len;
5558 cbBuf -= len;
5560 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5561 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5562 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5565 emA_cleanup:
5566 if (pcbNeeded) *pcbNeeded = needed;
5567 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5569 HeapFree(GetProcessHeap(), 0, nameW);
5570 HeapFree(GetProcessHeap(), 0, bufferW);
5572 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5573 (res), GetLastError(), needed, numentries);
5575 return (res);
5579 /*****************************************************************************
5580 * EnumMonitorsW [WINSPOOL.@]
5582 * Enumerate available Port-Monitors
5584 * PARAMS
5585 * pName [I] Servername or NULL (local Computer)
5586 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5587 * pMonitors [O] PTR to Buffer that receives the Result
5588 * cbBuf [I] Size of Buffer at pMonitors
5589 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5590 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5592 * RETURNS
5593 * Success: TRUE
5594 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5596 * NOTES
5597 * Windows reads the Registry once and cache the Results.
5599 *| Language-Monitors are also installed in the same Registry-Location but
5600 *| they are filtered in Windows (not returned by EnumMonitors).
5601 *| We do no filtering to simplify our Code.
5604 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5605 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5607 DWORD needed = 0;
5608 DWORD numentries = 0;
5609 BOOL res = FALSE;
5611 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5612 cbBuf, pcbNeeded, pcReturned);
5614 if (pName && (lstrlenW(pName))) {
5615 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5616 SetLastError(ERROR_ACCESS_DENIED);
5617 goto emW_cleanup;
5620 /* Level is not checked in win9x */
5621 if (!Level || (Level > 2)) {
5622 WARN("level (%ld) is ignored in win9x\n", Level);
5623 SetLastError(ERROR_INVALID_LEVEL);
5624 goto emW_cleanup;
5626 if (!pcbNeeded) {
5627 SetLastError(RPC_X_NULL_REF_POINTER);
5628 goto emW_cleanup;
5631 /* Scan all Monitor-Keys */
5632 numentries = 0;
5633 needed = get_local_monitors(Level, NULL, 0, &numentries);
5635 /* we calculated the needed buffersize. now do the error-checks */
5636 if (cbBuf < needed) {
5637 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5638 goto emW_cleanup;
5640 else if (!pMonitors || !pcReturned) {
5641 SetLastError(RPC_X_NULL_REF_POINTER);
5642 goto emW_cleanup;
5645 /* fill the Buffer with the Monitor-Keys */
5646 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5647 res = TRUE;
5649 emW_cleanup:
5650 if (pcbNeeded) *pcbNeeded = needed;
5651 if (pcReturned) *pcReturned = numentries;
5653 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5654 res, GetLastError(), needed, numentries);
5656 return (res);
5659 /******************************************************************************
5660 * XcvDataW (WINSPOOL.@)
5662 * Notes:
5663 * There doesn't seem to be an A version...
5665 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5666 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5667 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5669 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5670 pInputData, cbInputData, pOutputData,
5671 cbOutputData, pcbOutputNeeded, pdwStatus);
5672 return FALSE;
5675 /*****************************************************************************
5676 * EnumPrinterDataA [WINSPOOL.@]
5679 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5680 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5681 DWORD cbData, LPDWORD pcbData )
5683 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5684 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5685 return ERROR_NO_MORE_ITEMS;
5688 /*****************************************************************************
5689 * EnumPrinterDataW [WINSPOOL.@]
5692 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5693 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5694 DWORD cbData, LPDWORD pcbData )
5696 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5697 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5698 return ERROR_NO_MORE_ITEMS;
5701 /*****************************************************************************
5702 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5705 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5706 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5707 LPDWORD pcbNeeded, LPDWORD pcReturned)
5709 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5710 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5711 pcbNeeded, pcReturned);
5712 return FALSE;
5715 /*****************************************************************************
5716 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5719 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5720 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5721 LPDWORD pcbNeeded, LPDWORD pcReturned)
5723 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5724 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5725 pcbNeeded, pcReturned);
5726 return FALSE;
5729 /*****************************************************************************
5730 * EnumPrintProcessorsA [WINSPOOL.@]
5733 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5734 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5736 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5737 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5738 return FALSE;
5741 /*****************************************************************************
5742 * EnumPrintProcessorsW [WINSPOOL.@]
5745 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5746 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5748 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5749 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5750 cbBuf, pcbNeeded, pcbReturned);
5751 return FALSE;
5754 /*****************************************************************************
5755 * ExtDeviceMode [WINSPOOL.@]
5758 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5759 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5760 DWORD fMode)
5762 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5763 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5764 debugstr_a(pProfile), fMode);
5765 return -1;
5768 /*****************************************************************************
5769 * FindClosePrinterChangeNotification [WINSPOOL.@]
5772 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5774 FIXME("Stub: %p\n", hChange);
5775 return TRUE;
5778 /*****************************************************************************
5779 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5782 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5783 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5785 FIXME("Stub: %p %lx %lx %p\n",
5786 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5787 return INVALID_HANDLE_VALUE;
5790 /*****************************************************************************
5791 * FindNextPrinterChangeNotification [WINSPOOL.@]
5794 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5795 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5797 FIXME("Stub: %p %p %p %p\n",
5798 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5799 return FALSE;
5802 /*****************************************************************************
5803 * FreePrinterNotifyInfo [WINSPOOL.@]
5806 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5808 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5809 return TRUE;
5812 /*****************************************************************************
5813 * string_to_buf
5815 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5816 * ansi depending on the unicode parameter.
5818 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5820 if(!str)
5822 *size = 0;
5823 return TRUE;
5826 if(unicode)
5828 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5829 if(*size <= cb)
5831 memcpy(ptr, str, *size);
5832 return TRUE;
5834 return FALSE;
5836 else
5838 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5839 if(*size <= cb)
5841 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5842 return TRUE;
5844 return FALSE;
5848 /*****************************************************************************
5849 * get_job_info_1
5851 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5852 LPDWORD pcbNeeded, BOOL unicode)
5854 DWORD size, left = cbBuf;
5855 BOOL space = (cbBuf > 0);
5856 LPBYTE ptr = buf;
5858 *pcbNeeded = 0;
5860 if(space)
5862 ji1->JobId = job->job_id;
5865 string_to_buf(job->document_title, ptr, left, &size, unicode);
5866 if(space && size <= left)
5868 ji1->pDocument = (LPWSTR)ptr;
5869 ptr += size;
5870 left -= size;
5872 else
5873 space = FALSE;
5874 *pcbNeeded += size;
5876 return space;
5879 /*****************************************************************************
5880 * get_job_info_2
5882 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5883 LPDWORD pcbNeeded, BOOL unicode)
5885 DWORD size, left = cbBuf;
5886 BOOL space = (cbBuf > 0);
5887 LPBYTE ptr = buf;
5889 *pcbNeeded = 0;
5891 if(space)
5893 ji2->JobId = job->job_id;
5896 string_to_buf(job->document_title, ptr, left, &size, unicode);
5897 if(space && size <= left)
5899 ji2->pDocument = (LPWSTR)ptr;
5900 ptr += size;
5901 left -= size;
5903 else
5904 space = FALSE;
5905 *pcbNeeded += size;
5907 return space;
5910 /*****************************************************************************
5911 * get_job_info
5913 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5914 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5916 BOOL ret = FALSE;
5917 DWORD needed = 0, size;
5918 job_t *job;
5919 LPBYTE ptr = pJob;
5921 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5923 EnterCriticalSection(&printer_handles_cs);
5924 job = get_job(hPrinter, JobId);
5925 if(!job)
5926 goto end;
5928 switch(Level)
5930 case 1:
5931 size = sizeof(JOB_INFO_1W);
5932 if(cbBuf >= size)
5934 cbBuf -= size;
5935 ptr += size;
5936 memset(pJob, 0, size);
5938 else
5939 cbBuf = 0;
5940 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5941 needed += size;
5942 break;
5944 case 2:
5945 size = sizeof(JOB_INFO_2W);
5946 if(cbBuf >= size)
5948 cbBuf -= size;
5949 ptr += size;
5950 memset(pJob, 0, size);
5952 else
5953 cbBuf = 0;
5954 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5955 needed += size;
5956 break;
5958 case 3:
5959 size = sizeof(JOB_INFO_3);
5960 if(cbBuf >= size)
5962 cbBuf -= size;
5963 memset(pJob, 0, size);
5964 ret = TRUE;
5966 else
5967 cbBuf = 0;
5968 needed = size;
5969 break;
5971 default:
5972 SetLastError(ERROR_INVALID_LEVEL);
5973 goto end;
5975 if(pcbNeeded)
5976 *pcbNeeded = needed;
5977 end:
5978 LeaveCriticalSection(&printer_handles_cs);
5979 return ret;
5982 /*****************************************************************************
5983 * GetJobA [WINSPOOL.@]
5986 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5987 DWORD cbBuf, LPDWORD pcbNeeded)
5989 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5992 /*****************************************************************************
5993 * GetJobW [WINSPOOL.@]
5996 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5997 DWORD cbBuf, LPDWORD pcbNeeded)
5999 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6002 /*****************************************************************************
6003 * schedule_lpr
6005 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6007 char *unixname, *queue, *cmd;
6008 char fmt[] = "lpr -P%s %s";
6009 DWORD len;
6011 if(!(unixname = wine_get_unix_file_name(filename)))
6012 return FALSE;
6014 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6015 queue = HeapAlloc(GetProcessHeap(), 0, len);
6016 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6018 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6019 sprintf(cmd, fmt, queue, unixname);
6021 TRACE("printing with: %s\n", cmd);
6022 system(cmd);
6024 HeapFree(GetProcessHeap(), 0, cmd);
6025 HeapFree(GetProcessHeap(), 0, queue);
6026 HeapFree(GetProcessHeap(), 0, unixname);
6027 return TRUE;
6030 /*****************************************************************************
6031 * schedule_cups
6033 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6035 #if HAVE_CUPS_CUPS_H
6036 if(pcupsPrintFile)
6038 char *unixname, *queue, *doc_titleA;
6039 DWORD len;
6040 BOOL ret;
6042 if(!(unixname = wine_get_unix_file_name(filename)))
6043 return FALSE;
6045 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6046 queue = HeapAlloc(GetProcessHeap(), 0, len);
6047 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6049 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6050 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6051 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6053 TRACE("printing via cups\n");
6054 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6055 HeapFree(GetProcessHeap(), 0, doc_titleA);
6056 HeapFree(GetProcessHeap(), 0, queue);
6057 HeapFree(GetProcessHeap(), 0, unixname);
6058 return ret;
6060 else
6061 #endif
6063 return schedule_lpr(printer_name, filename);
6067 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6069 LPWSTR filename;
6071 switch(msg)
6073 case WM_INITDIALOG:
6074 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6075 return TRUE;
6077 case WM_COMMAND:
6078 if(HIWORD(wparam) == BN_CLICKED)
6080 if(LOWORD(wparam) == IDOK)
6082 HANDLE hf;
6083 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6084 LPWSTR *output;
6086 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6087 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6089 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6091 WCHAR caption[200], message[200];
6092 int mb_ret;
6094 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6095 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6096 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6097 if(mb_ret == IDCANCEL)
6099 HeapFree(GetProcessHeap(), 0, filename);
6100 return TRUE;
6103 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6104 if(hf == INVALID_HANDLE_VALUE)
6106 WCHAR caption[200], message[200];
6108 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6109 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6110 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6111 HeapFree(GetProcessHeap(), 0, filename);
6112 return TRUE;
6114 CloseHandle(hf);
6115 DeleteFileW(filename);
6116 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6117 *output = filename;
6118 EndDialog(hwnd, IDOK);
6119 return TRUE;
6121 if(LOWORD(wparam) == IDCANCEL)
6123 EndDialog(hwnd, IDCANCEL);
6124 return TRUE;
6127 return FALSE;
6129 return FALSE;
6132 /*****************************************************************************
6133 * get_filename
6135 static BOOL get_filename(LPWSTR *filename)
6137 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6138 file_dlg_proc, (LPARAM)filename) == IDOK;
6141 /*****************************************************************************
6142 * schedule_file
6144 static BOOL schedule_file(LPCWSTR filename)
6146 LPWSTR output = NULL;
6148 if(get_filename(&output))
6150 TRACE("copy to %s\n", debugstr_w(output));
6151 CopyFileW(filename, output, FALSE);
6152 HeapFree(GetProcessHeap(), 0, output);
6153 return TRUE;
6155 return FALSE;
6158 /*****************************************************************************
6159 * schedule_pipe
6161 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6163 #ifdef HAVE_FORK
6164 char *unixname, *cmdA;
6165 DWORD len;
6166 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6167 BOOL ret = FALSE;
6168 char buf[1024];
6170 if(!(unixname = wine_get_unix_file_name(filename)))
6171 return FALSE;
6173 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6174 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6175 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6177 TRACE("printing with: %s\n", cmdA);
6179 if((file_fd = open(unixname, O_RDONLY)) == -1)
6180 goto end;
6182 if (pipe(fds))
6184 ERR("pipe() failed!\n");
6185 goto end;
6188 if (fork() == 0)
6190 close(0);
6191 dup2(fds[0], 0);
6192 close(fds[1]);
6194 /* reset signals that we previously set to SIG_IGN */
6195 signal(SIGPIPE, SIG_DFL);
6196 signal(SIGCHLD, SIG_DFL);
6198 system(cmdA);
6199 exit(0);
6202 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6203 write(fds[1], buf, no_read);
6205 ret = TRUE;
6207 end:
6208 if(file_fd != -1) close(file_fd);
6209 if(fds[0] != -1) close(fds[0]);
6210 if(fds[1] != -1) close(fds[1]);
6212 HeapFree(GetProcessHeap(), 0, cmdA);
6213 HeapFree(GetProcessHeap(), 0, unixname);
6214 return ret;
6215 #else
6216 return FALSE;
6217 #endif
6220 /*****************************************************************************
6221 * schedule_unixfile
6223 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6225 int in_fd, out_fd, no_read;
6226 char buf[1024];
6227 BOOL ret = FALSE;
6228 char *unixname, *outputA;
6229 DWORD len;
6231 if(!(unixname = wine_get_unix_file_name(filename)))
6232 return FALSE;
6234 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6235 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6236 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6238 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6239 in_fd = open(unixname, O_RDONLY);
6240 if(out_fd == -1 || in_fd == -1)
6241 goto end;
6243 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6244 write(out_fd, buf, no_read);
6246 ret = TRUE;
6247 end:
6248 if(in_fd != -1) close(in_fd);
6249 if(out_fd != -1) close(out_fd);
6250 HeapFree(GetProcessHeap(), 0, outputA);
6251 HeapFree(GetProcessHeap(), 0, unixname);
6252 return ret;
6255 /*****************************************************************************
6256 * ScheduleJob [WINSPOOL.@]
6259 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6261 opened_printer_t *printer;
6262 BOOL ret = FALSE;
6263 struct list *cursor, *cursor2;
6265 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6266 EnterCriticalSection(&printer_handles_cs);
6267 printer = get_opened_printer(hPrinter);
6268 if(!printer)
6269 goto end;
6271 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6273 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6274 HANDLE hf;
6276 if(job->job_id != dwJobID) continue;
6278 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6279 if(hf != INVALID_HANDLE_VALUE)
6281 PRINTER_INFO_5W *pi5;
6282 DWORD needed;
6283 HKEY hkey;
6284 WCHAR output[1024];
6285 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6286 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6288 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6289 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6290 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6291 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6292 debugstr_w(pi5->pPortName));
6294 output[0] = 0;
6296 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6297 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6299 DWORD type, count = sizeof(output);
6300 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6301 RegCloseKey(hkey);
6303 if(output[0] == '|')
6305 schedule_pipe(output + 1, job->filename);
6307 else if(output[0])
6309 schedule_unixfile(output, job->filename);
6311 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6313 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6315 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6317 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6319 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6321 schedule_file(job->filename);
6323 else
6325 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6327 HeapFree(GetProcessHeap(), 0, pi5);
6328 CloseHandle(hf);
6329 DeleteFileW(job->filename);
6331 list_remove(cursor);
6332 HeapFree(GetProcessHeap(), 0, job->document_title);
6333 HeapFree(GetProcessHeap(), 0, job->filename);
6334 HeapFree(GetProcessHeap(), 0, job);
6335 ret = TRUE;
6336 break;
6338 end:
6339 LeaveCriticalSection(&printer_handles_cs);
6340 return ret;
6343 /*****************************************************************************
6344 * StartDocDlgA [WINSPOOL.@]
6346 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6348 UNICODE_STRING usBuffer;
6349 DOCINFOW docW;
6350 LPWSTR retW;
6351 LPSTR ret = NULL;
6353 docW.cbSize = sizeof(docW);
6354 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6355 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6356 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6357 docW.fwType = doc->fwType;
6359 retW = StartDocDlgW(hPrinter, &docW);
6361 if(retW)
6363 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6364 ret = HeapAlloc(GetProcessHeap(), 0, len);
6365 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6366 HeapFree(GetProcessHeap(), 0, retW);
6369 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6370 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6371 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6373 return ret;
6376 /*****************************************************************************
6377 * StartDocDlgW [WINSPOOL.@]
6379 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6380 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6381 * port is "FILE:". Also returns the full path if passed a relative path.
6383 * The caller should free the returned string from the process heap.
6385 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6387 LPWSTR ret = NULL;
6388 DWORD len, attr;
6390 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6392 PRINTER_INFO_5W *pi5;
6393 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6394 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6395 return NULL;
6396 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6397 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6398 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6400 HeapFree(GetProcessHeap(), 0, pi5);
6401 return NULL;
6403 HeapFree(GetProcessHeap(), 0, pi5);
6406 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6408 LPWSTR name;
6409 get_filename(&name);
6410 if(name)
6412 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6414 HeapFree(GetProcessHeap(), 0, name);
6415 return NULL;
6417 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6418 GetFullPathNameW(name, len, ret, NULL);
6419 HeapFree(GetProcessHeap(), 0, name);
6421 return ret;
6424 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6425 return NULL;
6427 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6428 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6430 attr = GetFileAttributesW(ret);
6431 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6433 HeapFree(GetProcessHeap(), 0, ret);
6434 ret = NULL;
6436 return ret;