winspool: Printing environment support for GetPrinterDriverDirectory.
[wine/wine64.git] / dlls / winspool / info.c
blobd0f51aafb9ff3cc5fd05fcb90b8eba6e84a75994
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 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
211 static const printenv_t * validate_envW(LPCWSTR env)
213 static const printenv_t env_x86 = {envname_x86W, subdir_x86W};
214 static const printenv_t env_win40 = {envname_win40W, subdir_win40W};
215 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
217 const printenv_t *result = NULL;
218 unsigned int i;
220 TRACE("testing %s\n", debugstr_w(env));
221 if (env)
223 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
225 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
227 result = all_printenv[i];
228 break;
232 if (result == NULL) {
233 FIXME("unsupported Environment: %s\n", debugstr_w(env));
234 SetLastError(ERROR_INVALID_ENVIRONMENT);
236 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
238 else
240 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
242 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
244 return result;
248 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
249 if passed a NULL string. This returns NULLs to the result.
251 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
253 if ( (src) )
255 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
256 return usBufferPtr->Buffer;
258 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
259 return NULL;
262 static LPWSTR strdupW(LPCWSTR p)
264 LPWSTR ret;
265 DWORD len;
267 if(!p) return NULL;
268 len = (strlenW(p) + 1) * sizeof(WCHAR);
269 ret = HeapAlloc(GetProcessHeap(), 0, len);
270 memcpy(ret, p, len);
271 return ret;
274 static void
275 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
276 char qbuf[200];
278 /* If forcing, or no profile string entry for device yet, set the entry
280 * The always change entry if not WINEPS yet is discussable.
282 if (force ||
283 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
284 !strcmp(qbuf,"*") ||
285 !strstr(qbuf,"WINEPS.DRV")
287 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
288 HKEY hkey;
290 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
291 WriteProfileStringA("windows","device",buf);
292 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
293 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
294 RegCloseKey(hkey);
296 HeapFree(GetProcessHeap(),0,buf);
300 #ifdef HAVE_CUPS_CUPS_H
301 static typeof(cupsGetDests) *pcupsGetDests;
302 static typeof(cupsGetPPD) *pcupsGetPPD;
303 static typeof(cupsPrintFile) *pcupsPrintFile;
304 static void *cupshandle;
306 static BOOL CUPS_LoadPrinters(void)
308 int i, nrofdests;
309 BOOL hadprinter = FALSE;
310 cups_dest_t *dests;
311 PRINTER_INFO_2A pinfo2a;
312 char *port,*devline;
313 HKEY hkeyPrinter, hkeyPrinters, hkey;
315 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
316 if (!cupshandle)
317 return FALSE;
318 TRACE("loaded %s\n", SONAME_LIBCUPS);
320 #define DYNCUPS(x) \
321 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
322 if (!p##x) return FALSE;
324 DYNCUPS(cupsGetPPD);
325 DYNCUPS(cupsGetDests);
326 DYNCUPS(cupsPrintFile);
327 #undef DYNCUPS
329 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
330 ERROR_SUCCESS) {
331 ERR("Can't create Printers key\n");
332 return FALSE;
335 nrofdests = pcupsGetDests(&dests);
336 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
337 for (i=0;i<nrofdests;i++) {
338 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
339 sprintf(port,"LPR:%s",dests[i].name);
340 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
341 sprintf(devline,"WINEPS.DRV,%s",port);
342 WriteProfileStringA("devices",dests[i].name,devline);
343 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
344 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
345 RegCloseKey(hkey);
347 HeapFree(GetProcessHeap(),0,devline);
349 TRACE("Printer %d: %s\n", i, dests[i].name);
350 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
351 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
352 and continue */
353 TRACE("Printer already exists\n");
354 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
355 RegCloseKey(hkeyPrinter);
356 } else {
357 memset(&pinfo2a,0,sizeof(pinfo2a));
358 pinfo2a.pPrinterName = dests[i].name;
359 pinfo2a.pDatatype = "RAW";
360 pinfo2a.pPrintProcessor = "WinPrint";
361 pinfo2a.pDriverName = "PS Driver";
362 pinfo2a.pComment = "WINEPS Printer using CUPS";
363 pinfo2a.pLocation = "<physical location of printer>";
364 pinfo2a.pPortName = port;
365 pinfo2a.pParameters = "<parameters?>";
366 pinfo2a.pShareName = "<share name?>";
367 pinfo2a.pSepFile = "<sep file?>";
369 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
370 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
371 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
374 HeapFree(GetProcessHeap(),0,port);
376 hadprinter = TRUE;
377 if (dests[i].is_default)
378 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
380 RegCloseKey(hkeyPrinters);
381 return hadprinter;
383 #endif
385 static BOOL
386 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
387 PRINTER_INFO_2A pinfo2a;
388 char *e,*s,*name,*prettyname,*devname;
389 BOOL ret = FALSE, set_default = FALSE;
390 char *port,*devline,*env_default;
391 HKEY hkeyPrinter, hkeyPrinters, hkey;
393 while (isspace(*pent)) pent++;
394 s = strchr(pent,':');
395 if(s) *s='\0';
396 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
397 strcpy(name,pent);
398 if(s) {
399 *s=':';
400 pent = s;
401 } else
402 pent = "";
404 TRACE("name=%s entry=%s\n",name, pent);
406 if(ispunct(*name)) { /* a tc entry, not a real printer */
407 TRACE("skipping tc entry\n");
408 goto end;
411 if(strstr(pent,":server")) { /* server only version so skip */
412 TRACE("skipping server entry\n");
413 goto end;
416 /* Determine whether this is a postscript printer. */
418 ret = TRUE;
419 env_default = getenv("PRINTER");
420 prettyname = name;
421 /* Get longest name, usually the one at the right for later display. */
422 while((s=strchr(prettyname,'|'))) {
423 *s = '\0';
424 e = s;
425 while(isspace(*--e)) *e = '\0';
426 TRACE("\t%s\n", debugstr_a(prettyname));
427 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
428 for(prettyname = s+1; isspace(*prettyname); prettyname++)
431 e = prettyname + strlen(prettyname);
432 while(isspace(*--e)) *e = '\0';
433 TRACE("\t%s\n", debugstr_a(prettyname));
434 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
436 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
437 * if it is too long, we use it as comment below. */
438 devname = prettyname;
439 if (strlen(devname)>=CCHDEVICENAME-1)
440 devname = name;
441 if (strlen(devname)>=CCHDEVICENAME-1) {
442 ret = FALSE;
443 goto end;
446 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
447 sprintf(port,"LPR:%s",name);
449 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
450 sprintf(devline,"WINEPS.DRV,%s",port);
451 WriteProfileStringA("devices",devname,devline);
452 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
453 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
454 RegCloseKey(hkey);
456 HeapFree(GetProcessHeap(),0,devline);
458 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
459 ERROR_SUCCESS) {
460 ERR("Can't create Printers key\n");
461 ret = FALSE;
462 goto end;
464 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
465 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
466 and continue */
467 TRACE("Printer already exists\n");
468 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
469 RegCloseKey(hkeyPrinter);
470 } else {
471 memset(&pinfo2a,0,sizeof(pinfo2a));
472 pinfo2a.pPrinterName = devname;
473 pinfo2a.pDatatype = "RAW";
474 pinfo2a.pPrintProcessor = "WinPrint";
475 pinfo2a.pDriverName = "PS Driver";
476 pinfo2a.pComment = "WINEPS Printer using LPR";
477 pinfo2a.pLocation = prettyname;
478 pinfo2a.pPortName = port;
479 pinfo2a.pParameters = "<parameters?>";
480 pinfo2a.pShareName = "<share name?>";
481 pinfo2a.pSepFile = "<sep file?>";
483 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
484 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
485 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
488 RegCloseKey(hkeyPrinters);
490 if (isfirst || set_default)
491 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
493 HeapFree(GetProcessHeap(), 0, port);
494 end:
495 HeapFree(GetProcessHeap(), 0, name);
496 return ret;
499 static BOOL
500 PRINTCAP_LoadPrinters(void) {
501 BOOL hadprinter = FALSE;
502 char buf[200];
503 FILE *f;
504 char *pent = NULL;
505 BOOL had_bash = FALSE;
507 f = fopen("/etc/printcap","r");
508 if (!f)
509 return FALSE;
511 while(fgets(buf,sizeof(buf),f)) {
512 char *start, *end;
514 end=strchr(buf,'\n');
515 if (end) *end='\0';
517 start = buf;
518 while(isspace(*start)) start++;
519 if(*start == '#' || *start == '\0')
520 continue;
522 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
523 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
524 HeapFree(GetProcessHeap(),0,pent);
525 pent = NULL;
528 if (end && *--end == '\\') {
529 *end = '\0';
530 had_bash = TRUE;
531 } else
532 had_bash = FALSE;
534 if (pent) {
535 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
536 strcat(pent,start);
537 } else {
538 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
539 strcpy(pent,start);
543 if(pent) {
544 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
545 HeapFree(GetProcessHeap(),0,pent);
547 fclose(f);
548 return hadprinter;
551 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
553 if (value)
554 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
555 lstrlenW(value) * sizeof(WCHAR));
556 else
557 return ERROR_FILE_NOT_FOUND;
560 void WINSPOOL_LoadSystemPrinters(void)
562 HKEY hkey, hkeyPrinters;
563 DRIVER_INFO_3A di3a;
564 HANDLE hprn;
565 DWORD needed, num, i;
566 WCHAR PrinterName[256];
567 BOOL done = FALSE;
569 di3a.cVersion = 0x400;
570 di3a.pName = "PS Driver";
571 di3a.pEnvironment = NULL; /* NULL means auto */
572 di3a.pDriverPath = "wineps16";
573 di3a.pDataFile = "<datafile?>";
574 di3a.pConfigFile = "wineps16";
575 di3a.pHelpFile = "<helpfile?>";
576 di3a.pDependentFiles = "<dependend files?>";
577 di3a.pMonitorName = "<monitor name?>";
578 di3a.pDefaultDataType = "RAW";
580 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
581 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
582 return;
585 /* This ensures that all printer entries have a valid Name value. If causes
586 problems later if they don't. If one is found to be missed we create one
587 and set it equal to the name of the key */
588 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
589 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
590 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
591 for(i = 0; i < num; i++) {
592 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
593 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
594 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
595 set_reg_szW(hkey, NameW, PrinterName);
597 RegCloseKey(hkey);
602 RegCloseKey(hkeyPrinters);
605 /* We want to avoid calling AddPrinter on printers as much as
606 possible, because on cups printers this will (eventually) lead
607 to a call to cupsGetPPD which takes forever, even with non-cups
608 printers AddPrinter takes a while. So we'll tag all printers that
609 were automatically added last time around, if they still exist
610 we'll leave them be otherwise we'll delete them. */
611 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
612 if(needed) {
613 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
614 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
615 for(i = 0; i < num; i++) {
616 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
617 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
618 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
619 DWORD dw = 1;
620 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
621 RegCloseKey(hkey);
623 ClosePrinter(hprn);
628 HeapFree(GetProcessHeap(), 0, pi);
632 #ifdef HAVE_CUPS_CUPS_H
633 done = CUPS_LoadPrinters();
634 #endif
636 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
637 /* Check for [ppd] section in config file before parsing /etc/printcap */
638 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
639 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
640 &hkey) == ERROR_SUCCESS) {
641 RegCloseKey(hkey);
642 PRINTCAP_LoadPrinters();
646 /* Now enumerate the list again and delete any printers that a still tagged */
647 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
648 if(needed) {
649 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
650 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
651 for(i = 0; i < num; i++) {
652 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
653 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
654 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
655 DWORD dw, type, size = sizeof(dw);
656 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
657 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
658 DeletePrinter(hprn);
660 RegCloseKey(hkey);
662 ClosePrinter(hprn);
667 HeapFree(GetProcessHeap(), 0, pi);
670 return;
675 /******************************************************************
676 * get_opened_printer_entry
677 * Get the first place empty in the opened printer table
679 static HANDLE get_opened_printer_entry( LPCWSTR name )
681 UINT_PTR handle = nb_printer_handles, i;
682 jobqueue_t *queue = NULL;
683 opened_printer_t *printer;
685 EnterCriticalSection(&printer_handles_cs);
687 for (i = 0; i < nb_printer_handles; i++)
689 if (!printer_handles[i])
691 if(handle == nb_printer_handles)
692 handle = i;
694 else if(!queue && !strcmpW(name, printer_handles[i]->name))
695 queue = printer_handles[i]->queue;
698 if (handle >= nb_printer_handles)
700 opened_printer_t **new_array;
701 if (printer_handles)
702 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
703 (nb_printer_handles + 16) * sizeof(*new_array) );
704 else
705 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
706 (nb_printer_handles + 16) * sizeof(*new_array) );
708 if (!new_array)
710 handle = 0;
711 goto end;
713 printer_handles = new_array;
714 nb_printer_handles += 16;
717 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
719 handle = 0;
720 goto end;
723 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
724 strcpyW(printer->name, name);
725 if(queue)
726 printer->queue = queue;
727 else
729 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
730 list_init(&printer->queue->jobs);
731 printer->queue->ref = 0;
733 InterlockedIncrement(&printer->queue->ref);
734 printer->doc = NULL;
736 printer_handles[handle] = printer;
737 handle++;
738 end:
739 LeaveCriticalSection(&printer_handles_cs);
741 return (HANDLE)handle;
744 /******************************************************************
745 * get_opened_printer
746 * Get the pointer to the opened printer referred by the handle
748 static opened_printer_t *get_opened_printer(HANDLE hprn)
750 UINT_PTR idx = (UINT_PTR)hprn;
751 opened_printer_t *ret = NULL;
753 EnterCriticalSection(&printer_handles_cs);
755 if ((idx <= 0) || (idx > nb_printer_handles))
756 goto end;
758 ret = printer_handles[idx - 1];
759 end:
760 LeaveCriticalSection(&printer_handles_cs);
761 return ret;
764 /******************************************************************
765 * get_opened_printer_name
766 * Get the pointer to the opened printer name referred by the handle
768 static LPCWSTR get_opened_printer_name(HANDLE hprn)
770 opened_printer_t *printer = get_opened_printer(hprn);
771 if(!printer) return NULL;
772 return printer->name;
775 /******************************************************************
776 * WINSPOOL_GetOpenedPrinterRegKey
779 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
781 LPCWSTR name = get_opened_printer_name(hPrinter);
782 DWORD ret;
783 HKEY hkeyPrinters;
785 if(!name) return ERROR_INVALID_HANDLE;
787 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
788 ERROR_SUCCESS)
789 return ret;
791 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
793 ERR("Can't find opened printer %s in registry\n",
794 debugstr_w(name));
795 RegCloseKey(hkeyPrinters);
796 return ERROR_INVALID_PRINTER_NAME; /* ? */
798 RegCloseKey(hkeyPrinters);
799 return ERROR_SUCCESS;
802 /******************************************************************
803 * get_job
805 * Get the pointer to the specified job.
806 * Should hold the printer_handles_cs before calling.
808 static job_t *get_job(HANDLE hprn, DWORD JobId)
810 opened_printer_t *printer = get_opened_printer(hprn);
811 job_t *job;
813 if(!printer) return NULL;
814 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
816 if(job->job_id == JobId)
817 return job;
819 return NULL;
822 /***********************************************************
823 * DEVMODEcpyAtoW
825 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
827 BOOL Formname;
828 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
829 DWORD size;
831 Formname = (dmA->dmSize > off_formname);
832 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
833 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
834 dmW->dmDeviceName, CCHDEVICENAME);
835 if(!Formname) {
836 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
837 dmA->dmSize - CCHDEVICENAME);
838 } else {
839 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
840 off_formname - CCHDEVICENAME);
841 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
842 dmW->dmFormName, CCHFORMNAME);
843 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
844 (off_formname + CCHFORMNAME));
846 dmW->dmSize = size;
847 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
848 dmA->dmDriverExtra);
849 return dmW;
852 /***********************************************************
853 * DEVMODEdupWtoA
854 * Creates an ascii copy of supplied devmode on heap
856 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
858 LPDEVMODEA dmA;
859 DWORD size;
860 BOOL Formname;
861 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
863 if(!dmW) return NULL;
864 Formname = (dmW->dmSize > off_formname);
865 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
866 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
867 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
868 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
869 if(!Formname) {
870 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
871 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
872 } else {
873 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
874 off_formname - CCHDEVICENAME * sizeof(WCHAR));
875 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
876 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
877 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
878 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
880 dmA->dmSize = size;
881 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
882 dmW->dmDriverExtra);
883 return dmA;
886 /***********************************************************
887 * PRINTER_INFO_2AtoW
888 * Creates a unicode copy of PRINTER_INFO_2A on heap
890 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
892 LPPRINTER_INFO_2W piW;
893 UNICODE_STRING usBuffer;
895 if(!piA) return NULL;
896 piW = HeapAlloc(heap, 0, sizeof(*piW));
897 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
899 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
900 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
901 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
902 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
903 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
904 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
905 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
906 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
907 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
908 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
909 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
910 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
911 return piW;
914 /***********************************************************
915 * FREE_PRINTER_INFO_2W
916 * Free PRINTER_INFO_2W and all strings
918 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
920 if(!piW) return;
922 HeapFree(heap,0,piW->pServerName);
923 HeapFree(heap,0,piW->pPrinterName);
924 HeapFree(heap,0,piW->pShareName);
925 HeapFree(heap,0,piW->pPortName);
926 HeapFree(heap,0,piW->pDriverName);
927 HeapFree(heap,0,piW->pComment);
928 HeapFree(heap,0,piW->pLocation);
929 HeapFree(heap,0,piW->pDevMode);
930 HeapFree(heap,0,piW->pSepFile);
931 HeapFree(heap,0,piW->pPrintProcessor);
932 HeapFree(heap,0,piW->pDatatype);
933 HeapFree(heap,0,piW->pParameters);
934 HeapFree(heap,0,piW);
935 return;
938 /******************************************************************
939 * DeviceCapabilities [WINSPOOL.@]
940 * DeviceCapabilitiesA [WINSPOOL.@]
943 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
944 LPSTR pOutput, LPDEVMODEA lpdm)
946 INT ret;
948 if (!GDI_CallDeviceCapabilities16)
950 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
951 (LPCSTR)104 );
952 if (!GDI_CallDeviceCapabilities16) return -1;
954 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
956 /* If DC_PAPERSIZE map POINT16s to POINTs */
957 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
958 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
959 POINT *pt = (POINT *)pOutput;
960 INT i;
961 memcpy(tmp, pOutput, ret * sizeof(POINT16));
962 for(i = 0; i < ret; i++, pt++)
964 pt->x = tmp[i].x;
965 pt->y = tmp[i].y;
967 HeapFree( GetProcessHeap(), 0, tmp );
969 return ret;
973 /*****************************************************************************
974 * DeviceCapabilitiesW [WINSPOOL.@]
976 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
979 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
980 WORD fwCapability, LPWSTR pOutput,
981 const DEVMODEW *pDevMode)
983 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
984 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
985 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
986 INT ret;
988 if(pOutput && (fwCapability == DC_BINNAMES ||
989 fwCapability == DC_FILEDEPENDENCIES ||
990 fwCapability == DC_PAPERNAMES)) {
991 /* These need A -> W translation */
992 INT size = 0, i;
993 LPSTR pOutputA;
994 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
995 dmA);
996 if(ret == -1)
997 return ret;
998 switch(fwCapability) {
999 case DC_BINNAMES:
1000 size = 24;
1001 break;
1002 case DC_PAPERNAMES:
1003 case DC_FILEDEPENDENCIES:
1004 size = 64;
1005 break;
1007 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1008 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1009 dmA);
1010 for(i = 0; i < ret; i++)
1011 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1012 pOutput + (i * size), size);
1013 HeapFree(GetProcessHeap(), 0, pOutputA);
1014 } else {
1015 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1016 (LPSTR)pOutput, dmA);
1018 HeapFree(GetProcessHeap(),0,pPortA);
1019 HeapFree(GetProcessHeap(),0,pDeviceA);
1020 HeapFree(GetProcessHeap(),0,dmA);
1021 return ret;
1024 /******************************************************************
1025 * DocumentPropertiesA [WINSPOOL.@]
1027 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1029 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1030 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1031 LPDEVMODEA pDevModeInput,DWORD fMode )
1033 LPSTR lpName = pDeviceName;
1034 LONG ret;
1036 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1037 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1040 if(!pDeviceName) {
1041 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1042 if(!lpNameW) {
1043 ERR("no name from hPrinter?\n");
1044 SetLastError(ERROR_INVALID_HANDLE);
1045 return -1;
1047 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1050 if (!GDI_CallExtDeviceMode16)
1052 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1053 (LPCSTR)102 );
1054 if (!GDI_CallExtDeviceMode16) {
1055 ERR("No CallExtDeviceMode16?\n");
1056 return -1;
1059 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1060 pDevModeInput, NULL, fMode);
1062 if(!pDeviceName)
1063 HeapFree(GetProcessHeap(),0,lpName);
1064 return ret;
1068 /*****************************************************************************
1069 * DocumentPropertiesW (WINSPOOL.@)
1071 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1073 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1074 LPWSTR pDeviceName,
1075 LPDEVMODEW pDevModeOutput,
1076 LPDEVMODEW pDevModeInput, DWORD fMode)
1079 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1080 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1081 LPDEVMODEA pDevModeOutputA = NULL;
1082 LONG ret;
1084 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1085 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1086 fMode);
1087 if(pDevModeOutput) {
1088 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1089 if(ret < 0) return ret;
1090 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1092 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1093 pDevModeInputA, fMode);
1094 if(pDevModeOutput) {
1095 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1096 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1098 if(fMode == 0 && ret > 0)
1099 ret += (CCHDEVICENAME + CCHFORMNAME);
1100 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1101 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1102 return ret;
1105 /******************************************************************
1106 * OpenPrinterA [WINSPOOL.@]
1108 * See OpenPrinterW.
1111 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1112 LPPRINTER_DEFAULTSA pDefault)
1114 UNICODE_STRING lpPrinterNameW;
1115 UNICODE_STRING usBuffer;
1116 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1117 PWSTR pwstrPrinterNameW;
1118 BOOL ret;
1120 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1122 if(pDefault) {
1123 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1124 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1125 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1126 pDefaultW = &DefaultW;
1128 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1129 if(pDefault) {
1130 RtlFreeUnicodeString(&usBuffer);
1131 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1133 RtlFreeUnicodeString(&lpPrinterNameW);
1134 return ret;
1137 /******************************************************************
1138 * OpenPrinterW [WINSPOOL.@]
1140 * Open a Printer / Printserver or a Printer-Object
1142 * PARAMS
1143 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1144 * phPrinter [O] The resulting Handle is stored here
1145 * pDefault [I] PTR to Default Printer Settings or NULL
1147 * RETURNS
1148 * Success: TRUE
1149 * Failure: FALSE
1151 * NOTES
1152 * lpPrinterName is one of:
1153 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1154 *| Printer: "PrinterName"
1155 *| Printer-Object: "PrinterName,Job xxx"
1156 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1157 *| XcvPort: "Servername,XcvPort PortName"
1159 * BUGS
1160 *| Printserver not supported
1161 *| Printer-Object not supported
1162 *| XcvMonitor not supported
1163 *| XcvPort not supported
1164 *| pDefaults not supported
1167 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
1168 LPPRINTER_DEFAULTSW pDefault)
1170 HKEY hkeyPrinters, hkeyPrinter;
1172 if (!lpPrinterName) {
1173 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1174 SetLastError(ERROR_INVALID_PARAMETER);
1175 return FALSE;
1178 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1179 pDefault);
1181 /* Check Printer exists */
1182 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1183 ERROR_SUCCESS) {
1184 ERR("Can't create Printers key\n");
1185 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1186 return FALSE;
1189 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1190 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1191 != ERROR_SUCCESS) {
1192 TRACE("Can't find printer %s in registry\n",
1193 debugstr_w(lpPrinterName));
1194 RegCloseKey(hkeyPrinters);
1195 SetLastError(ERROR_INVALID_PRINTER_NAME);
1196 return FALSE;
1198 RegCloseKey(hkeyPrinter);
1199 RegCloseKey(hkeyPrinters);
1201 if(!phPrinter) /* This seems to be what win95 does anyway */
1202 return TRUE;
1204 /* Get the unique handle of the printer*/
1205 *phPrinter = get_opened_printer_entry( lpPrinterName );
1207 if (pDefault != NULL)
1208 FIXME("Not handling pDefault\n");
1210 return TRUE;
1213 /******************************************************************
1214 * AddMonitorA [WINSPOOL.@]
1216 * See AddMonitorW.
1219 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1221 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
1222 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1223 return FALSE;
1226 /******************************************************************************
1227 * AddMonitorW [WINSPOOL.@]
1229 * Install a Printmonitor
1231 * PARAMS
1232 * pName [I] Servername or NULL (local Computer)
1233 * Level [I] Structure-Level (Must be 2)
1234 * pMonitors [I] PTR to MONITOR_INFO_2
1236 * RETURNS
1237 * Success: TRUE
1238 * Failure: FALSE
1240 * NOTES
1241 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1243 * BUGS
1244 * only a Stub
1247 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1249 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1250 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1251 return FALSE;
1254 /******************************************************************
1255 * DeletePrinterDriverA [WINSPOOL.@]
1258 BOOL WINAPI
1259 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1261 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1262 debugstr_a(pDriverName));
1263 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1264 return FALSE;
1267 /******************************************************************
1268 * DeletePrinterDriverW [WINSPOOL.@]
1271 BOOL WINAPI
1272 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1274 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1275 debugstr_w(pDriverName));
1276 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1277 return FALSE;
1280 /******************************************************************
1281 * DeleteMonitorA [WINSPOOL.@]
1283 * See DeleteMonitorW.
1286 BOOL WINAPI
1287 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1289 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1290 debugstr_a(pMonitorName));
1291 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1292 return FALSE;
1295 /******************************************************************
1296 * DeleteMonitorW [WINSPOOL.@]
1298 * Delete a specific Printmonitor from a Printing-Environment
1300 * PARAMS
1301 * pName [I] Servername or NULL (local Computer)
1302 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1303 * pMonitorName [I] Name of the Monitor, that should be deleted
1305 * RETURNS
1306 * Success: TRUE
1307 * Failure: FALSE
1309 * BUGS
1310 * only a Stub
1313 BOOL WINAPI
1314 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1316 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1317 debugstr_w(pMonitorName));
1318 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1319 return FALSE;
1322 /******************************************************************
1323 * DeletePortA [WINSPOOL.@]
1325 * See DeletePortW.
1328 BOOL WINAPI
1329 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1331 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1332 debugstr_a(pPortName));
1333 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1334 return FALSE;
1337 /******************************************************************
1338 * DeletePortW [WINSPOOL.@]
1340 * Delete a specific Port
1342 * PARAMS
1343 * pName [I] Servername or NULL (local Computer)
1344 * hWnd [I] Handle to parent Window for the Dialog-Box
1345 * pPortName [I] Name of the Port, that should be deleted
1347 * RETURNS
1348 * Success: TRUE
1349 * Failure: FALSE
1351 * BUGS
1352 * only a Stub
1355 BOOL WINAPI
1356 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1358 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1359 debugstr_w(pPortName));
1360 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1361 return FALSE;
1364 /******************************************************************************
1365 * SetPrinterW [WINSPOOL.@]
1367 BOOL WINAPI
1368 SetPrinterW(
1369 HANDLE hPrinter,
1370 DWORD Level,
1371 LPBYTE pPrinter,
1372 DWORD Command) {
1374 FIXME("():stub\n");
1375 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1376 return FALSE;
1379 /******************************************************************************
1380 * WritePrinter [WINSPOOL.@]
1382 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1384 opened_printer_t *printer;
1385 BOOL ret = FALSE;
1387 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1389 EnterCriticalSection(&printer_handles_cs);
1390 printer = get_opened_printer(hPrinter);
1391 if(!printer)
1393 SetLastError(ERROR_INVALID_HANDLE);
1394 goto end;
1397 if(!printer->doc)
1399 SetLastError(ERROR_SPL_NO_STARTDOC);
1400 goto end;
1403 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1404 end:
1405 LeaveCriticalSection(&printer_handles_cs);
1406 return ret;
1409 /*****************************************************************************
1410 * AddFormA [WINSPOOL.@]
1412 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1414 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1415 return 1;
1418 /*****************************************************************************
1419 * AddFormW [WINSPOOL.@]
1421 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1423 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1424 return 1;
1427 /*****************************************************************************
1428 * AddJobA [WINSPOOL.@]
1430 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1432 BOOL ret;
1433 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1434 DWORD needed;
1436 if(Level != 1) {
1437 SetLastError(ERROR_INVALID_LEVEL);
1438 return FALSE;
1441 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1443 if(ret) {
1444 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1445 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1446 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1447 if(*pcbNeeded > cbBuf) {
1448 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1449 ret = FALSE;
1450 } else {
1451 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1452 addjobA->JobId = addjobW->JobId;
1453 addjobA->Path = (char *)(addjobA + 1);
1454 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1457 return ret;
1460 /*****************************************************************************
1461 * AddJobW [WINSPOOL.@]
1463 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1465 opened_printer_t *printer;
1466 job_t *job;
1467 BOOL ret = FALSE;
1468 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1469 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1470 WCHAR path[MAX_PATH], filename[MAX_PATH];
1471 DWORD len;
1472 ADDJOB_INFO_1W *addjob;
1474 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1476 EnterCriticalSection(&printer_handles_cs);
1478 printer = get_opened_printer(hPrinter);
1480 if(!printer) {
1481 SetLastError(ERROR_INVALID_HANDLE);
1482 goto end;
1485 if(Level != 1) {
1486 SetLastError(ERROR_INVALID_LEVEL);
1487 goto end;
1490 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1491 if(!job)
1492 goto end;
1494 job->job_id = InterlockedIncrement(&next_job_id);
1496 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1497 if(path[len - 1] != '\\')
1498 path[len++] = '\\';
1499 memcpy(path + len, spool_path, sizeof(spool_path));
1500 sprintfW(filename, fmtW, path, job->job_id);
1502 len = strlenW(filename);
1503 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1504 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1505 job->document_title = strdupW(default_doc_title);
1506 list_add_tail(&printer->queue->jobs, &job->entry);
1508 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1509 if(*pcbNeeded <= cbBuf) {
1510 addjob = (ADDJOB_INFO_1W*)pData;
1511 addjob->JobId = job->job_id;
1512 addjob->Path = (WCHAR *)(addjob + 1);
1513 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1514 ret = TRUE;
1515 } else
1516 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1518 end:
1519 LeaveCriticalSection(&printer_handles_cs);
1520 return ret;
1523 /*****************************************************************************
1524 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1526 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1527 DWORD level, LPBYTE Info,
1528 DWORD cbBuf, LPDWORD needed)
1530 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1531 level, Info, cbBuf);
1532 return 0;
1535 /*****************************************************************************
1536 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1538 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1539 DWORD level, LPBYTE Info,
1540 DWORD cbBuf, LPDWORD needed)
1542 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1543 level, Info, cbBuf);
1544 return 0;
1547 /*****************************************************************************
1548 * WINSPOOL_OpenDriverReg [internal]
1550 * opens the registry for the printer drivers depending on the given input
1551 * variable pEnvironment
1553 * RETURNS:
1554 * the opened hkey on success
1555 * NULL on error
1557 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1559 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1560 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1561 HKEY retval;
1562 LPWSTR lpKey, buffer = NULL;
1563 LPCWSTR pEnvW;
1565 TRACE("%s\n",
1566 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1568 if(pEnvironment) {
1569 if (unicode) {
1570 pEnvW = pEnvironment;
1571 } else {
1572 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1573 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1574 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1575 pEnvW = buffer;
1577 } else {
1578 OSVERSIONINFOW ver;
1579 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1581 if(!GetVersionExW( &ver))
1582 return 0;
1584 switch (ver.dwPlatformId) {
1585 case VER_PLATFORM_WIN32s:
1586 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1587 return 0;
1588 case VER_PLATFORM_WIN32_NT:
1589 pEnvW = WinNTW;
1590 break;
1591 default:
1592 pEnvW = Win40W;
1593 break;
1595 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1598 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1599 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1600 wsprintfW( lpKey, DriversW, pEnvW);
1602 TRACE("%s\n", debugstr_w(lpKey));
1604 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1605 retval = 0;
1607 HeapFree( GetProcessHeap(), 0, buffer);
1608 HeapFree( GetProcessHeap(), 0, lpKey);
1610 return retval;
1613 /*****************************************************************************
1614 * AddPrinterW [WINSPOOL.@]
1616 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1618 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1619 LPDEVMODEA dmA;
1620 LPDEVMODEW dmW;
1621 HANDLE retval;
1622 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1623 LONG size;
1625 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1627 if(pName != NULL) {
1628 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1629 SetLastError(ERROR_INVALID_PARAMETER);
1630 return 0;
1632 if(Level != 2) {
1633 ERR("Level = %ld, unsupported!\n", Level);
1634 SetLastError(ERROR_INVALID_LEVEL);
1635 return 0;
1637 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1638 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1639 debugstr_w(pi->pPrinterName)
1641 SetLastError(ERROR_INVALID_LEVEL);
1642 return 0;
1644 if(!pPrinter) {
1645 SetLastError(ERROR_INVALID_PARAMETER);
1646 return 0;
1648 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1649 ERROR_SUCCESS) {
1650 ERR("Can't create Printers key\n");
1651 return 0;
1653 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1654 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1655 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1656 RegCloseKey(hkeyPrinter);
1657 RegCloseKey(hkeyPrinters);
1658 return 0;
1660 RegCloseKey(hkeyPrinter);
1662 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1663 if(!hkeyDrivers) {
1664 ERR("Can't create Drivers key\n");
1665 RegCloseKey(hkeyPrinters);
1666 return 0;
1668 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1669 ERROR_SUCCESS) {
1670 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1671 RegCloseKey(hkeyPrinters);
1672 RegCloseKey(hkeyDrivers);
1673 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1674 return 0;
1676 RegCloseKey(hkeyDriver);
1677 RegCloseKey(hkeyDrivers);
1679 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1680 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1681 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1682 RegCloseKey(hkeyPrinters);
1683 return 0;
1686 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1687 ERROR_SUCCESS) {
1688 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1689 SetLastError(ERROR_INVALID_PRINTER_NAME);
1690 RegCloseKey(hkeyPrinters);
1691 return 0;
1693 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1694 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1695 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1697 /* See if we can load the driver. We may need the devmode structure anyway
1699 * FIXME:
1700 * Note that DocumentPropertiesW will briefly try to open the printer we
1701 * just create to find a DEVMODEA struct (it will use the WINEPS default
1702 * one in case it is not there, so we are ok).
1704 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1706 if(size < 0) {
1707 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1708 size = sizeof(DEVMODEW);
1710 if(pi->pDevMode)
1711 dmW = pi->pDevMode;
1712 else
1714 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1715 ZeroMemory(dmW,size);
1716 dmW->dmSize = size;
1717 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1719 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1720 HeapFree(GetProcessHeap(),0,dmW);
1721 dmW=NULL;
1723 else
1725 /* set devmode to printer name */
1726 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1730 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1731 and we support these drivers. NT writes DEVMODEW so somehow
1732 we'll need to distinguish between these when we support NT
1733 drivers */
1734 if (dmW)
1736 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1737 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1738 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1739 HeapFree(GetProcessHeap(), 0, dmA);
1740 if(!pi->pDevMode)
1741 HeapFree(GetProcessHeap(), 0, dmW);
1743 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1744 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1745 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1746 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1748 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1749 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1750 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1751 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1752 (LPBYTE)&pi->Priority, sizeof(DWORD));
1753 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1754 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1755 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1756 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1757 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1758 (LPBYTE)&pi->Status, sizeof(DWORD));
1759 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1760 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1762 RegCloseKey(hkeyPrinter);
1763 RegCloseKey(hkeyPrinters);
1764 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1765 ERR("OpenPrinter failing\n");
1766 return 0;
1768 return retval;
1771 /*****************************************************************************
1772 * AddPrinterA [WINSPOOL.@]
1774 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1776 UNICODE_STRING pNameW;
1777 PWSTR pwstrNameW;
1778 PRINTER_INFO_2W *piW;
1779 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1780 HANDLE ret;
1782 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1783 if(Level != 2) {
1784 ERR("Level = %ld, unsupported!\n", Level);
1785 SetLastError(ERROR_INVALID_LEVEL);
1786 return 0;
1788 pwstrNameW = asciitounicode(&pNameW,pName);
1789 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1791 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1793 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1794 RtlFreeUnicodeString(&pNameW);
1795 return ret;
1799 /*****************************************************************************
1800 * ClosePrinter [WINSPOOL.@]
1802 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1804 UINT_PTR i = (UINT_PTR)hPrinter;
1805 opened_printer_t *printer = NULL;
1806 BOOL ret = FALSE;
1808 TRACE("Handle %p\n", hPrinter);
1810 EnterCriticalSection(&printer_handles_cs);
1812 if ((i > 0) && (i <= nb_printer_handles))
1813 printer = printer_handles[i - 1];
1815 if(printer)
1817 struct list *cursor, *cursor2;
1819 if(printer->doc)
1820 EndDocPrinter(hPrinter);
1822 if(InterlockedDecrement(&printer->queue->ref) == 0)
1824 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
1826 job_t *job = LIST_ENTRY(cursor, job_t, entry);
1827 ScheduleJob(hPrinter, job->job_id);
1829 HeapFree(GetProcessHeap(), 0, printer->queue);
1831 HeapFree(GetProcessHeap(), 0, printer->name);
1832 HeapFree(GetProcessHeap(), 0, printer);
1833 printer_handles[i - 1] = NULL;
1834 ret = TRUE;
1836 LeaveCriticalSection(&printer_handles_cs);
1837 return ret;
1840 /*****************************************************************************
1841 * DeleteFormA [WINSPOOL.@]
1843 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1845 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1846 return 1;
1849 /*****************************************************************************
1850 * DeleteFormW [WINSPOOL.@]
1852 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1854 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1855 return 1;
1858 /*****************************************************************************
1859 * WINSPOOL_SHRegDeleteKey
1861 * Recursively delete subkeys.
1862 * Cut & paste from shlwapi.
1865 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1867 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1868 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1869 HKEY hSubKey = 0;
1871 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1872 if(!dwRet)
1874 /* Find how many subkeys there are */
1875 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1876 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1877 if(!dwRet)
1879 dwMaxSubkeyLen++;
1880 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1881 /* Name too big: alloc a buffer for it */
1882 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1884 if(!lpszName)
1885 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1886 else
1888 /* Recursively delete all the subkeys */
1889 for(i = 0; i < dwKeyCount && !dwRet; i++)
1891 dwSize = dwMaxSubkeyLen;
1892 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1893 if(!dwRet)
1894 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1897 if (lpszName != szNameBuf)
1898 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1902 RegCloseKey(hSubKey);
1903 if(!dwRet)
1904 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1906 return dwRet;
1909 /*****************************************************************************
1910 * DeletePrinter [WINSPOOL.@]
1912 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1914 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1915 HKEY hkeyPrinters, hkey;
1917 if(!lpNameW) {
1918 SetLastError(ERROR_INVALID_HANDLE);
1919 return FALSE;
1921 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1922 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1923 RegCloseKey(hkeyPrinters);
1925 WriteProfileStringW(devicesW, lpNameW, NULL);
1926 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1927 RegDeleteValueW(hkey, lpNameW);
1928 RegCloseKey(hkey);
1930 return TRUE;
1933 /*****************************************************************************
1934 * SetPrinterA [WINSPOOL.@]
1936 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1937 DWORD Command)
1939 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1940 return FALSE;
1943 /*****************************************************************************
1944 * SetJobA [WINSPOOL.@]
1946 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1947 LPBYTE pJob, DWORD Command)
1949 BOOL ret;
1950 LPBYTE JobW;
1951 UNICODE_STRING usBuffer;
1953 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
1955 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1956 are all ignored by SetJob, so we don't bother copying them */
1957 switch(Level)
1959 case 0:
1960 JobW = NULL;
1961 break;
1962 case 1:
1964 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
1965 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
1967 JobW = (LPBYTE)info1W;
1968 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
1969 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
1970 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
1971 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
1972 info1W->Status = info1A->Status;
1973 info1W->Priority = info1A->Priority;
1974 info1W->Position = info1A->Position;
1975 info1W->PagesPrinted = info1A->PagesPrinted;
1976 break;
1978 case 2:
1980 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
1981 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
1983 JobW = (LPBYTE)info2W;
1984 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
1985 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
1986 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
1987 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
1988 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
1989 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
1990 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
1991 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
1992 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
1993 info2W->Status = info2A->Status;
1994 info2W->Priority = info2A->Priority;
1995 info2W->Position = info2A->Position;
1996 info2W->StartTime = info2A->StartTime;
1997 info2W->UntilTime = info2A->UntilTime;
1998 info2W->PagesPrinted = info2A->PagesPrinted;
1999 break;
2001 case 3:
2002 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2003 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2004 break;
2005 default:
2006 SetLastError(ERROR_INVALID_LEVEL);
2007 return FALSE;
2010 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2012 switch(Level)
2014 case 1:
2016 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2017 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2018 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2019 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2020 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2021 break;
2023 case 2:
2025 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2026 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2027 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2028 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2029 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2030 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2031 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2032 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2033 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2034 break;
2037 HeapFree(GetProcessHeap(), 0, JobW);
2039 return ret;
2042 /*****************************************************************************
2043 * SetJobW [WINSPOOL.@]
2045 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2046 LPBYTE pJob, DWORD Command)
2048 BOOL ret = FALSE;
2049 job_t *job;
2051 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2052 FIXME("Ignoring everything other than document title\n");
2054 EnterCriticalSection(&printer_handles_cs);
2055 job = get_job(hPrinter, JobId);
2056 if(!job)
2057 goto end;
2059 switch(Level)
2061 case 0:
2062 break;
2063 case 1:
2065 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2066 HeapFree(GetProcessHeap(), 0, job->document_title);
2067 job->document_title = strdupW(info1->pDocument);
2068 break;
2070 case 2:
2072 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2073 HeapFree(GetProcessHeap(), 0, job->document_title);
2074 job->document_title = strdupW(info2->pDocument);
2075 break;
2077 case 3:
2078 break;
2079 default:
2080 SetLastError(ERROR_INVALID_LEVEL);
2081 goto end;
2083 ret = TRUE;
2084 end:
2085 LeaveCriticalSection(&printer_handles_cs);
2086 return ret;
2089 /*****************************************************************************
2090 * EndDocPrinter [WINSPOOL.@]
2092 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2094 opened_printer_t *printer;
2095 BOOL ret = FALSE;
2096 TRACE("(%p)\n", hPrinter);
2098 EnterCriticalSection(&printer_handles_cs);
2100 printer = get_opened_printer(hPrinter);
2101 if(!printer)
2103 SetLastError(ERROR_INVALID_HANDLE);
2104 goto end;
2107 if(!printer->doc)
2109 SetLastError(ERROR_SPL_NO_STARTDOC);
2110 goto end;
2113 CloseHandle(printer->doc->hf);
2114 ScheduleJob(hPrinter, printer->doc->job_id);
2115 HeapFree(GetProcessHeap(), 0, printer->doc);
2116 printer->doc = NULL;
2117 ret = TRUE;
2118 end:
2119 LeaveCriticalSection(&printer_handles_cs);
2120 return ret;
2123 /*****************************************************************************
2124 * EndPagePrinter [WINSPOOL.@]
2126 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2128 FIXME("(%p): stub\n", hPrinter);
2129 return TRUE;
2132 /*****************************************************************************
2133 * StartDocPrinterA [WINSPOOL.@]
2135 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2137 UNICODE_STRING usBuffer;
2138 DOC_INFO_2W doc2W;
2139 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2140 DWORD ret;
2142 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2143 or one (DOC_INFO_3) extra DWORDs */
2145 switch(Level) {
2146 case 2:
2147 doc2W.JobId = doc2->JobId;
2148 /* fall through */
2149 case 3:
2150 doc2W.dwMode = doc2->dwMode;
2151 /* fall through */
2152 case 1:
2153 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2154 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2155 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2156 break;
2158 default:
2159 SetLastError(ERROR_INVALID_LEVEL);
2160 return FALSE;
2163 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2165 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2166 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2167 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2169 return ret;
2172 /*****************************************************************************
2173 * StartDocPrinterW [WINSPOOL.@]
2175 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2177 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2178 opened_printer_t *printer;
2179 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2180 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2181 JOB_INFO_1W job_info;
2182 DWORD needed, ret = 0;
2183 HANDLE hf;
2184 WCHAR *filename;
2186 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2187 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2188 debugstr_w(doc->pDatatype));
2190 if(Level < 1 || Level > 3)
2192 SetLastError(ERROR_INVALID_LEVEL);
2193 return 0;
2196 EnterCriticalSection(&printer_handles_cs);
2197 printer = get_opened_printer(hPrinter);
2198 if(!printer)
2200 SetLastError(ERROR_INVALID_HANDLE);
2201 goto end;
2204 if(printer->doc)
2206 SetLastError(ERROR_INVALID_PRINTER_STATE);
2207 goto end;
2210 /* Even if we're printing to a file we still add a print job, we'll
2211 just ignore the spool file name */
2213 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2215 ERR("AddJob failed gle %08lx\n", GetLastError());
2216 goto end;
2219 if(doc->pOutputFile)
2220 filename = doc->pOutputFile;
2221 else
2222 filename = addjob->Path;
2224 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2225 if(hf == INVALID_HANDLE_VALUE)
2226 goto end;
2228 memset(&job_info, 0, sizeof(job_info));
2229 job_info.pDocument = doc->pDocName;
2230 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2232 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2233 printer->doc->hf = hf;
2234 ret = printer->doc->job_id = addjob->JobId;
2235 end:
2236 LeaveCriticalSection(&printer_handles_cs);
2238 return ret;
2241 /*****************************************************************************
2242 * StartPagePrinter [WINSPOOL.@]
2244 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2246 FIXME("(%p): stub\n", hPrinter);
2247 return TRUE;
2250 /*****************************************************************************
2251 * GetFormA [WINSPOOL.@]
2253 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2254 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2256 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2257 Level,pForm,cbBuf,pcbNeeded);
2258 return FALSE;
2261 /*****************************************************************************
2262 * GetFormW [WINSPOOL.@]
2264 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2265 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2267 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2268 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2269 return FALSE;
2272 /*****************************************************************************
2273 * SetFormA [WINSPOOL.@]
2275 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2276 LPBYTE pForm)
2278 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2279 return FALSE;
2282 /*****************************************************************************
2283 * SetFormW [WINSPOOL.@]
2285 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2286 LPBYTE pForm)
2288 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2289 return FALSE;
2292 /*****************************************************************************
2293 * ReadPrinter [WINSPOOL.@]
2295 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2296 LPDWORD pNoBytesRead)
2298 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2299 return FALSE;
2302 /*****************************************************************************
2303 * ResetPrinterA [WINSPOOL.@]
2305 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2307 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2308 return FALSE;
2311 /*****************************************************************************
2312 * ResetPrinterW [WINSPOOL.@]
2314 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2316 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2317 return FALSE;
2320 /*****************************************************************************
2321 * WINSPOOL_GetDWORDFromReg
2323 * Return DWORD associated with ValueName from hkey.
2325 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2327 DWORD sz = sizeof(DWORD), type, value = 0;
2328 LONG ret;
2330 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2332 if(ret != ERROR_SUCCESS) {
2333 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2334 return 0;
2336 if(type != REG_DWORD) {
2337 ERR("Got type %ld\n", type);
2338 return 0;
2340 return value;
2343 /*****************************************************************************
2344 * WINSPOOL_GetStringFromReg
2346 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2347 * String is stored either as unicode or ascii.
2348 * Bit of a hack here to get the ValueName if we want ascii.
2350 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2351 DWORD buflen, DWORD *needed,
2352 BOOL unicode)
2354 DWORD sz = buflen, type;
2355 LONG ret;
2357 if(unicode)
2358 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2359 else {
2360 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2361 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2362 HeapFree(GetProcessHeap(),0,ValueNameA);
2364 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2365 WARN("Got ret = %ld\n", ret);
2366 *needed = 0;
2367 return FALSE;
2369 *needed = sz;
2370 return TRUE;
2373 /*****************************************************************************
2374 * WINSPOOL_GetDefaultDevMode
2376 * Get a default DevMode values for wineps.
2377 * FIXME - use ppd.
2380 static void WINSPOOL_GetDefaultDevMode(
2381 LPBYTE ptr,
2382 DWORD buflen, DWORD *needed,
2383 BOOL unicode)
2385 DEVMODEA dm;
2386 static const char szwps[] = "wineps.drv";
2388 /* fill default DEVMODE - should be read from ppd... */
2389 ZeroMemory( &dm, sizeof(dm) );
2390 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2391 dm.dmSpecVersion = DM_SPECVERSION;
2392 dm.dmDriverVersion = 1;
2393 dm.dmSize = sizeof(DEVMODEA);
2394 dm.dmDriverExtra = 0;
2395 dm.dmFields =
2396 DM_ORIENTATION | DM_PAPERSIZE |
2397 DM_PAPERLENGTH | DM_PAPERWIDTH |
2398 DM_SCALE |
2399 DM_COPIES |
2400 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2401 DM_YRESOLUTION | DM_TTOPTION;
2403 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2404 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2405 dm.u1.s1.dmPaperLength = 2970;
2406 dm.u1.s1.dmPaperWidth = 2100;
2408 dm.dmScale = 100;
2409 dm.dmCopies = 1;
2410 dm.dmDefaultSource = DMBIN_AUTO;
2411 dm.dmPrintQuality = DMRES_MEDIUM;
2412 /* dm.dmColor */
2413 /* dm.dmDuplex */
2414 dm.dmYResolution = 300; /* 300dpi */
2415 dm.dmTTOption = DMTT_BITMAP;
2416 /* dm.dmCollate */
2417 /* dm.dmFormName */
2418 /* dm.dmLogPixels */
2419 /* dm.dmBitsPerPel */
2420 /* dm.dmPelsWidth */
2421 /* dm.dmPelsHeight */
2422 /* dm.dmDisplayFlags */
2423 /* dm.dmDisplayFrequency */
2424 /* dm.dmICMMethod */
2425 /* dm.dmICMIntent */
2426 /* dm.dmMediaType */
2427 /* dm.dmDitherType */
2428 /* dm.dmReserved1 */
2429 /* dm.dmReserved2 */
2430 /* dm.dmPanningWidth */
2431 /* dm.dmPanningHeight */
2433 if(unicode) {
2434 if(buflen >= sizeof(DEVMODEW)) {
2435 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2436 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2437 HeapFree(GetProcessHeap(),0,pdmW);
2439 *needed = sizeof(DEVMODEW);
2441 else
2443 if(buflen >= sizeof(DEVMODEA)) {
2444 memcpy(ptr, &dm, sizeof(DEVMODEA));
2446 *needed = sizeof(DEVMODEA);
2450 /*****************************************************************************
2451 * WINSPOOL_GetDevModeFromReg
2453 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2454 * DevMode is stored either as unicode or ascii.
2456 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2457 LPBYTE ptr,
2458 DWORD buflen, DWORD *needed,
2459 BOOL unicode)
2461 DWORD sz = buflen, type;
2462 LONG ret;
2464 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2465 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2466 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2467 if (sz < sizeof(DEVMODEA))
2469 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2470 return FALSE;
2472 /* ensures that dmSize is not erratically bogus if registry is invalid */
2473 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2474 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2475 if(unicode) {
2476 sz += (CCHDEVICENAME + CCHFORMNAME);
2477 if(buflen >= sz) {
2478 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2479 memcpy(ptr, dmW, sz);
2480 HeapFree(GetProcessHeap(),0,dmW);
2483 *needed = sz;
2484 return TRUE;
2487 /*********************************************************************
2488 * WINSPOOL_GetPrinter_2
2490 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2491 * The strings are either stored as unicode or ascii.
2493 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2494 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2495 BOOL unicode)
2497 DWORD size, left = cbBuf;
2498 BOOL space = (cbBuf > 0);
2499 LPBYTE ptr = buf;
2501 *pcbNeeded = 0;
2503 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2504 unicode)) {
2505 if(space && size <= left) {
2506 pi2->pPrinterName = (LPWSTR)ptr;
2507 ptr += size;
2508 left -= size;
2509 } else
2510 space = FALSE;
2511 *pcbNeeded += size;
2513 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2514 unicode)) {
2515 if(space && size <= left) {
2516 pi2->pShareName = (LPWSTR)ptr;
2517 ptr += size;
2518 left -= size;
2519 } else
2520 space = FALSE;
2521 *pcbNeeded += size;
2523 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2524 unicode)) {
2525 if(space && size <= left) {
2526 pi2->pPortName = (LPWSTR)ptr;
2527 ptr += size;
2528 left -= size;
2529 } else
2530 space = FALSE;
2531 *pcbNeeded += size;
2533 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2534 &size, unicode)) {
2535 if(space && size <= left) {
2536 pi2->pDriverName = (LPWSTR)ptr;
2537 ptr += size;
2538 left -= size;
2539 } else
2540 space = FALSE;
2541 *pcbNeeded += size;
2543 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2544 unicode)) {
2545 if(space && size <= left) {
2546 pi2->pComment = (LPWSTR)ptr;
2547 ptr += size;
2548 left -= size;
2549 } else
2550 space = FALSE;
2551 *pcbNeeded += size;
2553 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2554 unicode)) {
2555 if(space && size <= left) {
2556 pi2->pLocation = (LPWSTR)ptr;
2557 ptr += size;
2558 left -= size;
2559 } else
2560 space = FALSE;
2561 *pcbNeeded += size;
2563 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2564 &size, unicode)) {
2565 if(space && size <= left) {
2566 pi2->pDevMode = (LPDEVMODEW)ptr;
2567 ptr += size;
2568 left -= size;
2569 } else
2570 space = FALSE;
2571 *pcbNeeded += size;
2573 else
2575 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2576 if(space && size <= left) {
2577 pi2->pDevMode = (LPDEVMODEW)ptr;
2578 ptr += size;
2579 left -= size;
2580 } else
2581 space = FALSE;
2582 *pcbNeeded += size;
2584 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2585 &size, unicode)) {
2586 if(space && size <= left) {
2587 pi2->pSepFile = (LPWSTR)ptr;
2588 ptr += size;
2589 left -= size;
2590 } else
2591 space = FALSE;
2592 *pcbNeeded += size;
2594 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2595 &size, unicode)) {
2596 if(space && size <= left) {
2597 pi2->pPrintProcessor = (LPWSTR)ptr;
2598 ptr += size;
2599 left -= size;
2600 } else
2601 space = FALSE;
2602 *pcbNeeded += size;
2604 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2605 &size, unicode)) {
2606 if(space && size <= left) {
2607 pi2->pDatatype = (LPWSTR)ptr;
2608 ptr += size;
2609 left -= size;
2610 } else
2611 space = FALSE;
2612 *pcbNeeded += size;
2614 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2615 &size, unicode)) {
2616 if(space && size <= left) {
2617 pi2->pParameters = (LPWSTR)ptr;
2618 ptr += size;
2619 left -= size;
2620 } else
2621 space = FALSE;
2622 *pcbNeeded += size;
2624 if(pi2) {
2625 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2626 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2627 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2628 "Default Priority");
2629 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2630 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2633 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2634 memset(pi2, 0, sizeof(*pi2));
2636 return space;
2639 /*********************************************************************
2640 * WINSPOOL_GetPrinter_4
2642 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2644 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2645 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2646 BOOL unicode)
2648 DWORD size, left = cbBuf;
2649 BOOL space = (cbBuf > 0);
2650 LPBYTE ptr = buf;
2652 *pcbNeeded = 0;
2654 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2655 unicode)) {
2656 if(space && size <= left) {
2657 pi4->pPrinterName = (LPWSTR)ptr;
2658 ptr += size;
2659 left -= size;
2660 } else
2661 space = FALSE;
2662 *pcbNeeded += size;
2664 if(pi4) {
2665 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2668 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2669 memset(pi4, 0, sizeof(*pi4));
2671 return space;
2674 /*********************************************************************
2675 * WINSPOOL_GetPrinter_5
2677 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2679 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2680 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2681 BOOL unicode)
2683 DWORD size, left = cbBuf;
2684 BOOL space = (cbBuf > 0);
2685 LPBYTE ptr = buf;
2687 *pcbNeeded = 0;
2689 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2690 unicode)) {
2691 if(space && size <= left) {
2692 pi5->pPrinterName = (LPWSTR)ptr;
2693 ptr += size;
2694 left -= size;
2695 } else
2696 space = FALSE;
2697 *pcbNeeded += size;
2699 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2700 unicode)) {
2701 if(space && size <= left) {
2702 pi5->pPortName = (LPWSTR)ptr;
2703 ptr += size;
2704 left -= size;
2705 } else
2706 space = FALSE;
2707 *pcbNeeded += size;
2709 if(pi5) {
2710 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2711 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2712 "dnsTimeout");
2713 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2714 "txTimeout");
2717 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2718 memset(pi5, 0, sizeof(*pi5));
2720 return space;
2723 /*****************************************************************************
2724 * WINSPOOL_GetPrinter
2726 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2727 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2728 * just a collection of pointers to strings.
2730 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2731 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2733 LPCWSTR name;
2734 DWORD size, needed = 0;
2735 LPBYTE ptr = NULL;
2736 HKEY hkeyPrinter, hkeyPrinters;
2737 BOOL ret;
2739 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2741 if (!(name = get_opened_printer_name(hPrinter))) {
2742 SetLastError(ERROR_INVALID_HANDLE);
2743 return FALSE;
2746 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2747 ERROR_SUCCESS) {
2748 ERR("Can't create Printers key\n");
2749 return FALSE;
2751 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2753 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2754 RegCloseKey(hkeyPrinters);
2755 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2756 return FALSE;
2759 switch(Level) {
2760 case 2:
2762 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2764 size = sizeof(PRINTER_INFO_2W);
2765 if(size <= cbBuf) {
2766 ptr = pPrinter + size;
2767 cbBuf -= size;
2768 memset(pPrinter, 0, size);
2769 } else {
2770 pi2 = NULL;
2771 cbBuf = 0;
2773 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2774 unicode);
2775 needed += size;
2776 break;
2779 case 4:
2781 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2783 size = sizeof(PRINTER_INFO_4W);
2784 if(size <= cbBuf) {
2785 ptr = pPrinter + size;
2786 cbBuf -= size;
2787 memset(pPrinter, 0, size);
2788 } else {
2789 pi4 = NULL;
2790 cbBuf = 0;
2792 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2793 unicode);
2794 needed += size;
2795 break;
2799 case 5:
2801 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2803 size = sizeof(PRINTER_INFO_5W);
2804 if(size <= cbBuf) {
2805 ptr = pPrinter + size;
2806 cbBuf -= size;
2807 memset(pPrinter, 0, size);
2808 } else {
2809 pi5 = NULL;
2810 cbBuf = 0;
2813 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2814 unicode);
2815 needed += size;
2816 break;
2819 default:
2820 FIXME("Unimplemented level %ld\n", Level);
2821 SetLastError(ERROR_INVALID_LEVEL);
2822 RegCloseKey(hkeyPrinters);
2823 RegCloseKey(hkeyPrinter);
2824 return FALSE;
2827 RegCloseKey(hkeyPrinter);
2828 RegCloseKey(hkeyPrinters);
2830 TRACE("returning %d needed = %ld\n", ret, needed);
2831 if(pcbNeeded) *pcbNeeded = needed;
2832 if(!ret)
2833 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2834 return ret;
2837 /*****************************************************************************
2838 * GetPrinterW [WINSPOOL.@]
2840 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2841 DWORD cbBuf, LPDWORD pcbNeeded)
2843 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2844 TRUE);
2847 /*****************************************************************************
2848 * GetPrinterA [WINSPOOL.@]
2850 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2851 DWORD cbBuf, LPDWORD pcbNeeded)
2853 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2854 FALSE);
2857 /*****************************************************************************
2858 * WINSPOOL_EnumPrinters
2860 * Implementation of EnumPrintersA|W
2862 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2863 DWORD dwLevel, LPBYTE lpbPrinters,
2864 DWORD cbBuf, LPDWORD lpdwNeeded,
2865 LPDWORD lpdwReturned, BOOL unicode)
2868 HKEY hkeyPrinters, hkeyPrinter;
2869 WCHAR PrinterName[255];
2870 DWORD needed = 0, number = 0;
2871 DWORD used, i, left;
2872 PBYTE pi, buf;
2874 if(lpbPrinters)
2875 memset(lpbPrinters, 0, cbBuf);
2876 if(lpdwReturned)
2877 *lpdwReturned = 0;
2878 if(lpdwNeeded)
2879 *lpdwNeeded = 0;
2881 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2882 if(dwType == PRINTER_ENUM_DEFAULT)
2883 return TRUE;
2885 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2886 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2887 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2888 if(!dwType) return TRUE;
2891 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2892 FIXME("dwType = %08lx\n", dwType);
2893 SetLastError(ERROR_INVALID_FLAGS);
2894 return FALSE;
2897 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2898 ERROR_SUCCESS) {
2899 ERR("Can't create Printers key\n");
2900 return FALSE;
2903 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2904 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2905 RegCloseKey(hkeyPrinters);
2906 ERR("Can't query Printers key\n");
2907 return FALSE;
2909 TRACE("Found %ld printers\n", number);
2911 switch(dwLevel) {
2912 case 1:
2913 RegCloseKey(hkeyPrinters);
2914 if (lpdwReturned)
2915 *lpdwReturned = number;
2916 return TRUE;
2918 case 2:
2919 used = number * sizeof(PRINTER_INFO_2W);
2920 break;
2921 case 4:
2922 used = number * sizeof(PRINTER_INFO_4W);
2923 break;
2924 case 5:
2925 used = number * sizeof(PRINTER_INFO_5W);
2926 break;
2928 default:
2929 SetLastError(ERROR_INVALID_LEVEL);
2930 RegCloseKey(hkeyPrinters);
2931 return FALSE;
2933 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2935 for(i = 0; i < number; i++) {
2936 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2937 ERROR_SUCCESS) {
2938 ERR("Can't enum key number %ld\n", i);
2939 RegCloseKey(hkeyPrinters);
2940 return FALSE;
2942 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2943 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2944 ERROR_SUCCESS) {
2945 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2946 RegCloseKey(hkeyPrinters);
2947 return FALSE;
2950 if(cbBuf > used) {
2951 buf = lpbPrinters + used;
2952 left = cbBuf - used;
2953 } else {
2954 buf = NULL;
2955 left = 0;
2958 switch(dwLevel) {
2959 case 2:
2960 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2961 left, &needed, unicode);
2962 used += needed;
2963 if(pi) pi += sizeof(PRINTER_INFO_2W);
2964 break;
2965 case 4:
2966 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2967 left, &needed, unicode);
2968 used += needed;
2969 if(pi) pi += sizeof(PRINTER_INFO_4W);
2970 break;
2971 case 5:
2972 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2973 left, &needed, unicode);
2974 used += needed;
2975 if(pi) pi += sizeof(PRINTER_INFO_5W);
2976 break;
2977 default:
2978 ERR("Shouldn't be here!\n");
2979 RegCloseKey(hkeyPrinter);
2980 RegCloseKey(hkeyPrinters);
2981 return FALSE;
2983 RegCloseKey(hkeyPrinter);
2985 RegCloseKey(hkeyPrinters);
2987 if(lpdwNeeded)
2988 *lpdwNeeded = used;
2990 if(used > cbBuf) {
2991 if(lpbPrinters)
2992 memset(lpbPrinters, 0, cbBuf);
2993 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2994 return FALSE;
2996 if(lpdwReturned)
2997 *lpdwReturned = number;
2998 SetLastError(ERROR_SUCCESS);
2999 return TRUE;
3003 /******************************************************************
3004 * EnumPrintersW [WINSPOOL.@]
3006 * Enumerates the available printers, print servers and print
3007 * providers, depending on the specified flags, name and level.
3009 * RETURNS:
3011 * If level is set to 1:
3012 * Not implemented yet!
3013 * Returns TRUE with an empty list.
3015 * If level is set to 2:
3016 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3017 * Returns an array of PRINTER_INFO_2 data structures in the
3018 * lpbPrinters buffer. Note that according to MSDN also an
3019 * OpenPrinter should be performed on every remote printer.
3021 * If level is set to 4 (officially WinNT only):
3022 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3023 * Fast: Only the registry is queried to retrieve printer names,
3024 * no connection to the driver is made.
3025 * Returns an array of PRINTER_INFO_4 data structures in the
3026 * lpbPrinters buffer.
3028 * If level is set to 5 (officially WinNT4/Win9x only):
3029 * Fast: Only the registry is queried to retrieve printer names,
3030 * no connection to the driver is made.
3031 * Returns an array of PRINTER_INFO_5 data structures in the
3032 * lpbPrinters buffer.
3034 * If level set to 3 or 6+:
3035 * returns zero (failure!)
3037 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3038 * for information.
3040 * BUGS:
3041 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3042 * - Only levels 2, 4 and 5 are implemented at the moment.
3043 * - 16-bit printer drivers are not enumerated.
3044 * - Returned amount of bytes used/needed does not match the real Windoze
3045 * implementation (as in this implementation, all strings are part
3046 * of the buffer, whereas Win32 keeps them somewhere else)
3047 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3049 * NOTE:
3050 * - In a regular Wine installation, no registry settings for printers
3051 * exist, which makes this function return an empty list.
3053 BOOL WINAPI EnumPrintersW(
3054 DWORD dwType, /* [in] Types of print objects to enumerate */
3055 LPWSTR lpszName, /* [in] name of objects to enumerate */
3056 DWORD dwLevel, /* [in] type of printer info structure */
3057 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3058 DWORD cbBuf, /* [in] max size of buffer in bytes */
3059 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3060 LPDWORD lpdwReturned /* [out] number of entries returned */
3063 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3064 lpdwNeeded, lpdwReturned, TRUE);
3067 /******************************************************************
3068 * EnumPrintersA [WINSPOOL.@]
3071 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3072 DWORD dwLevel, LPBYTE lpbPrinters,
3073 DWORD cbBuf, LPDWORD lpdwNeeded,
3074 LPDWORD lpdwReturned)
3076 BOOL ret;
3077 UNICODE_STRING lpszNameW;
3078 PWSTR pwstrNameW;
3080 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3081 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3082 lpdwNeeded, lpdwReturned, FALSE);
3083 RtlFreeUnicodeString(&lpszNameW);
3084 return ret;
3087 /*****************************************************************************
3088 * WINSPOOL_GetDriverInfoFromReg [internal]
3090 * Enters the information from the registry into the DRIVER_INFO struct
3092 * RETURNS
3093 * zero if the printer driver does not exist in the registry
3094 * (only if Level > 1) otherwise nonzero
3096 static BOOL WINSPOOL_GetDriverInfoFromReg(
3097 HKEY hkeyDrivers,
3098 LPWSTR DriverName,
3099 LPWSTR pEnvironment,
3100 DWORD Level,
3101 LPBYTE ptr, /* DRIVER_INFO */
3102 LPBYTE pDriverStrings, /* strings buffer */
3103 DWORD cbBuf, /* size of string buffer */
3104 LPDWORD pcbNeeded, /* space needed for str. */
3105 BOOL unicode) /* type of strings */
3106 { DWORD dw, size, tmp, type;
3107 HKEY hkeyDriver;
3108 LPBYTE strPtr = pDriverStrings;
3110 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3111 debugstr_w(DriverName), debugstr_w(pEnvironment),
3112 Level, ptr, pDriverStrings, cbBuf, unicode);
3114 if(unicode) {
3115 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3116 if (*pcbNeeded <= cbBuf)
3117 strcpyW((LPWSTR)strPtr, DriverName);
3118 } else {
3119 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3120 NULL, NULL);
3121 if(*pcbNeeded <= cbBuf)
3122 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3123 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3125 if(Level == 1) {
3126 if(ptr)
3127 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3128 return TRUE;
3129 } else {
3130 if(ptr)
3131 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
3132 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3135 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3136 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3137 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3138 return FALSE;
3141 size = sizeof(dw);
3142 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
3143 ERROR_SUCCESS)
3144 WARN("Can't get Version\n");
3145 else if(ptr)
3146 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
3148 if(!pEnvironment)
3149 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3150 if(unicode)
3151 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3152 else
3153 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3154 NULL, NULL);
3155 *pcbNeeded += size;
3156 if(*pcbNeeded <= cbBuf) {
3157 if(unicode)
3158 strcpyW((LPWSTR)strPtr, pEnvironment);
3159 else
3160 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3161 (LPSTR)strPtr, size, NULL, NULL);
3162 if(ptr)
3163 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
3164 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3167 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3168 unicode)) {
3169 *pcbNeeded += size;
3170 if(*pcbNeeded <= cbBuf)
3171 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3172 unicode);
3173 if(ptr)
3174 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
3175 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3178 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3179 unicode)) {
3180 *pcbNeeded += size;
3181 if(*pcbNeeded <= cbBuf)
3182 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3183 &tmp, unicode);
3184 if(ptr)
3185 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
3186 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3189 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3190 0, &size, unicode)) {
3191 *pcbNeeded += size;
3192 if(*pcbNeeded <= cbBuf)
3193 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3194 size, &tmp, unicode);
3195 if(ptr)
3196 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
3197 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3200 if(Level == 2 ) {
3201 RegCloseKey(hkeyDriver);
3202 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3203 return TRUE;
3206 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3207 unicode)) {
3208 *pcbNeeded += size;
3209 if(*pcbNeeded <= cbBuf)
3210 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3211 size, &tmp, unicode);
3212 if(ptr)
3213 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3214 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3217 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3218 &size, unicode)) {
3219 *pcbNeeded += size;
3220 if(*pcbNeeded <= cbBuf)
3221 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3222 size, &tmp, unicode);
3223 if(ptr)
3224 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3225 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3228 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3229 unicode)) {
3230 *pcbNeeded += size;
3231 if(*pcbNeeded <= cbBuf)
3232 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3233 size, &tmp, unicode);
3234 if(ptr)
3235 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3236 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3239 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3240 unicode)) {
3241 *pcbNeeded += size;
3242 if(*pcbNeeded <= cbBuf)
3243 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3244 size, &tmp, unicode);
3245 if(ptr)
3246 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3247 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3250 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3251 RegCloseKey(hkeyDriver);
3252 return TRUE;
3255 /*****************************************************************************
3256 * WINSPOOL_GetPrinterDriver
3258 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3259 DWORD Level, LPBYTE pDriverInfo,
3260 DWORD cbBuf, LPDWORD pcbNeeded,
3261 BOOL unicode)
3263 LPCWSTR name;
3264 WCHAR DriverName[100];
3265 DWORD ret, type, size, needed = 0;
3266 LPBYTE ptr = NULL;
3267 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3269 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3270 Level,pDriverInfo,cbBuf, pcbNeeded);
3272 ZeroMemory(pDriverInfo, cbBuf);
3274 if (!(name = get_opened_printer_name(hPrinter))) {
3275 SetLastError(ERROR_INVALID_HANDLE);
3276 return FALSE;
3278 if(Level < 1 || Level > 3) {
3279 SetLastError(ERROR_INVALID_LEVEL);
3280 return FALSE;
3282 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3283 ERROR_SUCCESS) {
3284 ERR("Can't create Printers key\n");
3285 return FALSE;
3287 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3288 != ERROR_SUCCESS) {
3289 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3290 RegCloseKey(hkeyPrinters);
3291 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3292 return FALSE;
3294 size = sizeof(DriverName);
3295 DriverName[0] = 0;
3296 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3297 (LPBYTE)DriverName, &size);
3298 RegCloseKey(hkeyPrinter);
3299 RegCloseKey(hkeyPrinters);
3300 if(ret != ERROR_SUCCESS) {
3301 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3302 return FALSE;
3305 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3306 if(!hkeyDrivers) {
3307 ERR("Can't create Drivers key\n");
3308 return FALSE;
3311 switch(Level) {
3312 case 1:
3313 size = sizeof(DRIVER_INFO_1W);
3314 break;
3315 case 2:
3316 size = sizeof(DRIVER_INFO_2W);
3317 break;
3318 case 3:
3319 size = sizeof(DRIVER_INFO_3W);
3320 break;
3321 default:
3322 ERR("Invalid level\n");
3323 return FALSE;
3326 if(size <= cbBuf)
3327 ptr = pDriverInfo + size;
3329 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3330 pEnvironment, Level, pDriverInfo,
3331 (cbBuf < size) ? NULL : ptr,
3332 (cbBuf < size) ? 0 : cbBuf - size,
3333 &needed, unicode)) {
3334 RegCloseKey(hkeyDrivers);
3335 return FALSE;
3338 RegCloseKey(hkeyDrivers);
3340 if(pcbNeeded) *pcbNeeded = size + needed;
3341 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3342 if(cbBuf >= needed) return TRUE;
3343 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3344 return FALSE;
3347 /*****************************************************************************
3348 * GetPrinterDriverA [WINSPOOL.@]
3350 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3351 DWORD Level, LPBYTE pDriverInfo,
3352 DWORD cbBuf, LPDWORD pcbNeeded)
3354 BOOL ret;
3355 UNICODE_STRING pEnvW;
3356 PWSTR pwstrEnvW;
3358 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3359 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3360 cbBuf, pcbNeeded, FALSE);
3361 RtlFreeUnicodeString(&pEnvW);
3362 return ret;
3364 /*****************************************************************************
3365 * GetPrinterDriverW [WINSPOOL.@]
3367 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3368 DWORD Level, LPBYTE pDriverInfo,
3369 DWORD cbBuf, LPDWORD pcbNeeded)
3371 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3372 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3375 /*****************************************************************************
3376 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3378 * Return the PATH for the Printer-Drivers (UNICODE)
3380 * PARAMS
3381 * pName [I] Servername (NT only) or NULL (local Computer)
3382 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3383 * Level [I] Structure-Level (must be 1)
3384 * pDriverDirectory [O] PTR to Buffer that receives the Result
3385 * cbBuf [I] Size of Buffer at pDriverDirectory
3386 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3387 * required for pDriverDirectory
3389 * RETURNS
3390 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3391 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3392 * if cbBuf is too small
3394 * Native Values returned in pDriverDirectory on Success:
3395 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3396 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3397 *| win9x(Windows 4.0): "%winsysdir%"
3399 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3401 * FIXME
3402 *- pName != NULL not supported
3403 *- pEnvironment != NULL not supported
3404 *- Current Implementation returns always "%winsysdir%"
3407 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3408 DWORD Level, LPBYTE pDriverDirectory,
3409 DWORD cbBuf, LPDWORD pcbNeeded)
3411 DWORD needed;
3412 const printenv_t * env;
3414 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3415 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3416 if(pName != NULL) {
3417 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3418 SetLastError(ERROR_INVALID_PARAMETER);
3419 return FALSE;
3422 env = validate_envW(pEnvironment);
3423 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3425 if(Level != 1) {
3426 WARN("(Level: %ld) is ignored in win9x\n", Level);
3427 SetLastError(ERROR_INVALID_LEVEL);
3428 return FALSE;
3431 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3432 needed = GetSystemDirectoryW(NULL, 0);
3433 /* add the Size for the Subdirectories */
3434 needed += lstrlenW(spooldriversW);
3435 needed += lstrlenW(env->subdir);
3436 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3438 if(pcbNeeded)
3439 *pcbNeeded = needed;
3440 TRACE("required: 0x%lx/%ld\n", needed, needed);
3441 if(needed > cbBuf) {
3442 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3443 return FALSE;
3445 if(pcbNeeded == NULL) {
3446 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3447 SetLastError(RPC_X_NULL_REF_POINTER);
3448 return FALSE;
3450 if(pDriverDirectory == NULL) {
3451 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3452 SetLastError(ERROR_INVALID_USER_BUFFER);
3453 return FALSE;
3456 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3457 /* add the Subdirectories */
3458 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3459 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3460 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3461 return TRUE;
3465 /*****************************************************************************
3466 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3468 * Return the PATH for the Printer-Drivers (ANSI)
3470 * See GetPrinterDriverDirectoryW.
3472 * NOTES
3473 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3476 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3477 DWORD Level, LPBYTE pDriverDirectory,
3478 DWORD cbBuf, LPDWORD pcbNeeded)
3480 UNICODE_STRING nameW, environmentW;
3481 BOOL ret;
3482 DWORD pcbNeededW;
3483 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3484 WCHAR *driverDirectoryW = NULL;
3486 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3487 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3489 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3491 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3492 else nameW.Buffer = NULL;
3493 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3494 else environmentW.Buffer = NULL;
3496 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3497 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3498 if (ret) {
3499 DWORD needed;
3500 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3501 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3502 if(pcbNeeded)
3503 *pcbNeeded = needed;
3504 ret = (needed <= cbBuf) ? TRUE : FALSE;
3505 } else
3506 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3508 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3510 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3511 RtlFreeUnicodeString(&environmentW);
3512 RtlFreeUnicodeString(&nameW);
3514 return ret;
3517 /*****************************************************************************
3518 * AddPrinterDriverA [WINSPOOL.@]
3520 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3522 DRIVER_INFO_3A di3;
3523 HKEY hkeyDrivers, hkeyName;
3525 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3527 if(level != 2 && level != 3) {
3528 SetLastError(ERROR_INVALID_LEVEL);
3529 return FALSE;
3531 if(pName != NULL) {
3532 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3533 SetLastError(ERROR_INVALID_PARAMETER);
3534 return FALSE;
3536 if(!pDriverInfo) {
3537 WARN("pDriverInfo == NULL\n");
3538 SetLastError(ERROR_INVALID_PARAMETER);
3539 return FALSE;
3542 if(level == 3)
3543 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3544 else {
3545 memset(&di3, 0, sizeof(di3));
3546 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3549 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3550 !di3.pDataFile) {
3551 SetLastError(ERROR_INVALID_PARAMETER);
3552 return FALSE;
3554 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3555 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3556 if(!di3.pHelpFile) di3.pHelpFile = "";
3557 if(!di3.pMonitorName) di3.pMonitorName = "";
3559 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3561 if(!hkeyDrivers) {
3562 ERR("Can't create Drivers key\n");
3563 return FALSE;
3566 if(level == 2) { /* apparently can't overwrite with level2 */
3567 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3568 RegCloseKey(hkeyName);
3569 RegCloseKey(hkeyDrivers);
3570 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3571 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3572 return FALSE;
3575 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3576 RegCloseKey(hkeyDrivers);
3577 ERR("Can't create Name key\n");
3578 return FALSE;
3580 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3582 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3583 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3584 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3585 sizeof(DWORD));
3586 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3587 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3588 (LPBYTE) di3.pDependentFiles, 0);
3589 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3590 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3591 RegCloseKey(hkeyName);
3592 RegCloseKey(hkeyDrivers);
3594 return TRUE;
3597 /*****************************************************************************
3598 * AddPrinterDriverW [WINSPOOL.@]
3600 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3601 LPBYTE pDriverInfo)
3603 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3604 level,pDriverInfo);
3605 return FALSE;
3608 /*****************************************************************************
3609 * AddPrintProcessorA [WINSPOOL.@]
3611 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3612 LPSTR pPrintProcessorName)
3614 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3615 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3616 return FALSE;
3619 /*****************************************************************************
3620 * AddPrintProcessorW [WINSPOOL.@]
3622 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3623 LPWSTR pPrintProcessorName)
3625 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3626 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3627 return FALSE;
3630 /*****************************************************************************
3631 * AddPrintProvidorA [WINSPOOL.@]
3633 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3635 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3636 return FALSE;
3639 /*****************************************************************************
3640 * AddPrintProvidorW [WINSPOOL.@]
3642 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3644 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3645 return FALSE;
3648 /*****************************************************************************
3649 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3651 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3652 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3654 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3655 pDevModeOutput, pDevModeInput);
3656 return 0;
3659 /*****************************************************************************
3660 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3662 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3663 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3665 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3666 pDevModeOutput, pDevModeInput);
3667 return 0;
3670 /*****************************************************************************
3671 * PrinterProperties [WINSPOOL.@]
3673 * Displays a dialog to set the properties of the printer.
3675 * RETURNS
3676 * nonzero on success or zero on failure
3678 * BUGS
3679 * implemented as stub only
3681 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3682 HANDLE hPrinter /* [in] handle to printer object */
3684 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3685 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3686 return FALSE;
3689 /*****************************************************************************
3690 * EnumJobsA [WINSPOOL.@]
3693 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3694 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3695 LPDWORD pcReturned)
3697 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3698 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3700 if(pcbNeeded) *pcbNeeded = 0;
3701 if(pcReturned) *pcReturned = 0;
3702 return FALSE;
3706 /*****************************************************************************
3707 * EnumJobsW [WINSPOOL.@]
3710 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3711 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3712 LPDWORD pcReturned)
3714 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3715 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3717 if(pcbNeeded) *pcbNeeded = 0;
3718 if(pcReturned) *pcReturned = 0;
3719 return FALSE;
3722 /*****************************************************************************
3723 * WINSPOOL_EnumPrinterDrivers [internal]
3725 * Delivers information about all printer drivers installed on the
3726 * localhost or a given server
3728 * RETURNS
3729 * nonzero on success or zero on failure. If the buffer for the returned
3730 * information is too small the function will return an error
3732 * BUGS
3733 * - only implemented for localhost, foreign hosts will return an error
3735 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3736 DWORD Level, LPBYTE pDriverInfo,
3737 DWORD cbBuf, LPDWORD pcbNeeded,
3738 LPDWORD pcReturned, BOOL unicode)
3740 { HKEY hkeyDrivers;
3741 DWORD i, needed, number = 0, size = 0;
3742 WCHAR DriverNameW[255];
3743 PBYTE ptr;
3745 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3746 debugstr_w(pName), debugstr_w(pEnvironment),
3747 Level, pDriverInfo, cbBuf, unicode);
3749 /* check for local drivers */
3750 if(pName) {
3751 ERR("remote drivers unsupported! Current remote host is %s\n",
3752 debugstr_w(pName));
3753 return FALSE;
3756 /* check input parameter */
3757 if((Level < 1) || (Level > 3)) {
3758 ERR("unsupported level %ld\n", Level);
3759 SetLastError(ERROR_INVALID_LEVEL);
3760 return FALSE;
3763 /* initialize return values */
3764 if(pDriverInfo)
3765 memset( pDriverInfo, 0, cbBuf);
3766 *pcbNeeded = 0;
3767 *pcReturned = 0;
3769 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3770 if(!hkeyDrivers) {
3771 ERR("Can't open Drivers key\n");
3772 return FALSE;
3775 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3776 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3777 RegCloseKey(hkeyDrivers);
3778 ERR("Can't query Drivers key\n");
3779 return FALSE;
3781 TRACE("Found %ld Drivers\n", number);
3783 /* get size of single struct
3784 * unicode and ascii structure have the same size
3786 switch (Level) {
3787 case 1:
3788 size = sizeof(DRIVER_INFO_1A);
3789 break;
3790 case 2:
3791 size = sizeof(DRIVER_INFO_2A);
3792 break;
3793 case 3:
3794 size = sizeof(DRIVER_INFO_3A);
3795 break;
3798 /* calculate required buffer size */
3799 *pcbNeeded = size * number;
3801 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3802 i < number;
3803 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3804 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3805 != ERROR_SUCCESS) {
3806 ERR("Can't enum key number %ld\n", i);
3807 RegCloseKey(hkeyDrivers);
3808 return FALSE;
3810 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3811 pEnvironment, Level, ptr,
3812 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3813 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3814 &needed, unicode)) {
3815 RegCloseKey(hkeyDrivers);
3816 return FALSE;
3818 (*pcbNeeded) += needed;
3821 RegCloseKey(hkeyDrivers);
3823 if(cbBuf < *pcbNeeded){
3824 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3825 return FALSE;
3828 *pcReturned = number;
3829 return TRUE;
3832 /*****************************************************************************
3833 * EnumPrinterDriversW [WINSPOOL.@]
3835 * see function EnumPrinterDrivers for RETURNS, BUGS
3837 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3838 LPBYTE pDriverInfo, DWORD cbBuf,
3839 LPDWORD pcbNeeded, LPDWORD pcReturned)
3841 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3842 cbBuf, pcbNeeded, pcReturned, TRUE);
3845 /*****************************************************************************
3846 * EnumPrinterDriversA [WINSPOOL.@]
3848 * see function EnumPrinterDrivers for RETURNS, BUGS
3850 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3851 LPBYTE pDriverInfo, DWORD cbBuf,
3852 LPDWORD pcbNeeded, LPDWORD pcReturned)
3853 { BOOL ret;
3854 UNICODE_STRING pNameW, pEnvironmentW;
3855 PWSTR pwstrNameW, pwstrEnvironmentW;
3857 pwstrNameW = asciitounicode(&pNameW, pName);
3858 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3860 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3861 Level, pDriverInfo, cbBuf, pcbNeeded,
3862 pcReturned, FALSE);
3863 RtlFreeUnicodeString(&pNameW);
3864 RtlFreeUnicodeString(&pEnvironmentW);
3866 return ret;
3869 static CHAR PortMonitor[] = "Wine Port Monitor";
3870 static CHAR PortDescription[] = "Wine Port";
3872 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3874 HANDLE handle;
3876 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3877 NULL, OPEN_EXISTING, 0, NULL );
3878 if (handle == INVALID_HANDLE_VALUE)
3879 return FALSE;
3880 TRACE("Checking %s exists\n", name );
3881 CloseHandle( handle );
3882 return TRUE;
3885 static DWORD WINSPOOL_CountSerialPorts(void)
3887 CHAR name[6];
3888 DWORD n = 0, i;
3890 for (i=0; i<4; i++)
3892 strcpy( name, "COMx:" );
3893 name[3] = '1' + i;
3894 if (WINSPOOL_ComPortExists( name ))
3895 n++;
3898 return n;
3901 /******************************************************************************
3902 * EnumPortsA (WINSPOOL.@)
3904 * See EnumPortsW.
3906 * BUGS
3907 * ANSI-Version did not call the UNICODE-Version
3910 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3911 LPDWORD bufneeded,LPDWORD bufreturned)
3913 CHAR portname[10];
3914 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3915 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3916 HKEY hkey_printer;
3917 BOOL retval = TRUE;
3919 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3920 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3922 switch( level )
3924 case 1:
3925 info_size = sizeof (PORT_INFO_1A);
3926 break;
3927 case 2:
3928 info_size = sizeof (PORT_INFO_2A);
3929 break;
3930 default:
3931 SetLastError(ERROR_INVALID_LEVEL);
3932 return FALSE;
3935 /* see how many exist */
3937 hkey_printer = 0;
3938 serial_count = WINSPOOL_CountSerialPorts();
3939 printer_count = 0;
3941 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3942 if ( r == ERROR_SUCCESS )
3944 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3945 &printer_count, NULL, NULL, NULL, NULL);
3947 count = serial_count + printer_count;
3949 /* then fill in the structure info structure once
3950 we know the offset to the first string */
3952 memset( buffer, 0, bufsize );
3953 n = 0;
3954 ofs = info_size*count;
3955 for ( i=0; i<count; i++)
3957 DWORD vallen = sizeof(portname) - 1;
3959 /* get the serial port values, then the printer values */
3960 if ( i < serial_count )
3962 strcpy( portname, "COMx:" );
3963 portname[3] = '1' + i;
3964 if (!WINSPOOL_ComPortExists( portname ))
3965 continue;
3967 TRACE("Found %s\n", portname );
3968 vallen = strlen( portname );
3970 else
3972 r = RegEnumValueA( hkey_printer, i-serial_count,
3973 portname, &vallen, NULL, NULL, NULL, 0 );
3974 if ( r )
3975 continue;
3978 /* add a colon if necessary, and make it upper case */
3979 CharUpperBuffA(portname,vallen);
3980 if (strcasecmp(portname,"nul")!=0)
3981 if (vallen && (portname[vallen-1] != ':') )
3982 lstrcatA(portname,":");
3984 /* add the port info structure if we can fit it */
3985 if ( info_size*(n+1) < bufsize )
3987 if ( level == 1)
3989 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3990 info->pName = (LPSTR) &buffer[ofs];
3992 else if ( level == 2)
3994 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3995 info->pPortName = (LPSTR) &buffer[ofs];
3996 /* FIXME: fill in more stuff here */
3997 info->pMonitorName = PortMonitor;
3998 info->pDescription = PortDescription;
3999 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4002 /* add the name of the port if we can fit it */
4003 if ( ofs < bufsize )
4004 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4006 n++;
4008 else
4009 retval = FALSE;
4010 ofs += lstrlenA(portname)+1;
4013 RegCloseKey(hkey_printer);
4015 if(bufneeded)
4016 *bufneeded = ofs;
4018 if(bufreturned)
4019 *bufreturned = n;
4021 return retval;
4024 /******************************************************************************
4025 * EnumPortsW (WINSPOOL.@)
4027 * Enumerate available Ports
4029 * PARAMS
4030 * name [I] Servername or NULL (local Computer)
4031 * level [I] Structure-Level (1 or 2)
4032 * buffer [O] PTR to Buffer that receives the Result
4033 * bufsize [I] Size of Buffer at buffer
4034 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4035 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4037 * RETURNS
4038 * Success: TRUE
4039 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4041 * BUGS
4042 * UNICODE-Version is a stub
4045 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4046 LPDWORD bufneeded,LPDWORD bufreturned)
4048 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4049 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4050 return FALSE;
4053 /******************************************************************************
4054 * GetDefaultPrinterW (WINSPOOL.@)
4056 * FIXME
4057 * This function must read the value from data 'device' of key
4058 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4060 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4062 BOOL retval = TRUE;
4063 DWORD insize, len;
4064 WCHAR *buffer, *ptr;
4066 if (!namesize)
4068 SetLastError(ERROR_INVALID_PARAMETER);
4069 return FALSE;
4072 /* make the buffer big enough for the stuff from the profile/registry,
4073 * the content must fit into the local buffer to compute the correct
4074 * size even if the extern buffer is too small or not given.
4075 * (20 for ,driver,port) */
4076 insize = *namesize;
4077 len = max(100, (insize + 20));
4078 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4080 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4082 SetLastError (ERROR_FILE_NOT_FOUND);
4083 retval = FALSE;
4084 goto end;
4086 TRACE("%s\n", debugstr_w(buffer));
4088 if ((ptr = strchrW(buffer, ',')) == NULL)
4090 SetLastError(ERROR_INVALID_NAME);
4091 retval = FALSE;
4092 goto end;
4095 *ptr = 0;
4096 *namesize = strlenW(buffer) + 1;
4097 if(!name || (*namesize > insize))
4099 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4100 retval = FALSE;
4101 goto end;
4103 strcpyW(name, buffer);
4105 end:
4106 HeapFree( GetProcessHeap(), 0, buffer);
4107 return retval;
4111 /******************************************************************************
4112 * GetDefaultPrinterA (WINSPOOL.@)
4114 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4116 BOOL retval = TRUE;
4117 DWORD insize = 0;
4118 WCHAR *bufferW = NULL;
4120 if (!namesize)
4122 SetLastError(ERROR_INVALID_PARAMETER);
4123 return FALSE;
4126 if(name && *namesize) {
4127 insize = *namesize;
4128 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4131 if(!GetDefaultPrinterW( bufferW, namesize)) {
4132 retval = FALSE;
4133 goto end;
4136 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4137 NULL, NULL);
4138 if (!*namesize)
4140 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4141 retval = FALSE;
4143 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4145 end:
4146 HeapFree( GetProcessHeap(), 0, bufferW);
4147 return retval;
4151 /******************************************************************************
4152 * SetPrinterDataExA (WINSPOOL.@)
4154 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4155 LPCSTR pValueName, DWORD Type,
4156 LPBYTE pData, DWORD cbData)
4158 HKEY hkeyPrinter, hkeySubkey;
4159 DWORD ret;
4161 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4162 debugstr_a(pValueName), Type, pData, cbData);
4164 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4165 != ERROR_SUCCESS)
4166 return ret;
4168 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4169 != ERROR_SUCCESS) {
4170 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4171 RegCloseKey(hkeyPrinter);
4172 return ret;
4174 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4175 RegCloseKey(hkeySubkey);
4176 RegCloseKey(hkeyPrinter);
4177 return ret;
4180 /******************************************************************************
4181 * SetPrinterDataExW (WINSPOOL.@)
4183 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4184 LPCWSTR pValueName, DWORD Type,
4185 LPBYTE pData, DWORD cbData)
4187 HKEY hkeyPrinter, hkeySubkey;
4188 DWORD ret;
4190 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4191 debugstr_w(pValueName), Type, pData, cbData);
4193 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4194 != ERROR_SUCCESS)
4195 return ret;
4197 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4198 != ERROR_SUCCESS) {
4199 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4200 RegCloseKey(hkeyPrinter);
4201 return ret;
4203 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4204 RegCloseKey(hkeySubkey);
4205 RegCloseKey(hkeyPrinter);
4206 return ret;
4209 /******************************************************************************
4210 * SetPrinterDataA (WINSPOOL.@)
4212 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4213 LPBYTE pData, DWORD cbData)
4215 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4216 pData, cbData);
4219 /******************************************************************************
4220 * SetPrinterDataW (WINSPOOL.@)
4222 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4223 LPBYTE pData, DWORD cbData)
4225 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4226 pData, cbData);
4229 /******************************************************************************
4230 * GetPrinterDataExA (WINSPOOL.@)
4232 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4233 LPCSTR pValueName, LPDWORD pType,
4234 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4236 HKEY hkeyPrinter, hkeySubkey;
4237 DWORD ret;
4239 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4240 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4241 pcbNeeded);
4243 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4244 != ERROR_SUCCESS)
4245 return ret;
4247 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4248 != ERROR_SUCCESS) {
4249 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4250 RegCloseKey(hkeyPrinter);
4251 return ret;
4253 *pcbNeeded = nSize;
4254 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4255 RegCloseKey(hkeySubkey);
4256 RegCloseKey(hkeyPrinter);
4257 return ret;
4260 /******************************************************************************
4261 * GetPrinterDataExW (WINSPOOL.@)
4263 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4264 LPCWSTR pValueName, LPDWORD pType,
4265 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4267 HKEY hkeyPrinter, hkeySubkey;
4268 DWORD ret;
4270 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4271 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4272 pcbNeeded);
4274 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4275 != ERROR_SUCCESS)
4276 return ret;
4278 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4279 != ERROR_SUCCESS) {
4280 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4281 RegCloseKey(hkeyPrinter);
4282 return ret;
4284 *pcbNeeded = nSize;
4285 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4286 RegCloseKey(hkeySubkey);
4287 RegCloseKey(hkeyPrinter);
4288 return ret;
4291 /******************************************************************************
4292 * GetPrinterDataA (WINSPOOL.@)
4294 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4295 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4297 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4298 pData, nSize, pcbNeeded);
4301 /******************************************************************************
4302 * GetPrinterDataW (WINSPOOL.@)
4304 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4305 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4307 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4308 pData, nSize, pcbNeeded);
4311 /*******************************************************************************
4312 * EnumPrinterDataExW [WINSPOOL.@]
4314 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4315 LPBYTE pEnumValues, DWORD cbEnumValues,
4316 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4318 HKEY hkPrinter, hkSubKey;
4319 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4320 cbValueNameLen, cbMaxValueLen, cbValueLen,
4321 cbBufSize, dwType;
4322 LPWSTR lpValueName;
4323 HANDLE hHeap;
4324 PBYTE lpValue;
4325 PPRINTER_ENUM_VALUESW ppev;
4327 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4329 if (pKeyName == NULL || *pKeyName == 0)
4330 return ERROR_INVALID_PARAMETER;
4332 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4333 if (ret != ERROR_SUCCESS)
4335 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4336 hPrinter, ret);
4337 return ret;
4340 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4341 if (ret != ERROR_SUCCESS)
4343 r = RegCloseKey (hkPrinter);
4344 if (r != ERROR_SUCCESS)
4345 WARN ("RegCloseKey returned %li\n", r);
4346 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4347 debugstr_w (pKeyName), ret);
4348 return ret;
4351 ret = RegCloseKey (hkPrinter);
4352 if (ret != ERROR_SUCCESS)
4354 ERR ("RegCloseKey returned %li\n", ret);
4355 r = RegCloseKey (hkSubKey);
4356 if (r != ERROR_SUCCESS)
4357 WARN ("RegCloseKey returned %li\n", r);
4358 return ret;
4361 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4362 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4363 if (ret != ERROR_SUCCESS)
4365 r = RegCloseKey (hkSubKey);
4366 if (r != ERROR_SUCCESS)
4367 WARN ("RegCloseKey returned %li\n", r);
4368 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4369 return ret;
4372 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4373 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4375 if (cValues == 0) /* empty key */
4377 r = RegCloseKey (hkSubKey);
4378 if (r != ERROR_SUCCESS)
4379 WARN ("RegCloseKey returned %li\n", r);
4380 *pcbEnumValues = *pnEnumValues = 0;
4381 return ERROR_SUCCESS;
4384 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4386 hHeap = GetProcessHeap ();
4387 if (hHeap == NULL)
4389 ERR ("GetProcessHeap failed\n");
4390 r = RegCloseKey (hkSubKey);
4391 if (r != ERROR_SUCCESS)
4392 WARN ("RegCloseKey returned %li\n", r);
4393 return ERROR_OUTOFMEMORY;
4396 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4397 if (lpValueName == NULL)
4399 ERR ("Failed to allocate %li bytes from process heap\n",
4400 cbMaxValueNameLen * sizeof (WCHAR));
4401 r = RegCloseKey (hkSubKey);
4402 if (r != ERROR_SUCCESS)
4403 WARN ("RegCloseKey returned %li\n", r);
4404 return ERROR_OUTOFMEMORY;
4407 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4408 if (lpValue == NULL)
4410 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4411 if (HeapFree (hHeap, 0, lpValueName) == 0)
4412 WARN ("HeapFree failed with code %li\n", GetLastError ());
4413 r = RegCloseKey (hkSubKey);
4414 if (r != ERROR_SUCCESS)
4415 WARN ("RegCloseKey returned %li\n", r);
4416 return ERROR_OUTOFMEMORY;
4419 TRACE ("pass 1: calculating buffer required for all names and values\n");
4421 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4423 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4425 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4427 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4428 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4429 NULL, NULL, lpValue, &cbValueLen);
4430 if (ret != ERROR_SUCCESS)
4432 if (HeapFree (hHeap, 0, lpValue) == 0)
4433 WARN ("HeapFree failed with code %li\n", GetLastError ());
4434 if (HeapFree (hHeap, 0, lpValueName) == 0)
4435 WARN ("HeapFree failed with code %li\n", GetLastError ());
4436 r = RegCloseKey (hkSubKey);
4437 if (r != ERROR_SUCCESS)
4438 WARN ("RegCloseKey returned %li\n", r);
4439 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4440 return ret;
4443 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4444 debugstr_w (lpValueName), dwIndex,
4445 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4447 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4448 cbBufSize += cbValueLen;
4451 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4453 *pcbEnumValues = cbBufSize;
4454 *pnEnumValues = cValues;
4456 if (cbEnumValues < cbBufSize) /* buffer too small */
4458 if (HeapFree (hHeap, 0, lpValue) == 0)
4459 WARN ("HeapFree failed with code %li\n", GetLastError ());
4460 if (HeapFree (hHeap, 0, lpValueName) == 0)
4461 WARN ("HeapFree failed with code %li\n", GetLastError ());
4462 r = RegCloseKey (hkSubKey);
4463 if (r != ERROR_SUCCESS)
4464 WARN ("RegCloseKey returned %li\n", r);
4465 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4466 return ERROR_MORE_DATA;
4469 TRACE ("pass 2: copying all names and values to buffer\n");
4471 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4472 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4474 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4476 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4477 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4478 NULL, &dwType, lpValue, &cbValueLen);
4479 if (ret != ERROR_SUCCESS)
4481 if (HeapFree (hHeap, 0, lpValue) == 0)
4482 WARN ("HeapFree failed with code %li\n", GetLastError ());
4483 if (HeapFree (hHeap, 0, lpValueName) == 0)
4484 WARN ("HeapFree failed with code %li\n", GetLastError ());
4485 r = RegCloseKey (hkSubKey);
4486 if (r != ERROR_SUCCESS)
4487 WARN ("RegCloseKey returned %li\n", r);
4488 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4489 return ret;
4492 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4493 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4494 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4495 pEnumValues += cbValueNameLen;
4497 /* return # of *bytes* (including trailing \0), not # of chars */
4498 ppev[dwIndex].cbValueName = cbValueNameLen;
4500 ppev[dwIndex].dwType = dwType;
4502 memcpy (pEnumValues, lpValue, cbValueLen);
4503 ppev[dwIndex].pData = pEnumValues;
4504 pEnumValues += cbValueLen;
4506 ppev[dwIndex].cbData = cbValueLen;
4508 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4509 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4512 if (HeapFree (hHeap, 0, lpValue) == 0)
4514 ret = GetLastError ();
4515 ERR ("HeapFree failed with code %li\n", ret);
4516 if (HeapFree (hHeap, 0, lpValueName) == 0)
4517 WARN ("HeapFree failed with code %li\n", GetLastError ());
4518 r = RegCloseKey (hkSubKey);
4519 if (r != ERROR_SUCCESS)
4520 WARN ("RegCloseKey returned %li\n", r);
4521 return ret;
4524 if (HeapFree (hHeap, 0, lpValueName) == 0)
4526 ret = GetLastError ();
4527 ERR ("HeapFree failed with code %li\n", ret);
4528 r = RegCloseKey (hkSubKey);
4529 if (r != ERROR_SUCCESS)
4530 WARN ("RegCloseKey returned %li\n", r);
4531 return ret;
4534 ret = RegCloseKey (hkSubKey);
4535 if (ret != ERROR_SUCCESS)
4537 ERR ("RegCloseKey returned %li\n", ret);
4538 return ret;
4541 return ERROR_SUCCESS;
4544 /*******************************************************************************
4545 * EnumPrinterDataExA [WINSPOOL.@]
4547 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4548 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4549 * what Windows 2000 SP1 does.
4552 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4553 LPBYTE pEnumValues, DWORD cbEnumValues,
4554 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4556 INT len;
4557 LPWSTR pKeyNameW;
4558 DWORD ret, dwIndex, dwBufSize;
4559 HANDLE hHeap;
4560 LPSTR pBuffer;
4562 TRACE ("%p %s\n", hPrinter, pKeyName);
4564 if (pKeyName == NULL || *pKeyName == 0)
4565 return ERROR_INVALID_PARAMETER;
4567 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4568 if (len == 0)
4570 ret = GetLastError ();
4571 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4572 return ret;
4575 hHeap = GetProcessHeap ();
4576 if (hHeap == NULL)
4578 ERR ("GetProcessHeap failed\n");
4579 return ERROR_OUTOFMEMORY;
4582 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4583 if (pKeyNameW == NULL)
4585 ERR ("Failed to allocate %li bytes from process heap\n",
4586 (LONG) len * sizeof (WCHAR));
4587 return ERROR_OUTOFMEMORY;
4590 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4592 ret = GetLastError ();
4593 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4594 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4595 WARN ("HeapFree failed with code %li\n", GetLastError ());
4596 return ret;
4599 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4600 pcbEnumValues, pnEnumValues);
4601 if (ret != ERROR_SUCCESS)
4603 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4604 WARN ("HeapFree failed with code %li\n", GetLastError ());
4605 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4606 return ret;
4609 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4611 ret = GetLastError ();
4612 ERR ("HeapFree failed with code %li\n", ret);
4613 return ret;
4616 if (*pnEnumValues == 0) /* empty key */
4617 return ERROR_SUCCESS;
4619 dwBufSize = 0;
4620 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4622 PPRINTER_ENUM_VALUESW ppev =
4623 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4625 if (dwBufSize < ppev->cbValueName)
4626 dwBufSize = ppev->cbValueName;
4628 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4629 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4630 dwBufSize = ppev->cbData;
4633 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4635 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4636 if (pBuffer == NULL)
4638 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4639 return ERROR_OUTOFMEMORY;
4642 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4644 PPRINTER_ENUM_VALUESW ppev =
4645 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4647 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4648 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4649 NULL);
4650 if (len == 0)
4652 ret = GetLastError ();
4653 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4654 if (HeapFree (hHeap, 0, pBuffer) == 0)
4655 WARN ("HeapFree failed with code %li\n", GetLastError ());
4656 return ret;
4659 memcpy (ppev->pValueName, pBuffer, len);
4661 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4663 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4664 ppev->dwType != REG_MULTI_SZ)
4665 continue;
4667 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4668 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4669 if (len == 0)
4671 ret = GetLastError ();
4672 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4673 if (HeapFree (hHeap, 0, pBuffer) == 0)
4674 WARN ("HeapFree failed with code %li\n", GetLastError ());
4675 return ret;
4678 memcpy (ppev->pData, pBuffer, len);
4680 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4681 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4684 if (HeapFree (hHeap, 0, pBuffer) == 0)
4686 ret = GetLastError ();
4687 ERR ("HeapFree failed with code %li\n", ret);
4688 return ret;
4691 return ERROR_SUCCESS;
4694 /******************************************************************************
4695 * AbortPrinter (WINSPOOL.@)
4697 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4699 FIXME("(%p), stub!\n", hPrinter);
4700 return TRUE;
4703 /******************************************************************************
4704 * AddPortA (WINSPOOL.@)
4706 * See AddPortW.
4709 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4711 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4712 return FALSE;
4715 /******************************************************************************
4716 * AddPortW (WINSPOOL.@)
4718 * Add a Port for a specific Monitor
4720 * PARAMS
4721 * pName [I] Servername or NULL (local Computer)
4722 * hWnd [I] Handle to parent Window for the Dialog-Box
4723 * pMonitorName [I] Name of the Monitor that manage the Port
4725 * RETURNS
4726 * Success: TRUE
4727 * Failure: FALSE
4729 * BUGS
4730 * only a Stub
4733 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4735 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4736 return FALSE;
4739 /******************************************************************************
4740 * AddPortExA (WINSPOOL.@)
4742 * See AddPortExW.
4745 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4747 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4748 lpBuffer, debugstr_a(lpMonitorName));
4749 return FALSE;
4752 /******************************************************************************
4753 * AddPortExW (WINSPOOL.@)
4755 * Add a Port for a specific Monitor, without presenting a user interface
4757 * PARAMS
4758 * hMonitor [I] Handle from InitializePrintMonitor2()
4759 * pName [I] Servername or NULL (local Computer)
4760 * Level [I] Structure-Level (1 or 2) for lpBuffer
4761 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
4762 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
4764 * RETURNS
4765 * Success: TRUE
4766 * Failure: FALSE
4768 * BUGS
4769 * only a Stub
4772 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4774 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4775 lpBuffer, debugstr_w(lpMonitorName));
4776 return FALSE;
4779 /******************************************************************************
4780 * AddPrinterConnectionA (WINSPOOL.@)
4782 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4784 FIXME("%s\n", debugstr_a(pName));
4785 return FALSE;
4788 /******************************************************************************
4789 * AddPrinterConnectionW (WINSPOOL.@)
4791 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4793 FIXME("%s\n", debugstr_w(pName));
4794 return FALSE;
4797 /******************************************************************************
4798 * AddPrinterDriverExW (WINSPOOL.@)
4800 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4801 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4803 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4804 Level, pDriverInfo, dwFileCopyFlags);
4805 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4806 return FALSE;
4809 /******************************************************************************
4810 * AddPrinterDriverExA (WINSPOOL.@)
4812 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4813 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4815 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4816 Level, pDriverInfo, dwFileCopyFlags);
4817 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4818 return FALSE;
4821 /******************************************************************************
4822 * ConfigurePortA (WINSPOOL.@)
4824 * See ConfigurePortW.
4827 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4829 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4830 return FALSE;
4833 /******************************************************************************
4834 * ConfigurePortW (WINSPOOL.@)
4836 * Display the Configuration-Dialog for a specific Port
4838 * PARAMS
4839 * pName [I] Servername or NULL (local Computer)
4840 * hWnd [I] Handle to parent Window for the Dialog-Box
4841 * pPortName [I] Name of the Port, that should be configured
4843 * RETURNS
4844 * Success: TRUE
4845 * Failure: FALSE
4847 * BUGS
4848 * only a Stub
4851 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4853 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4854 return FALSE;
4857 /******************************************************************************
4858 * ConnectToPrinterDlg (WINSPOOL.@)
4860 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4862 FIXME("%p %lx\n", hWnd, Flags);
4863 return NULL;
4866 /******************************************************************************
4867 * DeletePrinterConnectionA (WINSPOOL.@)
4869 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4871 FIXME("%s\n", debugstr_a(pName));
4872 return TRUE;
4875 /******************************************************************************
4876 * DeletePrinterConnectionW (WINSPOOL.@)
4878 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4880 FIXME("%s\n", debugstr_w(pName));
4881 return TRUE;
4884 /******************************************************************************
4885 * DeletePrinterDriverExW (WINSPOOL.@)
4887 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4888 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4890 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4891 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4892 return TRUE;
4895 /******************************************************************************
4896 * DeletePrinterDriverExA (WINSPOOL.@)
4898 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4899 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4901 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4902 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4903 return TRUE;
4906 /******************************************************************************
4907 * DeletePrinterDataExW (WINSPOOL.@)
4909 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4910 LPCWSTR pValueName)
4912 FIXME("%p %s %s\n", hPrinter,
4913 debugstr_w(pKeyName), debugstr_w(pValueName));
4914 return ERROR_INVALID_PARAMETER;
4917 /******************************************************************************
4918 * DeletePrinterDataExA (WINSPOOL.@)
4920 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4921 LPCSTR pValueName)
4923 FIXME("%p %s %s\n", hPrinter,
4924 debugstr_a(pKeyName), debugstr_a(pValueName));
4925 return ERROR_INVALID_PARAMETER;
4928 /******************************************************************************
4929 * DeletePrintProcessorA (WINSPOOL.@)
4931 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4933 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4934 debugstr_a(pPrintProcessorName));
4935 return TRUE;
4938 /******************************************************************************
4939 * DeletePrintProcessorW (WINSPOOL.@)
4941 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4943 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4944 debugstr_w(pPrintProcessorName));
4945 return TRUE;
4948 /******************************************************************************
4949 * DeletePrintProvidorA (WINSPOOL.@)
4951 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4953 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4954 debugstr_a(pPrintProviderName));
4955 return TRUE;
4958 /******************************************************************************
4959 * DeletePrintProvidorW (WINSPOOL.@)
4961 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4963 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4964 debugstr_w(pPrintProviderName));
4965 return TRUE;
4968 /******************************************************************************
4969 * EnumFormsA (WINSPOOL.@)
4971 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4972 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4974 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4975 return FALSE;
4978 /******************************************************************************
4979 * EnumFormsW (WINSPOOL.@)
4981 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4982 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4984 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4985 return FALSE;
4988 /*****************************************************************************
4989 * EnumMonitorsA [WINSPOOL.@]
4991 * See EnumMonitorsW.
4994 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4995 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4997 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4998 cbBuf, pcbNeeded, pcReturned);
4999 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5000 return 0;
5003 /*****************************************************************************
5004 * EnumMonitorsW [WINSPOOL.@]
5006 * Enumerate available Monitors
5008 * PARAMS
5009 * pName [I] Servername or NULL (local Computer)
5010 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5011 * pMonitors [O] PTR to Buffer that receives the Result
5012 * cbBuf [I] Size of Buffer at pMonitors
5013 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5014 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5016 * RETURNS
5017 * Success: TRUE
5018 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5020 * BUGS
5021 * only a Stub
5024 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5025 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5027 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
5028 cbBuf, pcbNeeded, pcReturned);
5029 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5030 return 0;
5033 /******************************************************************************
5034 * XcvDataW (WINSPOOL.@)
5036 * Notes:
5037 * There doesn't seem to be an A version...
5039 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5040 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5041 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5043 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5044 pInputData, cbInputData, pOutputData,
5045 cbOutputData, pcbOutputNeeded, pdwStatus);
5046 return FALSE;
5049 /*****************************************************************************
5050 * EnumPrinterDataA [WINSPOOL.@]
5053 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5054 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5055 DWORD cbData, LPDWORD pcbData )
5057 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5058 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5059 return ERROR_NO_MORE_ITEMS;
5062 /*****************************************************************************
5063 * EnumPrinterDataW [WINSPOOL.@]
5066 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5067 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5068 DWORD cbData, LPDWORD pcbData )
5070 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5071 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5072 return ERROR_NO_MORE_ITEMS;
5075 /*****************************************************************************
5076 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5079 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5080 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5081 LPDWORD pcbNeeded, LPDWORD pcReturned)
5083 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5084 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5085 pcbNeeded, pcReturned);
5086 return FALSE;
5089 /*****************************************************************************
5090 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5093 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5094 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5095 LPDWORD pcbNeeded, LPDWORD pcReturned)
5097 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5098 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5099 pcbNeeded, pcReturned);
5100 return FALSE;
5103 /*****************************************************************************
5104 * EnumPrintProcessorsA [WINSPOOL.@]
5107 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5108 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5110 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5111 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5112 return FALSE;
5115 /*****************************************************************************
5116 * EnumPrintProcessorsW [WINSPOOL.@]
5119 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5120 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5122 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5123 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5124 cbBuf, pcbNeeded, pcbReturned);
5125 return FALSE;
5128 /*****************************************************************************
5129 * ExtDeviceMode [WINSPOOL.@]
5132 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5133 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5134 DWORD fMode)
5136 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5137 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5138 debugstr_a(pProfile), fMode);
5139 return -1;
5142 /*****************************************************************************
5143 * FindClosePrinterChangeNotification [WINSPOOL.@]
5146 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5148 FIXME("Stub: %p\n", hChange);
5149 return TRUE;
5152 /*****************************************************************************
5153 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5156 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5157 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5159 FIXME("Stub: %p %lx %lx %p\n",
5160 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5161 return INVALID_HANDLE_VALUE;
5164 /*****************************************************************************
5165 * FindNextPrinterChangeNotification [WINSPOOL.@]
5168 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5169 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5171 FIXME("Stub: %p %p %p %p\n",
5172 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5173 return FALSE;
5176 /*****************************************************************************
5177 * FreePrinterNotifyInfo [WINSPOOL.@]
5180 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5182 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5183 return TRUE;
5186 /*****************************************************************************
5187 * string_to_buf
5189 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5190 * ansi depending on the unicode parameter.
5192 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5194 if(!str)
5196 *size = 0;
5197 return TRUE;
5200 if(unicode)
5202 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5203 if(*size <= cb)
5205 memcpy(ptr, str, *size);
5206 return TRUE;
5208 return FALSE;
5210 else
5212 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5213 if(*size <= cb)
5215 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5216 return TRUE;
5218 return FALSE;
5222 /*****************************************************************************
5223 * get_job_info_1
5225 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5226 LPDWORD pcbNeeded, BOOL unicode)
5228 DWORD size, left = cbBuf;
5229 BOOL space = (cbBuf > 0);
5230 LPBYTE ptr = buf;
5232 *pcbNeeded = 0;
5234 if(space)
5236 ji1->JobId = job->job_id;
5239 string_to_buf(job->document_title, ptr, left, &size, unicode);
5240 if(space && size <= left)
5242 ji1->pDocument = (LPWSTR)ptr;
5243 ptr += size;
5244 left -= size;
5246 else
5247 space = FALSE;
5248 *pcbNeeded += size;
5250 return space;
5253 /*****************************************************************************
5254 * get_job_info_2
5256 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5257 LPDWORD pcbNeeded, BOOL unicode)
5259 DWORD size, left = cbBuf;
5260 BOOL space = (cbBuf > 0);
5261 LPBYTE ptr = buf;
5263 *pcbNeeded = 0;
5265 if(space)
5267 ji2->JobId = job->job_id;
5270 string_to_buf(job->document_title, ptr, left, &size, unicode);
5271 if(space && size <= left)
5273 ji2->pDocument = (LPWSTR)ptr;
5274 ptr += size;
5275 left -= size;
5277 else
5278 space = FALSE;
5279 *pcbNeeded += size;
5281 return space;
5284 /*****************************************************************************
5285 * get_job_info
5287 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5288 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5290 BOOL ret = FALSE;
5291 DWORD needed = 0, size;
5292 job_t *job;
5293 LPBYTE ptr = pJob;
5295 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5297 EnterCriticalSection(&printer_handles_cs);
5298 job = get_job(hPrinter, JobId);
5299 if(!job)
5300 goto end;
5302 switch(Level)
5304 case 1:
5305 size = sizeof(JOB_INFO_1W);
5306 if(cbBuf >= size)
5308 cbBuf -= size;
5309 ptr += size;
5310 memset(pJob, 0, size);
5312 else
5313 cbBuf = 0;
5314 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5315 needed += size;
5316 break;
5318 case 2:
5319 size = sizeof(JOB_INFO_2W);
5320 if(cbBuf >= size)
5322 cbBuf -= size;
5323 ptr += size;
5324 memset(pJob, 0, size);
5326 else
5327 cbBuf = 0;
5328 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5329 needed += size;
5330 break;
5332 case 3:
5333 size = sizeof(JOB_INFO_3);
5334 if(cbBuf >= size)
5336 cbBuf -= size;
5337 memset(pJob, 0, size);
5338 ret = TRUE;
5340 else
5341 cbBuf = 0;
5342 needed = size;
5343 break;
5345 default:
5346 SetLastError(ERROR_INVALID_LEVEL);
5347 goto end;
5349 if(pcbNeeded)
5350 *pcbNeeded = needed;
5351 end:
5352 LeaveCriticalSection(&printer_handles_cs);
5353 return ret;
5356 /*****************************************************************************
5357 * GetJobA [WINSPOOL.@]
5360 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5361 DWORD cbBuf, LPDWORD pcbNeeded)
5363 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5366 /*****************************************************************************
5367 * GetJobW [WINSPOOL.@]
5370 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5371 DWORD cbBuf, LPDWORD pcbNeeded)
5373 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5376 /*****************************************************************************
5377 * schedule_lpr
5379 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5381 char *unixname, *queue, *cmd;
5382 char fmt[] = "lpr -P%s %s";
5383 DWORD len;
5385 if(!(unixname = wine_get_unix_file_name(filename)))
5386 return FALSE;
5388 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5389 queue = HeapAlloc(GetProcessHeap(), 0, len);
5390 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5392 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5393 sprintf(cmd, fmt, queue, unixname);
5395 TRACE("printing with: %s\n", cmd);
5396 system(cmd);
5398 HeapFree(GetProcessHeap(), 0, cmd);
5399 HeapFree(GetProcessHeap(), 0, queue);
5400 HeapFree(GetProcessHeap(), 0, unixname);
5401 return TRUE;
5404 /*****************************************************************************
5405 * schedule_cups
5407 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5409 #if HAVE_CUPS_CUPS_H
5410 if(pcupsPrintFile)
5412 char *unixname, *queue, *doc_titleA;
5413 DWORD len;
5414 BOOL ret;
5416 if(!(unixname = wine_get_unix_file_name(filename)))
5417 return FALSE;
5419 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5420 queue = HeapAlloc(GetProcessHeap(), 0, len);
5421 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5423 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5424 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5425 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5427 TRACE("printing via cups\n");
5428 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5429 HeapFree(GetProcessHeap(), 0, doc_titleA);
5430 HeapFree(GetProcessHeap(), 0, queue);
5431 HeapFree(GetProcessHeap(), 0, unixname);
5432 return ret;
5434 else
5435 #endif
5437 return schedule_lpr(printer_name, filename);
5441 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5443 LPWSTR filename;
5445 switch(msg)
5447 case WM_INITDIALOG:
5448 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5449 return TRUE;
5451 case WM_COMMAND:
5452 if(HIWORD(wparam) == BN_CLICKED)
5454 if(LOWORD(wparam) == IDOK)
5456 HANDLE hf;
5457 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5458 LPWSTR *output;
5460 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5461 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5463 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5465 WCHAR caption[200], message[200];
5466 int mb_ret;
5468 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5469 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5470 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5471 if(mb_ret == IDCANCEL)
5473 HeapFree(GetProcessHeap(), 0, filename);
5474 return TRUE;
5477 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5478 if(hf == INVALID_HANDLE_VALUE)
5480 WCHAR caption[200], message[200];
5482 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5483 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5484 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5485 HeapFree(GetProcessHeap(), 0, filename);
5486 return TRUE;
5488 CloseHandle(hf);
5489 DeleteFileW(filename);
5490 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5491 *output = filename;
5492 EndDialog(hwnd, IDOK);
5493 return TRUE;
5495 if(LOWORD(wparam) == IDCANCEL)
5497 EndDialog(hwnd, IDCANCEL);
5498 return TRUE;
5501 return FALSE;
5503 return FALSE;
5506 /*****************************************************************************
5507 * get_filename
5509 static BOOL get_filename(LPWSTR *filename)
5511 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
5512 file_dlg_proc, (LPARAM)filename) == IDOK;
5515 /*****************************************************************************
5516 * schedule_file
5518 static BOOL schedule_file(LPCWSTR filename)
5520 LPWSTR output = NULL;
5522 if(get_filename(&output))
5524 TRACE("copy to %s\n", debugstr_w(output));
5525 CopyFileW(filename, output, FALSE);
5526 HeapFree(GetProcessHeap(), 0, output);
5527 return TRUE;
5529 return FALSE;
5532 /*****************************************************************************
5533 * schedule_pipe
5535 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
5537 #ifdef HAVE_FORK
5538 char *unixname, *cmdA;
5539 DWORD len;
5540 int fds[2] = {-1, -1}, file_fd = -1, no_read;
5541 BOOL ret = FALSE;
5542 char buf[1024];
5544 if(!(unixname = wine_get_unix_file_name(filename)))
5545 return FALSE;
5547 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
5548 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
5549 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
5551 TRACE("printing with: %s\n", cmdA);
5553 if((file_fd = open(unixname, O_RDONLY)) == -1)
5554 goto end;
5556 if (pipe(fds))
5558 ERR("pipe() failed!\n");
5559 goto end;
5562 if (fork() == 0)
5564 close(0);
5565 dup2(fds[0], 0);
5566 close(fds[1]);
5568 /* reset signals that we previously set to SIG_IGN */
5569 signal(SIGPIPE, SIG_DFL);
5570 signal(SIGCHLD, SIG_DFL);
5572 system(cmdA);
5573 exit(0);
5576 while((no_read = read(file_fd, buf, sizeof(buf))))
5577 write(fds[1], buf, no_read);
5579 ret = TRUE;
5581 end:
5582 if(file_fd != -1) close(file_fd);
5583 if(fds[0] != -1) close(fds[0]);
5584 if(fds[1] != -1) close(fds[1]);
5586 HeapFree(GetProcessHeap(), 0, cmdA);
5587 HeapFree(GetProcessHeap(), 0, unixname);
5588 return ret;
5589 #else
5590 return FALSE;
5591 #endif
5594 /*****************************************************************************
5595 * schedule_unixfile
5597 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
5599 int in_fd, out_fd, no_read;
5600 char buf[1024];
5601 BOOL ret = FALSE;
5602 char *unixname, *outputA;
5603 DWORD len;
5605 if(!(unixname = wine_get_unix_file_name(filename)))
5606 return FALSE;
5608 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
5609 outputA = HeapAlloc(GetProcessHeap(), 0, len);
5610 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
5612 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5613 in_fd = open(unixname, O_RDONLY);
5614 if(out_fd == -1 || in_fd == -1)
5615 goto end;
5617 while((no_read = read(in_fd, buf, sizeof(buf))))
5618 write(out_fd, buf, no_read);
5620 ret = TRUE;
5621 end:
5622 if(in_fd != -1) close(in_fd);
5623 if(out_fd != -1) close(out_fd);
5624 HeapFree(GetProcessHeap(), 0, outputA);
5625 HeapFree(GetProcessHeap(), 0, unixname);
5626 return ret;
5629 /*****************************************************************************
5630 * ScheduleJob [WINSPOOL.@]
5633 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
5635 opened_printer_t *printer;
5636 BOOL ret = FALSE;
5637 struct list *cursor, *cursor2;
5639 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
5640 EnterCriticalSection(&printer_handles_cs);
5641 printer = get_opened_printer(hPrinter);
5642 if(!printer)
5643 goto end;
5645 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
5647 job_t *job = LIST_ENTRY(cursor, job_t, entry);
5648 HANDLE hf;
5650 if(job->job_id != dwJobID) continue;
5652 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
5653 if(hf != INVALID_HANDLE_VALUE)
5655 PRINTER_INFO_5W *pi5;
5656 DWORD needed;
5657 HKEY hkey;
5658 WCHAR output[1024];
5659 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5660 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5662 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
5663 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
5664 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
5665 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
5666 debugstr_w(pi5->pPortName));
5668 output[0] = 0;
5670 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5671 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
5673 DWORD type, count = sizeof(output);
5674 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
5675 RegCloseKey(hkey);
5677 if(output[0] == '|')
5679 schedule_pipe(output + 1, job->filename);
5681 else if(output[0])
5683 schedule_unixfile(output, job->filename);
5685 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
5687 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
5689 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
5691 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
5693 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
5695 schedule_file(job->filename);
5697 else
5699 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
5701 HeapFree(GetProcessHeap(), 0, pi5);
5702 CloseHandle(hf);
5703 DeleteFileW(job->filename);
5705 list_remove(cursor);
5706 HeapFree(GetProcessHeap(), 0, job->document_title);
5707 HeapFree(GetProcessHeap(), 0, job->filename);
5708 HeapFree(GetProcessHeap(), 0, job);
5709 ret = TRUE;
5710 break;
5712 end:
5713 LeaveCriticalSection(&printer_handles_cs);
5714 return ret;
5717 /*****************************************************************************
5718 * StartDocDlgA [WINSPOOL.@]
5720 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
5722 UNICODE_STRING usBuffer;
5723 DOCINFOW docW;
5724 LPWSTR retW;
5725 LPSTR ret = NULL;
5727 docW.cbSize = sizeof(docW);
5728 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
5729 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
5730 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
5731 docW.fwType = doc->fwType;
5733 retW = StartDocDlgW(hPrinter, &docW);
5735 if(retW)
5737 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
5738 ret = HeapAlloc(GetProcessHeap(), 0, len);
5739 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
5740 HeapFree(GetProcessHeap(), 0, retW);
5743 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
5744 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
5745 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
5747 return ret;
5750 /*****************************************************************************
5751 * StartDocDlgW [WINSPOOL.@]
5753 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5754 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5755 * port is "FILE:". Also returns the full path if passed a relative path.
5757 * The caller should free the returned string from the process heap.
5759 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
5761 LPWSTR ret = NULL;
5762 DWORD len, attr;
5764 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
5766 PRINTER_INFO_5W *pi5;
5767 GetPrinterW(hPrinter, 5, NULL, 0, &len);
5768 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
5769 return NULL;
5770 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
5771 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
5772 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
5774 HeapFree(GetProcessHeap(), 0, pi5);
5775 return NULL;
5777 HeapFree(GetProcessHeap(), 0, pi5);
5780 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
5782 LPWSTR name;
5783 get_filename(&name);
5784 if(name)
5786 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
5788 HeapFree(GetProcessHeap(), 0, name);
5789 return NULL;
5791 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5792 GetFullPathNameW(name, len, ret, NULL);
5793 HeapFree(GetProcessHeap(), 0, name);
5795 return ret;
5798 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
5799 return NULL;
5801 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5802 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
5804 attr = GetFileAttributesW(ret);
5805 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
5807 HeapFree(GetProcessHeap(), 0, ret);
5808 ret = NULL;
5810 return ret;