winspool.drv: Write-strings warnings fix.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blobd00192c6b9aed9e462aa05cc7c8847006d42c140
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 static CHAR data_type[] = "RAW",
380 print_proc[] = "WinPrint",
381 driver_name[] = "PS Driver",
382 comment[] = "WINEPS Printer using CUPS",
383 location[] = "<physical location of printer>",
384 params[] = "<parameters?>",
385 share_name[] = "<share name?>",
386 sep_file[] = "<sep file?>";
388 memset(&pinfo2a,0,sizeof(pinfo2a));
389 pinfo2a.pPrinterName = dests[i].name;
390 pinfo2a.pDatatype = data_type;
391 pinfo2a.pPrintProcessor = print_proc;
392 pinfo2a.pDriverName = driver_name;
393 pinfo2a.pComment = comment;
394 pinfo2a.pLocation = location;
395 pinfo2a.pPortName = port;
396 pinfo2a.pParameters = params;
397 pinfo2a.pShareName = share_name;
398 pinfo2a.pSepFile = sep_file;
400 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
401 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
402 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
405 HeapFree(GetProcessHeap(),0,port);
407 hadprinter = TRUE;
408 if (dests[i].is_default)
409 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
411 RegCloseKey(hkeyPrinters);
412 return hadprinter;
414 #endif
416 static BOOL
417 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
418 PRINTER_INFO_2A pinfo2a;
419 char *e,*s,*name,*prettyname,*devname;
420 BOOL ret = FALSE, set_default = FALSE;
421 char *port,*devline,*env_default;
422 HKEY hkeyPrinter, hkeyPrinters, hkey;
424 while (isspace(*pent)) pent++;
425 s = strchr(pent,':');
426 if(s) *s='\0';
427 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
428 strcpy(name,pent);
429 if(s) {
430 *s=':';
431 pent = s;
432 } else
433 pent = "";
435 TRACE("name=%s entry=%s\n",name, pent);
437 if(ispunct(*name)) { /* a tc entry, not a real printer */
438 TRACE("skipping tc entry\n");
439 goto end;
442 if(strstr(pent,":server")) { /* server only version so skip */
443 TRACE("skipping server entry\n");
444 goto end;
447 /* Determine whether this is a postscript printer. */
449 ret = TRUE;
450 env_default = getenv("PRINTER");
451 prettyname = name;
452 /* Get longest name, usually the one at the right for later display. */
453 while((s=strchr(prettyname,'|'))) {
454 *s = '\0';
455 e = s;
456 while(isspace(*--e)) *e = '\0';
457 TRACE("\t%s\n", debugstr_a(prettyname));
458 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
459 for(prettyname = s+1; isspace(*prettyname); prettyname++)
462 e = prettyname + strlen(prettyname);
463 while(isspace(*--e)) *e = '\0';
464 TRACE("\t%s\n", debugstr_a(prettyname));
465 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
467 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
468 * if it is too long, we use it as comment below. */
469 devname = prettyname;
470 if (strlen(devname)>=CCHDEVICENAME-1)
471 devname = name;
472 if (strlen(devname)>=CCHDEVICENAME-1) {
473 ret = FALSE;
474 goto end;
477 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
478 sprintf(port,"LPR:%s",name);
480 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
481 sprintf(devline,"WINEPS.DRV,%s",port);
482 WriteProfileStringA("devices",devname,devline);
483 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
484 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
485 RegCloseKey(hkey);
487 HeapFree(GetProcessHeap(),0,devline);
489 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
490 ERROR_SUCCESS) {
491 ERR("Can't create Printers key\n");
492 ret = FALSE;
493 goto end;
495 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
496 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
497 and continue */
498 TRACE("Printer already exists\n");
499 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
500 RegCloseKey(hkeyPrinter);
501 } else {
502 static CHAR data_type[] = "RAW",
503 print_proc[] = "WinPrint",
504 driver_name[] = "PS Driver",
505 comment[] = "WINEPS Printer using LPR",
506 params[] = "<parameters?>",
507 share_name[] = "<share name?>",
508 sep_file[] = "<sep file?>";
510 memset(&pinfo2a,0,sizeof(pinfo2a));
511 pinfo2a.pPrinterName = devname;
512 pinfo2a.pDatatype = data_type;
513 pinfo2a.pPrintProcessor = print_proc;
514 pinfo2a.pDriverName = driver_name;
515 pinfo2a.pComment = comment;
516 pinfo2a.pLocation = prettyname;
517 pinfo2a.pPortName = port;
518 pinfo2a.pParameters = params;
519 pinfo2a.pShareName = share_name;
520 pinfo2a.pSepFile = sep_file;
522 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
523 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
524 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
527 RegCloseKey(hkeyPrinters);
529 if (isfirst || set_default)
530 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
532 HeapFree(GetProcessHeap(), 0, port);
533 end:
534 HeapFree(GetProcessHeap(), 0, name);
535 return ret;
538 static BOOL
539 PRINTCAP_LoadPrinters(void) {
540 BOOL hadprinter = FALSE;
541 char buf[200];
542 FILE *f;
543 char *pent = NULL;
544 BOOL had_bash = FALSE;
546 f = fopen("/etc/printcap","r");
547 if (!f)
548 return FALSE;
550 while(fgets(buf,sizeof(buf),f)) {
551 char *start, *end;
553 end=strchr(buf,'\n');
554 if (end) *end='\0';
556 start = buf;
557 while(isspace(*start)) start++;
558 if(*start == '#' || *start == '\0')
559 continue;
561 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
562 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
563 HeapFree(GetProcessHeap(),0,pent);
564 pent = NULL;
567 if (end && *--end == '\\') {
568 *end = '\0';
569 had_bash = TRUE;
570 } else
571 had_bash = FALSE;
573 if (pent) {
574 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
575 strcat(pent,start);
576 } else {
577 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
578 strcpy(pent,start);
582 if(pent) {
583 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
584 HeapFree(GetProcessHeap(),0,pent);
586 fclose(f);
587 return hadprinter;
590 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
592 if (value)
593 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
594 lstrlenW(value) * sizeof(WCHAR));
595 else
596 return ERROR_FILE_NOT_FOUND;
599 void WINSPOOL_LoadSystemPrinters(void)
601 HKEY hkey, hkeyPrinters;
602 DRIVER_INFO_3A di3a;
603 HANDLE hprn;
604 DWORD needed, num, i;
605 WCHAR PrinterName[256];
606 BOOL done = FALSE;
607 static CHAR name[] = "PS Driver",
608 driver_path[] = "wineps16",
609 data_file[] = "<datafile?>",
610 config_file[] = "wineps16",
611 help_file[] = "<helpfile?>",
612 dep_file[] = "<dependend files?>",
613 monitor_name[] = "<monitor name?>",
614 default_data_type[] = "RAW";
616 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
617 di3a.pName = name;
618 di3a.pEnvironment = NULL; /* NULL means auto */
619 di3a.pDriverPath = driver_path;
620 di3a.pDataFile = data_file;
621 di3a.pConfigFile = config_file;
622 di3a.pHelpFile = help_file;
623 di3a.pDependentFiles = dep_file;
624 di3a.pMonitorName = monitor_name;
625 di3a.pDefaultDataType = default_data_type;
627 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
628 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
629 return;
632 /* This ensures that all printer entries have a valid Name value. If causes
633 problems later if they don't. If one is found to be missed we create one
634 and set it equal to the name of the key */
635 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
636 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
637 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
638 for(i = 0; i < num; i++) {
639 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
640 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
641 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
642 set_reg_szW(hkey, NameW, PrinterName);
644 RegCloseKey(hkey);
649 RegCloseKey(hkeyPrinters);
652 /* We want to avoid calling AddPrinter on printers as much as
653 possible, because on cups printers this will (eventually) lead
654 to a call to cupsGetPPD which takes forever, even with non-cups
655 printers AddPrinter takes a while. So we'll tag all printers that
656 were automatically added last time around, if they still exist
657 we'll leave them be otherwise we'll delete them. */
658 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
659 if(needed) {
660 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
661 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
662 for(i = 0; i < num; i++) {
663 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
664 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
665 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
666 DWORD dw = 1;
667 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
668 RegCloseKey(hkey);
670 ClosePrinter(hprn);
675 HeapFree(GetProcessHeap(), 0, pi);
679 #ifdef HAVE_CUPS_CUPS_H
680 done = CUPS_LoadPrinters();
681 #endif
683 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
684 /* Check for [ppd] section in config file before parsing /etc/printcap */
685 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
686 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
687 &hkey) == ERROR_SUCCESS) {
688 RegCloseKey(hkey);
689 PRINTCAP_LoadPrinters();
693 /* Now enumerate the list again and delete any printers that a still tagged */
694 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
695 if(needed) {
696 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
697 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
698 for(i = 0; i < num; i++) {
699 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
700 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
701 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
702 DWORD dw, type, size = sizeof(dw);
703 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
704 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
705 DeletePrinter(hprn);
707 RegCloseKey(hkey);
709 ClosePrinter(hprn);
714 HeapFree(GetProcessHeap(), 0, pi);
717 return;
721 /*****************************************************************************
722 * enumerate the local monitors (INTERNAL)
724 * returns the needed size (in bytes) for pMonitors
725 * and *lpreturned is set to number of entries returned in pMonitors
728 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
730 HKEY hroot = NULL;
731 HKEY hentry = NULL;
732 LPWSTR ptr;
733 LPMONITOR_INFO_2W mi;
734 WCHAR buffer[MAX_PATH];
735 WCHAR dllname[MAX_PATH];
736 DWORD dllsize;
737 DWORD len;
738 DWORD index = 0;
739 DWORD needed = 0;
740 DWORD numentries;
741 DWORD entrysize;
743 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
745 numentries = *lpreturned; /* this is 0, when we scan the registry */
746 len = entrysize * numentries;
747 ptr = (LPWSTR) &pMonitors[len];
749 numentries = 0;
750 len = sizeof(buffer);
751 buffer[0] = '\0';
753 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
754 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
755 /* Scan all Monitor-Registry-Keys */
756 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
757 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
758 dllsize = sizeof(dllname);
759 dllname[0] = '\0';
761 /* The Monitor must have a Driver-DLL */
762 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
763 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
764 /* We found a valid DLL for this Monitor. */
765 TRACE("using Driver: %s\n", debugstr_w(dllname));
767 RegCloseKey(hentry);
770 /* Windows returns only Port-Monitors here, but to simplify our code,
771 we do no filtering for Language-Monitors */
772 if (dllname[0]) {
773 numentries++;
774 needed += entrysize;
775 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
776 if (level > 1) {
777 /* we install and return only monitors for "Windows NT x86" */
778 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
779 needed += dllsize;
782 /* required size is calculated. Now fill the user-buffer */
783 if (pMonitors && (cbBuf >= needed)){
784 mi = (LPMONITOR_INFO_2W) pMonitors;
785 pMonitors += entrysize;
787 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
788 mi->pName = ptr;
789 lstrcpyW(ptr, buffer); /* Name of the Monitor */
790 ptr += (len+1); /* len is lstrlenW(monitorname) */
791 if (level > 1) {
792 mi->pEnvironment = ptr;
793 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
794 ptr += (lstrlenW(envname_x86W)+1);
796 mi->pDLLName = ptr;
797 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
798 ptr += (dllsize / sizeof(WCHAR));
802 index++;
803 len = sizeof(buffer);
804 buffer[0] = '\0';
806 RegCloseKey(hroot);
808 *lpreturned = numentries;
809 TRACE("need %ld byte for %ld entries\n", needed, numentries);
810 return needed;
813 /******************************************************************
814 * get_opened_printer_entry
815 * Get the first place empty in the opened printer table
817 * ToDo:
818 * - pDefault is ignored
820 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
822 UINT_PTR handle = nb_printer_handles, i;
823 jobqueue_t *queue = NULL;
824 opened_printer_t *printer = NULL;
826 EnterCriticalSection(&printer_handles_cs);
828 for (i = 0; i < nb_printer_handles; i++)
830 if (!printer_handles[i])
832 if(handle == nb_printer_handles)
833 handle = i;
835 else
837 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
838 queue = printer_handles[i]->queue;
842 if (handle >= nb_printer_handles)
844 opened_printer_t **new_array;
845 if (printer_handles)
846 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
847 (nb_printer_handles + 16) * sizeof(*new_array) );
848 else
849 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
850 (nb_printer_handles + 16) * sizeof(*new_array) );
852 if (!new_array)
854 handle = 0;
855 goto end;
857 printer_handles = new_array;
858 nb_printer_handles += 16;
861 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
863 handle = 0;
864 goto end;
867 if(name) {
868 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
869 if (!printer->name) {
870 handle = 0;
871 goto end;
873 strcpyW(printer->name, name);
876 if(queue)
877 printer->queue = queue;
878 else
880 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
881 if (!printer->queue) {
882 handle = 0;
883 goto end;
885 list_init(&printer->queue->jobs);
886 printer->queue->ref = 0;
888 InterlockedIncrement(&printer->queue->ref);
890 printer_handles[handle] = printer;
891 handle++;
892 end:
893 LeaveCriticalSection(&printer_handles_cs);
894 if (!handle && printer) {
895 /* Something Failed: Free the Buffers */
896 HeapFree(GetProcessHeap(), 0, printer->name);
897 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
898 HeapFree(GetProcessHeap(), 0, printer);
901 return (HANDLE)handle;
904 /******************************************************************
905 * get_opened_printer
906 * Get the pointer to the opened printer referred by the handle
908 static opened_printer_t *get_opened_printer(HANDLE hprn)
910 UINT_PTR idx = (UINT_PTR)hprn;
911 opened_printer_t *ret = NULL;
913 EnterCriticalSection(&printer_handles_cs);
915 if ((idx <= 0) || (idx > nb_printer_handles))
916 goto end;
918 ret = printer_handles[idx - 1];
919 end:
920 LeaveCriticalSection(&printer_handles_cs);
921 return ret;
924 /******************************************************************
925 * get_opened_printer_name
926 * Get the pointer to the opened printer name referred by the handle
928 static LPCWSTR get_opened_printer_name(HANDLE hprn)
930 opened_printer_t *printer = get_opened_printer(hprn);
931 if(!printer) return NULL;
932 return printer->name;
935 /******************************************************************
936 * WINSPOOL_GetOpenedPrinterRegKey
939 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
941 LPCWSTR name = get_opened_printer_name(hPrinter);
942 DWORD ret;
943 HKEY hkeyPrinters;
945 if(!name) return ERROR_INVALID_HANDLE;
947 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
948 ERROR_SUCCESS)
949 return ret;
951 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
953 ERR("Can't find opened printer %s in registry\n",
954 debugstr_w(name));
955 RegCloseKey(hkeyPrinters);
956 return ERROR_INVALID_PRINTER_NAME; /* ? */
958 RegCloseKey(hkeyPrinters);
959 return ERROR_SUCCESS;
962 /******************************************************************
963 * get_job
965 * Get the pointer to the specified job.
966 * Should hold the printer_handles_cs before calling.
968 static job_t *get_job(HANDLE hprn, DWORD JobId)
970 opened_printer_t *printer = get_opened_printer(hprn);
971 job_t *job;
973 if(!printer) return NULL;
974 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
976 if(job->job_id == JobId)
977 return job;
979 return NULL;
982 /***********************************************************
983 * DEVMODEcpyAtoW
985 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
987 BOOL Formname;
988 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
989 DWORD size;
991 Formname = (dmA->dmSize > off_formname);
992 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
993 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
994 dmW->dmDeviceName, CCHDEVICENAME);
995 if(!Formname) {
996 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
997 dmA->dmSize - CCHDEVICENAME);
998 } else {
999 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1000 off_formname - CCHDEVICENAME);
1001 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1002 dmW->dmFormName, CCHFORMNAME);
1003 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1004 (off_formname + CCHFORMNAME));
1006 dmW->dmSize = size;
1007 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1008 dmA->dmDriverExtra);
1009 return dmW;
1012 /***********************************************************
1013 * DEVMODEdupWtoA
1014 * Creates an ascii copy of supplied devmode on heap
1016 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1018 LPDEVMODEA dmA;
1019 DWORD size;
1020 BOOL Formname;
1021 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1023 if(!dmW) return NULL;
1024 Formname = (dmW->dmSize > off_formname);
1025 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1026 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1027 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1028 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1029 if(!Formname) {
1030 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1031 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1032 } else {
1033 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1034 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1035 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1036 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1037 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1038 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1040 dmA->dmSize = size;
1041 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1042 dmW->dmDriverExtra);
1043 return dmA;
1046 /***********************************************************
1047 * PRINTER_INFO_2AtoW
1048 * Creates a unicode copy of PRINTER_INFO_2A on heap
1050 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1052 LPPRINTER_INFO_2W piW;
1053 UNICODE_STRING usBuffer;
1055 if(!piA) return NULL;
1056 piW = HeapAlloc(heap, 0, sizeof(*piW));
1057 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1059 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1060 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1061 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1062 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1063 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1064 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1065 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1066 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1067 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1068 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1069 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1070 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1071 return piW;
1074 /***********************************************************
1075 * FREE_PRINTER_INFO_2W
1076 * Free PRINTER_INFO_2W and all strings
1078 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1080 if(!piW) return;
1082 HeapFree(heap,0,piW->pServerName);
1083 HeapFree(heap,0,piW->pPrinterName);
1084 HeapFree(heap,0,piW->pShareName);
1085 HeapFree(heap,0,piW->pPortName);
1086 HeapFree(heap,0,piW->pDriverName);
1087 HeapFree(heap,0,piW->pComment);
1088 HeapFree(heap,0,piW->pLocation);
1089 HeapFree(heap,0,piW->pDevMode);
1090 HeapFree(heap,0,piW->pSepFile);
1091 HeapFree(heap,0,piW->pPrintProcessor);
1092 HeapFree(heap,0,piW->pDatatype);
1093 HeapFree(heap,0,piW->pParameters);
1094 HeapFree(heap,0,piW);
1095 return;
1098 /******************************************************************
1099 * DeviceCapabilities [WINSPOOL.@]
1100 * DeviceCapabilitiesA [WINSPOOL.@]
1103 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1104 LPSTR pOutput, LPDEVMODEA lpdm)
1106 INT ret;
1108 if (!GDI_CallDeviceCapabilities16)
1110 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1111 (LPCSTR)104 );
1112 if (!GDI_CallDeviceCapabilities16) return -1;
1114 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1116 /* If DC_PAPERSIZE map POINT16s to POINTs */
1117 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1118 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1119 POINT *pt = (POINT *)pOutput;
1120 INT i;
1121 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1122 for(i = 0; i < ret; i++, pt++)
1124 pt->x = tmp[i].x;
1125 pt->y = tmp[i].y;
1127 HeapFree( GetProcessHeap(), 0, tmp );
1129 return ret;
1133 /*****************************************************************************
1134 * DeviceCapabilitiesW [WINSPOOL.@]
1136 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1139 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1140 WORD fwCapability, LPWSTR pOutput,
1141 const DEVMODEW *pDevMode)
1143 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1144 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1145 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1146 INT ret;
1148 if(pOutput && (fwCapability == DC_BINNAMES ||
1149 fwCapability == DC_FILEDEPENDENCIES ||
1150 fwCapability == DC_PAPERNAMES)) {
1151 /* These need A -> W translation */
1152 INT size = 0, i;
1153 LPSTR pOutputA;
1154 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1155 dmA);
1156 if(ret == -1)
1157 return ret;
1158 switch(fwCapability) {
1159 case DC_BINNAMES:
1160 size = 24;
1161 break;
1162 case DC_PAPERNAMES:
1163 case DC_FILEDEPENDENCIES:
1164 size = 64;
1165 break;
1167 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1168 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1169 dmA);
1170 for(i = 0; i < ret; i++)
1171 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1172 pOutput + (i * size), size);
1173 HeapFree(GetProcessHeap(), 0, pOutputA);
1174 } else {
1175 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1176 (LPSTR)pOutput, dmA);
1178 HeapFree(GetProcessHeap(),0,pPortA);
1179 HeapFree(GetProcessHeap(),0,pDeviceA);
1180 HeapFree(GetProcessHeap(),0,dmA);
1181 return ret;
1184 /******************************************************************
1185 * DocumentPropertiesA [WINSPOOL.@]
1187 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1189 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1190 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1191 LPDEVMODEA pDevModeInput,DWORD fMode )
1193 LPSTR lpName = pDeviceName;
1194 static CHAR port[] = "LPT1:";
1195 LONG ret;
1197 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1198 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1201 if(!pDeviceName) {
1202 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1203 if(!lpNameW) {
1204 ERR("no name from hPrinter?\n");
1205 SetLastError(ERROR_INVALID_HANDLE);
1206 return -1;
1208 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1211 if (!GDI_CallExtDeviceMode16)
1213 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1214 (LPCSTR)102 );
1215 if (!GDI_CallExtDeviceMode16) {
1216 ERR("No CallExtDeviceMode16?\n");
1217 return -1;
1220 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1221 pDevModeInput, NULL, fMode);
1223 if(!pDeviceName)
1224 HeapFree(GetProcessHeap(),0,lpName);
1225 return ret;
1229 /*****************************************************************************
1230 * DocumentPropertiesW (WINSPOOL.@)
1232 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1234 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1235 LPWSTR pDeviceName,
1236 LPDEVMODEW pDevModeOutput,
1237 LPDEVMODEW pDevModeInput, DWORD fMode)
1240 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1241 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1242 LPDEVMODEA pDevModeOutputA = NULL;
1243 LONG ret;
1245 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1246 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1247 fMode);
1248 if(pDevModeOutput) {
1249 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1250 if(ret < 0) return ret;
1251 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1253 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1254 pDevModeInputA, fMode);
1255 if(pDevModeOutput) {
1256 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1257 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1259 if(fMode == 0 && ret > 0)
1260 ret += (CCHDEVICENAME + CCHFORMNAME);
1261 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1262 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1263 return ret;
1266 /******************************************************************
1267 * OpenPrinterA [WINSPOOL.@]
1269 * See OpenPrinterW.
1272 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1273 LPPRINTER_DEFAULTSA pDefault)
1275 UNICODE_STRING lpPrinterNameW;
1276 UNICODE_STRING usBuffer;
1277 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1278 PWSTR pwstrPrinterNameW;
1279 BOOL ret;
1281 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1283 if(pDefault) {
1284 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1285 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1286 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1287 pDefaultW = &DefaultW;
1289 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1290 if(pDefault) {
1291 RtlFreeUnicodeString(&usBuffer);
1292 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1294 RtlFreeUnicodeString(&lpPrinterNameW);
1295 return ret;
1298 /******************************************************************
1299 * OpenPrinterW [WINSPOOL.@]
1301 * Open a Printer / Printserver or a Printer-Object
1303 * PARAMS
1304 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1305 * phPrinter [O] The resulting Handle is stored here
1306 * pDefault [I] PTR to Default Printer Settings or NULL
1308 * RETURNS
1309 * Success: TRUE
1310 * Failure: FALSE
1312 * NOTES
1313 * lpPrinterName is one of:
1314 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1315 *| Printer: "PrinterName"
1316 *| Printer-Object: "PrinterName,Job xxx"
1317 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1318 *| XcvPort: "Servername,XcvPort PortName"
1320 * BUGS
1321 *| Printer-Object not supported
1322 *| XcvMonitor not supported
1323 *| XcvPort not supported
1324 *| pDefaults is ignored
1327 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1329 HKEY hkeyPrinters = NULL;
1330 HKEY hkeyPrinter = NULL;
1332 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1333 if (pDefault) {
1334 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08lx\n",
1335 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1338 if(lpPrinterName != NULL)
1340 /* Check any Printer exists */
1341 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1342 ERR("Can't create Printers key\n");
1343 SetLastError(ERROR_FILE_NOT_FOUND);
1344 return FALSE;
1346 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1347 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1349 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1350 RegCloseKey(hkeyPrinters);
1351 SetLastError(ERROR_INVALID_PRINTER_NAME);
1352 return FALSE;
1354 RegCloseKey(hkeyPrinter);
1355 RegCloseKey(hkeyPrinters);
1357 if(!phPrinter) {
1358 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1359 SetLastError(ERROR_INVALID_PARAMETER);
1360 return FALSE;
1363 /* Get the unique handle of the printer or Printserver */
1364 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1365 return (*phPrinter != 0);
1368 /******************************************************************
1369 * AddMonitorA [WINSPOOL.@]
1371 * See AddMonitorW.
1374 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1376 LPWSTR nameW = NULL;
1377 INT len;
1378 BOOL res;
1379 LPMONITOR_INFO_2A mi2a;
1380 MONITOR_INFO_2W mi2w;
1382 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1383 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1384 mi2a ? debugstr_a(mi2a->pName) : NULL,
1385 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1386 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1388 if (Level != 2) {
1389 SetLastError(ERROR_INVALID_LEVEL);
1390 return FALSE;
1393 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1394 if (mi2a == NULL) {
1395 return FALSE;
1398 if (pName) {
1399 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1400 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1401 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1404 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1405 if (mi2a->pName) {
1406 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1407 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1408 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1410 if (mi2a->pEnvironment) {
1411 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1412 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1413 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1415 if (mi2a->pDLLName) {
1416 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1417 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1418 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1421 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1423 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1424 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1425 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1427 HeapFree(GetProcessHeap(), 0, nameW);
1428 return (res);
1431 /******************************************************************************
1432 * AddMonitorW [WINSPOOL.@]
1434 * Install a Printmonitor
1436 * PARAMS
1437 * pName [I] Servername or NULL (local Computer)
1438 * Level [I] Structure-Level (Must be 2)
1439 * pMonitors [I] PTR to MONITOR_INFO_2
1441 * RETURNS
1442 * Success: TRUE
1443 * Failure: FALSE
1445 * NOTES
1446 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1449 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1451 LPMONITOR_INFO_2W mi2w;
1452 HKEY hroot = NULL;
1453 HKEY hentry = NULL;
1454 HMODULE hdll = NULL;
1455 DWORD disposition;
1456 BOOL res = FALSE;
1458 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1459 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1460 mi2w ? debugstr_w(mi2w->pName) : NULL,
1461 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1462 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1464 if (Level != 2) {
1465 SetLastError(ERROR_INVALID_LEVEL);
1466 return FALSE;
1469 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1470 if (mi2w == NULL) {
1471 return FALSE;
1474 if (pName && (pName[0])) {
1475 FIXME("for server %s not implemented\n", debugstr_w(pName));
1476 SetLastError(ERROR_ACCESS_DENIED);
1477 return FALSE;
1481 if (!mi2w->pName || (! mi2w->pName[0])) {
1482 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1483 SetLastError(ERROR_INVALID_PARAMETER);
1484 return FALSE;
1486 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1487 WARN("Environment %s requested (we support only %s)\n",
1488 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1489 SetLastError(ERROR_INVALID_ENVIRONMENT);
1490 return FALSE;
1493 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1494 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1495 SetLastError(ERROR_INVALID_PARAMETER);
1496 return FALSE;
1499 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1500 return FALSE;
1502 FreeLibrary(hdll);
1504 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1505 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1506 return FALSE;
1509 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1510 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1511 &disposition) == ERROR_SUCCESS) {
1513 /* Some installers set options for the port before calling AddMonitor.
1514 We query the "Driver" entry to verify that the monitor is installed,
1515 before we return an error.
1516 When a user installs two print monitors at the same time with the
1517 same name but with a different driver DLL and a task switch comes
1518 between RegQueryValueExW and RegSetValueExW, a race condition
1519 is possible but silently ignored. */
1521 DWORD namesize = 0;
1523 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1524 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1525 &namesize) == ERROR_SUCCESS)) {
1526 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1527 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1528 9x: ERROR_ALREADY_EXISTS (183) */
1529 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1531 else
1533 INT len;
1534 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1535 res = (RegSetValueExW(hentry, DriverW, 0,
1536 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1538 RegCloseKey(hentry);
1541 RegCloseKey(hroot);
1542 return (res);
1545 /******************************************************************
1546 * DeletePrinterDriverA [WINSPOOL.@]
1549 BOOL WINAPI
1550 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1552 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1553 debugstr_a(pDriverName));
1554 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1555 return FALSE;
1558 /******************************************************************
1559 * DeletePrinterDriverW [WINSPOOL.@]
1562 BOOL WINAPI
1563 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1565 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1566 debugstr_w(pDriverName));
1567 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1568 return FALSE;
1571 /******************************************************************
1572 * DeleteMonitorA [WINSPOOL.@]
1574 * See DeleteMonitorW.
1577 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1579 LPWSTR nameW = NULL;
1580 LPWSTR EnvironmentW = NULL;
1581 LPWSTR MonitorNameW = NULL;
1582 BOOL res;
1583 INT len;
1585 if (pName) {
1586 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1587 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1588 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1591 if (pEnvironment) {
1592 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1593 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1594 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1596 if (pMonitorName) {
1597 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1598 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1599 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1602 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1604 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1605 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1606 HeapFree(GetProcessHeap(), 0, nameW);
1607 return (res);
1610 /******************************************************************
1611 * DeleteMonitorW [WINSPOOL.@]
1613 * Delete a specific Printmonitor from a Printing-Environment
1615 * PARAMS
1616 * pName [I] Servername or NULL (local Computer)
1617 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1618 * pMonitorName [I] Name of the Monitor, that should be deleted
1620 * RETURNS
1621 * Success: TRUE
1622 * Failure: FALSE
1624 * NOTES
1625 * pEnvironment is ignored in Windows for the local Computer.
1629 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1631 HKEY hroot = NULL;
1633 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1634 debugstr_w(pMonitorName));
1636 if (pName && (pName[0])) {
1637 FIXME("for server %s not implemented\n", debugstr_w(pName));
1638 SetLastError(ERROR_ACCESS_DENIED);
1639 return FALSE;
1642 /* pEnvironment is ignored in Windows for the local Computer */
1644 if (!pMonitorName || !pMonitorName[0]) {
1645 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1646 SetLastError(ERROR_INVALID_PARAMETER);
1647 return FALSE;
1650 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1651 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1652 return FALSE;
1655 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1656 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1657 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1658 RegCloseKey(hroot);
1659 return TRUE;
1662 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1663 RegCloseKey(hroot);
1665 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1666 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1667 return (FALSE);
1670 /******************************************************************
1671 * DeletePortA [WINSPOOL.@]
1673 * See DeletePortW.
1676 BOOL WINAPI
1677 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1679 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1680 debugstr_a(pPortName));
1681 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1682 return FALSE;
1685 /******************************************************************
1686 * DeletePortW [WINSPOOL.@]
1688 * Delete a specific Port
1690 * PARAMS
1691 * pName [I] Servername or NULL (local Computer)
1692 * hWnd [I] Handle to parent Window for the Dialog-Box
1693 * pPortName [I] Name of the Port, that should be deleted
1695 * RETURNS
1696 * Success: TRUE
1697 * Failure: FALSE
1699 * BUGS
1700 * only a Stub
1703 BOOL WINAPI
1704 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1706 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1707 debugstr_w(pPortName));
1708 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1709 return FALSE;
1712 /******************************************************************************
1713 * SetPrinterW [WINSPOOL.@]
1715 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1717 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1718 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1719 return FALSE;
1722 /******************************************************************************
1723 * WritePrinter [WINSPOOL.@]
1725 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1727 opened_printer_t *printer;
1728 BOOL ret = FALSE;
1730 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1732 EnterCriticalSection(&printer_handles_cs);
1733 printer = get_opened_printer(hPrinter);
1734 if(!printer)
1736 SetLastError(ERROR_INVALID_HANDLE);
1737 goto end;
1740 if(!printer->doc)
1742 SetLastError(ERROR_SPL_NO_STARTDOC);
1743 goto end;
1746 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1747 end:
1748 LeaveCriticalSection(&printer_handles_cs);
1749 return ret;
1752 /*****************************************************************************
1753 * AddFormA [WINSPOOL.@]
1755 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1757 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1758 return 1;
1761 /*****************************************************************************
1762 * AddFormW [WINSPOOL.@]
1764 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1766 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1767 return 1;
1770 /*****************************************************************************
1771 * AddJobA [WINSPOOL.@]
1773 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1775 BOOL ret;
1776 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1777 DWORD needed;
1779 if(Level != 1) {
1780 SetLastError(ERROR_INVALID_LEVEL);
1781 return FALSE;
1784 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1786 if(ret) {
1787 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1788 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1789 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1790 if(*pcbNeeded > cbBuf) {
1791 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1792 ret = FALSE;
1793 } else {
1794 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1795 addjobA->JobId = addjobW->JobId;
1796 addjobA->Path = (char *)(addjobA + 1);
1797 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1800 return ret;
1803 /*****************************************************************************
1804 * AddJobW [WINSPOOL.@]
1806 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1808 opened_printer_t *printer;
1809 job_t *job;
1810 BOOL ret = FALSE;
1811 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1812 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1813 WCHAR path[MAX_PATH], filename[MAX_PATH];
1814 DWORD len;
1815 ADDJOB_INFO_1W *addjob;
1817 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1819 EnterCriticalSection(&printer_handles_cs);
1821 printer = get_opened_printer(hPrinter);
1823 if(!printer) {
1824 SetLastError(ERROR_INVALID_HANDLE);
1825 goto end;
1828 if(Level != 1) {
1829 SetLastError(ERROR_INVALID_LEVEL);
1830 goto end;
1833 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1834 if(!job)
1835 goto end;
1837 job->job_id = InterlockedIncrement(&next_job_id);
1839 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1840 if(path[len - 1] != '\\')
1841 path[len++] = '\\';
1842 memcpy(path + len, spool_path, sizeof(spool_path));
1843 sprintfW(filename, fmtW, path, job->job_id);
1845 len = strlenW(filename);
1846 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1847 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1848 job->document_title = strdupW(default_doc_title);
1849 list_add_tail(&printer->queue->jobs, &job->entry);
1851 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1852 if(*pcbNeeded <= cbBuf) {
1853 addjob = (ADDJOB_INFO_1W*)pData;
1854 addjob->JobId = job->job_id;
1855 addjob->Path = (WCHAR *)(addjob + 1);
1856 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1857 ret = TRUE;
1858 } else
1859 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1861 end:
1862 LeaveCriticalSection(&printer_handles_cs);
1863 return ret;
1866 /*****************************************************************************
1867 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1869 * Return the PATH for the Print-Processors
1871 * See GetPrintProcessorDirectoryW.
1875 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1876 DWORD level, LPBYTE Info,
1877 DWORD cbBuf, LPDWORD pcbNeeded)
1879 LPWSTR serverW = NULL;
1880 LPWSTR envW = NULL;
1881 BOOL ret;
1882 INT len;
1884 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
1885 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
1888 if (server) {
1889 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
1890 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1891 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
1894 if (env) {
1895 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
1896 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1897 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
1900 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
1901 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
1903 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
1904 cbBuf, pcbNeeded);
1906 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
1907 cbBuf, NULL, NULL) > 0;
1910 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
1911 HeapFree(GetProcessHeap(), 0, envW);
1912 HeapFree(GetProcessHeap(), 0, serverW);
1913 return ret;
1916 /*****************************************************************************
1917 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1919 * Return the PATH for the Print-Processors
1921 * PARAMS
1922 * server [I] Servername (NT only) or NULL (local Computer)
1923 * env [I] Printing-Environment (see below) or NULL (Default)
1924 * level [I] Structure-Level (must be 1)
1925 * Info [O] PTR to Buffer that receives the Result
1926 * cbBuf [I] Size of Buffer at "Info"
1927 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1928 * required for the Buffer at "Info"
1930 * RETURNS
1931 * Success: TRUE and in pcbNeeded the Bytes used in Info
1932 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
1933 * if cbBuf is too small
1935 * Native Values returned in Info on Success:
1936 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
1937 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
1938 *| win9x(Windows 4.0): "%winsysdir%"
1940 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1942 * BUGS
1943 * Only NULL or "" is supported for server
1946 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1947 DWORD level, LPBYTE Info,
1948 DWORD cbBuf, LPDWORD pcbNeeded)
1950 DWORD needed;
1951 const printenv_t * env_t;
1953 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server),
1954 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
1956 if(server != NULL && server[0]) {
1957 FIXME("server not supported: %s\n", debugstr_w(server));
1958 SetLastError(ERROR_INVALID_PARAMETER);
1959 return FALSE;
1962 env_t = validate_envW(env);
1963 if(!env_t) return FALSE; /* environment invalid or unsupported */
1965 if(level != 1) {
1966 WARN("(Level: %ld) is ignored in win9x\n", level);
1967 SetLastError(ERROR_INVALID_LEVEL);
1968 return FALSE;
1971 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1972 needed = GetSystemDirectoryW(NULL, 0);
1973 /* add the Size for the Subdirectories */
1974 needed += lstrlenW(spoolprtprocsW);
1975 needed += lstrlenW(env_t->subdir);
1976 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1978 if(pcbNeeded) *pcbNeeded = needed;
1979 TRACE ("required: 0x%lx/%ld\n", needed, needed);
1980 if (needed > cbBuf) {
1981 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1982 return FALSE;
1984 if(pcbNeeded == NULL) {
1985 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
1986 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
1987 SetLastError(RPC_X_NULL_REF_POINTER);
1988 return FALSE;
1990 if(Info == NULL) {
1991 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
1992 SetLastError(RPC_X_NULL_REF_POINTER);
1993 return FALSE;
1996 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
1997 /* add the Subdirectories */
1998 lstrcatW((LPWSTR) Info, spoolprtprocsW);
1999 lstrcatW((LPWSTR) Info, env_t->subdir);
2000 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2001 return TRUE;
2004 /*****************************************************************************
2005 * WINSPOOL_OpenDriverReg [internal]
2007 * opens the registry for the printer drivers depending on the given input
2008 * variable pEnvironment
2010 * RETURNS:
2011 * the opened hkey on success
2012 * NULL on error
2014 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2016 HKEY retval = NULL;
2017 LPWSTR buffer;
2018 const printenv_t * env;
2020 TRACE("(%s, %d)\n",
2021 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2023 if (!pEnvironment || unicode) {
2024 /* pEnvironment was NULL or an Unicode-String: use it direct */
2025 env = validate_envW(pEnvironment);
2027 else
2029 /* pEnvironment was an ANSI-String: convert to unicode first */
2030 LPWSTR buffer;
2031 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2032 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2033 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2034 env = validate_envW(buffer);
2035 HeapFree(GetProcessHeap(), 0, buffer);
2037 if (!env) return NULL;
2039 buffer = HeapAlloc( GetProcessHeap(), 0,
2040 (strlenW(DriversW) + strlenW(env->envname) +
2041 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2042 if(buffer) {
2043 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2044 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2045 HeapFree(GetProcessHeap(), 0, buffer);
2047 return retval;
2050 /*****************************************************************************
2051 * AddPrinterW [WINSPOOL.@]
2053 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2055 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2056 LPDEVMODEA dmA;
2057 LPDEVMODEW dmW;
2058 HANDLE retval;
2059 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2060 LONG size;
2062 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2064 if(pName != NULL) {
2065 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2066 SetLastError(ERROR_INVALID_PARAMETER);
2067 return 0;
2069 if(Level != 2) {
2070 ERR("Level = %ld, unsupported!\n", Level);
2071 SetLastError(ERROR_INVALID_LEVEL);
2072 return 0;
2074 if(!pPrinter) {
2075 SetLastError(ERROR_INVALID_PARAMETER);
2076 return 0;
2078 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2079 ERROR_SUCCESS) {
2080 ERR("Can't create Printers key\n");
2081 return 0;
2083 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2084 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2085 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2086 RegCloseKey(hkeyPrinter);
2087 RegCloseKey(hkeyPrinters);
2088 return 0;
2090 RegCloseKey(hkeyPrinter);
2092 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2093 if(!hkeyDrivers) {
2094 ERR("Can't create Drivers key\n");
2095 RegCloseKey(hkeyPrinters);
2096 return 0;
2098 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2099 ERROR_SUCCESS) {
2100 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2101 RegCloseKey(hkeyPrinters);
2102 RegCloseKey(hkeyDrivers);
2103 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2104 return 0;
2106 RegCloseKey(hkeyDriver);
2107 RegCloseKey(hkeyDrivers);
2109 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2110 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2111 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2112 RegCloseKey(hkeyPrinters);
2113 return 0;
2116 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2117 ERROR_SUCCESS) {
2118 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2119 SetLastError(ERROR_INVALID_PRINTER_NAME);
2120 RegCloseKey(hkeyPrinters);
2121 return 0;
2123 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2124 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2125 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2127 /* See if we can load the driver. We may need the devmode structure anyway
2129 * FIXME:
2130 * Note that DocumentPropertiesW will briefly try to open the printer we
2131 * just create to find a DEVMODEA struct (it will use the WINEPS default
2132 * one in case it is not there, so we are ok).
2134 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2136 if(size < 0) {
2137 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2138 size = sizeof(DEVMODEW);
2140 if(pi->pDevMode)
2141 dmW = pi->pDevMode;
2142 else
2144 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2145 ZeroMemory(dmW,size);
2146 dmW->dmSize = size;
2147 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2149 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2150 HeapFree(GetProcessHeap(),0,dmW);
2151 dmW=NULL;
2153 else
2155 /* set devmode to printer name */
2156 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2160 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2161 and we support these drivers. NT writes DEVMODEW so somehow
2162 we'll need to distinguish between these when we support NT
2163 drivers */
2164 if (dmW)
2166 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2167 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2168 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2169 HeapFree(GetProcessHeap(), 0, dmA);
2170 if(!pi->pDevMode)
2171 HeapFree(GetProcessHeap(), 0, dmW);
2173 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2174 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2175 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2176 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2178 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2179 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2180 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2181 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2182 (LPBYTE)&pi->Priority, sizeof(DWORD));
2183 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2184 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2185 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2186 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2187 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2188 (LPBYTE)&pi->Status, sizeof(DWORD));
2189 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2190 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2192 RegCloseKey(hkeyPrinter);
2193 RegCloseKey(hkeyPrinters);
2194 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2195 ERR("OpenPrinter failing\n");
2196 return 0;
2198 return retval;
2201 /*****************************************************************************
2202 * AddPrinterA [WINSPOOL.@]
2204 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2206 UNICODE_STRING pNameW;
2207 PWSTR pwstrNameW;
2208 PRINTER_INFO_2W *piW;
2209 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2210 HANDLE ret;
2212 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2213 if(Level != 2) {
2214 ERR("Level = %ld, unsupported!\n", Level);
2215 SetLastError(ERROR_INVALID_LEVEL);
2216 return 0;
2218 pwstrNameW = asciitounicode(&pNameW,pName);
2219 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2221 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2223 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2224 RtlFreeUnicodeString(&pNameW);
2225 return ret;
2229 /*****************************************************************************
2230 * ClosePrinter [WINSPOOL.@]
2232 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2234 UINT_PTR i = (UINT_PTR)hPrinter;
2235 opened_printer_t *printer = NULL;
2236 BOOL ret = FALSE;
2238 TRACE("Handle %p\n", hPrinter);
2240 EnterCriticalSection(&printer_handles_cs);
2242 if ((i > 0) && (i <= nb_printer_handles))
2243 printer = printer_handles[i - 1];
2245 if(printer)
2247 struct list *cursor, *cursor2;
2249 if(printer->doc)
2250 EndDocPrinter(hPrinter);
2252 if(InterlockedDecrement(&printer->queue->ref) == 0)
2254 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2256 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2257 ScheduleJob(hPrinter, job->job_id);
2259 HeapFree(GetProcessHeap(), 0, printer->queue);
2261 HeapFree(GetProcessHeap(), 0, printer->name);
2262 HeapFree(GetProcessHeap(), 0, printer);
2263 printer_handles[i - 1] = NULL;
2264 ret = TRUE;
2266 LeaveCriticalSection(&printer_handles_cs);
2267 return ret;
2270 /*****************************************************************************
2271 * DeleteFormA [WINSPOOL.@]
2273 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2275 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2276 return 1;
2279 /*****************************************************************************
2280 * DeleteFormW [WINSPOOL.@]
2282 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2284 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2285 return 1;
2288 /*****************************************************************************
2289 * WINSPOOL_SHRegDeleteKey
2291 * Recursively delete subkeys.
2292 * Cut & paste from shlwapi.
2295 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2297 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2298 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2299 HKEY hSubKey = 0;
2301 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2302 if(!dwRet)
2304 /* Find how many subkeys there are */
2305 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2306 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2307 if(!dwRet)
2309 dwMaxSubkeyLen++;
2310 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2311 /* Name too big: alloc a buffer for it */
2312 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2314 if(!lpszName)
2315 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2316 else
2318 /* Recursively delete all the subkeys */
2319 for(i = 0; i < dwKeyCount && !dwRet; i++)
2321 dwSize = dwMaxSubkeyLen;
2322 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2323 if(!dwRet)
2324 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2327 if (lpszName != szNameBuf)
2328 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2332 RegCloseKey(hSubKey);
2333 if(!dwRet)
2334 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2336 return dwRet;
2339 /*****************************************************************************
2340 * DeletePrinter [WINSPOOL.@]
2342 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2344 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2345 HKEY hkeyPrinters, hkey;
2347 if(!lpNameW) {
2348 SetLastError(ERROR_INVALID_HANDLE);
2349 return FALSE;
2351 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2352 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2353 RegCloseKey(hkeyPrinters);
2355 WriteProfileStringW(devicesW, lpNameW, NULL);
2356 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2357 RegDeleteValueW(hkey, lpNameW);
2358 RegCloseKey(hkey);
2360 return TRUE;
2363 /*****************************************************************************
2364 * SetPrinterA [WINSPOOL.@]
2366 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2367 DWORD Command)
2369 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2370 return FALSE;
2373 /*****************************************************************************
2374 * SetJobA [WINSPOOL.@]
2376 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2377 LPBYTE pJob, DWORD Command)
2379 BOOL ret;
2380 LPBYTE JobW;
2381 UNICODE_STRING usBuffer;
2383 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2385 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2386 are all ignored by SetJob, so we don't bother copying them */
2387 switch(Level)
2389 case 0:
2390 JobW = NULL;
2391 break;
2392 case 1:
2394 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2395 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2397 JobW = (LPBYTE)info1W;
2398 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2399 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2400 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2401 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2402 info1W->Status = info1A->Status;
2403 info1W->Priority = info1A->Priority;
2404 info1W->Position = info1A->Position;
2405 info1W->PagesPrinted = info1A->PagesPrinted;
2406 break;
2408 case 2:
2410 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2411 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2413 JobW = (LPBYTE)info2W;
2414 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2415 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2416 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2417 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2418 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2419 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2420 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2421 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2422 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2423 info2W->Status = info2A->Status;
2424 info2W->Priority = info2A->Priority;
2425 info2W->Position = info2A->Position;
2426 info2W->StartTime = info2A->StartTime;
2427 info2W->UntilTime = info2A->UntilTime;
2428 info2W->PagesPrinted = info2A->PagesPrinted;
2429 break;
2431 case 3:
2432 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2433 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2434 break;
2435 default:
2436 SetLastError(ERROR_INVALID_LEVEL);
2437 return FALSE;
2440 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2442 switch(Level)
2444 case 1:
2446 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2447 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2448 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2449 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2450 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2451 break;
2453 case 2:
2455 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2456 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2457 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2458 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2459 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2460 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2461 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2462 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2463 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2464 break;
2467 HeapFree(GetProcessHeap(), 0, JobW);
2469 return ret;
2472 /*****************************************************************************
2473 * SetJobW [WINSPOOL.@]
2475 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2476 LPBYTE pJob, DWORD Command)
2478 BOOL ret = FALSE;
2479 job_t *job;
2481 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2482 FIXME("Ignoring everything other than document title\n");
2484 EnterCriticalSection(&printer_handles_cs);
2485 job = get_job(hPrinter, JobId);
2486 if(!job)
2487 goto end;
2489 switch(Level)
2491 case 0:
2492 break;
2493 case 1:
2495 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2496 HeapFree(GetProcessHeap(), 0, job->document_title);
2497 job->document_title = strdupW(info1->pDocument);
2498 break;
2500 case 2:
2502 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2503 HeapFree(GetProcessHeap(), 0, job->document_title);
2504 job->document_title = strdupW(info2->pDocument);
2505 break;
2507 case 3:
2508 break;
2509 default:
2510 SetLastError(ERROR_INVALID_LEVEL);
2511 goto end;
2513 ret = TRUE;
2514 end:
2515 LeaveCriticalSection(&printer_handles_cs);
2516 return ret;
2519 /*****************************************************************************
2520 * EndDocPrinter [WINSPOOL.@]
2522 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2524 opened_printer_t *printer;
2525 BOOL ret = FALSE;
2526 TRACE("(%p)\n", hPrinter);
2528 EnterCriticalSection(&printer_handles_cs);
2530 printer = get_opened_printer(hPrinter);
2531 if(!printer)
2533 SetLastError(ERROR_INVALID_HANDLE);
2534 goto end;
2537 if(!printer->doc)
2539 SetLastError(ERROR_SPL_NO_STARTDOC);
2540 goto end;
2543 CloseHandle(printer->doc->hf);
2544 ScheduleJob(hPrinter, printer->doc->job_id);
2545 HeapFree(GetProcessHeap(), 0, printer->doc);
2546 printer->doc = NULL;
2547 ret = TRUE;
2548 end:
2549 LeaveCriticalSection(&printer_handles_cs);
2550 return ret;
2553 /*****************************************************************************
2554 * EndPagePrinter [WINSPOOL.@]
2556 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2558 FIXME("(%p): stub\n", hPrinter);
2559 return TRUE;
2562 /*****************************************************************************
2563 * StartDocPrinterA [WINSPOOL.@]
2565 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2567 UNICODE_STRING usBuffer;
2568 DOC_INFO_2W doc2W;
2569 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2570 DWORD ret;
2572 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2573 or one (DOC_INFO_3) extra DWORDs */
2575 switch(Level) {
2576 case 2:
2577 doc2W.JobId = doc2->JobId;
2578 /* fall through */
2579 case 3:
2580 doc2W.dwMode = doc2->dwMode;
2581 /* fall through */
2582 case 1:
2583 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2584 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2585 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2586 break;
2588 default:
2589 SetLastError(ERROR_INVALID_LEVEL);
2590 return FALSE;
2593 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2595 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2596 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2597 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2599 return ret;
2602 /*****************************************************************************
2603 * StartDocPrinterW [WINSPOOL.@]
2605 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2607 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2608 opened_printer_t *printer;
2609 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2610 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2611 JOB_INFO_1W job_info;
2612 DWORD needed, ret = 0;
2613 HANDLE hf;
2614 WCHAR *filename;
2616 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2617 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2618 debugstr_w(doc->pDatatype));
2620 if(Level < 1 || Level > 3)
2622 SetLastError(ERROR_INVALID_LEVEL);
2623 return 0;
2626 EnterCriticalSection(&printer_handles_cs);
2627 printer = get_opened_printer(hPrinter);
2628 if(!printer)
2630 SetLastError(ERROR_INVALID_HANDLE);
2631 goto end;
2634 if(printer->doc)
2636 SetLastError(ERROR_INVALID_PRINTER_STATE);
2637 goto end;
2640 /* Even if we're printing to a file we still add a print job, we'll
2641 just ignore the spool file name */
2643 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2645 ERR("AddJob failed gle %08lx\n", GetLastError());
2646 goto end;
2649 if(doc->pOutputFile)
2650 filename = doc->pOutputFile;
2651 else
2652 filename = addjob->Path;
2654 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2655 if(hf == INVALID_HANDLE_VALUE)
2656 goto end;
2658 memset(&job_info, 0, sizeof(job_info));
2659 job_info.pDocument = doc->pDocName;
2660 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2662 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2663 printer->doc->hf = hf;
2664 ret = printer->doc->job_id = addjob->JobId;
2665 end:
2666 LeaveCriticalSection(&printer_handles_cs);
2668 return ret;
2671 /*****************************************************************************
2672 * StartPagePrinter [WINSPOOL.@]
2674 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2676 FIXME("(%p): stub\n", hPrinter);
2677 return TRUE;
2680 /*****************************************************************************
2681 * GetFormA [WINSPOOL.@]
2683 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2684 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2686 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2687 Level,pForm,cbBuf,pcbNeeded);
2688 return FALSE;
2691 /*****************************************************************************
2692 * GetFormW [WINSPOOL.@]
2694 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2695 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2697 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2698 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2699 return FALSE;
2702 /*****************************************************************************
2703 * SetFormA [WINSPOOL.@]
2705 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2706 LPBYTE pForm)
2708 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2709 return FALSE;
2712 /*****************************************************************************
2713 * SetFormW [WINSPOOL.@]
2715 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2716 LPBYTE pForm)
2718 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2719 return FALSE;
2722 /*****************************************************************************
2723 * ReadPrinter [WINSPOOL.@]
2725 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2726 LPDWORD pNoBytesRead)
2728 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2729 return FALSE;
2732 /*****************************************************************************
2733 * ResetPrinterA [WINSPOOL.@]
2735 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2737 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2738 return FALSE;
2741 /*****************************************************************************
2742 * ResetPrinterW [WINSPOOL.@]
2744 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2746 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2747 return FALSE;
2750 /*****************************************************************************
2751 * WINSPOOL_GetDWORDFromReg
2753 * Return DWORD associated with ValueName from hkey.
2755 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2757 DWORD sz = sizeof(DWORD), type, value = 0;
2758 LONG ret;
2760 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2762 if(ret != ERROR_SUCCESS) {
2763 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2764 return 0;
2766 if(type != REG_DWORD) {
2767 ERR("Got type %ld\n", type);
2768 return 0;
2770 return value;
2773 /*****************************************************************************
2774 * WINSPOOL_GetStringFromReg
2776 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2777 * String is stored either as unicode or ascii.
2778 * Bit of a hack here to get the ValueName if we want ascii.
2780 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2781 DWORD buflen, DWORD *needed,
2782 BOOL unicode)
2784 DWORD sz = buflen, type;
2785 LONG ret;
2787 if(unicode)
2788 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2789 else {
2790 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2791 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2792 HeapFree(GetProcessHeap(),0,ValueNameA);
2794 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2795 WARN("Got ret = %ld\n", ret);
2796 *needed = 0;
2797 return FALSE;
2799 /* add space for terminating '\0' */
2800 sz += unicode ? sizeof(WCHAR) : 1;
2801 *needed = sz;
2803 if (ptr)
2804 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2806 return TRUE;
2809 /*****************************************************************************
2810 * WINSPOOL_GetDefaultDevMode
2812 * Get a default DevMode values for wineps.
2813 * FIXME - use ppd.
2816 static void WINSPOOL_GetDefaultDevMode(
2817 LPBYTE ptr,
2818 DWORD buflen, DWORD *needed,
2819 BOOL unicode)
2821 DEVMODEA dm;
2822 static const char szwps[] = "wineps.drv";
2824 /* fill default DEVMODE - should be read from ppd... */
2825 ZeroMemory( &dm, sizeof(dm) );
2826 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2827 dm.dmSpecVersion = DM_SPECVERSION;
2828 dm.dmDriverVersion = 1;
2829 dm.dmSize = sizeof(DEVMODEA);
2830 dm.dmDriverExtra = 0;
2831 dm.dmFields =
2832 DM_ORIENTATION | DM_PAPERSIZE |
2833 DM_PAPERLENGTH | DM_PAPERWIDTH |
2834 DM_SCALE |
2835 DM_COPIES |
2836 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2837 DM_YRESOLUTION | DM_TTOPTION;
2839 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2840 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2841 dm.u1.s1.dmPaperLength = 2970;
2842 dm.u1.s1.dmPaperWidth = 2100;
2844 dm.dmScale = 100;
2845 dm.dmCopies = 1;
2846 dm.dmDefaultSource = DMBIN_AUTO;
2847 dm.dmPrintQuality = DMRES_MEDIUM;
2848 /* dm.dmColor */
2849 /* dm.dmDuplex */
2850 dm.dmYResolution = 300; /* 300dpi */
2851 dm.dmTTOption = DMTT_BITMAP;
2852 /* dm.dmCollate */
2853 /* dm.dmFormName */
2854 /* dm.dmLogPixels */
2855 /* dm.dmBitsPerPel */
2856 /* dm.dmPelsWidth */
2857 /* dm.dmPelsHeight */
2858 /* dm.dmDisplayFlags */
2859 /* dm.dmDisplayFrequency */
2860 /* dm.dmICMMethod */
2861 /* dm.dmICMIntent */
2862 /* dm.dmMediaType */
2863 /* dm.dmDitherType */
2864 /* dm.dmReserved1 */
2865 /* dm.dmReserved2 */
2866 /* dm.dmPanningWidth */
2867 /* dm.dmPanningHeight */
2869 if(unicode) {
2870 if(buflen >= sizeof(DEVMODEW)) {
2871 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2872 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2873 HeapFree(GetProcessHeap(),0,pdmW);
2875 *needed = sizeof(DEVMODEW);
2877 else
2879 if(buflen >= sizeof(DEVMODEA)) {
2880 memcpy(ptr, &dm, sizeof(DEVMODEA));
2882 *needed = sizeof(DEVMODEA);
2886 /*****************************************************************************
2887 * WINSPOOL_GetDevModeFromReg
2889 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2890 * DevMode is stored either as unicode or ascii.
2892 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2893 LPBYTE ptr,
2894 DWORD buflen, DWORD *needed,
2895 BOOL unicode)
2897 DWORD sz = buflen, type;
2898 LONG ret;
2900 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2901 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2902 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2903 if (sz < sizeof(DEVMODEA))
2905 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2906 return FALSE;
2908 /* ensures that dmSize is not erratically bogus if registry is invalid */
2909 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2910 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2911 if(unicode) {
2912 sz += (CCHDEVICENAME + CCHFORMNAME);
2913 if(buflen >= sz) {
2914 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2915 memcpy(ptr, dmW, sz);
2916 HeapFree(GetProcessHeap(),0,dmW);
2919 *needed = sz;
2920 return TRUE;
2923 /*********************************************************************
2924 * WINSPOOL_GetPrinter_2
2926 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2927 * The strings are either stored as unicode or ascii.
2929 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2930 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2931 BOOL unicode)
2933 DWORD size, left = cbBuf;
2934 BOOL space = (cbBuf > 0);
2935 LPBYTE ptr = buf;
2937 *pcbNeeded = 0;
2939 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2940 unicode)) {
2941 if(space && size <= left) {
2942 pi2->pPrinterName = (LPWSTR)ptr;
2943 ptr += size;
2944 left -= size;
2945 } else
2946 space = FALSE;
2947 *pcbNeeded += size;
2949 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2950 unicode)) {
2951 if(space && size <= left) {
2952 pi2->pShareName = (LPWSTR)ptr;
2953 ptr += size;
2954 left -= size;
2955 } else
2956 space = FALSE;
2957 *pcbNeeded += size;
2959 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2960 unicode)) {
2961 if(space && size <= left) {
2962 pi2->pPortName = (LPWSTR)ptr;
2963 ptr += size;
2964 left -= size;
2965 } else
2966 space = FALSE;
2967 *pcbNeeded += size;
2969 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2970 &size, unicode)) {
2971 if(space && size <= left) {
2972 pi2->pDriverName = (LPWSTR)ptr;
2973 ptr += size;
2974 left -= size;
2975 } else
2976 space = FALSE;
2977 *pcbNeeded += size;
2979 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2980 unicode)) {
2981 if(space && size <= left) {
2982 pi2->pComment = (LPWSTR)ptr;
2983 ptr += size;
2984 left -= size;
2985 } else
2986 space = FALSE;
2987 *pcbNeeded += size;
2989 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2990 unicode)) {
2991 if(space && size <= left) {
2992 pi2->pLocation = (LPWSTR)ptr;
2993 ptr += size;
2994 left -= size;
2995 } else
2996 space = FALSE;
2997 *pcbNeeded += size;
2999 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3000 &size, unicode)) {
3001 if(space && size <= left) {
3002 pi2->pDevMode = (LPDEVMODEW)ptr;
3003 ptr += size;
3004 left -= size;
3005 } else
3006 space = FALSE;
3007 *pcbNeeded += size;
3009 else
3011 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3012 if(space && size <= left) {
3013 pi2->pDevMode = (LPDEVMODEW)ptr;
3014 ptr += size;
3015 left -= size;
3016 } else
3017 space = FALSE;
3018 *pcbNeeded += size;
3020 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3021 &size, unicode)) {
3022 if(space && size <= left) {
3023 pi2->pSepFile = (LPWSTR)ptr;
3024 ptr += size;
3025 left -= size;
3026 } else
3027 space = FALSE;
3028 *pcbNeeded += size;
3030 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3031 &size, unicode)) {
3032 if(space && size <= left) {
3033 pi2->pPrintProcessor = (LPWSTR)ptr;
3034 ptr += size;
3035 left -= size;
3036 } else
3037 space = FALSE;
3038 *pcbNeeded += size;
3040 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3041 &size, unicode)) {
3042 if(space && size <= left) {
3043 pi2->pDatatype = (LPWSTR)ptr;
3044 ptr += size;
3045 left -= size;
3046 } else
3047 space = FALSE;
3048 *pcbNeeded += size;
3050 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3051 &size, unicode)) {
3052 if(space && size <= left) {
3053 pi2->pParameters = (LPWSTR)ptr;
3054 ptr += size;
3055 left -= size;
3056 } else
3057 space = FALSE;
3058 *pcbNeeded += size;
3060 if(pi2) {
3061 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3062 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3063 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3064 "Default Priority");
3065 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3066 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3069 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3070 memset(pi2, 0, sizeof(*pi2));
3072 return space;
3075 /*********************************************************************
3076 * WINSPOOL_GetPrinter_4
3078 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3080 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3081 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3082 BOOL unicode)
3084 DWORD size, left = cbBuf;
3085 BOOL space = (cbBuf > 0);
3086 LPBYTE ptr = buf;
3088 *pcbNeeded = 0;
3090 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3091 unicode)) {
3092 if(space && size <= left) {
3093 pi4->pPrinterName = (LPWSTR)ptr;
3094 ptr += size;
3095 left -= size;
3096 } else
3097 space = FALSE;
3098 *pcbNeeded += size;
3100 if(pi4) {
3101 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3104 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3105 memset(pi4, 0, sizeof(*pi4));
3107 return space;
3110 /*********************************************************************
3111 * WINSPOOL_GetPrinter_5
3113 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3115 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3116 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3117 BOOL unicode)
3119 DWORD size, left = cbBuf;
3120 BOOL space = (cbBuf > 0);
3121 LPBYTE ptr = buf;
3123 *pcbNeeded = 0;
3125 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3126 unicode)) {
3127 if(space && size <= left) {
3128 pi5->pPrinterName = (LPWSTR)ptr;
3129 ptr += size;
3130 left -= size;
3131 } else
3132 space = FALSE;
3133 *pcbNeeded += size;
3135 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3136 unicode)) {
3137 if(space && size <= left) {
3138 pi5->pPortName = (LPWSTR)ptr;
3139 ptr += size;
3140 left -= size;
3141 } else
3142 space = FALSE;
3143 *pcbNeeded += size;
3145 if(pi5) {
3146 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3147 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3148 "dnsTimeout");
3149 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3150 "txTimeout");
3153 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3154 memset(pi5, 0, sizeof(*pi5));
3156 return space;
3159 /*****************************************************************************
3160 * WINSPOOL_GetPrinter
3162 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3163 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3164 * just a collection of pointers to strings.
3166 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3167 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3169 LPCWSTR name;
3170 DWORD size, needed = 0;
3171 LPBYTE ptr = NULL;
3172 HKEY hkeyPrinter, hkeyPrinters;
3173 BOOL ret;
3175 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3177 if (!(name = get_opened_printer_name(hPrinter))) {
3178 SetLastError(ERROR_INVALID_HANDLE);
3179 return FALSE;
3182 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3183 ERROR_SUCCESS) {
3184 ERR("Can't create Printers key\n");
3185 return FALSE;
3187 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3189 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3190 RegCloseKey(hkeyPrinters);
3191 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3192 return FALSE;
3195 switch(Level) {
3196 case 2:
3198 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3200 size = sizeof(PRINTER_INFO_2W);
3201 if(size <= cbBuf) {
3202 ptr = pPrinter + size;
3203 cbBuf -= size;
3204 memset(pPrinter, 0, size);
3205 } else {
3206 pi2 = NULL;
3207 cbBuf = 0;
3209 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3210 unicode);
3211 needed += size;
3212 break;
3215 case 4:
3217 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3219 size = sizeof(PRINTER_INFO_4W);
3220 if(size <= cbBuf) {
3221 ptr = pPrinter + size;
3222 cbBuf -= size;
3223 memset(pPrinter, 0, size);
3224 } else {
3225 pi4 = NULL;
3226 cbBuf = 0;
3228 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3229 unicode);
3230 needed += size;
3231 break;
3235 case 5:
3237 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3239 size = sizeof(PRINTER_INFO_5W);
3240 if(size <= cbBuf) {
3241 ptr = pPrinter + size;
3242 cbBuf -= size;
3243 memset(pPrinter, 0, size);
3244 } else {
3245 pi5 = NULL;
3246 cbBuf = 0;
3249 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3250 unicode);
3251 needed += size;
3252 break;
3255 default:
3256 FIXME("Unimplemented level %ld\n", Level);
3257 SetLastError(ERROR_INVALID_LEVEL);
3258 RegCloseKey(hkeyPrinters);
3259 RegCloseKey(hkeyPrinter);
3260 return FALSE;
3263 RegCloseKey(hkeyPrinter);
3264 RegCloseKey(hkeyPrinters);
3266 TRACE("returning %d needed = %ld\n", ret, needed);
3267 if(pcbNeeded) *pcbNeeded = needed;
3268 if(!ret)
3269 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3270 return ret;
3273 /*****************************************************************************
3274 * GetPrinterW [WINSPOOL.@]
3276 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3277 DWORD cbBuf, LPDWORD pcbNeeded)
3279 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3280 TRUE);
3283 /*****************************************************************************
3284 * GetPrinterA [WINSPOOL.@]
3286 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3287 DWORD cbBuf, LPDWORD pcbNeeded)
3289 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3290 FALSE);
3293 /*****************************************************************************
3294 * WINSPOOL_EnumPrinters
3296 * Implementation of EnumPrintersA|W
3298 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3299 DWORD dwLevel, LPBYTE lpbPrinters,
3300 DWORD cbBuf, LPDWORD lpdwNeeded,
3301 LPDWORD lpdwReturned, BOOL unicode)
3304 HKEY hkeyPrinters, hkeyPrinter;
3305 WCHAR PrinterName[255];
3306 DWORD needed = 0, number = 0;
3307 DWORD used, i, left;
3308 PBYTE pi, buf;
3310 if(lpbPrinters)
3311 memset(lpbPrinters, 0, cbBuf);
3312 if(lpdwReturned)
3313 *lpdwReturned = 0;
3314 if(lpdwNeeded)
3315 *lpdwNeeded = 0;
3317 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3318 if(dwType == PRINTER_ENUM_DEFAULT)
3319 return TRUE;
3321 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3322 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3323 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3324 if(!dwType) return TRUE;
3327 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3328 FIXME("dwType = %08lx\n", dwType);
3329 SetLastError(ERROR_INVALID_FLAGS);
3330 return FALSE;
3333 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3334 ERROR_SUCCESS) {
3335 ERR("Can't create Printers key\n");
3336 return FALSE;
3339 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3340 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3341 RegCloseKey(hkeyPrinters);
3342 ERR("Can't query Printers key\n");
3343 return FALSE;
3345 TRACE("Found %ld printers\n", number);
3347 switch(dwLevel) {
3348 case 1:
3349 RegCloseKey(hkeyPrinters);
3350 if (lpdwReturned)
3351 *lpdwReturned = number;
3352 return TRUE;
3354 case 2:
3355 used = number * sizeof(PRINTER_INFO_2W);
3356 break;
3357 case 4:
3358 used = number * sizeof(PRINTER_INFO_4W);
3359 break;
3360 case 5:
3361 used = number * sizeof(PRINTER_INFO_5W);
3362 break;
3364 default:
3365 SetLastError(ERROR_INVALID_LEVEL);
3366 RegCloseKey(hkeyPrinters);
3367 return FALSE;
3369 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3371 for(i = 0; i < number; i++) {
3372 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3373 ERROR_SUCCESS) {
3374 ERR("Can't enum key number %ld\n", i);
3375 RegCloseKey(hkeyPrinters);
3376 return FALSE;
3378 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3379 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3380 ERROR_SUCCESS) {
3381 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3382 RegCloseKey(hkeyPrinters);
3383 return FALSE;
3386 if(cbBuf > used) {
3387 buf = lpbPrinters + used;
3388 left = cbBuf - used;
3389 } else {
3390 buf = NULL;
3391 left = 0;
3394 switch(dwLevel) {
3395 case 2:
3396 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3397 left, &needed, unicode);
3398 used += needed;
3399 if(pi) pi += sizeof(PRINTER_INFO_2W);
3400 break;
3401 case 4:
3402 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3403 left, &needed, unicode);
3404 used += needed;
3405 if(pi) pi += sizeof(PRINTER_INFO_4W);
3406 break;
3407 case 5:
3408 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3409 left, &needed, unicode);
3410 used += needed;
3411 if(pi) pi += sizeof(PRINTER_INFO_5W);
3412 break;
3413 default:
3414 ERR("Shouldn't be here!\n");
3415 RegCloseKey(hkeyPrinter);
3416 RegCloseKey(hkeyPrinters);
3417 return FALSE;
3419 RegCloseKey(hkeyPrinter);
3421 RegCloseKey(hkeyPrinters);
3423 if(lpdwNeeded)
3424 *lpdwNeeded = used;
3426 if(used > cbBuf) {
3427 if(lpbPrinters)
3428 memset(lpbPrinters, 0, cbBuf);
3429 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3430 return FALSE;
3432 if(lpdwReturned)
3433 *lpdwReturned = number;
3434 SetLastError(ERROR_SUCCESS);
3435 return TRUE;
3439 /******************************************************************
3440 * EnumPrintersW [WINSPOOL.@]
3442 * Enumerates the available printers, print servers and print
3443 * providers, depending on the specified flags, name and level.
3445 * RETURNS:
3447 * If level is set to 1:
3448 * Not implemented yet!
3449 * Returns TRUE with an empty list.
3451 * If level is set to 2:
3452 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3453 * Returns an array of PRINTER_INFO_2 data structures in the
3454 * lpbPrinters buffer. Note that according to MSDN also an
3455 * OpenPrinter should be performed on every remote printer.
3457 * If level is set to 4 (officially WinNT only):
3458 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3459 * Fast: Only the registry is queried to retrieve printer names,
3460 * no connection to the driver is made.
3461 * Returns an array of PRINTER_INFO_4 data structures in the
3462 * lpbPrinters buffer.
3464 * If level is set to 5 (officially WinNT4/Win9x only):
3465 * Fast: Only the registry is queried to retrieve printer names,
3466 * no connection to the driver is made.
3467 * Returns an array of PRINTER_INFO_5 data structures in the
3468 * lpbPrinters buffer.
3470 * If level set to 3 or 6+:
3471 * returns zero (failure!)
3473 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3474 * for information.
3476 * BUGS:
3477 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3478 * - Only levels 2, 4 and 5 are implemented at the moment.
3479 * - 16-bit printer drivers are not enumerated.
3480 * - Returned amount of bytes used/needed does not match the real Windoze
3481 * implementation (as in this implementation, all strings are part
3482 * of the buffer, whereas Win32 keeps them somewhere else)
3483 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3485 * NOTE:
3486 * - In a regular Wine installation, no registry settings for printers
3487 * exist, which makes this function return an empty list.
3489 BOOL WINAPI EnumPrintersW(
3490 DWORD dwType, /* [in] Types of print objects to enumerate */
3491 LPWSTR lpszName, /* [in] name of objects to enumerate */
3492 DWORD dwLevel, /* [in] type of printer info structure */
3493 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3494 DWORD cbBuf, /* [in] max size of buffer in bytes */
3495 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3496 LPDWORD lpdwReturned /* [out] number of entries returned */
3499 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3500 lpdwNeeded, lpdwReturned, TRUE);
3503 /******************************************************************
3504 * EnumPrintersA [WINSPOOL.@]
3507 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3508 DWORD dwLevel, LPBYTE lpbPrinters,
3509 DWORD cbBuf, LPDWORD lpdwNeeded,
3510 LPDWORD lpdwReturned)
3512 BOOL ret;
3513 UNICODE_STRING lpszNameW;
3514 PWSTR pwstrNameW;
3516 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3517 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3518 lpdwNeeded, lpdwReturned, FALSE);
3519 RtlFreeUnicodeString(&lpszNameW);
3520 return ret;
3523 /*****************************************************************************
3524 * WINSPOOL_GetDriverInfoFromReg [internal]
3526 * Enters the information from the registry into the DRIVER_INFO struct
3528 * RETURNS
3529 * zero if the printer driver does not exist in the registry
3530 * (only if Level > 1) otherwise nonzero
3532 static BOOL WINSPOOL_GetDriverInfoFromReg(
3533 HKEY hkeyDrivers,
3534 LPWSTR DriverName,
3535 LPWSTR pEnvironment,
3536 DWORD Level,
3537 LPBYTE ptr, /* DRIVER_INFO */
3538 LPBYTE pDriverStrings, /* strings buffer */
3539 DWORD cbBuf, /* size of string buffer */
3540 LPDWORD pcbNeeded, /* space needed for str. */
3541 BOOL unicode) /* type of strings */
3543 DWORD size, tmp;
3544 HKEY hkeyDriver;
3545 LPBYTE strPtr = pDriverStrings;
3547 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3548 debugstr_w(DriverName), debugstr_w(pEnvironment),
3549 Level, ptr, pDriverStrings, cbBuf, unicode);
3551 if(unicode) {
3552 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3553 if (*pcbNeeded <= cbBuf)
3554 strcpyW((LPWSTR)strPtr, DriverName);
3555 } else {
3556 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3557 NULL, NULL);
3558 if(*pcbNeeded <= cbBuf)
3559 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3560 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3562 if(Level == 1) {
3563 if(ptr)
3564 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3565 return TRUE;
3566 } else {
3567 if(ptr)
3568 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3569 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3572 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3573 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3574 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3575 return FALSE;
3578 if(ptr)
3579 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3581 if(!pEnvironment)
3582 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3583 if(unicode)
3584 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3585 else
3586 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3587 NULL, NULL);
3588 *pcbNeeded += size;
3589 if(*pcbNeeded <= cbBuf) {
3590 if(unicode)
3591 strcpyW((LPWSTR)strPtr, pEnvironment);
3592 else
3593 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3594 (LPSTR)strPtr, size, NULL, NULL);
3595 if(ptr)
3596 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3597 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3600 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3601 unicode)) {
3602 *pcbNeeded += size;
3603 if(*pcbNeeded <= cbBuf)
3604 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3605 unicode);
3606 if(ptr)
3607 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3608 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3611 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3612 unicode)) {
3613 *pcbNeeded += size;
3614 if(*pcbNeeded <= cbBuf)
3615 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3616 &tmp, unicode);
3617 if(ptr)
3618 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3619 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3622 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3623 0, &size, unicode)) {
3624 *pcbNeeded += size;
3625 if(*pcbNeeded <= cbBuf)
3626 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3627 size, &tmp, unicode);
3628 if(ptr)
3629 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3630 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3633 if(Level == 2 ) {
3634 RegCloseKey(hkeyDriver);
3635 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3636 return TRUE;
3639 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3640 unicode)) {
3641 *pcbNeeded += size;
3642 if(*pcbNeeded <= cbBuf)
3643 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3644 size, &tmp, unicode);
3645 if(ptr)
3646 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3647 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3650 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3651 &size, unicode)) {
3652 *pcbNeeded += size;
3653 if(*pcbNeeded <= cbBuf)
3654 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3655 size, &tmp, unicode);
3656 if(ptr)
3657 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3658 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3661 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3662 unicode)) {
3663 *pcbNeeded += size;
3664 if(*pcbNeeded <= cbBuf)
3665 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3666 size, &tmp, unicode);
3667 if(ptr)
3668 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3669 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3672 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3673 unicode)) {
3674 *pcbNeeded += size;
3675 if(*pcbNeeded <= cbBuf)
3676 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3677 size, &tmp, unicode);
3678 if(ptr)
3679 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3680 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3683 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3684 RegCloseKey(hkeyDriver);
3685 return TRUE;
3688 /*****************************************************************************
3689 * WINSPOOL_GetPrinterDriver
3691 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3692 DWORD Level, LPBYTE pDriverInfo,
3693 DWORD cbBuf, LPDWORD pcbNeeded,
3694 BOOL unicode)
3696 LPCWSTR name;
3697 WCHAR DriverName[100];
3698 DWORD ret, type, size, needed = 0;
3699 LPBYTE ptr = NULL;
3700 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3702 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3703 Level,pDriverInfo,cbBuf, pcbNeeded);
3705 ZeroMemory(pDriverInfo, cbBuf);
3707 if (!(name = get_opened_printer_name(hPrinter))) {
3708 SetLastError(ERROR_INVALID_HANDLE);
3709 return FALSE;
3711 if(Level < 1 || Level > 6) {
3712 SetLastError(ERROR_INVALID_LEVEL);
3713 return FALSE;
3715 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3716 ERROR_SUCCESS) {
3717 ERR("Can't create Printers key\n");
3718 return FALSE;
3720 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3721 != ERROR_SUCCESS) {
3722 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3723 RegCloseKey(hkeyPrinters);
3724 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3725 return FALSE;
3727 size = sizeof(DriverName);
3728 DriverName[0] = 0;
3729 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3730 (LPBYTE)DriverName, &size);
3731 RegCloseKey(hkeyPrinter);
3732 RegCloseKey(hkeyPrinters);
3733 if(ret != ERROR_SUCCESS) {
3734 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3735 return FALSE;
3738 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3739 if(!hkeyDrivers) {
3740 ERR("Can't create Drivers key\n");
3741 return FALSE;
3744 switch(Level) {
3745 case 1:
3746 size = sizeof(DRIVER_INFO_1W);
3747 break;
3748 case 2:
3749 size = sizeof(DRIVER_INFO_2W);
3750 break;
3751 case 3:
3752 size = sizeof(DRIVER_INFO_3W);
3753 break;
3754 case 4:
3755 size = sizeof(DRIVER_INFO_4W);
3756 break;
3757 case 5:
3758 size = sizeof(DRIVER_INFO_5W);
3759 break;
3760 case 6:
3761 size = sizeof(DRIVER_INFO_6W);
3762 break;
3763 default:
3764 ERR("Invalid level\n");
3765 return FALSE;
3768 if(size <= cbBuf)
3769 ptr = pDriverInfo + size;
3771 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3772 pEnvironment, Level, pDriverInfo,
3773 (cbBuf < size) ? NULL : ptr,
3774 (cbBuf < size) ? 0 : cbBuf - size,
3775 &needed, unicode)) {
3776 RegCloseKey(hkeyDrivers);
3777 return FALSE;
3780 RegCloseKey(hkeyDrivers);
3782 if(pcbNeeded) *pcbNeeded = size + needed;
3783 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3784 if(cbBuf >= needed) return TRUE;
3785 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3786 return FALSE;
3789 /*****************************************************************************
3790 * GetPrinterDriverA [WINSPOOL.@]
3792 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3793 DWORD Level, LPBYTE pDriverInfo,
3794 DWORD cbBuf, LPDWORD pcbNeeded)
3796 BOOL ret;
3797 UNICODE_STRING pEnvW;
3798 PWSTR pwstrEnvW;
3800 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3801 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3802 cbBuf, pcbNeeded, FALSE);
3803 RtlFreeUnicodeString(&pEnvW);
3804 return ret;
3806 /*****************************************************************************
3807 * GetPrinterDriverW [WINSPOOL.@]
3809 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3810 DWORD Level, LPBYTE pDriverInfo,
3811 DWORD cbBuf, LPDWORD pcbNeeded)
3813 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3814 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3817 /*****************************************************************************
3818 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3820 * Return the PATH for the Printer-Drivers (UNICODE)
3822 * PARAMS
3823 * pName [I] Servername (NT only) or NULL (local Computer)
3824 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3825 * Level [I] Structure-Level (must be 1)
3826 * pDriverDirectory [O] PTR to Buffer that receives the Result
3827 * cbBuf [I] Size of Buffer at pDriverDirectory
3828 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3829 * required for pDriverDirectory
3831 * RETURNS
3832 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3833 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3834 * if cbBuf is too small
3836 * Native Values returned in pDriverDirectory on Success:
3837 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3838 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3839 *| win9x(Windows 4.0): "%winsysdir%"
3841 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3843 * FIXME
3844 *- Only NULL or "" is supported for pName
3847 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3848 DWORD Level, LPBYTE pDriverDirectory,
3849 DWORD cbBuf, LPDWORD pcbNeeded)
3851 DWORD needed;
3852 const printenv_t * env;
3854 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3855 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3856 if(pName != NULL && pName[0]) {
3857 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3858 SetLastError(ERROR_INVALID_PARAMETER);
3859 return FALSE;
3862 env = validate_envW(pEnvironment);
3863 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3865 if(Level != 1) {
3866 WARN("(Level: %ld) is ignored in win9x\n", Level);
3867 SetLastError(ERROR_INVALID_LEVEL);
3868 return FALSE;
3871 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3872 needed = GetSystemDirectoryW(NULL, 0);
3873 /* add the Size for the Subdirectories */
3874 needed += lstrlenW(spooldriversW);
3875 needed += lstrlenW(env->subdir);
3876 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3878 if(pcbNeeded)
3879 *pcbNeeded = needed;
3880 TRACE("required: 0x%lx/%ld\n", needed, needed);
3881 if(needed > cbBuf) {
3882 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3883 return FALSE;
3885 if(pcbNeeded == NULL) {
3886 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3887 SetLastError(RPC_X_NULL_REF_POINTER);
3888 return FALSE;
3890 if(pDriverDirectory == NULL) {
3891 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3892 SetLastError(ERROR_INVALID_USER_BUFFER);
3893 return FALSE;
3896 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3897 /* add the Subdirectories */
3898 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3899 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3900 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3901 return TRUE;
3905 /*****************************************************************************
3906 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3908 * Return the PATH for the Printer-Drivers (ANSI)
3910 * See GetPrinterDriverDirectoryW.
3912 * NOTES
3913 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3916 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3917 DWORD Level, LPBYTE pDriverDirectory,
3918 DWORD cbBuf, LPDWORD pcbNeeded)
3920 UNICODE_STRING nameW, environmentW;
3921 BOOL ret;
3922 DWORD pcbNeededW;
3923 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3924 WCHAR *driverDirectoryW = NULL;
3926 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3927 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3929 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3931 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3932 else nameW.Buffer = NULL;
3933 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3934 else environmentW.Buffer = NULL;
3936 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3937 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3938 if (ret) {
3939 DWORD needed;
3940 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3941 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3942 if(pcbNeeded)
3943 *pcbNeeded = needed;
3944 ret = (needed <= cbBuf) ? TRUE : FALSE;
3945 } else
3946 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3948 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3950 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3951 RtlFreeUnicodeString(&environmentW);
3952 RtlFreeUnicodeString(&nameW);
3954 return ret;
3957 /*****************************************************************************
3958 * AddPrinterDriverA [WINSPOOL.@]
3960 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3962 DRIVER_INFO_3A di3;
3963 HKEY hkeyDrivers, hkeyName;
3964 static CHAR empty[] = "",
3965 nullnull[] = "\0";
3967 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3969 if(level != 2 && level != 3) {
3970 SetLastError(ERROR_INVALID_LEVEL);
3971 return FALSE;
3973 if ((pName) && (pName[0])) {
3974 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3975 SetLastError(ERROR_INVALID_PARAMETER);
3976 return FALSE;
3978 if(!pDriverInfo) {
3979 WARN("pDriverInfo == NULL\n");
3980 SetLastError(ERROR_INVALID_PARAMETER);
3981 return FALSE;
3984 if(level == 3)
3985 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3986 else {
3987 memset(&di3, 0, sizeof(di3));
3988 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3991 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3992 !di3.pDataFile) {
3993 SetLastError(ERROR_INVALID_PARAMETER);
3994 return FALSE;
3997 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
3998 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
3999 if(!di3.pHelpFile) di3.pHelpFile = empty;
4000 if(!di3.pMonitorName) di3.pMonitorName = empty;
4002 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4004 if(!hkeyDrivers) {
4005 ERR("Can't create Drivers key\n");
4006 return FALSE;
4009 if(level == 2) { /* apparently can't overwrite with level2 */
4010 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4011 RegCloseKey(hkeyName);
4012 RegCloseKey(hkeyDrivers);
4013 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4014 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4015 return FALSE;
4018 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4019 RegCloseKey(hkeyDrivers);
4020 ERR("Can't create Name key\n");
4021 return FALSE;
4023 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4025 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
4026 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
4027 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4028 sizeof(DWORD));
4029 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
4030 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4031 (LPBYTE) di3.pDependentFiles, 0);
4032 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
4033 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
4034 RegCloseKey(hkeyName);
4035 RegCloseKey(hkeyDrivers);
4037 return TRUE;
4040 /*****************************************************************************
4041 * AddPrinterDriverW [WINSPOOL.@]
4043 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4044 LPBYTE pDriverInfo)
4046 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
4047 level,pDriverInfo);
4048 return FALSE;
4051 /*****************************************************************************
4052 * AddPrintProcessorA [WINSPOOL.@]
4054 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4055 LPSTR pPrintProcessorName)
4057 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4058 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4059 return FALSE;
4062 /*****************************************************************************
4063 * AddPrintProcessorW [WINSPOOL.@]
4065 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4066 LPWSTR pPrintProcessorName)
4068 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4069 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4070 return FALSE;
4073 /*****************************************************************************
4074 * AddPrintProvidorA [WINSPOOL.@]
4076 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4078 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4079 return FALSE;
4082 /*****************************************************************************
4083 * AddPrintProvidorW [WINSPOOL.@]
4085 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4087 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4088 return FALSE;
4091 /*****************************************************************************
4092 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4094 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4095 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4097 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4098 pDevModeOutput, pDevModeInput);
4099 return 0;
4102 /*****************************************************************************
4103 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4105 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4106 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4108 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4109 pDevModeOutput, pDevModeInput);
4110 return 0;
4113 /*****************************************************************************
4114 * PrinterProperties [WINSPOOL.@]
4116 * Displays a dialog to set the properties of the printer.
4118 * RETURNS
4119 * nonzero on success or zero on failure
4121 * BUGS
4122 * implemented as stub only
4124 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4125 HANDLE hPrinter /* [in] handle to printer object */
4127 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4128 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4129 return FALSE;
4132 /*****************************************************************************
4133 * EnumJobsA [WINSPOOL.@]
4136 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4137 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4138 LPDWORD pcReturned)
4140 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4141 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4143 if(pcbNeeded) *pcbNeeded = 0;
4144 if(pcReturned) *pcReturned = 0;
4145 return FALSE;
4149 /*****************************************************************************
4150 * EnumJobsW [WINSPOOL.@]
4153 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4154 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4155 LPDWORD pcReturned)
4157 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4158 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4160 if(pcbNeeded) *pcbNeeded = 0;
4161 if(pcReturned) *pcReturned = 0;
4162 return FALSE;
4165 /*****************************************************************************
4166 * WINSPOOL_EnumPrinterDrivers [internal]
4168 * Delivers information about all printer drivers installed on the
4169 * localhost or a given server
4171 * RETURNS
4172 * nonzero on success or zero on failure. If the buffer for the returned
4173 * information is too small the function will return an error
4175 * BUGS
4176 * - only implemented for localhost, foreign hosts will return an error
4178 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4179 DWORD Level, LPBYTE pDriverInfo,
4180 DWORD cbBuf, LPDWORD pcbNeeded,
4181 LPDWORD pcReturned, BOOL unicode)
4183 { HKEY hkeyDrivers;
4184 DWORD i, needed, number = 0, size = 0;
4185 WCHAR DriverNameW[255];
4186 PBYTE ptr;
4188 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4189 debugstr_w(pName), debugstr_w(pEnvironment),
4190 Level, pDriverInfo, cbBuf, unicode);
4192 /* check for local drivers */
4193 if((pName) && (pName[0])) {
4194 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4195 SetLastError(ERROR_ACCESS_DENIED);
4196 return FALSE;
4199 /* check input parameter */
4200 if((Level < 1) || (Level > 3)) {
4201 ERR("unsupported level %ld\n", Level);
4202 SetLastError(ERROR_INVALID_LEVEL);
4203 return FALSE;
4206 /* initialize return values */
4207 if(pDriverInfo)
4208 memset( pDriverInfo, 0, cbBuf);
4209 *pcbNeeded = 0;
4210 *pcReturned = 0;
4212 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4213 if(!hkeyDrivers) {
4214 ERR("Can't open Drivers key\n");
4215 return FALSE;
4218 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4219 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4220 RegCloseKey(hkeyDrivers);
4221 ERR("Can't query Drivers key\n");
4222 return FALSE;
4224 TRACE("Found %ld Drivers\n", number);
4226 /* get size of single struct
4227 * unicode and ascii structure have the same size
4229 switch (Level) {
4230 case 1:
4231 size = sizeof(DRIVER_INFO_1A);
4232 break;
4233 case 2:
4234 size = sizeof(DRIVER_INFO_2A);
4235 break;
4236 case 3:
4237 size = sizeof(DRIVER_INFO_3A);
4238 break;
4241 /* calculate required buffer size */
4242 *pcbNeeded = size * number;
4244 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4245 i < number;
4246 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4247 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4248 != ERROR_SUCCESS) {
4249 ERR("Can't enum key number %ld\n", i);
4250 RegCloseKey(hkeyDrivers);
4251 return FALSE;
4253 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4254 pEnvironment, Level, ptr,
4255 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4256 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4257 &needed, unicode)) {
4258 RegCloseKey(hkeyDrivers);
4259 return FALSE;
4261 (*pcbNeeded) += needed;
4264 RegCloseKey(hkeyDrivers);
4266 if(cbBuf < *pcbNeeded){
4267 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4268 return FALSE;
4271 *pcReturned = number;
4272 return TRUE;
4275 /*****************************************************************************
4276 * EnumPrinterDriversW [WINSPOOL.@]
4278 * see function EnumPrinterDrivers for RETURNS, BUGS
4280 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4281 LPBYTE pDriverInfo, DWORD cbBuf,
4282 LPDWORD pcbNeeded, LPDWORD pcReturned)
4284 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4285 cbBuf, pcbNeeded, pcReturned, TRUE);
4288 /*****************************************************************************
4289 * EnumPrinterDriversA [WINSPOOL.@]
4291 * see function EnumPrinterDrivers for RETURNS, BUGS
4293 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4294 LPBYTE pDriverInfo, DWORD cbBuf,
4295 LPDWORD pcbNeeded, LPDWORD pcReturned)
4296 { BOOL ret;
4297 UNICODE_STRING pNameW, pEnvironmentW;
4298 PWSTR pwstrNameW, pwstrEnvironmentW;
4300 pwstrNameW = asciitounicode(&pNameW, pName);
4301 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4303 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4304 Level, pDriverInfo, cbBuf, pcbNeeded,
4305 pcReturned, FALSE);
4306 RtlFreeUnicodeString(&pNameW);
4307 RtlFreeUnicodeString(&pEnvironmentW);
4309 return ret;
4312 static CHAR PortMonitor[] = "Wine Port Monitor";
4313 static CHAR PortDescription[] = "Wine Port";
4315 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4317 HANDLE handle;
4319 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4320 NULL, OPEN_EXISTING, 0, NULL );
4321 if (handle == INVALID_HANDLE_VALUE)
4322 return FALSE;
4323 TRACE("Checking %s exists\n", name );
4324 CloseHandle( handle );
4325 return TRUE;
4328 static DWORD WINSPOOL_CountSerialPorts(void)
4330 CHAR name[6];
4331 DWORD n = 0, i;
4333 for (i=0; i<4; i++)
4335 strcpy( name, "COMx:" );
4336 name[3] = '1' + i;
4337 if (WINSPOOL_ComPortExists( name ))
4338 n++;
4341 return n;
4344 /******************************************************************************
4345 * EnumPortsA (WINSPOOL.@)
4347 * See EnumPortsW.
4349 * BUGS
4350 * ANSI-Version did not call the UNICODE-Version
4353 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4354 LPDWORD bufneeded,LPDWORD bufreturned)
4356 CHAR portname[10];
4357 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4358 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4359 HKEY hkey_printer;
4360 BOOL retval = TRUE;
4362 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4363 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4365 switch( level )
4367 case 1:
4368 info_size = sizeof (PORT_INFO_1A);
4369 break;
4370 case 2:
4371 info_size = sizeof (PORT_INFO_2A);
4372 break;
4373 default:
4374 SetLastError(ERROR_INVALID_LEVEL);
4375 return FALSE;
4378 /* see how many exist */
4380 hkey_printer = 0;
4381 serial_count = WINSPOOL_CountSerialPorts();
4382 printer_count = 0;
4384 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4385 if ( r == ERROR_SUCCESS )
4387 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4388 &printer_count, NULL, NULL, NULL, NULL);
4390 count = serial_count + printer_count;
4392 /* then fill in the structure info structure once
4393 we know the offset to the first string */
4395 memset( buffer, 0, bufsize );
4396 n = 0;
4397 ofs = info_size*count;
4398 for ( i=0; i<count; i++)
4400 DWORD vallen = sizeof(portname) - 1;
4402 /* get the serial port values, then the printer values */
4403 if ( i < serial_count )
4405 strcpy( portname, "COMx:" );
4406 portname[3] = '1' + i;
4407 if (!WINSPOOL_ComPortExists( portname ))
4408 continue;
4410 TRACE("Found %s\n", portname );
4411 vallen = strlen( portname );
4413 else
4415 r = RegEnumValueA( hkey_printer, i-serial_count,
4416 portname, &vallen, NULL, NULL, NULL, 0 );
4417 if ( r )
4418 continue;
4421 /* add a colon if necessary, and make it upper case */
4422 CharUpperBuffA(portname,vallen);
4423 if (strcasecmp(portname,"nul")!=0)
4424 if (vallen && (portname[vallen-1] != ':') )
4425 lstrcatA(portname,":");
4427 /* add the port info structure if we can fit it */
4428 if ( info_size*(n+1) < bufsize )
4430 if ( level == 1)
4432 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4433 info->pName = (LPSTR) &buffer[ofs];
4435 else if ( level == 2)
4437 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4438 info->pPortName = (LPSTR) &buffer[ofs];
4439 /* FIXME: fill in more stuff here */
4440 info->pMonitorName = PortMonitor;
4441 info->pDescription = PortDescription;
4442 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4445 /* add the name of the port if we can fit it */
4446 if ( ofs < bufsize )
4447 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4449 n++;
4451 else
4452 retval = FALSE;
4453 ofs += lstrlenA(portname)+1;
4456 RegCloseKey(hkey_printer);
4458 if(bufneeded)
4459 *bufneeded = ofs;
4461 if(bufreturned)
4462 *bufreturned = n;
4464 return retval;
4467 /******************************************************************************
4468 * EnumPortsW (WINSPOOL.@)
4470 * Enumerate available Ports
4472 * PARAMS
4473 * name [I] Servername or NULL (local Computer)
4474 * level [I] Structure-Level (1 or 2)
4475 * buffer [O] PTR to Buffer that receives the Result
4476 * bufsize [I] Size of Buffer at buffer
4477 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4478 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4480 * RETURNS
4481 * Success: TRUE
4482 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4484 * BUGS
4485 * UNICODE-Version is a stub
4488 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4489 LPDWORD bufneeded,LPDWORD bufreturned)
4491 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4492 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4493 return FALSE;
4496 /******************************************************************************
4497 * GetDefaultPrinterW (WINSPOOL.@)
4499 * FIXME
4500 * This function must read the value from data 'device' of key
4501 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4503 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4505 BOOL retval = TRUE;
4506 DWORD insize, len;
4507 WCHAR *buffer, *ptr;
4509 if (!namesize)
4511 SetLastError(ERROR_INVALID_PARAMETER);
4512 return FALSE;
4515 /* make the buffer big enough for the stuff from the profile/registry,
4516 * the content must fit into the local buffer to compute the correct
4517 * size even if the extern buffer is too small or not given.
4518 * (20 for ,driver,port) */
4519 insize = *namesize;
4520 len = max(100, (insize + 20));
4521 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4523 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4525 SetLastError (ERROR_FILE_NOT_FOUND);
4526 retval = FALSE;
4527 goto end;
4529 TRACE("%s\n", debugstr_w(buffer));
4531 if ((ptr = strchrW(buffer, ',')) == NULL)
4533 SetLastError(ERROR_INVALID_NAME);
4534 retval = FALSE;
4535 goto end;
4538 *ptr = 0;
4539 *namesize = strlenW(buffer) + 1;
4540 if(!name || (*namesize > insize))
4542 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4543 retval = FALSE;
4544 goto end;
4546 strcpyW(name, buffer);
4548 end:
4549 HeapFree( GetProcessHeap(), 0, buffer);
4550 return retval;
4554 /******************************************************************************
4555 * GetDefaultPrinterA (WINSPOOL.@)
4557 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4559 BOOL retval = TRUE;
4560 DWORD insize = 0;
4561 WCHAR *bufferW = NULL;
4563 if (!namesize)
4565 SetLastError(ERROR_INVALID_PARAMETER);
4566 return FALSE;
4569 if(name && *namesize) {
4570 insize = *namesize;
4571 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4574 if(!GetDefaultPrinterW( bufferW, namesize)) {
4575 retval = FALSE;
4576 goto end;
4579 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4580 NULL, NULL);
4581 if (!*namesize)
4583 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4584 retval = FALSE;
4586 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4588 end:
4589 HeapFree( GetProcessHeap(), 0, bufferW);
4590 return retval;
4594 /******************************************************************************
4595 * SetDefaultPrinterW (WINSPOOL.204)
4597 * Set the Name of the Default Printer
4599 * PARAMS
4600 * pszPrinter [I] Name of the Printer or NULL
4602 * RETURNS
4603 * Success: True
4604 * Failure: FALSE
4606 * NOTES
4607 * When the Parameter is NULL or points to an Empty String and
4608 * a Default Printer was already present, then this Function changes nothing.
4609 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4610 * the First enumerated local Printer is used.
4613 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4616 TRACE("(%s)\n", debugstr_w(pszPrinter));
4618 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4619 return FALSE;
4622 /******************************************************************************
4623 * SetDefaultPrinterA (WINSPOOL.202)
4625 * See SetDefaultPrinterW.
4628 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4631 TRACE("(%s)\n", debugstr_a(pszPrinter));
4633 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4634 return FALSE;
4638 /******************************************************************************
4639 * SetPrinterDataExA (WINSPOOL.@)
4641 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4642 LPCSTR 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_a(pKeyName),
4649 debugstr_a(pValueName), Type, pData, cbData);
4651 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4652 != ERROR_SUCCESS)
4653 return ret;
4655 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4656 != ERROR_SUCCESS) {
4657 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4658 RegCloseKey(hkeyPrinter);
4659 return ret;
4661 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4662 RegCloseKey(hkeySubkey);
4663 RegCloseKey(hkeyPrinter);
4664 return ret;
4667 /******************************************************************************
4668 * SetPrinterDataExW (WINSPOOL.@)
4670 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4671 LPCWSTR pValueName, DWORD Type,
4672 LPBYTE pData, DWORD cbData)
4674 HKEY hkeyPrinter, hkeySubkey;
4675 DWORD ret;
4677 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4678 debugstr_w(pValueName), Type, pData, cbData);
4680 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4681 != ERROR_SUCCESS)
4682 return ret;
4684 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4685 != ERROR_SUCCESS) {
4686 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4687 RegCloseKey(hkeyPrinter);
4688 return ret;
4690 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4691 RegCloseKey(hkeySubkey);
4692 RegCloseKey(hkeyPrinter);
4693 return ret;
4696 /******************************************************************************
4697 * SetPrinterDataA (WINSPOOL.@)
4699 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4700 LPBYTE pData, DWORD cbData)
4702 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4703 pData, cbData);
4706 /******************************************************************************
4707 * SetPrinterDataW (WINSPOOL.@)
4709 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4710 LPBYTE pData, DWORD cbData)
4712 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4713 pData, cbData);
4716 /******************************************************************************
4717 * GetPrinterDataExA (WINSPOOL.@)
4719 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4720 LPCSTR pValueName, LPDWORD pType,
4721 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4723 HKEY hkeyPrinter, hkeySubkey;
4724 DWORD ret;
4726 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4727 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4728 pcbNeeded);
4730 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4731 != ERROR_SUCCESS)
4732 return ret;
4734 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4735 != ERROR_SUCCESS) {
4736 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4737 RegCloseKey(hkeyPrinter);
4738 return ret;
4740 *pcbNeeded = nSize;
4741 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4742 RegCloseKey(hkeySubkey);
4743 RegCloseKey(hkeyPrinter);
4744 return ret;
4747 /******************************************************************************
4748 * GetPrinterDataExW (WINSPOOL.@)
4750 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4751 LPCWSTR pValueName, LPDWORD pType,
4752 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4754 HKEY hkeyPrinter, hkeySubkey;
4755 DWORD ret;
4757 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4758 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4759 pcbNeeded);
4761 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4762 != ERROR_SUCCESS)
4763 return ret;
4765 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4766 != ERROR_SUCCESS) {
4767 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4768 RegCloseKey(hkeyPrinter);
4769 return ret;
4771 *pcbNeeded = nSize;
4772 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4773 RegCloseKey(hkeySubkey);
4774 RegCloseKey(hkeyPrinter);
4775 return ret;
4778 /******************************************************************************
4779 * GetPrinterDataA (WINSPOOL.@)
4781 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4782 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4784 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4785 pData, nSize, pcbNeeded);
4788 /******************************************************************************
4789 * GetPrinterDataW (WINSPOOL.@)
4791 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4792 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4794 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4795 pData, nSize, pcbNeeded);
4798 /*******************************************************************************
4799 * EnumPrinterDataExW [WINSPOOL.@]
4801 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4802 LPBYTE pEnumValues, DWORD cbEnumValues,
4803 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4805 HKEY hkPrinter, hkSubKey;
4806 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4807 cbValueNameLen, cbMaxValueLen, cbValueLen,
4808 cbBufSize, dwType;
4809 LPWSTR lpValueName;
4810 HANDLE hHeap;
4811 PBYTE lpValue;
4812 PPRINTER_ENUM_VALUESW ppev;
4814 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4816 if (pKeyName == NULL || *pKeyName == 0)
4817 return ERROR_INVALID_PARAMETER;
4819 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4820 if (ret != ERROR_SUCCESS)
4822 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4823 hPrinter, ret);
4824 return ret;
4827 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4828 if (ret != ERROR_SUCCESS)
4830 r = RegCloseKey (hkPrinter);
4831 if (r != ERROR_SUCCESS)
4832 WARN ("RegCloseKey returned %li\n", r);
4833 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4834 debugstr_w (pKeyName), ret);
4835 return ret;
4838 ret = RegCloseKey (hkPrinter);
4839 if (ret != ERROR_SUCCESS)
4841 ERR ("RegCloseKey returned %li\n", ret);
4842 r = RegCloseKey (hkSubKey);
4843 if (r != ERROR_SUCCESS)
4844 WARN ("RegCloseKey returned %li\n", r);
4845 return ret;
4848 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4849 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4850 if (ret != ERROR_SUCCESS)
4852 r = RegCloseKey (hkSubKey);
4853 if (r != ERROR_SUCCESS)
4854 WARN ("RegCloseKey returned %li\n", r);
4855 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4856 return ret;
4859 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4860 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4862 if (cValues == 0) /* empty key */
4864 r = RegCloseKey (hkSubKey);
4865 if (r != ERROR_SUCCESS)
4866 WARN ("RegCloseKey returned %li\n", r);
4867 *pcbEnumValues = *pnEnumValues = 0;
4868 return ERROR_SUCCESS;
4871 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4873 hHeap = GetProcessHeap ();
4874 if (hHeap == NULL)
4876 ERR ("GetProcessHeap failed\n");
4877 r = RegCloseKey (hkSubKey);
4878 if (r != ERROR_SUCCESS)
4879 WARN ("RegCloseKey returned %li\n", r);
4880 return ERROR_OUTOFMEMORY;
4883 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4884 if (lpValueName == NULL)
4886 ERR ("Failed to allocate %li bytes from process heap\n",
4887 cbMaxValueNameLen * sizeof (WCHAR));
4888 r = RegCloseKey (hkSubKey);
4889 if (r != ERROR_SUCCESS)
4890 WARN ("RegCloseKey returned %li\n", r);
4891 return ERROR_OUTOFMEMORY;
4894 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4895 if (lpValue == NULL)
4897 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4898 if (HeapFree (hHeap, 0, lpValueName) == 0)
4899 WARN ("HeapFree failed with code %li\n", GetLastError ());
4900 r = RegCloseKey (hkSubKey);
4901 if (r != ERROR_SUCCESS)
4902 WARN ("RegCloseKey returned %li\n", r);
4903 return ERROR_OUTOFMEMORY;
4906 TRACE ("pass 1: calculating buffer required for all names and values\n");
4908 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4910 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4912 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4914 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4915 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4916 NULL, NULL, lpValue, &cbValueLen);
4917 if (ret != ERROR_SUCCESS)
4919 if (HeapFree (hHeap, 0, lpValue) == 0)
4920 WARN ("HeapFree failed with code %li\n", GetLastError ());
4921 if (HeapFree (hHeap, 0, lpValueName) == 0)
4922 WARN ("HeapFree failed with code %li\n", GetLastError ());
4923 r = RegCloseKey (hkSubKey);
4924 if (r != ERROR_SUCCESS)
4925 WARN ("RegCloseKey returned %li\n", r);
4926 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4927 return ret;
4930 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4931 debugstr_w (lpValueName), dwIndex,
4932 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4934 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4935 cbBufSize += cbValueLen;
4938 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4940 *pcbEnumValues = cbBufSize;
4941 *pnEnumValues = cValues;
4943 if (cbEnumValues < cbBufSize) /* buffer too small */
4945 if (HeapFree (hHeap, 0, lpValue) == 0)
4946 WARN ("HeapFree failed with code %li\n", GetLastError ());
4947 if (HeapFree (hHeap, 0, lpValueName) == 0)
4948 WARN ("HeapFree failed with code %li\n", GetLastError ());
4949 r = RegCloseKey (hkSubKey);
4950 if (r != ERROR_SUCCESS)
4951 WARN ("RegCloseKey returned %li\n", r);
4952 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4953 return ERROR_MORE_DATA;
4956 TRACE ("pass 2: copying all names and values to buffer\n");
4958 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4959 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4961 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4963 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4964 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4965 NULL, &dwType, lpValue, &cbValueLen);
4966 if (ret != ERROR_SUCCESS)
4968 if (HeapFree (hHeap, 0, lpValue) == 0)
4969 WARN ("HeapFree failed with code %li\n", GetLastError ());
4970 if (HeapFree (hHeap, 0, lpValueName) == 0)
4971 WARN ("HeapFree failed with code %li\n", GetLastError ());
4972 r = RegCloseKey (hkSubKey);
4973 if (r != ERROR_SUCCESS)
4974 WARN ("RegCloseKey returned %li\n", r);
4975 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4976 return ret;
4979 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4980 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4981 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4982 pEnumValues += cbValueNameLen;
4984 /* return # of *bytes* (including trailing \0), not # of chars */
4985 ppev[dwIndex].cbValueName = cbValueNameLen;
4987 ppev[dwIndex].dwType = dwType;
4989 memcpy (pEnumValues, lpValue, cbValueLen);
4990 ppev[dwIndex].pData = pEnumValues;
4991 pEnumValues += cbValueLen;
4993 ppev[dwIndex].cbData = cbValueLen;
4995 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4996 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4999 if (HeapFree (hHeap, 0, lpValue) == 0)
5001 ret = GetLastError ();
5002 ERR ("HeapFree failed with code %li\n", ret);
5003 if (HeapFree (hHeap, 0, lpValueName) == 0)
5004 WARN ("HeapFree failed with code %li\n", GetLastError ());
5005 r = RegCloseKey (hkSubKey);
5006 if (r != ERROR_SUCCESS)
5007 WARN ("RegCloseKey returned %li\n", r);
5008 return ret;
5011 if (HeapFree (hHeap, 0, lpValueName) == 0)
5013 ret = GetLastError ();
5014 ERR ("HeapFree failed with code %li\n", ret);
5015 r = RegCloseKey (hkSubKey);
5016 if (r != ERROR_SUCCESS)
5017 WARN ("RegCloseKey returned %li\n", r);
5018 return ret;
5021 ret = RegCloseKey (hkSubKey);
5022 if (ret != ERROR_SUCCESS)
5024 ERR ("RegCloseKey returned %li\n", ret);
5025 return ret;
5028 return ERROR_SUCCESS;
5031 /*******************************************************************************
5032 * EnumPrinterDataExA [WINSPOOL.@]
5034 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5035 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5036 * what Windows 2000 SP1 does.
5039 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5040 LPBYTE pEnumValues, DWORD cbEnumValues,
5041 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5043 INT len;
5044 LPWSTR pKeyNameW;
5045 DWORD ret, dwIndex, dwBufSize;
5046 HANDLE hHeap;
5047 LPSTR pBuffer;
5049 TRACE ("%p %s\n", hPrinter, pKeyName);
5051 if (pKeyName == NULL || *pKeyName == 0)
5052 return ERROR_INVALID_PARAMETER;
5054 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5055 if (len == 0)
5057 ret = GetLastError ();
5058 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5059 return ret;
5062 hHeap = GetProcessHeap ();
5063 if (hHeap == NULL)
5065 ERR ("GetProcessHeap failed\n");
5066 return ERROR_OUTOFMEMORY;
5069 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5070 if (pKeyNameW == NULL)
5072 ERR ("Failed to allocate %li bytes from process heap\n",
5073 (LONG) len * sizeof (WCHAR));
5074 return ERROR_OUTOFMEMORY;
5077 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5079 ret = GetLastError ();
5080 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5081 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5082 WARN ("HeapFree failed with code %li\n", GetLastError ());
5083 return ret;
5086 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5087 pcbEnumValues, pnEnumValues);
5088 if (ret != ERROR_SUCCESS)
5090 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5091 WARN ("HeapFree failed with code %li\n", GetLastError ());
5092 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5093 return ret;
5096 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5098 ret = GetLastError ();
5099 ERR ("HeapFree failed with code %li\n", ret);
5100 return ret;
5103 if (*pnEnumValues == 0) /* empty key */
5104 return ERROR_SUCCESS;
5106 dwBufSize = 0;
5107 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5109 PPRINTER_ENUM_VALUESW ppev =
5110 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5112 if (dwBufSize < ppev->cbValueName)
5113 dwBufSize = ppev->cbValueName;
5115 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5116 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5117 dwBufSize = ppev->cbData;
5120 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5122 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5123 if (pBuffer == NULL)
5125 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5126 return ERROR_OUTOFMEMORY;
5129 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5131 PPRINTER_ENUM_VALUESW ppev =
5132 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5134 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5135 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5136 NULL);
5137 if (len == 0)
5139 ret = GetLastError ();
5140 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5141 if (HeapFree (hHeap, 0, pBuffer) == 0)
5142 WARN ("HeapFree failed with code %li\n", GetLastError ());
5143 return ret;
5146 memcpy (ppev->pValueName, pBuffer, len);
5148 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5150 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5151 ppev->dwType != REG_MULTI_SZ)
5152 continue;
5154 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5155 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5156 if (len == 0)
5158 ret = GetLastError ();
5159 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5160 if (HeapFree (hHeap, 0, pBuffer) == 0)
5161 WARN ("HeapFree failed with code %li\n", GetLastError ());
5162 return ret;
5165 memcpy (ppev->pData, pBuffer, len);
5167 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5168 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5171 if (HeapFree (hHeap, 0, pBuffer) == 0)
5173 ret = GetLastError ();
5174 ERR ("HeapFree failed with code %li\n", ret);
5175 return ret;
5178 return ERROR_SUCCESS;
5181 /******************************************************************************
5182 * AbortPrinter (WINSPOOL.@)
5184 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5186 FIXME("(%p), stub!\n", hPrinter);
5187 return TRUE;
5190 /******************************************************************************
5191 * AddPortA (WINSPOOL.@)
5193 * See AddPortW.
5196 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5198 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5199 return FALSE;
5202 /******************************************************************************
5203 * AddPortW (WINSPOOL.@)
5205 * Add a Port for a specific Monitor
5207 * PARAMS
5208 * pName [I] Servername or NULL (local Computer)
5209 * hWnd [I] Handle to parent Window for the Dialog-Box
5210 * pMonitorName [I] Name of the Monitor that manage the Port
5212 * RETURNS
5213 * Success: TRUE
5214 * Failure: FALSE
5216 * BUGS
5217 * only a Stub
5220 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5222 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5223 return FALSE;
5226 /******************************************************************************
5227 * AddPortExA (WINSPOOL.@)
5229 * See AddPortExW.
5232 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5234 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5235 lpBuffer, debugstr_a(lpMonitorName));
5236 return FALSE;
5239 /******************************************************************************
5240 * AddPortExW (WINSPOOL.@)
5242 * Add a Port for a specific Monitor, without presenting a user interface
5244 * PARAMS
5245 * hMonitor [I] Handle from InitializePrintMonitor2()
5246 * pName [I] Servername or NULL (local Computer)
5247 * Level [I] Structure-Level (1 or 2) for lpBuffer
5248 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5249 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5251 * RETURNS
5252 * Success: TRUE
5253 * Failure: FALSE
5255 * BUGS
5256 * only a Stub
5259 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5261 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5262 lpBuffer, debugstr_w(lpMonitorName));
5263 return FALSE;
5266 /******************************************************************************
5267 * AddPrinterConnectionA (WINSPOOL.@)
5269 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5271 FIXME("%s\n", debugstr_a(pName));
5272 return FALSE;
5275 /******************************************************************************
5276 * AddPrinterConnectionW (WINSPOOL.@)
5278 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5280 FIXME("%s\n", debugstr_w(pName));
5281 return FALSE;
5284 /******************************************************************************
5285 * AddPrinterDriverExW (WINSPOOL.@)
5287 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5288 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5290 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5291 Level, pDriverInfo, dwFileCopyFlags);
5292 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5293 return FALSE;
5296 /******************************************************************************
5297 * AddPrinterDriverExA (WINSPOOL.@)
5299 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5300 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5302 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5303 Level, pDriverInfo, dwFileCopyFlags);
5304 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5305 return FALSE;
5308 /******************************************************************************
5309 * ConfigurePortA (WINSPOOL.@)
5311 * See ConfigurePortW.
5314 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5316 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5317 return FALSE;
5320 /******************************************************************************
5321 * ConfigurePortW (WINSPOOL.@)
5323 * Display the Configuration-Dialog for a specific Port
5325 * PARAMS
5326 * pName [I] Servername or NULL (local Computer)
5327 * hWnd [I] Handle to parent Window for the Dialog-Box
5328 * pPortName [I] Name of the Port, that should be configured
5330 * RETURNS
5331 * Success: TRUE
5332 * Failure: FALSE
5334 * BUGS
5335 * only a Stub
5338 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5340 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5341 return FALSE;
5344 /******************************************************************************
5345 * ConnectToPrinterDlg (WINSPOOL.@)
5347 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5349 FIXME("%p %lx\n", hWnd, Flags);
5350 return NULL;
5353 /******************************************************************************
5354 * DeletePrinterConnectionA (WINSPOOL.@)
5356 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5358 FIXME("%s\n", debugstr_a(pName));
5359 return TRUE;
5362 /******************************************************************************
5363 * DeletePrinterConnectionW (WINSPOOL.@)
5365 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5367 FIXME("%s\n", debugstr_w(pName));
5368 return TRUE;
5371 /******************************************************************************
5372 * DeletePrinterDriverExW (WINSPOOL.@)
5374 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5375 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5377 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5378 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5379 return TRUE;
5382 /******************************************************************************
5383 * DeletePrinterDriverExA (WINSPOOL.@)
5385 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5386 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5388 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5389 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5390 return TRUE;
5393 /******************************************************************************
5394 * DeletePrinterDataExW (WINSPOOL.@)
5396 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5397 LPCWSTR pValueName)
5399 FIXME("%p %s %s\n", hPrinter,
5400 debugstr_w(pKeyName), debugstr_w(pValueName));
5401 return ERROR_INVALID_PARAMETER;
5404 /******************************************************************************
5405 * DeletePrinterDataExA (WINSPOOL.@)
5407 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5408 LPCSTR pValueName)
5410 FIXME("%p %s %s\n", hPrinter,
5411 debugstr_a(pKeyName), debugstr_a(pValueName));
5412 return ERROR_INVALID_PARAMETER;
5415 /******************************************************************************
5416 * DeletePrintProcessorA (WINSPOOL.@)
5418 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5420 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5421 debugstr_a(pPrintProcessorName));
5422 return TRUE;
5425 /******************************************************************************
5426 * DeletePrintProcessorW (WINSPOOL.@)
5428 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5430 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5431 debugstr_w(pPrintProcessorName));
5432 return TRUE;
5435 /******************************************************************************
5436 * DeletePrintProvidorA (WINSPOOL.@)
5438 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5440 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5441 debugstr_a(pPrintProviderName));
5442 return TRUE;
5445 /******************************************************************************
5446 * DeletePrintProvidorW (WINSPOOL.@)
5448 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5450 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5451 debugstr_w(pPrintProviderName));
5452 return TRUE;
5455 /******************************************************************************
5456 * EnumFormsA (WINSPOOL.@)
5458 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5459 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5461 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5462 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5463 return FALSE;
5466 /******************************************************************************
5467 * EnumFormsW (WINSPOOL.@)
5469 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5470 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5472 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5473 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5474 return FALSE;
5477 /*****************************************************************************
5478 * EnumMonitorsA [WINSPOOL.@]
5480 * See EnumMonitorsW.
5483 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5484 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5486 BOOL res;
5487 LPBYTE bufferW = NULL;
5488 LPWSTR nameW = NULL;
5489 DWORD needed = 0;
5490 DWORD numentries = 0;
5491 INT len;
5493 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5494 cbBuf, pcbNeeded, pcReturned);
5496 /* convert servername to unicode */
5497 if (pName) {
5498 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5499 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5500 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5502 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5503 needed = cbBuf * sizeof(WCHAR);
5504 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5505 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5507 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5508 if (pcbNeeded) needed = *pcbNeeded;
5509 /* HeapReAlloc return NULL, when bufferW was NULL */
5510 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5511 HeapAlloc(GetProcessHeap(), 0, needed);
5513 /* Try again with the large Buffer */
5514 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5516 numentries = pcReturned ? *pcReturned : 0;
5517 needed = 0;
5519 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5520 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5522 if (res) {
5523 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5524 DWORD entrysize = 0;
5525 DWORD index;
5526 LPSTR ptr;
5527 LPMONITOR_INFO_2W mi2w;
5528 LPMONITOR_INFO_2A mi2a;
5530 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5531 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5533 /* First pass: calculate the size for all Entries */
5534 mi2w = (LPMONITOR_INFO_2W) bufferW;
5535 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5536 index = 0;
5537 while (index < numentries) {
5538 index++;
5539 needed += entrysize; /* MONITOR_INFO_?A */
5540 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5542 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5543 NULL, 0, NULL, NULL);
5544 if (Level > 1) {
5545 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5546 NULL, 0, NULL, NULL);
5547 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5548 NULL, 0, NULL, NULL);
5550 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5551 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5552 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5555 /* check for errors and quit on failure */
5556 if (cbBuf < needed) {
5557 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5558 res = FALSE;
5559 goto emA_cleanup;
5561 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5562 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5563 cbBuf -= len ; /* free Bytes in the user-Buffer */
5564 mi2w = (LPMONITOR_INFO_2W) bufferW;
5565 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5566 index = 0;
5567 /* Second Pass: Fill the User Buffer (if we have one) */
5568 while ((index < numentries) && pMonitors) {
5569 index++;
5570 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5571 mi2a->pName = ptr;
5572 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5573 ptr, cbBuf , NULL, NULL);
5574 ptr += len;
5575 cbBuf -= len;
5576 if (Level > 1) {
5577 mi2a->pEnvironment = ptr;
5578 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5579 ptr, cbBuf, NULL, NULL);
5580 ptr += len;
5581 cbBuf -= len;
5583 mi2a->pDLLName = ptr;
5584 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5585 ptr, cbBuf, NULL, NULL);
5586 ptr += len;
5587 cbBuf -= len;
5589 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5590 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5591 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5594 emA_cleanup:
5595 if (pcbNeeded) *pcbNeeded = needed;
5596 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5598 HeapFree(GetProcessHeap(), 0, nameW);
5599 HeapFree(GetProcessHeap(), 0, bufferW);
5601 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5602 (res), GetLastError(), needed, numentries);
5604 return (res);
5608 /*****************************************************************************
5609 * EnumMonitorsW [WINSPOOL.@]
5611 * Enumerate available Port-Monitors
5613 * PARAMS
5614 * pName [I] Servername or NULL (local Computer)
5615 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5616 * pMonitors [O] PTR to Buffer that receives the Result
5617 * cbBuf [I] Size of Buffer at pMonitors
5618 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5619 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5621 * RETURNS
5622 * Success: TRUE
5623 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5625 * NOTES
5626 * Windows reads the Registry once and cache the Results.
5628 *| Language-Monitors are also installed in the same Registry-Location but
5629 *| they are filtered in Windows (not returned by EnumMonitors).
5630 *| We do no filtering to simplify our Code.
5633 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5634 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5636 DWORD needed = 0;
5637 DWORD numentries = 0;
5638 BOOL res = FALSE;
5640 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5641 cbBuf, pcbNeeded, pcReturned);
5643 if (pName && (lstrlenW(pName))) {
5644 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5645 SetLastError(ERROR_ACCESS_DENIED);
5646 goto emW_cleanup;
5649 /* Level is not checked in win9x */
5650 if (!Level || (Level > 2)) {
5651 WARN("level (%ld) is ignored in win9x\n", Level);
5652 SetLastError(ERROR_INVALID_LEVEL);
5653 goto emW_cleanup;
5655 if (!pcbNeeded) {
5656 SetLastError(RPC_X_NULL_REF_POINTER);
5657 goto emW_cleanup;
5660 /* Scan all Monitor-Keys */
5661 numentries = 0;
5662 needed = get_local_monitors(Level, NULL, 0, &numentries);
5664 /* we calculated the needed buffersize. now do the error-checks */
5665 if (cbBuf < needed) {
5666 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5667 goto emW_cleanup;
5669 else if (!pMonitors || !pcReturned) {
5670 SetLastError(RPC_X_NULL_REF_POINTER);
5671 goto emW_cleanup;
5674 /* fill the Buffer with the Monitor-Keys */
5675 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5676 res = TRUE;
5678 emW_cleanup:
5679 if (pcbNeeded) *pcbNeeded = needed;
5680 if (pcReturned) *pcReturned = numentries;
5682 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5683 res, GetLastError(), needed, numentries);
5685 return (res);
5688 /******************************************************************************
5689 * XcvDataW (WINSPOOL.@)
5691 * Notes:
5692 * There doesn't seem to be an A version...
5694 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5695 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5696 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5698 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5699 pInputData, cbInputData, pOutputData,
5700 cbOutputData, pcbOutputNeeded, pdwStatus);
5701 return FALSE;
5704 /*****************************************************************************
5705 * EnumPrinterDataA [WINSPOOL.@]
5708 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5709 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5710 DWORD cbData, LPDWORD pcbData )
5712 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5713 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5714 return ERROR_NO_MORE_ITEMS;
5717 /*****************************************************************************
5718 * EnumPrinterDataW [WINSPOOL.@]
5721 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5722 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5723 DWORD cbData, LPDWORD pcbData )
5725 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5726 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5727 return ERROR_NO_MORE_ITEMS;
5730 /*****************************************************************************
5731 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5734 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5735 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5736 LPDWORD pcbNeeded, LPDWORD pcReturned)
5738 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5739 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5740 pcbNeeded, pcReturned);
5741 return FALSE;
5744 /*****************************************************************************
5745 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5748 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5749 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5750 LPDWORD pcbNeeded, LPDWORD pcReturned)
5752 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5753 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5754 pcbNeeded, pcReturned);
5755 return FALSE;
5758 /*****************************************************************************
5759 * EnumPrintProcessorsA [WINSPOOL.@]
5762 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5763 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5765 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5766 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5767 return FALSE;
5770 /*****************************************************************************
5771 * EnumPrintProcessorsW [WINSPOOL.@]
5774 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5775 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5777 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5778 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5779 cbBuf, pcbNeeded, pcbReturned);
5780 return FALSE;
5783 /*****************************************************************************
5784 * ExtDeviceMode [WINSPOOL.@]
5787 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5788 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5789 DWORD fMode)
5791 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5792 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5793 debugstr_a(pProfile), fMode);
5794 return -1;
5797 /*****************************************************************************
5798 * FindClosePrinterChangeNotification [WINSPOOL.@]
5801 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5803 FIXME("Stub: %p\n", hChange);
5804 return TRUE;
5807 /*****************************************************************************
5808 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5811 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5812 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5814 FIXME("Stub: %p %lx %lx %p\n",
5815 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5816 return INVALID_HANDLE_VALUE;
5819 /*****************************************************************************
5820 * FindNextPrinterChangeNotification [WINSPOOL.@]
5823 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5824 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5826 FIXME("Stub: %p %p %p %p\n",
5827 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5828 return FALSE;
5831 /*****************************************************************************
5832 * FreePrinterNotifyInfo [WINSPOOL.@]
5835 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5837 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5838 return TRUE;
5841 /*****************************************************************************
5842 * string_to_buf
5844 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5845 * ansi depending on the unicode parameter.
5847 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5849 if(!str)
5851 *size = 0;
5852 return TRUE;
5855 if(unicode)
5857 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5858 if(*size <= cb)
5860 memcpy(ptr, str, *size);
5861 return TRUE;
5863 return FALSE;
5865 else
5867 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5868 if(*size <= cb)
5870 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5871 return TRUE;
5873 return FALSE;
5877 /*****************************************************************************
5878 * get_job_info_1
5880 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5881 LPDWORD pcbNeeded, BOOL unicode)
5883 DWORD size, left = cbBuf;
5884 BOOL space = (cbBuf > 0);
5885 LPBYTE ptr = buf;
5887 *pcbNeeded = 0;
5889 if(space)
5891 ji1->JobId = job->job_id;
5894 string_to_buf(job->document_title, ptr, left, &size, unicode);
5895 if(space && size <= left)
5897 ji1->pDocument = (LPWSTR)ptr;
5898 ptr += size;
5899 left -= size;
5901 else
5902 space = FALSE;
5903 *pcbNeeded += size;
5905 return space;
5908 /*****************************************************************************
5909 * get_job_info_2
5911 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5912 LPDWORD pcbNeeded, BOOL unicode)
5914 DWORD size, left = cbBuf;
5915 BOOL space = (cbBuf > 0);
5916 LPBYTE ptr = buf;
5918 *pcbNeeded = 0;
5920 if(space)
5922 ji2->JobId = job->job_id;
5925 string_to_buf(job->document_title, ptr, left, &size, unicode);
5926 if(space && size <= left)
5928 ji2->pDocument = (LPWSTR)ptr;
5929 ptr += size;
5930 left -= size;
5932 else
5933 space = FALSE;
5934 *pcbNeeded += size;
5936 return space;
5939 /*****************************************************************************
5940 * get_job_info
5942 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5943 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5945 BOOL ret = FALSE;
5946 DWORD needed = 0, size;
5947 job_t *job;
5948 LPBYTE ptr = pJob;
5950 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5952 EnterCriticalSection(&printer_handles_cs);
5953 job = get_job(hPrinter, JobId);
5954 if(!job)
5955 goto end;
5957 switch(Level)
5959 case 1:
5960 size = sizeof(JOB_INFO_1W);
5961 if(cbBuf >= size)
5963 cbBuf -= size;
5964 ptr += size;
5965 memset(pJob, 0, size);
5967 else
5968 cbBuf = 0;
5969 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5970 needed += size;
5971 break;
5973 case 2:
5974 size = sizeof(JOB_INFO_2W);
5975 if(cbBuf >= size)
5977 cbBuf -= size;
5978 ptr += size;
5979 memset(pJob, 0, size);
5981 else
5982 cbBuf = 0;
5983 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5984 needed += size;
5985 break;
5987 case 3:
5988 size = sizeof(JOB_INFO_3);
5989 if(cbBuf >= size)
5991 cbBuf -= size;
5992 memset(pJob, 0, size);
5993 ret = TRUE;
5995 else
5996 cbBuf = 0;
5997 needed = size;
5998 break;
6000 default:
6001 SetLastError(ERROR_INVALID_LEVEL);
6002 goto end;
6004 if(pcbNeeded)
6005 *pcbNeeded = needed;
6006 end:
6007 LeaveCriticalSection(&printer_handles_cs);
6008 return ret;
6011 /*****************************************************************************
6012 * GetJobA [WINSPOOL.@]
6015 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6016 DWORD cbBuf, LPDWORD pcbNeeded)
6018 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6021 /*****************************************************************************
6022 * GetJobW [WINSPOOL.@]
6025 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6026 DWORD cbBuf, LPDWORD pcbNeeded)
6028 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6031 /*****************************************************************************
6032 * schedule_lpr
6034 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6036 char *unixname, *queue, *cmd;
6037 char fmt[] = "lpr -P%s %s";
6038 DWORD len;
6040 if(!(unixname = wine_get_unix_file_name(filename)))
6041 return FALSE;
6043 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6044 queue = HeapAlloc(GetProcessHeap(), 0, len);
6045 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6047 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6048 sprintf(cmd, fmt, queue, unixname);
6050 TRACE("printing with: %s\n", cmd);
6051 system(cmd);
6053 HeapFree(GetProcessHeap(), 0, cmd);
6054 HeapFree(GetProcessHeap(), 0, queue);
6055 HeapFree(GetProcessHeap(), 0, unixname);
6056 return TRUE;
6059 /*****************************************************************************
6060 * schedule_cups
6062 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6064 #if HAVE_CUPS_CUPS_H
6065 if(pcupsPrintFile)
6067 char *unixname, *queue, *doc_titleA;
6068 DWORD len;
6069 BOOL ret;
6071 if(!(unixname = wine_get_unix_file_name(filename)))
6072 return FALSE;
6074 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6075 queue = HeapAlloc(GetProcessHeap(), 0, len);
6076 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6078 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6079 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6080 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6082 TRACE("printing via cups\n");
6083 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6084 HeapFree(GetProcessHeap(), 0, doc_titleA);
6085 HeapFree(GetProcessHeap(), 0, queue);
6086 HeapFree(GetProcessHeap(), 0, unixname);
6087 return ret;
6089 else
6090 #endif
6092 return schedule_lpr(printer_name, filename);
6096 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6098 LPWSTR filename;
6100 switch(msg)
6102 case WM_INITDIALOG:
6103 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6104 return TRUE;
6106 case WM_COMMAND:
6107 if(HIWORD(wparam) == BN_CLICKED)
6109 if(LOWORD(wparam) == IDOK)
6111 HANDLE hf;
6112 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6113 LPWSTR *output;
6115 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6116 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6118 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6120 WCHAR caption[200], message[200];
6121 int mb_ret;
6123 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6124 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6125 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6126 if(mb_ret == IDCANCEL)
6128 HeapFree(GetProcessHeap(), 0, filename);
6129 return TRUE;
6132 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6133 if(hf == INVALID_HANDLE_VALUE)
6135 WCHAR caption[200], message[200];
6137 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6138 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6139 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6140 HeapFree(GetProcessHeap(), 0, filename);
6141 return TRUE;
6143 CloseHandle(hf);
6144 DeleteFileW(filename);
6145 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6146 *output = filename;
6147 EndDialog(hwnd, IDOK);
6148 return TRUE;
6150 if(LOWORD(wparam) == IDCANCEL)
6152 EndDialog(hwnd, IDCANCEL);
6153 return TRUE;
6156 return FALSE;
6158 return FALSE;
6161 /*****************************************************************************
6162 * get_filename
6164 static BOOL get_filename(LPWSTR *filename)
6166 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6167 file_dlg_proc, (LPARAM)filename) == IDOK;
6170 /*****************************************************************************
6171 * schedule_file
6173 static BOOL schedule_file(LPCWSTR filename)
6175 LPWSTR output = NULL;
6177 if(get_filename(&output))
6179 TRACE("copy to %s\n", debugstr_w(output));
6180 CopyFileW(filename, output, FALSE);
6181 HeapFree(GetProcessHeap(), 0, output);
6182 return TRUE;
6184 return FALSE;
6187 /*****************************************************************************
6188 * schedule_pipe
6190 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6192 #ifdef HAVE_FORK
6193 char *unixname, *cmdA;
6194 DWORD len;
6195 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6196 BOOL ret = FALSE;
6197 char buf[1024];
6199 if(!(unixname = wine_get_unix_file_name(filename)))
6200 return FALSE;
6202 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6203 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6204 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6206 TRACE("printing with: %s\n", cmdA);
6208 if((file_fd = open(unixname, O_RDONLY)) == -1)
6209 goto end;
6211 if (pipe(fds))
6213 ERR("pipe() failed!\n");
6214 goto end;
6217 if (fork() == 0)
6219 close(0);
6220 dup2(fds[0], 0);
6221 close(fds[1]);
6223 /* reset signals that we previously set to SIG_IGN */
6224 signal(SIGPIPE, SIG_DFL);
6225 signal(SIGCHLD, SIG_DFL);
6227 system(cmdA);
6228 exit(0);
6231 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6232 write(fds[1], buf, no_read);
6234 ret = TRUE;
6236 end:
6237 if(file_fd != -1) close(file_fd);
6238 if(fds[0] != -1) close(fds[0]);
6239 if(fds[1] != -1) close(fds[1]);
6241 HeapFree(GetProcessHeap(), 0, cmdA);
6242 HeapFree(GetProcessHeap(), 0, unixname);
6243 return ret;
6244 #else
6245 return FALSE;
6246 #endif
6249 /*****************************************************************************
6250 * schedule_unixfile
6252 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6254 int in_fd, out_fd, no_read;
6255 char buf[1024];
6256 BOOL ret = FALSE;
6257 char *unixname, *outputA;
6258 DWORD len;
6260 if(!(unixname = wine_get_unix_file_name(filename)))
6261 return FALSE;
6263 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6264 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6265 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6267 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6268 in_fd = open(unixname, O_RDONLY);
6269 if(out_fd == -1 || in_fd == -1)
6270 goto end;
6272 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6273 write(out_fd, buf, no_read);
6275 ret = TRUE;
6276 end:
6277 if(in_fd != -1) close(in_fd);
6278 if(out_fd != -1) close(out_fd);
6279 HeapFree(GetProcessHeap(), 0, outputA);
6280 HeapFree(GetProcessHeap(), 0, unixname);
6281 return ret;
6284 /*****************************************************************************
6285 * ScheduleJob [WINSPOOL.@]
6288 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6290 opened_printer_t *printer;
6291 BOOL ret = FALSE;
6292 struct list *cursor, *cursor2;
6294 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6295 EnterCriticalSection(&printer_handles_cs);
6296 printer = get_opened_printer(hPrinter);
6297 if(!printer)
6298 goto end;
6300 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6302 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6303 HANDLE hf;
6305 if(job->job_id != dwJobID) continue;
6307 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6308 if(hf != INVALID_HANDLE_VALUE)
6310 PRINTER_INFO_5W *pi5;
6311 DWORD needed;
6312 HKEY hkey;
6313 WCHAR output[1024];
6314 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6315 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6317 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6318 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6319 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6320 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6321 debugstr_w(pi5->pPortName));
6323 output[0] = 0;
6325 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6326 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6328 DWORD type, count = sizeof(output);
6329 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6330 RegCloseKey(hkey);
6332 if(output[0] == '|')
6334 schedule_pipe(output + 1, job->filename);
6336 else if(output[0])
6338 schedule_unixfile(output, job->filename);
6340 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6342 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6344 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6346 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6348 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6350 schedule_file(job->filename);
6352 else
6354 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6356 HeapFree(GetProcessHeap(), 0, pi5);
6357 CloseHandle(hf);
6358 DeleteFileW(job->filename);
6360 list_remove(cursor);
6361 HeapFree(GetProcessHeap(), 0, job->document_title);
6362 HeapFree(GetProcessHeap(), 0, job->filename);
6363 HeapFree(GetProcessHeap(), 0, job);
6364 ret = TRUE;
6365 break;
6367 end:
6368 LeaveCriticalSection(&printer_handles_cs);
6369 return ret;
6372 /*****************************************************************************
6373 * StartDocDlgA [WINSPOOL.@]
6375 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6377 UNICODE_STRING usBuffer;
6378 DOCINFOW docW;
6379 LPWSTR retW;
6380 LPSTR ret = NULL;
6382 docW.cbSize = sizeof(docW);
6383 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6384 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6385 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6386 docW.fwType = doc->fwType;
6388 retW = StartDocDlgW(hPrinter, &docW);
6390 if(retW)
6392 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6393 ret = HeapAlloc(GetProcessHeap(), 0, len);
6394 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6395 HeapFree(GetProcessHeap(), 0, retW);
6398 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6399 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6400 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6402 return ret;
6405 /*****************************************************************************
6406 * StartDocDlgW [WINSPOOL.@]
6408 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6409 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6410 * port is "FILE:". Also returns the full path if passed a relative path.
6412 * The caller should free the returned string from the process heap.
6414 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6416 LPWSTR ret = NULL;
6417 DWORD len, attr;
6419 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6421 PRINTER_INFO_5W *pi5;
6422 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6423 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6424 return NULL;
6425 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6426 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6427 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6429 HeapFree(GetProcessHeap(), 0, pi5);
6430 return NULL;
6432 HeapFree(GetProcessHeap(), 0, pi5);
6435 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6437 LPWSTR name;
6438 get_filename(&name);
6439 if(name)
6441 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6443 HeapFree(GetProcessHeap(), 0, name);
6444 return NULL;
6446 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6447 GetFullPathNameW(name, len, ret, NULL);
6448 HeapFree(GetProcessHeap(), 0, name);
6450 return ret;
6453 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6454 return NULL;
6456 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6457 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6459 attr = GetFileAttributesW(ret);
6460 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6462 HeapFree(GetProcessHeap(), 0, ret);
6463 ret = NULL;
6465 return ret;