x11drv: Make UseXVidMode default to yes.
[wine/dibdrv.git] / dlls / winspool / info.c
blob83ae8f74e16ba89fe71e934743bc2cea5700d3f3
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stddef.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <signal.h>
38 #ifdef HAVE_CUPS_CUPS_H
39 # include <cups/cups.h>
40 # ifndef SONAME_LIBCUPS
41 # define SONAME_LIBCUPS "libcups.so"
42 # endif
43 #endif
45 #define NONAMELESSUNION
46 #define NONAMELESSSTRUCT
47 #include "wine/library.h"
48 #include "windef.h"
49 #include "winbase.h"
50 #include "winuser.h"
51 #include "winerror.h"
52 #include "winreg.h"
53 #include "wingdi.h"
54 #include "winspool.h"
55 #include "winternl.h"
56 #include "wine/windef16.h"
57 #include "wine/unicode.h"
58 #include "wine/debug.h"
59 #include "wine/list.h"
60 #include "heap.h"
61 #include "winnls.h"
63 #include "wspool.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
76 typedef struct {
77 DWORD job_id;
78 HANDLE hf;
79 } started_doc_t;
81 typedef struct {
82 struct list jobs;
83 LONG ref;
84 } jobqueue_t;
86 typedef struct {
87 LPWSTR name;
88 jobqueue_t *queue;
89 started_doc_t *doc;
90 } opened_printer_t;
92 typedef struct {
93 struct list entry;
94 DWORD job_id;
95 WCHAR *filename;
96 WCHAR *document_title;
97 } job_t;
100 typedef struct {
101 LPCWSTR envname;
102 LPCWSTR subdir;
103 } printenv_t;
105 /* ############################### */
107 static opened_printer_t **printer_handles;
108 static int nb_printer_handles;
109 static LONG next_job_id = 1;
111 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
112 WORD fwCapability, LPSTR lpszOutput,
113 LPDEVMODEA lpdm );
114 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
115 LPSTR lpszDevice, LPSTR lpszPort,
116 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
117 DWORD fwMode );
119 static const char Printers[] =
120 "System\\CurrentControlSet\\control\\Print\\Printers\\";
122 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
123 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
124 'c','o','n','t','r','o','l','\\',
125 'P','r','i','n','t','\\',
126 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
127 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
129 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
130 'M','i','c','r','o','s','o','f','t','\\',
131 'W','i','n','d','o','w','s',' ','N','T','\\',
132 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
133 'W','i','n','d','o','w','s',0};
135 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
136 'M','i','c','r','o','s','o','f','t','\\',
137 'W','i','n','d','o','w','s',' ','N','T','\\',
138 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
139 'D','e','v','i','c','e','s',0};
141 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
142 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
143 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
144 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
145 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
147 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
149 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
150 'i','o','n',' ','F','i','l','e',0};
151 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
152 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
153 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
154 'M','o','d','e',0};
155 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
156 'i','l','e','s',0};
157 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
158 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
159 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
160 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
161 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
162 static const WCHAR NameW[] = {'N','a','m','e',0};
163 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
164 static const WCHAR PortW[] = {'P','o','r','t',0};
165 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
166 's','s','o','r',0};
167 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
168 'v','e','r',0};
169 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
170 'v','e','r','D','a','t','a',0};
171 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
172 'i','l','e',0};
173 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
174 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
175 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
176 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
177 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
178 static const WCHAR emptyStringW[] = {0};
180 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
182 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
183 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
184 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
186 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
187 'D','o','c','u','m','e','n','t',0};
189 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
190 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
191 DWORD Level, LPBYTE pDriverInfo,
192 DWORD cbBuf, LPDWORD pcbNeeded,
193 BOOL unicode);
194 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
196 /******************************************************************
197 * validate the user-supplied printing-environment [internal]
199 * PARAMS
200 * env [I] PTR to Environment-String or NULL
202 * RETURNS
203 * Failure: NULL
204 * Success: PTR to printenv_t
206 * NOTES
207 * An empty string is handled the same way as NULL.
208 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
212 static const printenv_t * validate_envW(LPCWSTR env)
214 static const printenv_t env_x86 = {envname_x86W, subdir_x86W};
215 static const printenv_t env_win40 = {envname_win40W, subdir_win40W};
216 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
218 const printenv_t *result = NULL;
219 unsigned int i;
221 TRACE("testing %s\n", debugstr_w(env));
222 if (env && env[0])
224 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
226 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
228 result = all_printenv[i];
229 break;
233 if (result == NULL) {
234 FIXME("unsupported Environment: %s\n", debugstr_w(env));
235 SetLastError(ERROR_INVALID_ENVIRONMENT);
237 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
239 else
241 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
243 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
245 return result;
249 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
250 if passed a NULL string. This returns NULLs to the result.
252 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
254 if ( (src) )
256 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
257 return usBufferPtr->Buffer;
259 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
260 return NULL;
263 static LPWSTR strdupW(LPCWSTR p)
265 LPWSTR ret;
266 DWORD len;
268 if(!p) return NULL;
269 len = (strlenW(p) + 1) * sizeof(WCHAR);
270 ret = HeapAlloc(GetProcessHeap(), 0, len);
271 memcpy(ret, p, len);
272 return ret;
275 static void
276 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
277 char qbuf[200];
279 /* If forcing, or no profile string entry for device yet, set the entry
281 * The always change entry if not WINEPS yet is discussable.
283 if (force ||
284 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
285 !strcmp(qbuf,"*") ||
286 !strstr(qbuf,"WINEPS.DRV")
288 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
289 HKEY hkey;
291 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
292 WriteProfileStringA("windows","device",buf);
293 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
294 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
295 RegCloseKey(hkey);
297 HeapFree(GetProcessHeap(),0,buf);
301 #ifdef HAVE_CUPS_CUPS_H
302 static typeof(cupsGetDests) *pcupsGetDests;
303 static typeof(cupsGetPPD) *pcupsGetPPD;
304 static typeof(cupsPrintFile) *pcupsPrintFile;
305 static void *cupshandle;
307 static BOOL CUPS_LoadPrinters(void)
309 int i, nrofdests;
310 BOOL hadprinter = FALSE;
311 cups_dest_t *dests;
312 PRINTER_INFO_2A pinfo2a;
313 char *port,*devline;
314 HKEY hkeyPrinter, hkeyPrinters, hkey;
316 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
317 if (!cupshandle)
318 return FALSE;
319 TRACE("loaded %s\n", SONAME_LIBCUPS);
321 #define DYNCUPS(x) \
322 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
323 if (!p##x) return FALSE;
325 DYNCUPS(cupsGetPPD);
326 DYNCUPS(cupsGetDests);
327 DYNCUPS(cupsPrintFile);
328 #undef DYNCUPS
330 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
331 ERROR_SUCCESS) {
332 ERR("Can't create Printers key\n");
333 return FALSE;
336 nrofdests = pcupsGetDests(&dests);
337 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
338 for (i=0;i<nrofdests;i++) {
339 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
340 sprintf(port,"LPR:%s",dests[i].name);
341 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
342 sprintf(devline,"WINEPS.DRV,%s",port);
343 WriteProfileStringA("devices",dests[i].name,devline);
344 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
345 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
346 RegCloseKey(hkey);
348 HeapFree(GetProcessHeap(),0,devline);
350 TRACE("Printer %d: %s\n", i, dests[i].name);
351 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
352 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
353 and continue */
354 TRACE("Printer already exists\n");
355 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
356 RegCloseKey(hkeyPrinter);
357 } else {
358 memset(&pinfo2a,0,sizeof(pinfo2a));
359 pinfo2a.pPrinterName = dests[i].name;
360 pinfo2a.pDatatype = "RAW";
361 pinfo2a.pPrintProcessor = "WinPrint";
362 pinfo2a.pDriverName = "PS Driver";
363 pinfo2a.pComment = "WINEPS Printer using CUPS";
364 pinfo2a.pLocation = "<physical location of printer>";
365 pinfo2a.pPortName = port;
366 pinfo2a.pParameters = "<parameters?>";
367 pinfo2a.pShareName = "<share name?>";
368 pinfo2a.pSepFile = "<sep file?>";
370 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
371 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
372 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
375 HeapFree(GetProcessHeap(),0,port);
377 hadprinter = TRUE;
378 if (dests[i].is_default)
379 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
381 RegCloseKey(hkeyPrinters);
382 return hadprinter;
384 #endif
386 static BOOL
387 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
388 PRINTER_INFO_2A pinfo2a;
389 char *e,*s,*name,*prettyname,*devname;
390 BOOL ret = FALSE, set_default = FALSE;
391 char *port,*devline,*env_default;
392 HKEY hkeyPrinter, hkeyPrinters, hkey;
394 while (isspace(*pent)) pent++;
395 s = strchr(pent,':');
396 if(s) *s='\0';
397 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
398 strcpy(name,pent);
399 if(s) {
400 *s=':';
401 pent = s;
402 } else
403 pent = "";
405 TRACE("name=%s entry=%s\n",name, pent);
407 if(ispunct(*name)) { /* a tc entry, not a real printer */
408 TRACE("skipping tc entry\n");
409 goto end;
412 if(strstr(pent,":server")) { /* server only version so skip */
413 TRACE("skipping server entry\n");
414 goto end;
417 /* Determine whether this is a postscript printer. */
419 ret = TRUE;
420 env_default = getenv("PRINTER");
421 prettyname = name;
422 /* Get longest name, usually the one at the right for later display. */
423 while((s=strchr(prettyname,'|'))) {
424 *s = '\0';
425 e = s;
426 while(isspace(*--e)) *e = '\0';
427 TRACE("\t%s\n", debugstr_a(prettyname));
428 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
429 for(prettyname = s+1; isspace(*prettyname); prettyname++)
432 e = prettyname + strlen(prettyname);
433 while(isspace(*--e)) *e = '\0';
434 TRACE("\t%s\n", debugstr_a(prettyname));
435 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
437 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
438 * if it is too long, we use it as comment below. */
439 devname = prettyname;
440 if (strlen(devname)>=CCHDEVICENAME-1)
441 devname = name;
442 if (strlen(devname)>=CCHDEVICENAME-1) {
443 ret = FALSE;
444 goto end;
447 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
448 sprintf(port,"LPR:%s",name);
450 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
451 sprintf(devline,"WINEPS.DRV,%s",port);
452 WriteProfileStringA("devices",devname,devline);
453 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
454 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
455 RegCloseKey(hkey);
457 HeapFree(GetProcessHeap(),0,devline);
459 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
460 ERROR_SUCCESS) {
461 ERR("Can't create Printers key\n");
462 ret = FALSE;
463 goto end;
465 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
466 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
467 and continue */
468 TRACE("Printer already exists\n");
469 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
470 RegCloseKey(hkeyPrinter);
471 } else {
472 memset(&pinfo2a,0,sizeof(pinfo2a));
473 pinfo2a.pPrinterName = devname;
474 pinfo2a.pDatatype = "RAW";
475 pinfo2a.pPrintProcessor = "WinPrint";
476 pinfo2a.pDriverName = "PS Driver";
477 pinfo2a.pComment = "WINEPS Printer using LPR";
478 pinfo2a.pLocation = prettyname;
479 pinfo2a.pPortName = port;
480 pinfo2a.pParameters = "<parameters?>";
481 pinfo2a.pShareName = "<share name?>";
482 pinfo2a.pSepFile = "<sep file?>";
484 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
485 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
486 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
489 RegCloseKey(hkeyPrinters);
491 if (isfirst || set_default)
492 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
494 HeapFree(GetProcessHeap(), 0, port);
495 end:
496 HeapFree(GetProcessHeap(), 0, name);
497 return ret;
500 static BOOL
501 PRINTCAP_LoadPrinters(void) {
502 BOOL hadprinter = FALSE;
503 char buf[200];
504 FILE *f;
505 char *pent = NULL;
506 BOOL had_bash = FALSE;
508 f = fopen("/etc/printcap","r");
509 if (!f)
510 return FALSE;
512 while(fgets(buf,sizeof(buf),f)) {
513 char *start, *end;
515 end=strchr(buf,'\n');
516 if (end) *end='\0';
518 start = buf;
519 while(isspace(*start)) start++;
520 if(*start == '#' || *start == '\0')
521 continue;
523 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
524 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
525 HeapFree(GetProcessHeap(),0,pent);
526 pent = NULL;
529 if (end && *--end == '\\') {
530 *end = '\0';
531 had_bash = TRUE;
532 } else
533 had_bash = FALSE;
535 if (pent) {
536 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
537 strcat(pent,start);
538 } else {
539 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
540 strcpy(pent,start);
544 if(pent) {
545 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
546 HeapFree(GetProcessHeap(),0,pent);
548 fclose(f);
549 return hadprinter;
552 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
554 if (value)
555 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
556 lstrlenW(value) * sizeof(WCHAR));
557 else
558 return ERROR_FILE_NOT_FOUND;
561 void WINSPOOL_LoadSystemPrinters(void)
563 HKEY hkey, hkeyPrinters;
564 DRIVER_INFO_3A di3a;
565 HANDLE hprn;
566 DWORD needed, num, i;
567 WCHAR PrinterName[256];
568 BOOL done = FALSE;
570 di3a.cVersion = 0x400;
571 di3a.pName = "PS Driver";
572 di3a.pEnvironment = NULL; /* NULL means auto */
573 di3a.pDriverPath = "wineps16";
574 di3a.pDataFile = "<datafile?>";
575 di3a.pConfigFile = "wineps16";
576 di3a.pHelpFile = "<helpfile?>";
577 di3a.pDependentFiles = "<dependend files?>";
578 di3a.pMonitorName = "<monitor name?>";
579 di3a.pDefaultDataType = "RAW";
581 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
582 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
583 return;
586 /* This ensures that all printer entries have a valid Name value. If causes
587 problems later if they don't. If one is found to be missed we create one
588 and set it equal to the name of the key */
589 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
590 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
591 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
592 for(i = 0; i < num; i++) {
593 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
594 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
595 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
596 set_reg_szW(hkey, NameW, PrinterName);
598 RegCloseKey(hkey);
603 RegCloseKey(hkeyPrinters);
606 /* We want to avoid calling AddPrinter on printers as much as
607 possible, because on cups printers this will (eventually) lead
608 to a call to cupsGetPPD which takes forever, even with non-cups
609 printers AddPrinter takes a while. So we'll tag all printers that
610 were automatically added last time around, if they still exist
611 we'll leave them be otherwise we'll delete them. */
612 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
613 if(needed) {
614 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
615 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
616 for(i = 0; i < num; i++) {
617 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
618 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
619 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
620 DWORD dw = 1;
621 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
622 RegCloseKey(hkey);
624 ClosePrinter(hprn);
629 HeapFree(GetProcessHeap(), 0, pi);
633 #ifdef HAVE_CUPS_CUPS_H
634 done = CUPS_LoadPrinters();
635 #endif
637 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
638 /* Check for [ppd] section in config file before parsing /etc/printcap */
639 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
640 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
641 &hkey) == ERROR_SUCCESS) {
642 RegCloseKey(hkey);
643 PRINTCAP_LoadPrinters();
647 /* Now enumerate the list again and delete any printers that a still tagged */
648 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
649 if(needed) {
650 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
651 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
652 for(i = 0; i < num; i++) {
653 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
654 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
655 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
656 DWORD dw, type, size = sizeof(dw);
657 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
658 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
659 DeletePrinter(hprn);
661 RegCloseKey(hkey);
663 ClosePrinter(hprn);
668 HeapFree(GetProcessHeap(), 0, pi);
671 return;
676 /******************************************************************
677 * get_opened_printer_entry
678 * Get the first place empty in the opened printer table
680 static HANDLE get_opened_printer_entry( LPCWSTR name )
682 UINT_PTR handle = nb_printer_handles, i;
683 jobqueue_t *queue = NULL;
684 opened_printer_t *printer;
686 EnterCriticalSection(&printer_handles_cs);
688 for (i = 0; i < nb_printer_handles; i++)
690 if (!printer_handles[i])
692 if(handle == nb_printer_handles)
693 handle = i;
695 else if(!queue && !strcmpW(name, printer_handles[i]->name))
696 queue = printer_handles[i]->queue;
699 if (handle >= nb_printer_handles)
701 opened_printer_t **new_array;
702 if (printer_handles)
703 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
704 (nb_printer_handles + 16) * sizeof(*new_array) );
705 else
706 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
707 (nb_printer_handles + 16) * sizeof(*new_array) );
709 if (!new_array)
711 handle = 0;
712 goto end;
714 printer_handles = new_array;
715 nb_printer_handles += 16;
718 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
720 handle = 0;
721 goto end;
724 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
725 strcpyW(printer->name, name);
726 if(queue)
727 printer->queue = queue;
728 else
730 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
731 list_init(&printer->queue->jobs);
732 printer->queue->ref = 0;
734 InterlockedIncrement(&printer->queue->ref);
735 printer->doc = NULL;
737 printer_handles[handle] = printer;
738 handle++;
739 end:
740 LeaveCriticalSection(&printer_handles_cs);
742 return (HANDLE)handle;
745 /******************************************************************
746 * get_opened_printer
747 * Get the pointer to the opened printer referred by the handle
749 static opened_printer_t *get_opened_printer(HANDLE hprn)
751 UINT_PTR idx = (UINT_PTR)hprn;
752 opened_printer_t *ret = NULL;
754 EnterCriticalSection(&printer_handles_cs);
756 if ((idx <= 0) || (idx > nb_printer_handles))
757 goto end;
759 ret = printer_handles[idx - 1];
760 end:
761 LeaveCriticalSection(&printer_handles_cs);
762 return ret;
765 /******************************************************************
766 * get_opened_printer_name
767 * Get the pointer to the opened printer name referred by the handle
769 static LPCWSTR get_opened_printer_name(HANDLE hprn)
771 opened_printer_t *printer = get_opened_printer(hprn);
772 if(!printer) return NULL;
773 return printer->name;
776 /******************************************************************
777 * WINSPOOL_GetOpenedPrinterRegKey
780 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
782 LPCWSTR name = get_opened_printer_name(hPrinter);
783 DWORD ret;
784 HKEY hkeyPrinters;
786 if(!name) return ERROR_INVALID_HANDLE;
788 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
789 ERROR_SUCCESS)
790 return ret;
792 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
794 ERR("Can't find opened printer %s in registry\n",
795 debugstr_w(name));
796 RegCloseKey(hkeyPrinters);
797 return ERROR_INVALID_PRINTER_NAME; /* ? */
799 RegCloseKey(hkeyPrinters);
800 return ERROR_SUCCESS;
803 /******************************************************************
804 * get_job
806 * Get the pointer to the specified job.
807 * Should hold the printer_handles_cs before calling.
809 static job_t *get_job(HANDLE hprn, DWORD JobId)
811 opened_printer_t *printer = get_opened_printer(hprn);
812 job_t *job;
814 if(!printer) return NULL;
815 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
817 if(job->job_id == JobId)
818 return job;
820 return NULL;
823 /***********************************************************
824 * DEVMODEcpyAtoW
826 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
828 BOOL Formname;
829 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
830 DWORD size;
832 Formname = (dmA->dmSize > off_formname);
833 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
834 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
835 dmW->dmDeviceName, CCHDEVICENAME);
836 if(!Formname) {
837 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
838 dmA->dmSize - CCHDEVICENAME);
839 } else {
840 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
841 off_formname - CCHDEVICENAME);
842 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
843 dmW->dmFormName, CCHFORMNAME);
844 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
845 (off_formname + CCHFORMNAME));
847 dmW->dmSize = size;
848 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
849 dmA->dmDriverExtra);
850 return dmW;
853 /***********************************************************
854 * DEVMODEdupWtoA
855 * Creates an ascii copy of supplied devmode on heap
857 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
859 LPDEVMODEA dmA;
860 DWORD size;
861 BOOL Formname;
862 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
864 if(!dmW) return NULL;
865 Formname = (dmW->dmSize > off_formname);
866 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
867 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
868 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
869 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
870 if(!Formname) {
871 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
872 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
873 } else {
874 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
875 off_formname - CCHDEVICENAME * sizeof(WCHAR));
876 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
877 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
878 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
879 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
881 dmA->dmSize = size;
882 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
883 dmW->dmDriverExtra);
884 return dmA;
887 /***********************************************************
888 * PRINTER_INFO_2AtoW
889 * Creates a unicode copy of PRINTER_INFO_2A on heap
891 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
893 LPPRINTER_INFO_2W piW;
894 UNICODE_STRING usBuffer;
896 if(!piA) return NULL;
897 piW = HeapAlloc(heap, 0, sizeof(*piW));
898 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
900 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
901 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
902 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
903 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
904 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
905 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
906 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
907 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
908 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
909 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
910 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
911 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
912 return piW;
915 /***********************************************************
916 * FREE_PRINTER_INFO_2W
917 * Free PRINTER_INFO_2W and all strings
919 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
921 if(!piW) return;
923 HeapFree(heap,0,piW->pServerName);
924 HeapFree(heap,0,piW->pPrinterName);
925 HeapFree(heap,0,piW->pShareName);
926 HeapFree(heap,0,piW->pPortName);
927 HeapFree(heap,0,piW->pDriverName);
928 HeapFree(heap,0,piW->pComment);
929 HeapFree(heap,0,piW->pLocation);
930 HeapFree(heap,0,piW->pDevMode);
931 HeapFree(heap,0,piW->pSepFile);
932 HeapFree(heap,0,piW->pPrintProcessor);
933 HeapFree(heap,0,piW->pDatatype);
934 HeapFree(heap,0,piW->pParameters);
935 HeapFree(heap,0,piW);
936 return;
939 /******************************************************************
940 * DeviceCapabilities [WINSPOOL.@]
941 * DeviceCapabilitiesA [WINSPOOL.@]
944 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
945 LPSTR pOutput, LPDEVMODEA lpdm)
947 INT ret;
949 if (!GDI_CallDeviceCapabilities16)
951 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
952 (LPCSTR)104 );
953 if (!GDI_CallDeviceCapabilities16) return -1;
955 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
957 /* If DC_PAPERSIZE map POINT16s to POINTs */
958 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
959 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
960 POINT *pt = (POINT *)pOutput;
961 INT i;
962 memcpy(tmp, pOutput, ret * sizeof(POINT16));
963 for(i = 0; i < ret; i++, pt++)
965 pt->x = tmp[i].x;
966 pt->y = tmp[i].y;
968 HeapFree( GetProcessHeap(), 0, tmp );
970 return ret;
974 /*****************************************************************************
975 * DeviceCapabilitiesW [WINSPOOL.@]
977 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
980 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
981 WORD fwCapability, LPWSTR pOutput,
982 const DEVMODEW *pDevMode)
984 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
985 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
986 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
987 INT ret;
989 if(pOutput && (fwCapability == DC_BINNAMES ||
990 fwCapability == DC_FILEDEPENDENCIES ||
991 fwCapability == DC_PAPERNAMES)) {
992 /* These need A -> W translation */
993 INT size = 0, i;
994 LPSTR pOutputA;
995 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
996 dmA);
997 if(ret == -1)
998 return ret;
999 switch(fwCapability) {
1000 case DC_BINNAMES:
1001 size = 24;
1002 break;
1003 case DC_PAPERNAMES:
1004 case DC_FILEDEPENDENCIES:
1005 size = 64;
1006 break;
1008 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1009 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1010 dmA);
1011 for(i = 0; i < ret; i++)
1012 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1013 pOutput + (i * size), size);
1014 HeapFree(GetProcessHeap(), 0, pOutputA);
1015 } else {
1016 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1017 (LPSTR)pOutput, dmA);
1019 HeapFree(GetProcessHeap(),0,pPortA);
1020 HeapFree(GetProcessHeap(),0,pDeviceA);
1021 HeapFree(GetProcessHeap(),0,dmA);
1022 return ret;
1025 /******************************************************************
1026 * DocumentPropertiesA [WINSPOOL.@]
1028 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1030 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1031 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1032 LPDEVMODEA pDevModeInput,DWORD fMode )
1034 LPSTR lpName = pDeviceName;
1035 LONG ret;
1037 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1038 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1041 if(!pDeviceName) {
1042 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1043 if(!lpNameW) {
1044 ERR("no name from hPrinter?\n");
1045 SetLastError(ERROR_INVALID_HANDLE);
1046 return -1;
1048 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1051 if (!GDI_CallExtDeviceMode16)
1053 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1054 (LPCSTR)102 );
1055 if (!GDI_CallExtDeviceMode16) {
1056 ERR("No CallExtDeviceMode16?\n");
1057 return -1;
1060 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1061 pDevModeInput, NULL, fMode);
1063 if(!pDeviceName)
1064 HeapFree(GetProcessHeap(),0,lpName);
1065 return ret;
1069 /*****************************************************************************
1070 * DocumentPropertiesW (WINSPOOL.@)
1072 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1074 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1075 LPWSTR pDeviceName,
1076 LPDEVMODEW pDevModeOutput,
1077 LPDEVMODEW pDevModeInput, DWORD fMode)
1080 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1081 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1082 LPDEVMODEA pDevModeOutputA = NULL;
1083 LONG ret;
1085 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1086 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1087 fMode);
1088 if(pDevModeOutput) {
1089 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1090 if(ret < 0) return ret;
1091 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1093 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1094 pDevModeInputA, fMode);
1095 if(pDevModeOutput) {
1096 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1097 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1099 if(fMode == 0 && ret > 0)
1100 ret += (CCHDEVICENAME + CCHFORMNAME);
1101 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1102 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1103 return ret;
1106 /******************************************************************
1107 * OpenPrinterA [WINSPOOL.@]
1109 * See OpenPrinterW.
1112 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1113 LPPRINTER_DEFAULTSA pDefault)
1115 UNICODE_STRING lpPrinterNameW;
1116 UNICODE_STRING usBuffer;
1117 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1118 PWSTR pwstrPrinterNameW;
1119 BOOL ret;
1121 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1123 if(pDefault) {
1124 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1125 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1126 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1127 pDefaultW = &DefaultW;
1129 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1130 if(pDefault) {
1131 RtlFreeUnicodeString(&usBuffer);
1132 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1134 RtlFreeUnicodeString(&lpPrinterNameW);
1135 return ret;
1138 /******************************************************************
1139 * OpenPrinterW [WINSPOOL.@]
1141 * Open a Printer / Printserver or a Printer-Object
1143 * PARAMS
1144 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1145 * phPrinter [O] The resulting Handle is stored here
1146 * pDefault [I] PTR to Default Printer Settings or NULL
1148 * RETURNS
1149 * Success: TRUE
1150 * Failure: FALSE
1152 * NOTES
1153 * lpPrinterName is one of:
1154 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1155 *| Printer: "PrinterName"
1156 *| Printer-Object: "PrinterName,Job xxx"
1157 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1158 *| XcvPort: "Servername,XcvPort PortName"
1160 * BUGS
1161 *| Printserver not supported
1162 *| Printer-Object not supported
1163 *| XcvMonitor not supported
1164 *| XcvPort not supported
1165 *| pDefaults not supported
1168 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
1169 LPPRINTER_DEFAULTSW pDefault)
1171 HKEY hkeyPrinters, hkeyPrinter;
1173 if (!lpPrinterName) {
1174 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1175 SetLastError(ERROR_INVALID_PARAMETER);
1176 return FALSE;
1179 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1180 pDefault);
1182 /* Check Printer exists */
1183 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1184 ERROR_SUCCESS) {
1185 ERR("Can't create Printers key\n");
1186 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1187 return FALSE;
1190 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1191 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1192 != ERROR_SUCCESS) {
1193 TRACE("Can't find printer %s in registry\n",
1194 debugstr_w(lpPrinterName));
1195 RegCloseKey(hkeyPrinters);
1196 SetLastError(ERROR_INVALID_PRINTER_NAME);
1197 return FALSE;
1199 RegCloseKey(hkeyPrinter);
1200 RegCloseKey(hkeyPrinters);
1202 if(!phPrinter) /* This seems to be what win95 does anyway */
1203 return TRUE;
1205 /* Get the unique handle of the printer*/
1206 *phPrinter = get_opened_printer_entry( lpPrinterName );
1208 if (pDefault != NULL)
1209 FIXME("Not handling pDefault\n");
1211 return TRUE;
1214 /******************************************************************
1215 * AddMonitorA [WINSPOOL.@]
1217 * See AddMonitorW.
1220 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1222 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
1223 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1224 return FALSE;
1227 /******************************************************************************
1228 * AddMonitorW [WINSPOOL.@]
1230 * Install a Printmonitor
1232 * PARAMS
1233 * pName [I] Servername or NULL (local Computer)
1234 * Level [I] Structure-Level (Must be 2)
1235 * pMonitors [I] PTR to MONITOR_INFO_2
1237 * RETURNS
1238 * Success: TRUE
1239 * Failure: FALSE
1241 * NOTES
1242 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1244 * BUGS
1245 * only a Stub
1248 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1250 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1251 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1252 return FALSE;
1255 /******************************************************************
1256 * DeletePrinterDriverA [WINSPOOL.@]
1259 BOOL WINAPI
1260 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1262 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1263 debugstr_a(pDriverName));
1264 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1265 return FALSE;
1268 /******************************************************************
1269 * DeletePrinterDriverW [WINSPOOL.@]
1272 BOOL WINAPI
1273 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1275 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1276 debugstr_w(pDriverName));
1277 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1278 return FALSE;
1281 /******************************************************************
1282 * DeleteMonitorA [WINSPOOL.@]
1284 * See DeleteMonitorW.
1287 BOOL WINAPI
1288 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1290 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1291 debugstr_a(pMonitorName));
1292 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1293 return FALSE;
1296 /******************************************************************
1297 * DeleteMonitorW [WINSPOOL.@]
1299 * Delete a specific Printmonitor from a Printing-Environment
1301 * PARAMS
1302 * pName [I] Servername or NULL (local Computer)
1303 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1304 * pMonitorName [I] Name of the Monitor, that should be deleted
1306 * RETURNS
1307 * Success: TRUE
1308 * Failure: FALSE
1310 * BUGS
1311 * only a Stub
1314 BOOL WINAPI
1315 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1317 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1318 debugstr_w(pMonitorName));
1319 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1320 return FALSE;
1323 /******************************************************************
1324 * DeletePortA [WINSPOOL.@]
1326 * See DeletePortW.
1329 BOOL WINAPI
1330 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1332 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1333 debugstr_a(pPortName));
1334 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1335 return FALSE;
1338 /******************************************************************
1339 * DeletePortW [WINSPOOL.@]
1341 * Delete a specific Port
1343 * PARAMS
1344 * pName [I] Servername or NULL (local Computer)
1345 * hWnd [I] Handle to parent Window for the Dialog-Box
1346 * pPortName [I] Name of the Port, that should be deleted
1348 * RETURNS
1349 * Success: TRUE
1350 * Failure: FALSE
1352 * BUGS
1353 * only a Stub
1356 BOOL WINAPI
1357 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1359 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1360 debugstr_w(pPortName));
1361 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1362 return FALSE;
1365 /******************************************************************************
1366 * SetPrinterW [WINSPOOL.@]
1368 BOOL WINAPI
1369 SetPrinterW(
1370 HANDLE hPrinter,
1371 DWORD Level,
1372 LPBYTE pPrinter,
1373 DWORD Command) {
1375 FIXME("():stub\n");
1376 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1377 return FALSE;
1380 /******************************************************************************
1381 * WritePrinter [WINSPOOL.@]
1383 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1385 opened_printer_t *printer;
1386 BOOL ret = FALSE;
1388 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1390 EnterCriticalSection(&printer_handles_cs);
1391 printer = get_opened_printer(hPrinter);
1392 if(!printer)
1394 SetLastError(ERROR_INVALID_HANDLE);
1395 goto end;
1398 if(!printer->doc)
1400 SetLastError(ERROR_SPL_NO_STARTDOC);
1401 goto end;
1404 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1405 end:
1406 LeaveCriticalSection(&printer_handles_cs);
1407 return ret;
1410 /*****************************************************************************
1411 * AddFormA [WINSPOOL.@]
1413 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1415 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1416 return 1;
1419 /*****************************************************************************
1420 * AddFormW [WINSPOOL.@]
1422 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1424 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1425 return 1;
1428 /*****************************************************************************
1429 * AddJobA [WINSPOOL.@]
1431 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1433 BOOL ret;
1434 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1435 DWORD needed;
1437 if(Level != 1) {
1438 SetLastError(ERROR_INVALID_LEVEL);
1439 return FALSE;
1442 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1444 if(ret) {
1445 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1446 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1447 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1448 if(*pcbNeeded > cbBuf) {
1449 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1450 ret = FALSE;
1451 } else {
1452 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1453 addjobA->JobId = addjobW->JobId;
1454 addjobA->Path = (char *)(addjobA + 1);
1455 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1458 return ret;
1461 /*****************************************************************************
1462 * AddJobW [WINSPOOL.@]
1464 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1466 opened_printer_t *printer;
1467 job_t *job;
1468 BOOL ret = FALSE;
1469 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1470 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1471 WCHAR path[MAX_PATH], filename[MAX_PATH];
1472 DWORD len;
1473 ADDJOB_INFO_1W *addjob;
1475 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1477 EnterCriticalSection(&printer_handles_cs);
1479 printer = get_opened_printer(hPrinter);
1481 if(!printer) {
1482 SetLastError(ERROR_INVALID_HANDLE);
1483 goto end;
1486 if(Level != 1) {
1487 SetLastError(ERROR_INVALID_LEVEL);
1488 goto end;
1491 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1492 if(!job)
1493 goto end;
1495 job->job_id = InterlockedIncrement(&next_job_id);
1497 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1498 if(path[len - 1] != '\\')
1499 path[len++] = '\\';
1500 memcpy(path + len, spool_path, sizeof(spool_path));
1501 sprintfW(filename, fmtW, path, job->job_id);
1503 len = strlenW(filename);
1504 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1505 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1506 job->document_title = strdupW(default_doc_title);
1507 list_add_tail(&printer->queue->jobs, &job->entry);
1509 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1510 if(*pcbNeeded <= cbBuf) {
1511 addjob = (ADDJOB_INFO_1W*)pData;
1512 addjob->JobId = job->job_id;
1513 addjob->Path = (WCHAR *)(addjob + 1);
1514 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1515 ret = TRUE;
1516 } else
1517 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1519 end:
1520 LeaveCriticalSection(&printer_handles_cs);
1521 return ret;
1524 /*****************************************************************************
1525 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1527 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1528 DWORD level, LPBYTE Info,
1529 DWORD cbBuf, LPDWORD needed)
1531 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1532 level, Info, cbBuf);
1533 return 0;
1536 /*****************************************************************************
1537 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1539 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1540 DWORD level, LPBYTE Info,
1541 DWORD cbBuf, LPDWORD needed)
1543 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1544 level, Info, cbBuf);
1545 return 0;
1548 /*****************************************************************************
1549 * WINSPOOL_OpenDriverReg [internal]
1551 * opens the registry for the printer drivers depending on the given input
1552 * variable pEnvironment
1554 * RETURNS:
1555 * the opened hkey on success
1556 * NULL on error
1558 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1560 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1561 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1562 HKEY retval;
1563 LPWSTR lpKey, buffer = NULL;
1564 LPCWSTR pEnvW;
1566 TRACE("%s\n",
1567 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1569 if(pEnvironment) {
1570 if (unicode) {
1571 pEnvW = pEnvironment;
1572 } else {
1573 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1574 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1575 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1576 pEnvW = buffer;
1578 } else {
1579 OSVERSIONINFOW ver;
1580 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1582 if(!GetVersionExW( &ver))
1583 return 0;
1585 switch (ver.dwPlatformId) {
1586 case VER_PLATFORM_WIN32s:
1587 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1588 return 0;
1589 case VER_PLATFORM_WIN32_NT:
1590 pEnvW = WinNTW;
1591 break;
1592 default:
1593 pEnvW = Win40W;
1594 break;
1596 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1599 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1600 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1601 wsprintfW( lpKey, DriversW, pEnvW);
1603 TRACE("%s\n", debugstr_w(lpKey));
1605 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1606 retval = 0;
1608 HeapFree( GetProcessHeap(), 0, buffer);
1609 HeapFree( GetProcessHeap(), 0, lpKey);
1611 return retval;
1614 /*****************************************************************************
1615 * AddPrinterW [WINSPOOL.@]
1617 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1619 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1620 LPDEVMODEA dmA;
1621 LPDEVMODEW dmW;
1622 HANDLE retval;
1623 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1624 LONG size;
1626 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1628 if(pName != NULL) {
1629 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1630 SetLastError(ERROR_INVALID_PARAMETER);
1631 return 0;
1633 if(Level != 2) {
1634 ERR("Level = %ld, unsupported!\n", Level);
1635 SetLastError(ERROR_INVALID_LEVEL);
1636 return 0;
1638 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1639 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1640 debugstr_w(pi->pPrinterName)
1642 SetLastError(ERROR_INVALID_LEVEL);
1643 return 0;
1645 if(!pPrinter) {
1646 SetLastError(ERROR_INVALID_PARAMETER);
1647 return 0;
1649 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1650 ERROR_SUCCESS) {
1651 ERR("Can't create Printers key\n");
1652 return 0;
1654 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1655 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1656 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1657 RegCloseKey(hkeyPrinter);
1658 RegCloseKey(hkeyPrinters);
1659 return 0;
1661 RegCloseKey(hkeyPrinter);
1663 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1664 if(!hkeyDrivers) {
1665 ERR("Can't create Drivers key\n");
1666 RegCloseKey(hkeyPrinters);
1667 return 0;
1669 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1670 ERROR_SUCCESS) {
1671 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1672 RegCloseKey(hkeyPrinters);
1673 RegCloseKey(hkeyDrivers);
1674 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1675 return 0;
1677 RegCloseKey(hkeyDriver);
1678 RegCloseKey(hkeyDrivers);
1680 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1681 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1682 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1683 RegCloseKey(hkeyPrinters);
1684 return 0;
1687 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1688 ERROR_SUCCESS) {
1689 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1690 SetLastError(ERROR_INVALID_PRINTER_NAME);
1691 RegCloseKey(hkeyPrinters);
1692 return 0;
1694 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1695 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1696 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1698 /* See if we can load the driver. We may need the devmode structure anyway
1700 * FIXME:
1701 * Note that DocumentPropertiesW will briefly try to open the printer we
1702 * just create to find a DEVMODEA struct (it will use the WINEPS default
1703 * one in case it is not there, so we are ok).
1705 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1707 if(size < 0) {
1708 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1709 size = sizeof(DEVMODEW);
1711 if(pi->pDevMode)
1712 dmW = pi->pDevMode;
1713 else
1715 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1716 ZeroMemory(dmW,size);
1717 dmW->dmSize = size;
1718 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1720 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1721 HeapFree(GetProcessHeap(),0,dmW);
1722 dmW=NULL;
1724 else
1726 /* set devmode to printer name */
1727 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1731 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1732 and we support these drivers. NT writes DEVMODEW so somehow
1733 we'll need to distinguish between these when we support NT
1734 drivers */
1735 if (dmW)
1737 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1738 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1739 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1740 HeapFree(GetProcessHeap(), 0, dmA);
1741 if(!pi->pDevMode)
1742 HeapFree(GetProcessHeap(), 0, dmW);
1744 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1745 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1746 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1747 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1749 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1750 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1751 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1752 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1753 (LPBYTE)&pi->Priority, sizeof(DWORD));
1754 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1755 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1756 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1757 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1758 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1759 (LPBYTE)&pi->Status, sizeof(DWORD));
1760 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1761 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1763 RegCloseKey(hkeyPrinter);
1764 RegCloseKey(hkeyPrinters);
1765 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1766 ERR("OpenPrinter failing\n");
1767 return 0;
1769 return retval;
1772 /*****************************************************************************
1773 * AddPrinterA [WINSPOOL.@]
1775 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1777 UNICODE_STRING pNameW;
1778 PWSTR pwstrNameW;
1779 PRINTER_INFO_2W *piW;
1780 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1781 HANDLE ret;
1783 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1784 if(Level != 2) {
1785 ERR("Level = %ld, unsupported!\n", Level);
1786 SetLastError(ERROR_INVALID_LEVEL);
1787 return 0;
1789 pwstrNameW = asciitounicode(&pNameW,pName);
1790 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1792 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1794 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1795 RtlFreeUnicodeString(&pNameW);
1796 return ret;
1800 /*****************************************************************************
1801 * ClosePrinter [WINSPOOL.@]
1803 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1805 UINT_PTR i = (UINT_PTR)hPrinter;
1806 opened_printer_t *printer = NULL;
1807 BOOL ret = FALSE;
1809 TRACE("Handle %p\n", hPrinter);
1811 EnterCriticalSection(&printer_handles_cs);
1813 if ((i > 0) && (i <= nb_printer_handles))
1814 printer = printer_handles[i - 1];
1816 if(printer)
1818 struct list *cursor, *cursor2;
1820 if(printer->doc)
1821 EndDocPrinter(hPrinter);
1823 if(InterlockedDecrement(&printer->queue->ref) == 0)
1825 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
1827 job_t *job = LIST_ENTRY(cursor, job_t, entry);
1828 ScheduleJob(hPrinter, job->job_id);
1830 HeapFree(GetProcessHeap(), 0, printer->queue);
1832 HeapFree(GetProcessHeap(), 0, printer->name);
1833 HeapFree(GetProcessHeap(), 0, printer);
1834 printer_handles[i - 1] = NULL;
1835 ret = TRUE;
1837 LeaveCriticalSection(&printer_handles_cs);
1838 return ret;
1841 /*****************************************************************************
1842 * DeleteFormA [WINSPOOL.@]
1844 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1846 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1847 return 1;
1850 /*****************************************************************************
1851 * DeleteFormW [WINSPOOL.@]
1853 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1855 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1856 return 1;
1859 /*****************************************************************************
1860 * WINSPOOL_SHRegDeleteKey
1862 * Recursively delete subkeys.
1863 * Cut & paste from shlwapi.
1866 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1868 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1869 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1870 HKEY hSubKey = 0;
1872 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1873 if(!dwRet)
1875 /* Find how many subkeys there are */
1876 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1877 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1878 if(!dwRet)
1880 dwMaxSubkeyLen++;
1881 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1882 /* Name too big: alloc a buffer for it */
1883 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1885 if(!lpszName)
1886 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1887 else
1889 /* Recursively delete all the subkeys */
1890 for(i = 0; i < dwKeyCount && !dwRet; i++)
1892 dwSize = dwMaxSubkeyLen;
1893 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1894 if(!dwRet)
1895 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1898 if (lpszName != szNameBuf)
1899 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1903 RegCloseKey(hSubKey);
1904 if(!dwRet)
1905 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1907 return dwRet;
1910 /*****************************************************************************
1911 * DeletePrinter [WINSPOOL.@]
1913 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1915 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1916 HKEY hkeyPrinters, hkey;
1918 if(!lpNameW) {
1919 SetLastError(ERROR_INVALID_HANDLE);
1920 return FALSE;
1922 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1923 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1924 RegCloseKey(hkeyPrinters);
1926 WriteProfileStringW(devicesW, lpNameW, NULL);
1927 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1928 RegDeleteValueW(hkey, lpNameW);
1929 RegCloseKey(hkey);
1931 return TRUE;
1934 /*****************************************************************************
1935 * SetPrinterA [WINSPOOL.@]
1937 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1938 DWORD Command)
1940 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1941 return FALSE;
1944 /*****************************************************************************
1945 * SetJobA [WINSPOOL.@]
1947 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1948 LPBYTE pJob, DWORD Command)
1950 BOOL ret;
1951 LPBYTE JobW;
1952 UNICODE_STRING usBuffer;
1954 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
1956 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1957 are all ignored by SetJob, so we don't bother copying them */
1958 switch(Level)
1960 case 0:
1961 JobW = NULL;
1962 break;
1963 case 1:
1965 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
1966 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
1968 JobW = (LPBYTE)info1W;
1969 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
1970 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
1971 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
1972 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
1973 info1W->Status = info1A->Status;
1974 info1W->Priority = info1A->Priority;
1975 info1W->Position = info1A->Position;
1976 info1W->PagesPrinted = info1A->PagesPrinted;
1977 break;
1979 case 2:
1981 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
1982 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
1984 JobW = (LPBYTE)info2W;
1985 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
1986 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
1987 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
1988 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
1989 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
1990 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
1991 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
1992 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
1993 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
1994 info2W->Status = info2A->Status;
1995 info2W->Priority = info2A->Priority;
1996 info2W->Position = info2A->Position;
1997 info2W->StartTime = info2A->StartTime;
1998 info2W->UntilTime = info2A->UntilTime;
1999 info2W->PagesPrinted = info2A->PagesPrinted;
2000 break;
2002 case 3:
2003 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2004 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2005 break;
2006 default:
2007 SetLastError(ERROR_INVALID_LEVEL);
2008 return FALSE;
2011 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2013 switch(Level)
2015 case 1:
2017 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2018 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2019 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2020 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2021 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2022 break;
2024 case 2:
2026 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2027 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2028 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2029 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2030 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2031 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2032 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2033 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2034 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2035 break;
2038 HeapFree(GetProcessHeap(), 0, JobW);
2040 return ret;
2043 /*****************************************************************************
2044 * SetJobW [WINSPOOL.@]
2046 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2047 LPBYTE pJob, DWORD Command)
2049 BOOL ret = FALSE;
2050 job_t *job;
2052 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2053 FIXME("Ignoring everything other than document title\n");
2055 EnterCriticalSection(&printer_handles_cs);
2056 job = get_job(hPrinter, JobId);
2057 if(!job)
2058 goto end;
2060 switch(Level)
2062 case 0:
2063 break;
2064 case 1:
2066 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2067 HeapFree(GetProcessHeap(), 0, job->document_title);
2068 job->document_title = strdupW(info1->pDocument);
2069 break;
2071 case 2:
2073 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2074 HeapFree(GetProcessHeap(), 0, job->document_title);
2075 job->document_title = strdupW(info2->pDocument);
2076 break;
2078 case 3:
2079 break;
2080 default:
2081 SetLastError(ERROR_INVALID_LEVEL);
2082 goto end;
2084 ret = TRUE;
2085 end:
2086 LeaveCriticalSection(&printer_handles_cs);
2087 return ret;
2090 /*****************************************************************************
2091 * EndDocPrinter [WINSPOOL.@]
2093 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2095 opened_printer_t *printer;
2096 BOOL ret = FALSE;
2097 TRACE("(%p)\n", hPrinter);
2099 EnterCriticalSection(&printer_handles_cs);
2101 printer = get_opened_printer(hPrinter);
2102 if(!printer)
2104 SetLastError(ERROR_INVALID_HANDLE);
2105 goto end;
2108 if(!printer->doc)
2110 SetLastError(ERROR_SPL_NO_STARTDOC);
2111 goto end;
2114 CloseHandle(printer->doc->hf);
2115 ScheduleJob(hPrinter, printer->doc->job_id);
2116 HeapFree(GetProcessHeap(), 0, printer->doc);
2117 printer->doc = NULL;
2118 ret = TRUE;
2119 end:
2120 LeaveCriticalSection(&printer_handles_cs);
2121 return ret;
2124 /*****************************************************************************
2125 * EndPagePrinter [WINSPOOL.@]
2127 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2129 FIXME("(%p): stub\n", hPrinter);
2130 return TRUE;
2133 /*****************************************************************************
2134 * StartDocPrinterA [WINSPOOL.@]
2136 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2138 UNICODE_STRING usBuffer;
2139 DOC_INFO_2W doc2W;
2140 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2141 DWORD ret;
2143 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2144 or one (DOC_INFO_3) extra DWORDs */
2146 switch(Level) {
2147 case 2:
2148 doc2W.JobId = doc2->JobId;
2149 /* fall through */
2150 case 3:
2151 doc2W.dwMode = doc2->dwMode;
2152 /* fall through */
2153 case 1:
2154 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2155 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2156 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2157 break;
2159 default:
2160 SetLastError(ERROR_INVALID_LEVEL);
2161 return FALSE;
2164 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2166 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2167 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2168 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2170 return ret;
2173 /*****************************************************************************
2174 * StartDocPrinterW [WINSPOOL.@]
2176 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2178 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2179 opened_printer_t *printer;
2180 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2181 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2182 JOB_INFO_1W job_info;
2183 DWORD needed, ret = 0;
2184 HANDLE hf;
2185 WCHAR *filename;
2187 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2188 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2189 debugstr_w(doc->pDatatype));
2191 if(Level < 1 || Level > 3)
2193 SetLastError(ERROR_INVALID_LEVEL);
2194 return 0;
2197 EnterCriticalSection(&printer_handles_cs);
2198 printer = get_opened_printer(hPrinter);
2199 if(!printer)
2201 SetLastError(ERROR_INVALID_HANDLE);
2202 goto end;
2205 if(printer->doc)
2207 SetLastError(ERROR_INVALID_PRINTER_STATE);
2208 goto end;
2211 /* Even if we're printing to a file we still add a print job, we'll
2212 just ignore the spool file name */
2214 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2216 ERR("AddJob failed gle %08lx\n", GetLastError());
2217 goto end;
2220 if(doc->pOutputFile)
2221 filename = doc->pOutputFile;
2222 else
2223 filename = addjob->Path;
2225 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2226 if(hf == INVALID_HANDLE_VALUE)
2227 goto end;
2229 memset(&job_info, 0, sizeof(job_info));
2230 job_info.pDocument = doc->pDocName;
2231 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2233 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2234 printer->doc->hf = hf;
2235 ret = printer->doc->job_id = addjob->JobId;
2236 end:
2237 LeaveCriticalSection(&printer_handles_cs);
2239 return ret;
2242 /*****************************************************************************
2243 * StartPagePrinter [WINSPOOL.@]
2245 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2247 FIXME("(%p): stub\n", hPrinter);
2248 return TRUE;
2251 /*****************************************************************************
2252 * GetFormA [WINSPOOL.@]
2254 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2255 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2257 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2258 Level,pForm,cbBuf,pcbNeeded);
2259 return FALSE;
2262 /*****************************************************************************
2263 * GetFormW [WINSPOOL.@]
2265 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2266 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2268 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2269 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2270 return FALSE;
2273 /*****************************************************************************
2274 * SetFormA [WINSPOOL.@]
2276 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2277 LPBYTE pForm)
2279 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2280 return FALSE;
2283 /*****************************************************************************
2284 * SetFormW [WINSPOOL.@]
2286 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2287 LPBYTE pForm)
2289 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2290 return FALSE;
2293 /*****************************************************************************
2294 * ReadPrinter [WINSPOOL.@]
2296 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2297 LPDWORD pNoBytesRead)
2299 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2300 return FALSE;
2303 /*****************************************************************************
2304 * ResetPrinterA [WINSPOOL.@]
2306 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2308 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2309 return FALSE;
2312 /*****************************************************************************
2313 * ResetPrinterW [WINSPOOL.@]
2315 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2317 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2318 return FALSE;
2321 /*****************************************************************************
2322 * WINSPOOL_GetDWORDFromReg
2324 * Return DWORD associated with ValueName from hkey.
2326 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2328 DWORD sz = sizeof(DWORD), type, value = 0;
2329 LONG ret;
2331 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2333 if(ret != ERROR_SUCCESS) {
2334 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2335 return 0;
2337 if(type != REG_DWORD) {
2338 ERR("Got type %ld\n", type);
2339 return 0;
2341 return value;
2344 /*****************************************************************************
2345 * WINSPOOL_GetStringFromReg
2347 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2348 * String is stored either as unicode or ascii.
2349 * Bit of a hack here to get the ValueName if we want ascii.
2351 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2352 DWORD buflen, DWORD *needed,
2353 BOOL unicode)
2355 DWORD sz = buflen, type;
2356 LONG ret;
2358 if(unicode)
2359 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2360 else {
2361 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2362 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2363 HeapFree(GetProcessHeap(),0,ValueNameA);
2365 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2366 WARN("Got ret = %ld\n", ret);
2367 *needed = 0;
2368 return FALSE;
2370 *needed = sz;
2371 return TRUE;
2374 /*****************************************************************************
2375 * WINSPOOL_GetDefaultDevMode
2377 * Get a default DevMode values for wineps.
2378 * FIXME - use ppd.
2381 static void WINSPOOL_GetDefaultDevMode(
2382 LPBYTE ptr,
2383 DWORD buflen, DWORD *needed,
2384 BOOL unicode)
2386 DEVMODEA dm;
2387 static const char szwps[] = "wineps.drv";
2389 /* fill default DEVMODE - should be read from ppd... */
2390 ZeroMemory( &dm, sizeof(dm) );
2391 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2392 dm.dmSpecVersion = DM_SPECVERSION;
2393 dm.dmDriverVersion = 1;
2394 dm.dmSize = sizeof(DEVMODEA);
2395 dm.dmDriverExtra = 0;
2396 dm.dmFields =
2397 DM_ORIENTATION | DM_PAPERSIZE |
2398 DM_PAPERLENGTH | DM_PAPERWIDTH |
2399 DM_SCALE |
2400 DM_COPIES |
2401 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2402 DM_YRESOLUTION | DM_TTOPTION;
2404 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2405 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2406 dm.u1.s1.dmPaperLength = 2970;
2407 dm.u1.s1.dmPaperWidth = 2100;
2409 dm.dmScale = 100;
2410 dm.dmCopies = 1;
2411 dm.dmDefaultSource = DMBIN_AUTO;
2412 dm.dmPrintQuality = DMRES_MEDIUM;
2413 /* dm.dmColor */
2414 /* dm.dmDuplex */
2415 dm.dmYResolution = 300; /* 300dpi */
2416 dm.dmTTOption = DMTT_BITMAP;
2417 /* dm.dmCollate */
2418 /* dm.dmFormName */
2419 /* dm.dmLogPixels */
2420 /* dm.dmBitsPerPel */
2421 /* dm.dmPelsWidth */
2422 /* dm.dmPelsHeight */
2423 /* dm.dmDisplayFlags */
2424 /* dm.dmDisplayFrequency */
2425 /* dm.dmICMMethod */
2426 /* dm.dmICMIntent */
2427 /* dm.dmMediaType */
2428 /* dm.dmDitherType */
2429 /* dm.dmReserved1 */
2430 /* dm.dmReserved2 */
2431 /* dm.dmPanningWidth */
2432 /* dm.dmPanningHeight */
2434 if(unicode) {
2435 if(buflen >= sizeof(DEVMODEW)) {
2436 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2437 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2438 HeapFree(GetProcessHeap(),0,pdmW);
2440 *needed = sizeof(DEVMODEW);
2442 else
2444 if(buflen >= sizeof(DEVMODEA)) {
2445 memcpy(ptr, &dm, sizeof(DEVMODEA));
2447 *needed = sizeof(DEVMODEA);
2451 /*****************************************************************************
2452 * WINSPOOL_GetDevModeFromReg
2454 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2455 * DevMode is stored either as unicode or ascii.
2457 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2458 LPBYTE ptr,
2459 DWORD buflen, DWORD *needed,
2460 BOOL unicode)
2462 DWORD sz = buflen, type;
2463 LONG ret;
2465 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2466 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2467 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2468 if (sz < sizeof(DEVMODEA))
2470 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2471 return FALSE;
2473 /* ensures that dmSize is not erratically bogus if registry is invalid */
2474 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2475 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2476 if(unicode) {
2477 sz += (CCHDEVICENAME + CCHFORMNAME);
2478 if(buflen >= sz) {
2479 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2480 memcpy(ptr, dmW, sz);
2481 HeapFree(GetProcessHeap(),0,dmW);
2484 *needed = sz;
2485 return TRUE;
2488 /*********************************************************************
2489 * WINSPOOL_GetPrinter_2
2491 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2492 * The strings are either stored as unicode or ascii.
2494 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2495 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2496 BOOL unicode)
2498 DWORD size, left = cbBuf;
2499 BOOL space = (cbBuf > 0);
2500 LPBYTE ptr = buf;
2502 *pcbNeeded = 0;
2504 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2505 unicode)) {
2506 if(space && size <= left) {
2507 pi2->pPrinterName = (LPWSTR)ptr;
2508 ptr += size;
2509 left -= size;
2510 } else
2511 space = FALSE;
2512 *pcbNeeded += size;
2514 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2515 unicode)) {
2516 if(space && size <= left) {
2517 pi2->pShareName = (LPWSTR)ptr;
2518 ptr += size;
2519 left -= size;
2520 } else
2521 space = FALSE;
2522 *pcbNeeded += size;
2524 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2525 unicode)) {
2526 if(space && size <= left) {
2527 pi2->pPortName = (LPWSTR)ptr;
2528 ptr += size;
2529 left -= size;
2530 } else
2531 space = FALSE;
2532 *pcbNeeded += size;
2534 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2535 &size, unicode)) {
2536 if(space && size <= left) {
2537 pi2->pDriverName = (LPWSTR)ptr;
2538 ptr += size;
2539 left -= size;
2540 } else
2541 space = FALSE;
2542 *pcbNeeded += size;
2544 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2545 unicode)) {
2546 if(space && size <= left) {
2547 pi2->pComment = (LPWSTR)ptr;
2548 ptr += size;
2549 left -= size;
2550 } else
2551 space = FALSE;
2552 *pcbNeeded += size;
2554 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2555 unicode)) {
2556 if(space && size <= left) {
2557 pi2->pLocation = (LPWSTR)ptr;
2558 ptr += size;
2559 left -= size;
2560 } else
2561 space = FALSE;
2562 *pcbNeeded += size;
2564 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2565 &size, unicode)) {
2566 if(space && size <= left) {
2567 pi2->pDevMode = (LPDEVMODEW)ptr;
2568 ptr += size;
2569 left -= size;
2570 } else
2571 space = FALSE;
2572 *pcbNeeded += size;
2574 else
2576 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2577 if(space && size <= left) {
2578 pi2->pDevMode = (LPDEVMODEW)ptr;
2579 ptr += size;
2580 left -= size;
2581 } else
2582 space = FALSE;
2583 *pcbNeeded += size;
2585 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2586 &size, unicode)) {
2587 if(space && size <= left) {
2588 pi2->pSepFile = (LPWSTR)ptr;
2589 ptr += size;
2590 left -= size;
2591 } else
2592 space = FALSE;
2593 *pcbNeeded += size;
2595 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2596 &size, unicode)) {
2597 if(space && size <= left) {
2598 pi2->pPrintProcessor = (LPWSTR)ptr;
2599 ptr += size;
2600 left -= size;
2601 } else
2602 space = FALSE;
2603 *pcbNeeded += size;
2605 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2606 &size, unicode)) {
2607 if(space && size <= left) {
2608 pi2->pDatatype = (LPWSTR)ptr;
2609 ptr += size;
2610 left -= size;
2611 } else
2612 space = FALSE;
2613 *pcbNeeded += size;
2615 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2616 &size, unicode)) {
2617 if(space && size <= left) {
2618 pi2->pParameters = (LPWSTR)ptr;
2619 ptr += size;
2620 left -= size;
2621 } else
2622 space = FALSE;
2623 *pcbNeeded += size;
2625 if(pi2) {
2626 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2627 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2628 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2629 "Default Priority");
2630 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2631 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2634 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2635 memset(pi2, 0, sizeof(*pi2));
2637 return space;
2640 /*********************************************************************
2641 * WINSPOOL_GetPrinter_4
2643 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2645 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2646 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2647 BOOL unicode)
2649 DWORD size, left = cbBuf;
2650 BOOL space = (cbBuf > 0);
2651 LPBYTE ptr = buf;
2653 *pcbNeeded = 0;
2655 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2656 unicode)) {
2657 if(space && size <= left) {
2658 pi4->pPrinterName = (LPWSTR)ptr;
2659 ptr += size;
2660 left -= size;
2661 } else
2662 space = FALSE;
2663 *pcbNeeded += size;
2665 if(pi4) {
2666 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2669 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2670 memset(pi4, 0, sizeof(*pi4));
2672 return space;
2675 /*********************************************************************
2676 * WINSPOOL_GetPrinter_5
2678 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2680 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2681 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2682 BOOL unicode)
2684 DWORD size, left = cbBuf;
2685 BOOL space = (cbBuf > 0);
2686 LPBYTE ptr = buf;
2688 *pcbNeeded = 0;
2690 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2691 unicode)) {
2692 if(space && size <= left) {
2693 pi5->pPrinterName = (LPWSTR)ptr;
2694 ptr += size;
2695 left -= size;
2696 } else
2697 space = FALSE;
2698 *pcbNeeded += size;
2700 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2701 unicode)) {
2702 if(space && size <= left) {
2703 pi5->pPortName = (LPWSTR)ptr;
2704 ptr += size;
2705 left -= size;
2706 } else
2707 space = FALSE;
2708 *pcbNeeded += size;
2710 if(pi5) {
2711 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2712 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2713 "dnsTimeout");
2714 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2715 "txTimeout");
2718 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2719 memset(pi5, 0, sizeof(*pi5));
2721 return space;
2724 /*****************************************************************************
2725 * WINSPOOL_GetPrinter
2727 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2728 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2729 * just a collection of pointers to strings.
2731 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2732 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2734 LPCWSTR name;
2735 DWORD size, needed = 0;
2736 LPBYTE ptr = NULL;
2737 HKEY hkeyPrinter, hkeyPrinters;
2738 BOOL ret;
2740 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2742 if (!(name = get_opened_printer_name(hPrinter))) {
2743 SetLastError(ERROR_INVALID_HANDLE);
2744 return FALSE;
2747 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2748 ERROR_SUCCESS) {
2749 ERR("Can't create Printers key\n");
2750 return FALSE;
2752 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2754 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2755 RegCloseKey(hkeyPrinters);
2756 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2757 return FALSE;
2760 switch(Level) {
2761 case 2:
2763 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2765 size = sizeof(PRINTER_INFO_2W);
2766 if(size <= cbBuf) {
2767 ptr = pPrinter + size;
2768 cbBuf -= size;
2769 memset(pPrinter, 0, size);
2770 } else {
2771 pi2 = NULL;
2772 cbBuf = 0;
2774 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2775 unicode);
2776 needed += size;
2777 break;
2780 case 4:
2782 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2784 size = sizeof(PRINTER_INFO_4W);
2785 if(size <= cbBuf) {
2786 ptr = pPrinter + size;
2787 cbBuf -= size;
2788 memset(pPrinter, 0, size);
2789 } else {
2790 pi4 = NULL;
2791 cbBuf = 0;
2793 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2794 unicode);
2795 needed += size;
2796 break;
2800 case 5:
2802 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2804 size = sizeof(PRINTER_INFO_5W);
2805 if(size <= cbBuf) {
2806 ptr = pPrinter + size;
2807 cbBuf -= size;
2808 memset(pPrinter, 0, size);
2809 } else {
2810 pi5 = NULL;
2811 cbBuf = 0;
2814 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2815 unicode);
2816 needed += size;
2817 break;
2820 default:
2821 FIXME("Unimplemented level %ld\n", Level);
2822 SetLastError(ERROR_INVALID_LEVEL);
2823 RegCloseKey(hkeyPrinters);
2824 RegCloseKey(hkeyPrinter);
2825 return FALSE;
2828 RegCloseKey(hkeyPrinter);
2829 RegCloseKey(hkeyPrinters);
2831 TRACE("returning %d needed = %ld\n", ret, needed);
2832 if(pcbNeeded) *pcbNeeded = needed;
2833 if(!ret)
2834 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2835 return ret;
2838 /*****************************************************************************
2839 * GetPrinterW [WINSPOOL.@]
2841 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2842 DWORD cbBuf, LPDWORD pcbNeeded)
2844 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2845 TRUE);
2848 /*****************************************************************************
2849 * GetPrinterA [WINSPOOL.@]
2851 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2852 DWORD cbBuf, LPDWORD pcbNeeded)
2854 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2855 FALSE);
2858 /*****************************************************************************
2859 * WINSPOOL_EnumPrinters
2861 * Implementation of EnumPrintersA|W
2863 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2864 DWORD dwLevel, LPBYTE lpbPrinters,
2865 DWORD cbBuf, LPDWORD lpdwNeeded,
2866 LPDWORD lpdwReturned, BOOL unicode)
2869 HKEY hkeyPrinters, hkeyPrinter;
2870 WCHAR PrinterName[255];
2871 DWORD needed = 0, number = 0;
2872 DWORD used, i, left;
2873 PBYTE pi, buf;
2875 if(lpbPrinters)
2876 memset(lpbPrinters, 0, cbBuf);
2877 if(lpdwReturned)
2878 *lpdwReturned = 0;
2879 if(lpdwNeeded)
2880 *lpdwNeeded = 0;
2882 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2883 if(dwType == PRINTER_ENUM_DEFAULT)
2884 return TRUE;
2886 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2887 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2888 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2889 if(!dwType) return TRUE;
2892 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2893 FIXME("dwType = %08lx\n", dwType);
2894 SetLastError(ERROR_INVALID_FLAGS);
2895 return FALSE;
2898 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2899 ERROR_SUCCESS) {
2900 ERR("Can't create Printers key\n");
2901 return FALSE;
2904 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2905 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2906 RegCloseKey(hkeyPrinters);
2907 ERR("Can't query Printers key\n");
2908 return FALSE;
2910 TRACE("Found %ld printers\n", number);
2912 switch(dwLevel) {
2913 case 1:
2914 RegCloseKey(hkeyPrinters);
2915 if (lpdwReturned)
2916 *lpdwReturned = number;
2917 return TRUE;
2919 case 2:
2920 used = number * sizeof(PRINTER_INFO_2W);
2921 break;
2922 case 4:
2923 used = number * sizeof(PRINTER_INFO_4W);
2924 break;
2925 case 5:
2926 used = number * sizeof(PRINTER_INFO_5W);
2927 break;
2929 default:
2930 SetLastError(ERROR_INVALID_LEVEL);
2931 RegCloseKey(hkeyPrinters);
2932 return FALSE;
2934 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2936 for(i = 0; i < number; i++) {
2937 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2938 ERROR_SUCCESS) {
2939 ERR("Can't enum key number %ld\n", i);
2940 RegCloseKey(hkeyPrinters);
2941 return FALSE;
2943 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2944 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2945 ERROR_SUCCESS) {
2946 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2947 RegCloseKey(hkeyPrinters);
2948 return FALSE;
2951 if(cbBuf > used) {
2952 buf = lpbPrinters + used;
2953 left = cbBuf - used;
2954 } else {
2955 buf = NULL;
2956 left = 0;
2959 switch(dwLevel) {
2960 case 2:
2961 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2962 left, &needed, unicode);
2963 used += needed;
2964 if(pi) pi += sizeof(PRINTER_INFO_2W);
2965 break;
2966 case 4:
2967 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2968 left, &needed, unicode);
2969 used += needed;
2970 if(pi) pi += sizeof(PRINTER_INFO_4W);
2971 break;
2972 case 5:
2973 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2974 left, &needed, unicode);
2975 used += needed;
2976 if(pi) pi += sizeof(PRINTER_INFO_5W);
2977 break;
2978 default:
2979 ERR("Shouldn't be here!\n");
2980 RegCloseKey(hkeyPrinter);
2981 RegCloseKey(hkeyPrinters);
2982 return FALSE;
2984 RegCloseKey(hkeyPrinter);
2986 RegCloseKey(hkeyPrinters);
2988 if(lpdwNeeded)
2989 *lpdwNeeded = used;
2991 if(used > cbBuf) {
2992 if(lpbPrinters)
2993 memset(lpbPrinters, 0, cbBuf);
2994 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2995 return FALSE;
2997 if(lpdwReturned)
2998 *lpdwReturned = number;
2999 SetLastError(ERROR_SUCCESS);
3000 return TRUE;
3004 /******************************************************************
3005 * EnumPrintersW [WINSPOOL.@]
3007 * Enumerates the available printers, print servers and print
3008 * providers, depending on the specified flags, name and level.
3010 * RETURNS:
3012 * If level is set to 1:
3013 * Not implemented yet!
3014 * Returns TRUE with an empty list.
3016 * If level is set to 2:
3017 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3018 * Returns an array of PRINTER_INFO_2 data structures in the
3019 * lpbPrinters buffer. Note that according to MSDN also an
3020 * OpenPrinter should be performed on every remote printer.
3022 * If level is set to 4 (officially WinNT only):
3023 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3024 * Fast: Only the registry is queried to retrieve printer names,
3025 * no connection to the driver is made.
3026 * Returns an array of PRINTER_INFO_4 data structures in the
3027 * lpbPrinters buffer.
3029 * If level is set to 5 (officially WinNT4/Win9x only):
3030 * Fast: Only the registry is queried to retrieve printer names,
3031 * no connection to the driver is made.
3032 * Returns an array of PRINTER_INFO_5 data structures in the
3033 * lpbPrinters buffer.
3035 * If level set to 3 or 6+:
3036 * returns zero (failure!)
3038 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3039 * for information.
3041 * BUGS:
3042 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3043 * - Only levels 2, 4 and 5 are implemented at the moment.
3044 * - 16-bit printer drivers are not enumerated.
3045 * - Returned amount of bytes used/needed does not match the real Windoze
3046 * implementation (as in this implementation, all strings are part
3047 * of the buffer, whereas Win32 keeps them somewhere else)
3048 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3050 * NOTE:
3051 * - In a regular Wine installation, no registry settings for printers
3052 * exist, which makes this function return an empty list.
3054 BOOL WINAPI EnumPrintersW(
3055 DWORD dwType, /* [in] Types of print objects to enumerate */
3056 LPWSTR lpszName, /* [in] name of objects to enumerate */
3057 DWORD dwLevel, /* [in] type of printer info structure */
3058 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3059 DWORD cbBuf, /* [in] max size of buffer in bytes */
3060 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3061 LPDWORD lpdwReturned /* [out] number of entries returned */
3064 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3065 lpdwNeeded, lpdwReturned, TRUE);
3068 /******************************************************************
3069 * EnumPrintersA [WINSPOOL.@]
3072 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3073 DWORD dwLevel, LPBYTE lpbPrinters,
3074 DWORD cbBuf, LPDWORD lpdwNeeded,
3075 LPDWORD lpdwReturned)
3077 BOOL ret;
3078 UNICODE_STRING lpszNameW;
3079 PWSTR pwstrNameW;
3081 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3082 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3083 lpdwNeeded, lpdwReturned, FALSE);
3084 RtlFreeUnicodeString(&lpszNameW);
3085 return ret;
3088 /*****************************************************************************
3089 * WINSPOOL_GetDriverInfoFromReg [internal]
3091 * Enters the information from the registry into the DRIVER_INFO struct
3093 * RETURNS
3094 * zero if the printer driver does not exist in the registry
3095 * (only if Level > 1) otherwise nonzero
3097 static BOOL WINSPOOL_GetDriverInfoFromReg(
3098 HKEY hkeyDrivers,
3099 LPWSTR DriverName,
3100 LPWSTR pEnvironment,
3101 DWORD Level,
3102 LPBYTE ptr, /* DRIVER_INFO */
3103 LPBYTE pDriverStrings, /* strings buffer */
3104 DWORD cbBuf, /* size of string buffer */
3105 LPDWORD pcbNeeded, /* space needed for str. */
3106 BOOL unicode) /* type of strings */
3107 { DWORD dw, size, tmp, type;
3108 HKEY hkeyDriver;
3109 LPBYTE strPtr = pDriverStrings;
3111 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3112 debugstr_w(DriverName), debugstr_w(pEnvironment),
3113 Level, ptr, pDriverStrings, cbBuf, unicode);
3115 if(unicode) {
3116 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3117 if (*pcbNeeded <= cbBuf)
3118 strcpyW((LPWSTR)strPtr, DriverName);
3119 } else {
3120 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3121 NULL, NULL);
3122 if(*pcbNeeded <= cbBuf)
3123 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3124 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3126 if(Level == 1) {
3127 if(ptr)
3128 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3129 return TRUE;
3130 } else {
3131 if(ptr)
3132 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
3133 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3136 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3137 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3138 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3139 return FALSE;
3142 size = sizeof(dw);
3143 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
3144 ERROR_SUCCESS)
3145 WARN("Can't get Version\n");
3146 else if(ptr)
3147 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
3149 if(!pEnvironment)
3150 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3151 if(unicode)
3152 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3153 else
3154 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3155 NULL, NULL);
3156 *pcbNeeded += size;
3157 if(*pcbNeeded <= cbBuf) {
3158 if(unicode)
3159 strcpyW((LPWSTR)strPtr, pEnvironment);
3160 else
3161 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3162 (LPSTR)strPtr, size, NULL, NULL);
3163 if(ptr)
3164 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
3165 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3168 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3169 unicode)) {
3170 *pcbNeeded += size;
3171 if(*pcbNeeded <= cbBuf)
3172 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3173 unicode);
3174 if(ptr)
3175 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
3176 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3179 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3180 unicode)) {
3181 *pcbNeeded += size;
3182 if(*pcbNeeded <= cbBuf)
3183 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3184 &tmp, unicode);
3185 if(ptr)
3186 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
3187 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3190 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3191 0, &size, unicode)) {
3192 *pcbNeeded += size;
3193 if(*pcbNeeded <= cbBuf)
3194 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3195 size, &tmp, unicode);
3196 if(ptr)
3197 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
3198 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3201 if(Level == 2 ) {
3202 RegCloseKey(hkeyDriver);
3203 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3204 return TRUE;
3207 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3208 unicode)) {
3209 *pcbNeeded += size;
3210 if(*pcbNeeded <= cbBuf)
3211 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3212 size, &tmp, unicode);
3213 if(ptr)
3214 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3215 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3218 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3219 &size, unicode)) {
3220 *pcbNeeded += size;
3221 if(*pcbNeeded <= cbBuf)
3222 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3223 size, &tmp, unicode);
3224 if(ptr)
3225 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3226 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3229 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3230 unicode)) {
3231 *pcbNeeded += size;
3232 if(*pcbNeeded <= cbBuf)
3233 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3234 size, &tmp, unicode);
3235 if(ptr)
3236 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3237 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3240 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3241 unicode)) {
3242 *pcbNeeded += size;
3243 if(*pcbNeeded <= cbBuf)
3244 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3245 size, &tmp, unicode);
3246 if(ptr)
3247 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3248 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3251 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3252 RegCloseKey(hkeyDriver);
3253 return TRUE;
3256 /*****************************************************************************
3257 * WINSPOOL_GetPrinterDriver
3259 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3260 DWORD Level, LPBYTE pDriverInfo,
3261 DWORD cbBuf, LPDWORD pcbNeeded,
3262 BOOL unicode)
3264 LPCWSTR name;
3265 WCHAR DriverName[100];
3266 DWORD ret, type, size, needed = 0;
3267 LPBYTE ptr = NULL;
3268 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3270 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3271 Level,pDriverInfo,cbBuf, pcbNeeded);
3273 ZeroMemory(pDriverInfo, cbBuf);
3275 if (!(name = get_opened_printer_name(hPrinter))) {
3276 SetLastError(ERROR_INVALID_HANDLE);
3277 return FALSE;
3279 if(Level < 1 || Level > 3) {
3280 SetLastError(ERROR_INVALID_LEVEL);
3281 return FALSE;
3283 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3284 ERROR_SUCCESS) {
3285 ERR("Can't create Printers key\n");
3286 return FALSE;
3288 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3289 != ERROR_SUCCESS) {
3290 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3291 RegCloseKey(hkeyPrinters);
3292 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3293 return FALSE;
3295 size = sizeof(DriverName);
3296 DriverName[0] = 0;
3297 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3298 (LPBYTE)DriverName, &size);
3299 RegCloseKey(hkeyPrinter);
3300 RegCloseKey(hkeyPrinters);
3301 if(ret != ERROR_SUCCESS) {
3302 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3303 return FALSE;
3306 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3307 if(!hkeyDrivers) {
3308 ERR("Can't create Drivers key\n");
3309 return FALSE;
3312 switch(Level) {
3313 case 1:
3314 size = sizeof(DRIVER_INFO_1W);
3315 break;
3316 case 2:
3317 size = sizeof(DRIVER_INFO_2W);
3318 break;
3319 case 3:
3320 size = sizeof(DRIVER_INFO_3W);
3321 break;
3322 default:
3323 ERR("Invalid level\n");
3324 return FALSE;
3327 if(size <= cbBuf)
3328 ptr = pDriverInfo + size;
3330 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3331 pEnvironment, Level, pDriverInfo,
3332 (cbBuf < size) ? NULL : ptr,
3333 (cbBuf < size) ? 0 : cbBuf - size,
3334 &needed, unicode)) {
3335 RegCloseKey(hkeyDrivers);
3336 return FALSE;
3339 RegCloseKey(hkeyDrivers);
3341 if(pcbNeeded) *pcbNeeded = size + needed;
3342 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3343 if(cbBuf >= needed) return TRUE;
3344 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3345 return FALSE;
3348 /*****************************************************************************
3349 * GetPrinterDriverA [WINSPOOL.@]
3351 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3352 DWORD Level, LPBYTE pDriverInfo,
3353 DWORD cbBuf, LPDWORD pcbNeeded)
3355 BOOL ret;
3356 UNICODE_STRING pEnvW;
3357 PWSTR pwstrEnvW;
3359 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3360 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3361 cbBuf, pcbNeeded, FALSE);
3362 RtlFreeUnicodeString(&pEnvW);
3363 return ret;
3365 /*****************************************************************************
3366 * GetPrinterDriverW [WINSPOOL.@]
3368 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3369 DWORD Level, LPBYTE pDriverInfo,
3370 DWORD cbBuf, LPDWORD pcbNeeded)
3372 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3373 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3376 /*****************************************************************************
3377 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3379 * Return the PATH for the Printer-Drivers (UNICODE)
3381 * PARAMS
3382 * pName [I] Servername (NT only) or NULL (local Computer)
3383 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3384 * Level [I] Structure-Level (must be 1)
3385 * pDriverDirectory [O] PTR to Buffer that receives the Result
3386 * cbBuf [I] Size of Buffer at pDriverDirectory
3387 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3388 * required for pDriverDirectory
3390 * RETURNS
3391 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3392 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3393 * if cbBuf is too small
3395 * Native Values returned in pDriverDirectory on Success:
3396 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3397 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3398 *| win9x(Windows 4.0): "%winsysdir%"
3400 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3402 * FIXME
3403 *- Only NULL or "" is supported for pName
3406 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3407 DWORD Level, LPBYTE pDriverDirectory,
3408 DWORD cbBuf, LPDWORD pcbNeeded)
3410 DWORD needed;
3411 const printenv_t * env;
3413 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3414 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3415 if(pName != NULL && pName[0]) {
3416 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3417 SetLastError(ERROR_INVALID_PARAMETER);
3418 return FALSE;
3421 env = validate_envW(pEnvironment);
3422 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3424 if(Level != 1) {
3425 WARN("(Level: %ld) is ignored in win9x\n", Level);
3426 SetLastError(ERROR_INVALID_LEVEL);
3427 return FALSE;
3430 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3431 needed = GetSystemDirectoryW(NULL, 0);
3432 /* add the Size for the Subdirectories */
3433 needed += lstrlenW(spooldriversW);
3434 needed += lstrlenW(env->subdir);
3435 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3437 if(pcbNeeded)
3438 *pcbNeeded = needed;
3439 TRACE("required: 0x%lx/%ld\n", needed, needed);
3440 if(needed > cbBuf) {
3441 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3442 return FALSE;
3444 if(pcbNeeded == NULL) {
3445 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3446 SetLastError(RPC_X_NULL_REF_POINTER);
3447 return FALSE;
3449 if(pDriverDirectory == NULL) {
3450 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3451 SetLastError(ERROR_INVALID_USER_BUFFER);
3452 return FALSE;
3455 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3456 /* add the Subdirectories */
3457 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3458 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3459 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3460 return TRUE;
3464 /*****************************************************************************
3465 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3467 * Return the PATH for the Printer-Drivers (ANSI)
3469 * See GetPrinterDriverDirectoryW.
3471 * NOTES
3472 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3475 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3476 DWORD Level, LPBYTE pDriverDirectory,
3477 DWORD cbBuf, LPDWORD pcbNeeded)
3479 UNICODE_STRING nameW, environmentW;
3480 BOOL ret;
3481 DWORD pcbNeededW;
3482 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3483 WCHAR *driverDirectoryW = NULL;
3485 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3486 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3488 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3490 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3491 else nameW.Buffer = NULL;
3492 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3493 else environmentW.Buffer = NULL;
3495 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3496 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3497 if (ret) {
3498 DWORD needed;
3499 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3500 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3501 if(pcbNeeded)
3502 *pcbNeeded = needed;
3503 ret = (needed <= cbBuf) ? TRUE : FALSE;
3504 } else
3505 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3507 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3509 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3510 RtlFreeUnicodeString(&environmentW);
3511 RtlFreeUnicodeString(&nameW);
3513 return ret;
3516 /*****************************************************************************
3517 * AddPrinterDriverA [WINSPOOL.@]
3519 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3521 DRIVER_INFO_3A di3;
3522 HKEY hkeyDrivers, hkeyName;
3524 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3526 if(level != 2 && level != 3) {
3527 SetLastError(ERROR_INVALID_LEVEL);
3528 return FALSE;
3530 if(pName != NULL) {
3531 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3532 SetLastError(ERROR_INVALID_PARAMETER);
3533 return FALSE;
3535 if(!pDriverInfo) {
3536 WARN("pDriverInfo == NULL\n");
3537 SetLastError(ERROR_INVALID_PARAMETER);
3538 return FALSE;
3541 if(level == 3)
3542 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3543 else {
3544 memset(&di3, 0, sizeof(di3));
3545 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3548 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3549 !di3.pDataFile) {
3550 SetLastError(ERROR_INVALID_PARAMETER);
3551 return FALSE;
3553 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3554 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3555 if(!di3.pHelpFile) di3.pHelpFile = "";
3556 if(!di3.pMonitorName) di3.pMonitorName = "";
3558 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3560 if(!hkeyDrivers) {
3561 ERR("Can't create Drivers key\n");
3562 return FALSE;
3565 if(level == 2) { /* apparently can't overwrite with level2 */
3566 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3567 RegCloseKey(hkeyName);
3568 RegCloseKey(hkeyDrivers);
3569 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3570 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3571 return FALSE;
3574 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3575 RegCloseKey(hkeyDrivers);
3576 ERR("Can't create Name key\n");
3577 return FALSE;
3579 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3581 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3582 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3583 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3584 sizeof(DWORD));
3585 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3586 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3587 (LPBYTE) di3.pDependentFiles, 0);
3588 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3589 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3590 RegCloseKey(hkeyName);
3591 RegCloseKey(hkeyDrivers);
3593 return TRUE;
3596 /*****************************************************************************
3597 * AddPrinterDriverW [WINSPOOL.@]
3599 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3600 LPBYTE pDriverInfo)
3602 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3603 level,pDriverInfo);
3604 return FALSE;
3607 /*****************************************************************************
3608 * AddPrintProcessorA [WINSPOOL.@]
3610 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3611 LPSTR pPrintProcessorName)
3613 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3614 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3615 return FALSE;
3618 /*****************************************************************************
3619 * AddPrintProcessorW [WINSPOOL.@]
3621 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3622 LPWSTR pPrintProcessorName)
3624 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3625 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3626 return FALSE;
3629 /*****************************************************************************
3630 * AddPrintProvidorA [WINSPOOL.@]
3632 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3634 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3635 return FALSE;
3638 /*****************************************************************************
3639 * AddPrintProvidorW [WINSPOOL.@]
3641 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3643 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3644 return FALSE;
3647 /*****************************************************************************
3648 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3650 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3651 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3653 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3654 pDevModeOutput, pDevModeInput);
3655 return 0;
3658 /*****************************************************************************
3659 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3661 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3662 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3664 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3665 pDevModeOutput, pDevModeInput);
3666 return 0;
3669 /*****************************************************************************
3670 * PrinterProperties [WINSPOOL.@]
3672 * Displays a dialog to set the properties of the printer.
3674 * RETURNS
3675 * nonzero on success or zero on failure
3677 * BUGS
3678 * implemented as stub only
3680 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3681 HANDLE hPrinter /* [in] handle to printer object */
3683 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3684 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3685 return FALSE;
3688 /*****************************************************************************
3689 * EnumJobsA [WINSPOOL.@]
3692 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3693 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3694 LPDWORD pcReturned)
3696 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3697 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3699 if(pcbNeeded) *pcbNeeded = 0;
3700 if(pcReturned) *pcReturned = 0;
3701 return FALSE;
3705 /*****************************************************************************
3706 * EnumJobsW [WINSPOOL.@]
3709 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3710 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3711 LPDWORD pcReturned)
3713 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3714 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3716 if(pcbNeeded) *pcbNeeded = 0;
3717 if(pcReturned) *pcReturned = 0;
3718 return FALSE;
3721 /*****************************************************************************
3722 * WINSPOOL_EnumPrinterDrivers [internal]
3724 * Delivers information about all printer drivers installed on the
3725 * localhost or a given server
3727 * RETURNS
3728 * nonzero on success or zero on failure. If the buffer for the returned
3729 * information is too small the function will return an error
3731 * BUGS
3732 * - only implemented for localhost, foreign hosts will return an error
3734 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3735 DWORD Level, LPBYTE pDriverInfo,
3736 DWORD cbBuf, LPDWORD pcbNeeded,
3737 LPDWORD pcReturned, BOOL unicode)
3739 { HKEY hkeyDrivers;
3740 DWORD i, needed, number = 0, size = 0;
3741 WCHAR DriverNameW[255];
3742 PBYTE ptr;
3744 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3745 debugstr_w(pName), debugstr_w(pEnvironment),
3746 Level, pDriverInfo, cbBuf, unicode);
3748 /* check for local drivers */
3749 if(pName) {
3750 ERR("remote drivers unsupported! Current remote host is %s\n",
3751 debugstr_w(pName));
3752 return FALSE;
3755 /* check input parameter */
3756 if((Level < 1) || (Level > 3)) {
3757 ERR("unsupported level %ld\n", Level);
3758 SetLastError(ERROR_INVALID_LEVEL);
3759 return FALSE;
3762 /* initialize return values */
3763 if(pDriverInfo)
3764 memset( pDriverInfo, 0, cbBuf);
3765 *pcbNeeded = 0;
3766 *pcReturned = 0;
3768 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3769 if(!hkeyDrivers) {
3770 ERR("Can't open Drivers key\n");
3771 return FALSE;
3774 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3775 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3776 RegCloseKey(hkeyDrivers);
3777 ERR("Can't query Drivers key\n");
3778 return FALSE;
3780 TRACE("Found %ld Drivers\n", number);
3782 /* get size of single struct
3783 * unicode and ascii structure have the same size
3785 switch (Level) {
3786 case 1:
3787 size = sizeof(DRIVER_INFO_1A);
3788 break;
3789 case 2:
3790 size = sizeof(DRIVER_INFO_2A);
3791 break;
3792 case 3:
3793 size = sizeof(DRIVER_INFO_3A);
3794 break;
3797 /* calculate required buffer size */
3798 *pcbNeeded = size * number;
3800 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3801 i < number;
3802 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3803 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3804 != ERROR_SUCCESS) {
3805 ERR("Can't enum key number %ld\n", i);
3806 RegCloseKey(hkeyDrivers);
3807 return FALSE;
3809 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3810 pEnvironment, Level, ptr,
3811 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3812 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3813 &needed, unicode)) {
3814 RegCloseKey(hkeyDrivers);
3815 return FALSE;
3817 (*pcbNeeded) += needed;
3820 RegCloseKey(hkeyDrivers);
3822 if(cbBuf < *pcbNeeded){
3823 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3824 return FALSE;
3827 *pcReturned = number;
3828 return TRUE;
3831 /*****************************************************************************
3832 * EnumPrinterDriversW [WINSPOOL.@]
3834 * see function EnumPrinterDrivers for RETURNS, BUGS
3836 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3837 LPBYTE pDriverInfo, DWORD cbBuf,
3838 LPDWORD pcbNeeded, LPDWORD pcReturned)
3840 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3841 cbBuf, pcbNeeded, pcReturned, TRUE);
3844 /*****************************************************************************
3845 * EnumPrinterDriversA [WINSPOOL.@]
3847 * see function EnumPrinterDrivers for RETURNS, BUGS
3849 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3850 LPBYTE pDriverInfo, DWORD cbBuf,
3851 LPDWORD pcbNeeded, LPDWORD pcReturned)
3852 { BOOL ret;
3853 UNICODE_STRING pNameW, pEnvironmentW;
3854 PWSTR pwstrNameW, pwstrEnvironmentW;
3856 pwstrNameW = asciitounicode(&pNameW, pName);
3857 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3859 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3860 Level, pDriverInfo, cbBuf, pcbNeeded,
3861 pcReturned, FALSE);
3862 RtlFreeUnicodeString(&pNameW);
3863 RtlFreeUnicodeString(&pEnvironmentW);
3865 return ret;
3868 static CHAR PortMonitor[] = "Wine Port Monitor";
3869 static CHAR PortDescription[] = "Wine Port";
3871 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3873 HANDLE handle;
3875 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3876 NULL, OPEN_EXISTING, 0, NULL );
3877 if (handle == INVALID_HANDLE_VALUE)
3878 return FALSE;
3879 TRACE("Checking %s exists\n", name );
3880 CloseHandle( handle );
3881 return TRUE;
3884 static DWORD WINSPOOL_CountSerialPorts(void)
3886 CHAR name[6];
3887 DWORD n = 0, i;
3889 for (i=0; i<4; i++)
3891 strcpy( name, "COMx:" );
3892 name[3] = '1' + i;
3893 if (WINSPOOL_ComPortExists( name ))
3894 n++;
3897 return n;
3900 /******************************************************************************
3901 * EnumPortsA (WINSPOOL.@)
3903 * See EnumPortsW.
3905 * BUGS
3906 * ANSI-Version did not call the UNICODE-Version
3909 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3910 LPDWORD bufneeded,LPDWORD bufreturned)
3912 CHAR portname[10];
3913 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3914 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3915 HKEY hkey_printer;
3916 BOOL retval = TRUE;
3918 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3919 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3921 switch( level )
3923 case 1:
3924 info_size = sizeof (PORT_INFO_1A);
3925 break;
3926 case 2:
3927 info_size = sizeof (PORT_INFO_2A);
3928 break;
3929 default:
3930 SetLastError(ERROR_INVALID_LEVEL);
3931 return FALSE;
3934 /* see how many exist */
3936 hkey_printer = 0;
3937 serial_count = WINSPOOL_CountSerialPorts();
3938 printer_count = 0;
3940 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3941 if ( r == ERROR_SUCCESS )
3943 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3944 &printer_count, NULL, NULL, NULL, NULL);
3946 count = serial_count + printer_count;
3948 /* then fill in the structure info structure once
3949 we know the offset to the first string */
3951 memset( buffer, 0, bufsize );
3952 n = 0;
3953 ofs = info_size*count;
3954 for ( i=0; i<count; i++)
3956 DWORD vallen = sizeof(portname) - 1;
3958 /* get the serial port values, then the printer values */
3959 if ( i < serial_count )
3961 strcpy( portname, "COMx:" );
3962 portname[3] = '1' + i;
3963 if (!WINSPOOL_ComPortExists( portname ))
3964 continue;
3966 TRACE("Found %s\n", portname );
3967 vallen = strlen( portname );
3969 else
3971 r = RegEnumValueA( hkey_printer, i-serial_count,
3972 portname, &vallen, NULL, NULL, NULL, 0 );
3973 if ( r )
3974 continue;
3977 /* add a colon if necessary, and make it upper case */
3978 CharUpperBuffA(portname,vallen);
3979 if (strcasecmp(portname,"nul")!=0)
3980 if (vallen && (portname[vallen-1] != ':') )
3981 lstrcatA(portname,":");
3983 /* add the port info structure if we can fit it */
3984 if ( info_size*(n+1) < bufsize )
3986 if ( level == 1)
3988 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3989 info->pName = (LPSTR) &buffer[ofs];
3991 else if ( level == 2)
3993 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3994 info->pPortName = (LPSTR) &buffer[ofs];
3995 /* FIXME: fill in more stuff here */
3996 info->pMonitorName = PortMonitor;
3997 info->pDescription = PortDescription;
3998 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4001 /* add the name of the port if we can fit it */
4002 if ( ofs < bufsize )
4003 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4005 n++;
4007 else
4008 retval = FALSE;
4009 ofs += lstrlenA(portname)+1;
4012 RegCloseKey(hkey_printer);
4014 if(bufneeded)
4015 *bufneeded = ofs;
4017 if(bufreturned)
4018 *bufreturned = n;
4020 return retval;
4023 /******************************************************************************
4024 * EnumPortsW (WINSPOOL.@)
4026 * Enumerate available Ports
4028 * PARAMS
4029 * name [I] Servername or NULL (local Computer)
4030 * level [I] Structure-Level (1 or 2)
4031 * buffer [O] PTR to Buffer that receives the Result
4032 * bufsize [I] Size of Buffer at buffer
4033 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4034 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4036 * RETURNS
4037 * Success: TRUE
4038 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4040 * BUGS
4041 * UNICODE-Version is a stub
4044 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4045 LPDWORD bufneeded,LPDWORD bufreturned)
4047 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4048 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4049 return FALSE;
4052 /******************************************************************************
4053 * GetDefaultPrinterW (WINSPOOL.@)
4055 * FIXME
4056 * This function must read the value from data 'device' of key
4057 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4059 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4061 BOOL retval = TRUE;
4062 DWORD insize, len;
4063 WCHAR *buffer, *ptr;
4065 if (!namesize)
4067 SetLastError(ERROR_INVALID_PARAMETER);
4068 return FALSE;
4071 /* make the buffer big enough for the stuff from the profile/registry,
4072 * the content must fit into the local buffer to compute the correct
4073 * size even if the extern buffer is too small or not given.
4074 * (20 for ,driver,port) */
4075 insize = *namesize;
4076 len = max(100, (insize + 20));
4077 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4079 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4081 SetLastError (ERROR_FILE_NOT_FOUND);
4082 retval = FALSE;
4083 goto end;
4085 TRACE("%s\n", debugstr_w(buffer));
4087 if ((ptr = strchrW(buffer, ',')) == NULL)
4089 SetLastError(ERROR_INVALID_NAME);
4090 retval = FALSE;
4091 goto end;
4094 *ptr = 0;
4095 *namesize = strlenW(buffer) + 1;
4096 if(!name || (*namesize > insize))
4098 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4099 retval = FALSE;
4100 goto end;
4102 strcpyW(name, buffer);
4104 end:
4105 HeapFree( GetProcessHeap(), 0, buffer);
4106 return retval;
4110 /******************************************************************************
4111 * GetDefaultPrinterA (WINSPOOL.@)
4113 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4115 BOOL retval = TRUE;
4116 DWORD insize = 0;
4117 WCHAR *bufferW = NULL;
4119 if (!namesize)
4121 SetLastError(ERROR_INVALID_PARAMETER);
4122 return FALSE;
4125 if(name && *namesize) {
4126 insize = *namesize;
4127 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4130 if(!GetDefaultPrinterW( bufferW, namesize)) {
4131 retval = FALSE;
4132 goto end;
4135 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4136 NULL, NULL);
4137 if (!*namesize)
4139 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4140 retval = FALSE;
4142 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4144 end:
4145 HeapFree( GetProcessHeap(), 0, bufferW);
4146 return retval;
4150 /******************************************************************************
4151 * SetDefaultPrinterW (WINSPOOL.204)
4153 * Set the Name of the Default Printer
4155 * PARAMS
4156 * pszPrinter [I] Name of the Printer or NULL
4158 * RETURNS
4159 * Success: True
4160 * Failure: FALSE
4162 * NOTES
4163 * When the Parameter is NULL or points to an Empty String and
4164 * a Default Printer was already present, then this Function changes nothing.
4165 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4166 * the First enumerated local Printer is used.
4169 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4172 TRACE("(%s)\n", debugstr_w(pszPrinter));
4174 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4175 return FALSE;
4178 /******************************************************************************
4179 * SetDefaultPrinterA (WINSPOOL.202)
4181 * See SetDefaultPrinterW.
4184 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4187 TRACE("(%s)\n", debugstr_a(pszPrinter));
4189 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4190 return FALSE;
4194 /******************************************************************************
4195 * SetPrinterDataExA (WINSPOOL.@)
4197 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4198 LPCSTR pValueName, DWORD Type,
4199 LPBYTE pData, DWORD cbData)
4201 HKEY hkeyPrinter, hkeySubkey;
4202 DWORD ret;
4204 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4205 debugstr_a(pValueName), Type, pData, cbData);
4207 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4208 != ERROR_SUCCESS)
4209 return ret;
4211 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4212 != ERROR_SUCCESS) {
4213 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4214 RegCloseKey(hkeyPrinter);
4215 return ret;
4217 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4218 RegCloseKey(hkeySubkey);
4219 RegCloseKey(hkeyPrinter);
4220 return ret;
4223 /******************************************************************************
4224 * SetPrinterDataExW (WINSPOOL.@)
4226 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4227 LPCWSTR pValueName, DWORD Type,
4228 LPBYTE pData, DWORD cbData)
4230 HKEY hkeyPrinter, hkeySubkey;
4231 DWORD ret;
4233 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4234 debugstr_w(pValueName), Type, pData, cbData);
4236 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4237 != ERROR_SUCCESS)
4238 return ret;
4240 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4241 != ERROR_SUCCESS) {
4242 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4243 RegCloseKey(hkeyPrinter);
4244 return ret;
4246 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4247 RegCloseKey(hkeySubkey);
4248 RegCloseKey(hkeyPrinter);
4249 return ret;
4252 /******************************************************************************
4253 * SetPrinterDataA (WINSPOOL.@)
4255 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4256 LPBYTE pData, DWORD cbData)
4258 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4259 pData, cbData);
4262 /******************************************************************************
4263 * SetPrinterDataW (WINSPOOL.@)
4265 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4266 LPBYTE pData, DWORD cbData)
4268 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4269 pData, cbData);
4272 /******************************************************************************
4273 * GetPrinterDataExA (WINSPOOL.@)
4275 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4276 LPCSTR pValueName, LPDWORD pType,
4277 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4279 HKEY hkeyPrinter, hkeySubkey;
4280 DWORD ret;
4282 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4283 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4284 pcbNeeded);
4286 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4287 != ERROR_SUCCESS)
4288 return ret;
4290 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4291 != ERROR_SUCCESS) {
4292 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4293 RegCloseKey(hkeyPrinter);
4294 return ret;
4296 *pcbNeeded = nSize;
4297 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4298 RegCloseKey(hkeySubkey);
4299 RegCloseKey(hkeyPrinter);
4300 return ret;
4303 /******************************************************************************
4304 * GetPrinterDataExW (WINSPOOL.@)
4306 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4307 LPCWSTR pValueName, LPDWORD pType,
4308 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4310 HKEY hkeyPrinter, hkeySubkey;
4311 DWORD ret;
4313 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4314 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4315 pcbNeeded);
4317 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4318 != ERROR_SUCCESS)
4319 return ret;
4321 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4322 != ERROR_SUCCESS) {
4323 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4324 RegCloseKey(hkeyPrinter);
4325 return ret;
4327 *pcbNeeded = nSize;
4328 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4329 RegCloseKey(hkeySubkey);
4330 RegCloseKey(hkeyPrinter);
4331 return ret;
4334 /******************************************************************************
4335 * GetPrinterDataA (WINSPOOL.@)
4337 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4338 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4340 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4341 pData, nSize, pcbNeeded);
4344 /******************************************************************************
4345 * GetPrinterDataW (WINSPOOL.@)
4347 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4348 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4350 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4351 pData, nSize, pcbNeeded);
4354 /*******************************************************************************
4355 * EnumPrinterDataExW [WINSPOOL.@]
4357 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4358 LPBYTE pEnumValues, DWORD cbEnumValues,
4359 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4361 HKEY hkPrinter, hkSubKey;
4362 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4363 cbValueNameLen, cbMaxValueLen, cbValueLen,
4364 cbBufSize, dwType;
4365 LPWSTR lpValueName;
4366 HANDLE hHeap;
4367 PBYTE lpValue;
4368 PPRINTER_ENUM_VALUESW ppev;
4370 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4372 if (pKeyName == NULL || *pKeyName == 0)
4373 return ERROR_INVALID_PARAMETER;
4375 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4376 if (ret != ERROR_SUCCESS)
4378 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4379 hPrinter, ret);
4380 return ret;
4383 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4384 if (ret != ERROR_SUCCESS)
4386 r = RegCloseKey (hkPrinter);
4387 if (r != ERROR_SUCCESS)
4388 WARN ("RegCloseKey returned %li\n", r);
4389 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4390 debugstr_w (pKeyName), ret);
4391 return ret;
4394 ret = RegCloseKey (hkPrinter);
4395 if (ret != ERROR_SUCCESS)
4397 ERR ("RegCloseKey returned %li\n", ret);
4398 r = RegCloseKey (hkSubKey);
4399 if (r != ERROR_SUCCESS)
4400 WARN ("RegCloseKey returned %li\n", r);
4401 return ret;
4404 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4405 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4406 if (ret != ERROR_SUCCESS)
4408 r = RegCloseKey (hkSubKey);
4409 if (r != ERROR_SUCCESS)
4410 WARN ("RegCloseKey returned %li\n", r);
4411 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4412 return ret;
4415 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4416 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4418 if (cValues == 0) /* empty key */
4420 r = RegCloseKey (hkSubKey);
4421 if (r != ERROR_SUCCESS)
4422 WARN ("RegCloseKey returned %li\n", r);
4423 *pcbEnumValues = *pnEnumValues = 0;
4424 return ERROR_SUCCESS;
4427 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4429 hHeap = GetProcessHeap ();
4430 if (hHeap == NULL)
4432 ERR ("GetProcessHeap failed\n");
4433 r = RegCloseKey (hkSubKey);
4434 if (r != ERROR_SUCCESS)
4435 WARN ("RegCloseKey returned %li\n", r);
4436 return ERROR_OUTOFMEMORY;
4439 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4440 if (lpValueName == NULL)
4442 ERR ("Failed to allocate %li bytes from process heap\n",
4443 cbMaxValueNameLen * sizeof (WCHAR));
4444 r = RegCloseKey (hkSubKey);
4445 if (r != ERROR_SUCCESS)
4446 WARN ("RegCloseKey returned %li\n", r);
4447 return ERROR_OUTOFMEMORY;
4450 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4451 if (lpValue == NULL)
4453 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4454 if (HeapFree (hHeap, 0, lpValueName) == 0)
4455 WARN ("HeapFree failed with code %li\n", GetLastError ());
4456 r = RegCloseKey (hkSubKey);
4457 if (r != ERROR_SUCCESS)
4458 WARN ("RegCloseKey returned %li\n", r);
4459 return ERROR_OUTOFMEMORY;
4462 TRACE ("pass 1: calculating buffer required for all names and values\n");
4464 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4466 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4468 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4470 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4471 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4472 NULL, NULL, lpValue, &cbValueLen);
4473 if (ret != ERROR_SUCCESS)
4475 if (HeapFree (hHeap, 0, lpValue) == 0)
4476 WARN ("HeapFree failed with code %li\n", GetLastError ());
4477 if (HeapFree (hHeap, 0, lpValueName) == 0)
4478 WARN ("HeapFree failed with code %li\n", GetLastError ());
4479 r = RegCloseKey (hkSubKey);
4480 if (r != ERROR_SUCCESS)
4481 WARN ("RegCloseKey returned %li\n", r);
4482 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4483 return ret;
4486 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4487 debugstr_w (lpValueName), dwIndex,
4488 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4490 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4491 cbBufSize += cbValueLen;
4494 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4496 *pcbEnumValues = cbBufSize;
4497 *pnEnumValues = cValues;
4499 if (cbEnumValues < cbBufSize) /* buffer too small */
4501 if (HeapFree (hHeap, 0, lpValue) == 0)
4502 WARN ("HeapFree failed with code %li\n", GetLastError ());
4503 if (HeapFree (hHeap, 0, lpValueName) == 0)
4504 WARN ("HeapFree failed with code %li\n", GetLastError ());
4505 r = RegCloseKey (hkSubKey);
4506 if (r != ERROR_SUCCESS)
4507 WARN ("RegCloseKey returned %li\n", r);
4508 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4509 return ERROR_MORE_DATA;
4512 TRACE ("pass 2: copying all names and values to buffer\n");
4514 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4515 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4517 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4519 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4520 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4521 NULL, &dwType, lpValue, &cbValueLen);
4522 if (ret != ERROR_SUCCESS)
4524 if (HeapFree (hHeap, 0, lpValue) == 0)
4525 WARN ("HeapFree failed with code %li\n", GetLastError ());
4526 if (HeapFree (hHeap, 0, lpValueName) == 0)
4527 WARN ("HeapFree failed with code %li\n", GetLastError ());
4528 r = RegCloseKey (hkSubKey);
4529 if (r != ERROR_SUCCESS)
4530 WARN ("RegCloseKey returned %li\n", r);
4531 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4532 return ret;
4535 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4536 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4537 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4538 pEnumValues += cbValueNameLen;
4540 /* return # of *bytes* (including trailing \0), not # of chars */
4541 ppev[dwIndex].cbValueName = cbValueNameLen;
4543 ppev[dwIndex].dwType = dwType;
4545 memcpy (pEnumValues, lpValue, cbValueLen);
4546 ppev[dwIndex].pData = pEnumValues;
4547 pEnumValues += cbValueLen;
4549 ppev[dwIndex].cbData = cbValueLen;
4551 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4552 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4555 if (HeapFree (hHeap, 0, lpValue) == 0)
4557 ret = GetLastError ();
4558 ERR ("HeapFree failed with code %li\n", ret);
4559 if (HeapFree (hHeap, 0, lpValueName) == 0)
4560 WARN ("HeapFree failed with code %li\n", GetLastError ());
4561 r = RegCloseKey (hkSubKey);
4562 if (r != ERROR_SUCCESS)
4563 WARN ("RegCloseKey returned %li\n", r);
4564 return ret;
4567 if (HeapFree (hHeap, 0, lpValueName) == 0)
4569 ret = GetLastError ();
4570 ERR ("HeapFree failed with code %li\n", ret);
4571 r = RegCloseKey (hkSubKey);
4572 if (r != ERROR_SUCCESS)
4573 WARN ("RegCloseKey returned %li\n", r);
4574 return ret;
4577 ret = RegCloseKey (hkSubKey);
4578 if (ret != ERROR_SUCCESS)
4580 ERR ("RegCloseKey returned %li\n", ret);
4581 return ret;
4584 return ERROR_SUCCESS;
4587 /*******************************************************************************
4588 * EnumPrinterDataExA [WINSPOOL.@]
4590 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4591 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4592 * what Windows 2000 SP1 does.
4595 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4596 LPBYTE pEnumValues, DWORD cbEnumValues,
4597 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4599 INT len;
4600 LPWSTR pKeyNameW;
4601 DWORD ret, dwIndex, dwBufSize;
4602 HANDLE hHeap;
4603 LPSTR pBuffer;
4605 TRACE ("%p %s\n", hPrinter, pKeyName);
4607 if (pKeyName == NULL || *pKeyName == 0)
4608 return ERROR_INVALID_PARAMETER;
4610 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4611 if (len == 0)
4613 ret = GetLastError ();
4614 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4615 return ret;
4618 hHeap = GetProcessHeap ();
4619 if (hHeap == NULL)
4621 ERR ("GetProcessHeap failed\n");
4622 return ERROR_OUTOFMEMORY;
4625 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4626 if (pKeyNameW == NULL)
4628 ERR ("Failed to allocate %li bytes from process heap\n",
4629 (LONG) len * sizeof (WCHAR));
4630 return ERROR_OUTOFMEMORY;
4633 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4635 ret = GetLastError ();
4636 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4637 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4638 WARN ("HeapFree failed with code %li\n", GetLastError ());
4639 return ret;
4642 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4643 pcbEnumValues, pnEnumValues);
4644 if (ret != ERROR_SUCCESS)
4646 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4647 WARN ("HeapFree failed with code %li\n", GetLastError ());
4648 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4649 return ret;
4652 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4654 ret = GetLastError ();
4655 ERR ("HeapFree failed with code %li\n", ret);
4656 return ret;
4659 if (*pnEnumValues == 0) /* empty key */
4660 return ERROR_SUCCESS;
4662 dwBufSize = 0;
4663 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4665 PPRINTER_ENUM_VALUESW ppev =
4666 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4668 if (dwBufSize < ppev->cbValueName)
4669 dwBufSize = ppev->cbValueName;
4671 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4672 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4673 dwBufSize = ppev->cbData;
4676 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4678 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4679 if (pBuffer == NULL)
4681 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4682 return ERROR_OUTOFMEMORY;
4685 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4687 PPRINTER_ENUM_VALUESW ppev =
4688 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4690 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4691 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4692 NULL);
4693 if (len == 0)
4695 ret = GetLastError ();
4696 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4697 if (HeapFree (hHeap, 0, pBuffer) == 0)
4698 WARN ("HeapFree failed with code %li\n", GetLastError ());
4699 return ret;
4702 memcpy (ppev->pValueName, pBuffer, len);
4704 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4706 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4707 ppev->dwType != REG_MULTI_SZ)
4708 continue;
4710 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4711 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4712 if (len == 0)
4714 ret = GetLastError ();
4715 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4716 if (HeapFree (hHeap, 0, pBuffer) == 0)
4717 WARN ("HeapFree failed with code %li\n", GetLastError ());
4718 return ret;
4721 memcpy (ppev->pData, pBuffer, len);
4723 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4724 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4727 if (HeapFree (hHeap, 0, pBuffer) == 0)
4729 ret = GetLastError ();
4730 ERR ("HeapFree failed with code %li\n", ret);
4731 return ret;
4734 return ERROR_SUCCESS;
4737 /******************************************************************************
4738 * AbortPrinter (WINSPOOL.@)
4740 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4742 FIXME("(%p), stub!\n", hPrinter);
4743 return TRUE;
4746 /******************************************************************************
4747 * AddPortA (WINSPOOL.@)
4749 * See AddPortW.
4752 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4754 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4755 return FALSE;
4758 /******************************************************************************
4759 * AddPortW (WINSPOOL.@)
4761 * Add a Port for a specific Monitor
4763 * PARAMS
4764 * pName [I] Servername or NULL (local Computer)
4765 * hWnd [I] Handle to parent Window for the Dialog-Box
4766 * pMonitorName [I] Name of the Monitor that manage the Port
4768 * RETURNS
4769 * Success: TRUE
4770 * Failure: FALSE
4772 * BUGS
4773 * only a Stub
4776 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4778 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4779 return FALSE;
4782 /******************************************************************************
4783 * AddPortExA (WINSPOOL.@)
4785 * See AddPortExW.
4788 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4790 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4791 lpBuffer, debugstr_a(lpMonitorName));
4792 return FALSE;
4795 /******************************************************************************
4796 * AddPortExW (WINSPOOL.@)
4798 * Add a Port for a specific Monitor, without presenting a user interface
4800 * PARAMS
4801 * hMonitor [I] Handle from InitializePrintMonitor2()
4802 * pName [I] Servername or NULL (local Computer)
4803 * Level [I] Structure-Level (1 or 2) for lpBuffer
4804 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
4805 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
4807 * RETURNS
4808 * Success: TRUE
4809 * Failure: FALSE
4811 * BUGS
4812 * only a Stub
4815 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4817 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4818 lpBuffer, debugstr_w(lpMonitorName));
4819 return FALSE;
4822 /******************************************************************************
4823 * AddPrinterConnectionA (WINSPOOL.@)
4825 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4827 FIXME("%s\n", debugstr_a(pName));
4828 return FALSE;
4831 /******************************************************************************
4832 * AddPrinterConnectionW (WINSPOOL.@)
4834 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4836 FIXME("%s\n", debugstr_w(pName));
4837 return FALSE;
4840 /******************************************************************************
4841 * AddPrinterDriverExW (WINSPOOL.@)
4843 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4844 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4846 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4847 Level, pDriverInfo, dwFileCopyFlags);
4848 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4849 return FALSE;
4852 /******************************************************************************
4853 * AddPrinterDriverExA (WINSPOOL.@)
4855 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4856 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4858 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4859 Level, pDriverInfo, dwFileCopyFlags);
4860 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4861 return FALSE;
4864 /******************************************************************************
4865 * ConfigurePortA (WINSPOOL.@)
4867 * See ConfigurePortW.
4870 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4872 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4873 return FALSE;
4876 /******************************************************************************
4877 * ConfigurePortW (WINSPOOL.@)
4879 * Display the Configuration-Dialog for a specific Port
4881 * PARAMS
4882 * pName [I] Servername or NULL (local Computer)
4883 * hWnd [I] Handle to parent Window for the Dialog-Box
4884 * pPortName [I] Name of the Port, that should be configured
4886 * RETURNS
4887 * Success: TRUE
4888 * Failure: FALSE
4890 * BUGS
4891 * only a Stub
4894 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4896 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4897 return FALSE;
4900 /******************************************************************************
4901 * ConnectToPrinterDlg (WINSPOOL.@)
4903 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4905 FIXME("%p %lx\n", hWnd, Flags);
4906 return NULL;
4909 /******************************************************************************
4910 * DeletePrinterConnectionA (WINSPOOL.@)
4912 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4914 FIXME("%s\n", debugstr_a(pName));
4915 return TRUE;
4918 /******************************************************************************
4919 * DeletePrinterConnectionW (WINSPOOL.@)
4921 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4923 FIXME("%s\n", debugstr_w(pName));
4924 return TRUE;
4927 /******************************************************************************
4928 * DeletePrinterDriverExW (WINSPOOL.@)
4930 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4931 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4933 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4934 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4935 return TRUE;
4938 /******************************************************************************
4939 * DeletePrinterDriverExA (WINSPOOL.@)
4941 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4942 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4944 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4945 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4946 return TRUE;
4949 /******************************************************************************
4950 * DeletePrinterDataExW (WINSPOOL.@)
4952 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4953 LPCWSTR pValueName)
4955 FIXME("%p %s %s\n", hPrinter,
4956 debugstr_w(pKeyName), debugstr_w(pValueName));
4957 return ERROR_INVALID_PARAMETER;
4960 /******************************************************************************
4961 * DeletePrinterDataExA (WINSPOOL.@)
4963 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4964 LPCSTR pValueName)
4966 FIXME("%p %s %s\n", hPrinter,
4967 debugstr_a(pKeyName), debugstr_a(pValueName));
4968 return ERROR_INVALID_PARAMETER;
4971 /******************************************************************************
4972 * DeletePrintProcessorA (WINSPOOL.@)
4974 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4976 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4977 debugstr_a(pPrintProcessorName));
4978 return TRUE;
4981 /******************************************************************************
4982 * DeletePrintProcessorW (WINSPOOL.@)
4984 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4986 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4987 debugstr_w(pPrintProcessorName));
4988 return TRUE;
4991 /******************************************************************************
4992 * DeletePrintProvidorA (WINSPOOL.@)
4994 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4996 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4997 debugstr_a(pPrintProviderName));
4998 return TRUE;
5001 /******************************************************************************
5002 * DeletePrintProvidorW (WINSPOOL.@)
5004 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5006 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5007 debugstr_w(pPrintProviderName));
5008 return TRUE;
5011 /******************************************************************************
5012 * EnumFormsA (WINSPOOL.@)
5014 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5015 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5017 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5018 return FALSE;
5021 /******************************************************************************
5022 * EnumFormsW (WINSPOOL.@)
5024 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5025 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5027 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5028 return FALSE;
5031 /*****************************************************************************
5032 * EnumMonitorsA [WINSPOOL.@]
5034 * See EnumMonitorsW.
5037 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5038 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5040 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
5041 cbBuf, pcbNeeded, pcReturned);
5042 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5043 return 0;
5046 /*****************************************************************************
5047 * EnumMonitorsW [WINSPOOL.@]
5049 * Enumerate available Monitors
5051 * PARAMS
5052 * pName [I] Servername or NULL (local Computer)
5053 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5054 * pMonitors [O] PTR to Buffer that receives the Result
5055 * cbBuf [I] Size of Buffer at pMonitors
5056 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5057 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5059 * RETURNS
5060 * Success: TRUE
5061 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5063 * BUGS
5064 * only a Stub
5067 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5068 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5070 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
5071 cbBuf, pcbNeeded, pcReturned);
5072 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5073 return 0;
5076 /******************************************************************************
5077 * XcvDataW (WINSPOOL.@)
5079 * Notes:
5080 * There doesn't seem to be an A version...
5082 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5083 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5084 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5086 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5087 pInputData, cbInputData, pOutputData,
5088 cbOutputData, pcbOutputNeeded, pdwStatus);
5089 return FALSE;
5092 /*****************************************************************************
5093 * EnumPrinterDataA [WINSPOOL.@]
5096 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5097 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5098 DWORD cbData, LPDWORD pcbData )
5100 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5101 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5102 return ERROR_NO_MORE_ITEMS;
5105 /*****************************************************************************
5106 * EnumPrinterDataW [WINSPOOL.@]
5109 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5110 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5111 DWORD cbData, LPDWORD pcbData )
5113 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5114 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5115 return ERROR_NO_MORE_ITEMS;
5118 /*****************************************************************************
5119 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5122 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5123 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5124 LPDWORD pcbNeeded, LPDWORD pcReturned)
5126 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5127 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5128 pcbNeeded, pcReturned);
5129 return FALSE;
5132 /*****************************************************************************
5133 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5136 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5137 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5138 LPDWORD pcbNeeded, LPDWORD pcReturned)
5140 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5141 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5142 pcbNeeded, pcReturned);
5143 return FALSE;
5146 /*****************************************************************************
5147 * EnumPrintProcessorsA [WINSPOOL.@]
5150 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5151 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5153 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5154 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5155 return FALSE;
5158 /*****************************************************************************
5159 * EnumPrintProcessorsW [WINSPOOL.@]
5162 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5163 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5165 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5166 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5167 cbBuf, pcbNeeded, pcbReturned);
5168 return FALSE;
5171 /*****************************************************************************
5172 * ExtDeviceMode [WINSPOOL.@]
5175 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5176 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5177 DWORD fMode)
5179 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5180 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5181 debugstr_a(pProfile), fMode);
5182 return -1;
5185 /*****************************************************************************
5186 * FindClosePrinterChangeNotification [WINSPOOL.@]
5189 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5191 FIXME("Stub: %p\n", hChange);
5192 return TRUE;
5195 /*****************************************************************************
5196 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5199 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5200 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5202 FIXME("Stub: %p %lx %lx %p\n",
5203 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5204 return INVALID_HANDLE_VALUE;
5207 /*****************************************************************************
5208 * FindNextPrinterChangeNotification [WINSPOOL.@]
5211 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5212 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5214 FIXME("Stub: %p %p %p %p\n",
5215 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5216 return FALSE;
5219 /*****************************************************************************
5220 * FreePrinterNotifyInfo [WINSPOOL.@]
5223 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5225 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5226 return TRUE;
5229 /*****************************************************************************
5230 * string_to_buf
5232 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5233 * ansi depending on the unicode parameter.
5235 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5237 if(!str)
5239 *size = 0;
5240 return TRUE;
5243 if(unicode)
5245 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5246 if(*size <= cb)
5248 memcpy(ptr, str, *size);
5249 return TRUE;
5251 return FALSE;
5253 else
5255 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5256 if(*size <= cb)
5258 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5259 return TRUE;
5261 return FALSE;
5265 /*****************************************************************************
5266 * get_job_info_1
5268 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5269 LPDWORD pcbNeeded, BOOL unicode)
5271 DWORD size, left = cbBuf;
5272 BOOL space = (cbBuf > 0);
5273 LPBYTE ptr = buf;
5275 *pcbNeeded = 0;
5277 if(space)
5279 ji1->JobId = job->job_id;
5282 string_to_buf(job->document_title, ptr, left, &size, unicode);
5283 if(space && size <= left)
5285 ji1->pDocument = (LPWSTR)ptr;
5286 ptr += size;
5287 left -= size;
5289 else
5290 space = FALSE;
5291 *pcbNeeded += size;
5293 return space;
5296 /*****************************************************************************
5297 * get_job_info_2
5299 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5300 LPDWORD pcbNeeded, BOOL unicode)
5302 DWORD size, left = cbBuf;
5303 BOOL space = (cbBuf > 0);
5304 LPBYTE ptr = buf;
5306 *pcbNeeded = 0;
5308 if(space)
5310 ji2->JobId = job->job_id;
5313 string_to_buf(job->document_title, ptr, left, &size, unicode);
5314 if(space && size <= left)
5316 ji2->pDocument = (LPWSTR)ptr;
5317 ptr += size;
5318 left -= size;
5320 else
5321 space = FALSE;
5322 *pcbNeeded += size;
5324 return space;
5327 /*****************************************************************************
5328 * get_job_info
5330 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5331 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5333 BOOL ret = FALSE;
5334 DWORD needed = 0, size;
5335 job_t *job;
5336 LPBYTE ptr = pJob;
5338 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5340 EnterCriticalSection(&printer_handles_cs);
5341 job = get_job(hPrinter, JobId);
5342 if(!job)
5343 goto end;
5345 switch(Level)
5347 case 1:
5348 size = sizeof(JOB_INFO_1W);
5349 if(cbBuf >= size)
5351 cbBuf -= size;
5352 ptr += size;
5353 memset(pJob, 0, size);
5355 else
5356 cbBuf = 0;
5357 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5358 needed += size;
5359 break;
5361 case 2:
5362 size = sizeof(JOB_INFO_2W);
5363 if(cbBuf >= size)
5365 cbBuf -= size;
5366 ptr += size;
5367 memset(pJob, 0, size);
5369 else
5370 cbBuf = 0;
5371 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5372 needed += size;
5373 break;
5375 case 3:
5376 size = sizeof(JOB_INFO_3);
5377 if(cbBuf >= size)
5379 cbBuf -= size;
5380 memset(pJob, 0, size);
5381 ret = TRUE;
5383 else
5384 cbBuf = 0;
5385 needed = size;
5386 break;
5388 default:
5389 SetLastError(ERROR_INVALID_LEVEL);
5390 goto end;
5392 if(pcbNeeded)
5393 *pcbNeeded = needed;
5394 end:
5395 LeaveCriticalSection(&printer_handles_cs);
5396 return ret;
5399 /*****************************************************************************
5400 * GetJobA [WINSPOOL.@]
5403 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5404 DWORD cbBuf, LPDWORD pcbNeeded)
5406 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5409 /*****************************************************************************
5410 * GetJobW [WINSPOOL.@]
5413 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5414 DWORD cbBuf, LPDWORD pcbNeeded)
5416 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5419 /*****************************************************************************
5420 * schedule_lpr
5422 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5424 char *unixname, *queue, *cmd;
5425 char fmt[] = "lpr -P%s %s";
5426 DWORD len;
5428 if(!(unixname = wine_get_unix_file_name(filename)))
5429 return FALSE;
5431 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5432 queue = HeapAlloc(GetProcessHeap(), 0, len);
5433 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5435 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5436 sprintf(cmd, fmt, queue, unixname);
5438 TRACE("printing with: %s\n", cmd);
5439 system(cmd);
5441 HeapFree(GetProcessHeap(), 0, cmd);
5442 HeapFree(GetProcessHeap(), 0, queue);
5443 HeapFree(GetProcessHeap(), 0, unixname);
5444 return TRUE;
5447 /*****************************************************************************
5448 * schedule_cups
5450 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5452 #if HAVE_CUPS_CUPS_H
5453 if(pcupsPrintFile)
5455 char *unixname, *queue, *doc_titleA;
5456 DWORD len;
5457 BOOL ret;
5459 if(!(unixname = wine_get_unix_file_name(filename)))
5460 return FALSE;
5462 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5463 queue = HeapAlloc(GetProcessHeap(), 0, len);
5464 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5466 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5467 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5468 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5470 TRACE("printing via cups\n");
5471 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5472 HeapFree(GetProcessHeap(), 0, doc_titleA);
5473 HeapFree(GetProcessHeap(), 0, queue);
5474 HeapFree(GetProcessHeap(), 0, unixname);
5475 return ret;
5477 else
5478 #endif
5480 return schedule_lpr(printer_name, filename);
5484 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5486 LPWSTR filename;
5488 switch(msg)
5490 case WM_INITDIALOG:
5491 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5492 return TRUE;
5494 case WM_COMMAND:
5495 if(HIWORD(wparam) == BN_CLICKED)
5497 if(LOWORD(wparam) == IDOK)
5499 HANDLE hf;
5500 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5501 LPWSTR *output;
5503 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5504 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5506 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5508 WCHAR caption[200], message[200];
5509 int mb_ret;
5511 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5512 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5513 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5514 if(mb_ret == IDCANCEL)
5516 HeapFree(GetProcessHeap(), 0, filename);
5517 return TRUE;
5520 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5521 if(hf == INVALID_HANDLE_VALUE)
5523 WCHAR caption[200], message[200];
5525 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5526 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5527 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5528 HeapFree(GetProcessHeap(), 0, filename);
5529 return TRUE;
5531 CloseHandle(hf);
5532 DeleteFileW(filename);
5533 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5534 *output = filename;
5535 EndDialog(hwnd, IDOK);
5536 return TRUE;
5538 if(LOWORD(wparam) == IDCANCEL)
5540 EndDialog(hwnd, IDCANCEL);
5541 return TRUE;
5544 return FALSE;
5546 return FALSE;
5549 /*****************************************************************************
5550 * get_filename
5552 static BOOL get_filename(LPWSTR *filename)
5554 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
5555 file_dlg_proc, (LPARAM)filename) == IDOK;
5558 /*****************************************************************************
5559 * schedule_file
5561 static BOOL schedule_file(LPCWSTR filename)
5563 LPWSTR output = NULL;
5565 if(get_filename(&output))
5567 TRACE("copy to %s\n", debugstr_w(output));
5568 CopyFileW(filename, output, FALSE);
5569 HeapFree(GetProcessHeap(), 0, output);
5570 return TRUE;
5572 return FALSE;
5575 /*****************************************************************************
5576 * schedule_pipe
5578 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
5580 #ifdef HAVE_FORK
5581 char *unixname, *cmdA;
5582 DWORD len;
5583 int fds[2] = {-1, -1}, file_fd = -1, no_read;
5584 BOOL ret = FALSE;
5585 char buf[1024];
5587 if(!(unixname = wine_get_unix_file_name(filename)))
5588 return FALSE;
5590 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
5591 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
5592 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
5594 TRACE("printing with: %s\n", cmdA);
5596 if((file_fd = open(unixname, O_RDONLY)) == -1)
5597 goto end;
5599 if (pipe(fds))
5601 ERR("pipe() failed!\n");
5602 goto end;
5605 if (fork() == 0)
5607 close(0);
5608 dup2(fds[0], 0);
5609 close(fds[1]);
5611 /* reset signals that we previously set to SIG_IGN */
5612 signal(SIGPIPE, SIG_DFL);
5613 signal(SIGCHLD, SIG_DFL);
5615 system(cmdA);
5616 exit(0);
5619 while((no_read = read(file_fd, buf, sizeof(buf))))
5620 write(fds[1], buf, no_read);
5622 ret = TRUE;
5624 end:
5625 if(file_fd != -1) close(file_fd);
5626 if(fds[0] != -1) close(fds[0]);
5627 if(fds[1] != -1) close(fds[1]);
5629 HeapFree(GetProcessHeap(), 0, cmdA);
5630 HeapFree(GetProcessHeap(), 0, unixname);
5631 return ret;
5632 #else
5633 return FALSE;
5634 #endif
5637 /*****************************************************************************
5638 * schedule_unixfile
5640 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
5642 int in_fd, out_fd, no_read;
5643 char buf[1024];
5644 BOOL ret = FALSE;
5645 char *unixname, *outputA;
5646 DWORD len;
5648 if(!(unixname = wine_get_unix_file_name(filename)))
5649 return FALSE;
5651 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
5652 outputA = HeapAlloc(GetProcessHeap(), 0, len);
5653 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
5655 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5656 in_fd = open(unixname, O_RDONLY);
5657 if(out_fd == -1 || in_fd == -1)
5658 goto end;
5660 while((no_read = read(in_fd, buf, sizeof(buf))))
5661 write(out_fd, buf, no_read);
5663 ret = TRUE;
5664 end:
5665 if(in_fd != -1) close(in_fd);
5666 if(out_fd != -1) close(out_fd);
5667 HeapFree(GetProcessHeap(), 0, outputA);
5668 HeapFree(GetProcessHeap(), 0, unixname);
5669 return ret;
5672 /*****************************************************************************
5673 * ScheduleJob [WINSPOOL.@]
5676 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
5678 opened_printer_t *printer;
5679 BOOL ret = FALSE;
5680 struct list *cursor, *cursor2;
5682 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
5683 EnterCriticalSection(&printer_handles_cs);
5684 printer = get_opened_printer(hPrinter);
5685 if(!printer)
5686 goto end;
5688 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
5690 job_t *job = LIST_ENTRY(cursor, job_t, entry);
5691 HANDLE hf;
5693 if(job->job_id != dwJobID) continue;
5695 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
5696 if(hf != INVALID_HANDLE_VALUE)
5698 PRINTER_INFO_5W *pi5;
5699 DWORD needed;
5700 HKEY hkey;
5701 WCHAR output[1024];
5702 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5703 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5705 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
5706 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
5707 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
5708 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
5709 debugstr_w(pi5->pPortName));
5711 output[0] = 0;
5713 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5714 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
5716 DWORD type, count = sizeof(output);
5717 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
5718 RegCloseKey(hkey);
5720 if(output[0] == '|')
5722 schedule_pipe(output + 1, job->filename);
5724 else if(output[0])
5726 schedule_unixfile(output, job->filename);
5728 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
5730 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
5732 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
5734 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
5736 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
5738 schedule_file(job->filename);
5740 else
5742 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
5744 HeapFree(GetProcessHeap(), 0, pi5);
5745 CloseHandle(hf);
5746 DeleteFileW(job->filename);
5748 list_remove(cursor);
5749 HeapFree(GetProcessHeap(), 0, job->document_title);
5750 HeapFree(GetProcessHeap(), 0, job->filename);
5751 HeapFree(GetProcessHeap(), 0, job);
5752 ret = TRUE;
5753 break;
5755 end:
5756 LeaveCriticalSection(&printer_handles_cs);
5757 return ret;
5760 /*****************************************************************************
5761 * StartDocDlgA [WINSPOOL.@]
5763 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
5765 UNICODE_STRING usBuffer;
5766 DOCINFOW docW;
5767 LPWSTR retW;
5768 LPSTR ret = NULL;
5770 docW.cbSize = sizeof(docW);
5771 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
5772 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
5773 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
5774 docW.fwType = doc->fwType;
5776 retW = StartDocDlgW(hPrinter, &docW);
5778 if(retW)
5780 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
5781 ret = HeapAlloc(GetProcessHeap(), 0, len);
5782 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
5783 HeapFree(GetProcessHeap(), 0, retW);
5786 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
5787 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
5788 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
5790 return ret;
5793 /*****************************************************************************
5794 * StartDocDlgW [WINSPOOL.@]
5796 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5797 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5798 * port is "FILE:". Also returns the full path if passed a relative path.
5800 * The caller should free the returned string from the process heap.
5802 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
5804 LPWSTR ret = NULL;
5805 DWORD len, attr;
5807 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
5809 PRINTER_INFO_5W *pi5;
5810 GetPrinterW(hPrinter, 5, NULL, 0, &len);
5811 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
5812 return NULL;
5813 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
5814 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
5815 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
5817 HeapFree(GetProcessHeap(), 0, pi5);
5818 return NULL;
5820 HeapFree(GetProcessHeap(), 0, pi5);
5823 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
5825 LPWSTR name;
5826 get_filename(&name);
5827 if(name)
5829 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
5831 HeapFree(GetProcessHeap(), 0, name);
5832 return NULL;
5834 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5835 GetFullPathNameW(name, len, ret, NULL);
5836 HeapFree(GetProcessHeap(), 0, name);
5838 return ret;
5841 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
5842 return NULL;
5844 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5845 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
5847 attr = GetFileAttributesW(ret);
5848 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
5850 HeapFree(GetProcessHeap(), 0, ret);
5851 ret = NULL;
5853 return ret;