shdocvw: Move IOleInPlaceSite to DocHost object.
[wine/wine64.git] / dlls / winspool / info.c
blob028826975e9915ea986dbf23799e6f23ed365a2d
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 MonitorsW[] = { 'S','y','s','t','e','m','\\',
130 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'C','o','n','t','r','o','l','\\',
132 'P','r','i','n','t','\\',
133 'M','o','n','i','t','o','r','s',0};
135 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
137 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
138 'M','i','c','r','o','s','o','f','t','\\',
139 'W','i','n','d','o','w','s',' ','N','T','\\',
140 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
141 'W','i','n','d','o','w','s',0};
143 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s',' ','N','T','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'D','e','v','i','c','e','s',0};
149 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
150 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
151 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
152 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
153 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
155 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
157 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
158 'i','o','n',' ','F','i','l','e',0};
159 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
160 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
161 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
162 'M','o','d','e',0};
163 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
164 'i','l','e','s',0};
165 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
166 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
167 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
168 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
169 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
170 static const WCHAR NameW[] = {'N','a','m','e',0};
171 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
172 static const WCHAR PortW[] = {'P','o','r','t',0};
173 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
174 's','s','o','r',0};
175 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
176 'v','e','r',0};
177 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
178 'v','e','r','D','a','t','a',0};
179 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
180 'i','l','e',0};
181 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
182 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
183 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
184 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
185 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
186 static const WCHAR emptyStringW[] = {0};
188 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
190 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
191 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
192 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
194 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
195 'D','o','c','u','m','e','n','t',0};
197 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
198 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
199 DWORD Level, LPBYTE pDriverInfo,
200 DWORD cbBuf, LPDWORD pcbNeeded,
201 BOOL unicode);
202 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
203 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
205 /******************************************************************
206 * validate the user-supplied printing-environment [internal]
208 * PARAMS
209 * env [I] PTR to Environment-String or NULL
211 * RETURNS
212 * Failure: NULL
213 * Success: PTR to printenv_t
215 * NOTES
216 * An empty string is handled the same way as NULL.
217 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
221 static const printenv_t * validate_envW(LPCWSTR env)
223 static const printenv_t env_x86 = {envname_x86W, subdir_x86W};
224 static const printenv_t env_win40 = {envname_win40W, subdir_win40W};
225 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
227 const printenv_t *result = NULL;
228 unsigned int i;
230 TRACE("testing %s\n", debugstr_w(env));
231 if (env && env[0])
233 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
235 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
237 result = all_printenv[i];
238 break;
242 if (result == NULL) {
243 FIXME("unsupported Environment: %s\n", debugstr_w(env));
244 SetLastError(ERROR_INVALID_ENVIRONMENT);
246 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
248 else
250 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
252 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
254 return result;
258 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
259 if passed a NULL string. This returns NULLs to the result.
261 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
263 if ( (src) )
265 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
266 return usBufferPtr->Buffer;
268 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
269 return NULL;
272 static LPWSTR strdupW(LPCWSTR p)
274 LPWSTR ret;
275 DWORD len;
277 if(!p) return NULL;
278 len = (strlenW(p) + 1) * sizeof(WCHAR);
279 ret = HeapAlloc(GetProcessHeap(), 0, len);
280 memcpy(ret, p, len);
281 return ret;
284 static void
285 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
286 char qbuf[200];
288 /* If forcing, or no profile string entry for device yet, set the entry
290 * The always change entry if not WINEPS yet is discussable.
292 if (force ||
293 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
294 !strcmp(qbuf,"*") ||
295 !strstr(qbuf,"WINEPS.DRV")
297 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
298 HKEY hkey;
300 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
301 WriteProfileStringA("windows","device",buf);
302 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
303 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
304 RegCloseKey(hkey);
306 HeapFree(GetProcessHeap(),0,buf);
310 #ifdef HAVE_CUPS_CUPS_H
311 static typeof(cupsGetDests) *pcupsGetDests;
312 static typeof(cupsGetPPD) *pcupsGetPPD;
313 static typeof(cupsPrintFile) *pcupsPrintFile;
314 static void *cupshandle;
316 static BOOL CUPS_LoadPrinters(void)
318 int i, nrofdests;
319 BOOL hadprinter = FALSE;
320 cups_dest_t *dests;
321 PRINTER_INFO_2A pinfo2a;
322 char *port,*devline;
323 HKEY hkeyPrinter, hkeyPrinters, hkey;
325 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
326 if (!cupshandle)
327 return FALSE;
328 TRACE("loaded %s\n", SONAME_LIBCUPS);
330 #define DYNCUPS(x) \
331 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
332 if (!p##x) return FALSE;
334 DYNCUPS(cupsGetPPD);
335 DYNCUPS(cupsGetDests);
336 DYNCUPS(cupsPrintFile);
337 #undef DYNCUPS
339 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
340 ERROR_SUCCESS) {
341 ERR("Can't create Printers key\n");
342 return FALSE;
345 nrofdests = pcupsGetDests(&dests);
346 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
347 for (i=0;i<nrofdests;i++) {
348 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
349 sprintf(port,"LPR:%s",dests[i].name);
350 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
351 sprintf(devline,"WINEPS.DRV,%s",port);
352 WriteProfileStringA("devices",dests[i].name,devline);
353 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
354 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
355 RegCloseKey(hkey);
357 HeapFree(GetProcessHeap(),0,devline);
359 TRACE("Printer %d: %s\n", i, dests[i].name);
360 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
361 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
362 and continue */
363 TRACE("Printer already exists\n");
364 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
365 RegCloseKey(hkeyPrinter);
366 } else {
367 memset(&pinfo2a,0,sizeof(pinfo2a));
368 pinfo2a.pPrinterName = dests[i].name;
369 pinfo2a.pDatatype = "RAW";
370 pinfo2a.pPrintProcessor = "WinPrint";
371 pinfo2a.pDriverName = "PS Driver";
372 pinfo2a.pComment = "WINEPS Printer using CUPS";
373 pinfo2a.pLocation = "<physical location of printer>";
374 pinfo2a.pPortName = port;
375 pinfo2a.pParameters = "<parameters?>";
376 pinfo2a.pShareName = "<share name?>";
377 pinfo2a.pSepFile = "<sep file?>";
379 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
380 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
381 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
384 HeapFree(GetProcessHeap(),0,port);
386 hadprinter = TRUE;
387 if (dests[i].is_default)
388 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
390 RegCloseKey(hkeyPrinters);
391 return hadprinter;
393 #endif
395 static BOOL
396 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
397 PRINTER_INFO_2A pinfo2a;
398 char *e,*s,*name,*prettyname,*devname;
399 BOOL ret = FALSE, set_default = FALSE;
400 char *port,*devline,*env_default;
401 HKEY hkeyPrinter, hkeyPrinters, hkey;
403 while (isspace(*pent)) pent++;
404 s = strchr(pent,':');
405 if(s) *s='\0';
406 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
407 strcpy(name,pent);
408 if(s) {
409 *s=':';
410 pent = s;
411 } else
412 pent = "";
414 TRACE("name=%s entry=%s\n",name, pent);
416 if(ispunct(*name)) { /* a tc entry, not a real printer */
417 TRACE("skipping tc entry\n");
418 goto end;
421 if(strstr(pent,":server")) { /* server only version so skip */
422 TRACE("skipping server entry\n");
423 goto end;
426 /* Determine whether this is a postscript printer. */
428 ret = TRUE;
429 env_default = getenv("PRINTER");
430 prettyname = name;
431 /* Get longest name, usually the one at the right for later display. */
432 while((s=strchr(prettyname,'|'))) {
433 *s = '\0';
434 e = s;
435 while(isspace(*--e)) *e = '\0';
436 TRACE("\t%s\n", debugstr_a(prettyname));
437 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
438 for(prettyname = s+1; isspace(*prettyname); prettyname++)
441 e = prettyname + strlen(prettyname);
442 while(isspace(*--e)) *e = '\0';
443 TRACE("\t%s\n", debugstr_a(prettyname));
444 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
446 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
447 * if it is too long, we use it as comment below. */
448 devname = prettyname;
449 if (strlen(devname)>=CCHDEVICENAME-1)
450 devname = name;
451 if (strlen(devname)>=CCHDEVICENAME-1) {
452 ret = FALSE;
453 goto end;
456 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
457 sprintf(port,"LPR:%s",name);
459 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
460 sprintf(devline,"WINEPS.DRV,%s",port);
461 WriteProfileStringA("devices",devname,devline);
462 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
463 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
464 RegCloseKey(hkey);
466 HeapFree(GetProcessHeap(),0,devline);
468 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
469 ERROR_SUCCESS) {
470 ERR("Can't create Printers key\n");
471 ret = FALSE;
472 goto end;
474 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
475 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
476 and continue */
477 TRACE("Printer already exists\n");
478 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
479 RegCloseKey(hkeyPrinter);
480 } else {
481 memset(&pinfo2a,0,sizeof(pinfo2a));
482 pinfo2a.pPrinterName = devname;
483 pinfo2a.pDatatype = "RAW";
484 pinfo2a.pPrintProcessor = "WinPrint";
485 pinfo2a.pDriverName = "PS Driver";
486 pinfo2a.pComment = "WINEPS Printer using LPR";
487 pinfo2a.pLocation = prettyname;
488 pinfo2a.pPortName = port;
489 pinfo2a.pParameters = "<parameters?>";
490 pinfo2a.pShareName = "<share name?>";
491 pinfo2a.pSepFile = "<sep file?>";
493 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
494 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
495 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
498 RegCloseKey(hkeyPrinters);
500 if (isfirst || set_default)
501 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
503 HeapFree(GetProcessHeap(), 0, port);
504 end:
505 HeapFree(GetProcessHeap(), 0, name);
506 return ret;
509 static BOOL
510 PRINTCAP_LoadPrinters(void) {
511 BOOL hadprinter = FALSE;
512 char buf[200];
513 FILE *f;
514 char *pent = NULL;
515 BOOL had_bash = FALSE;
517 f = fopen("/etc/printcap","r");
518 if (!f)
519 return FALSE;
521 while(fgets(buf,sizeof(buf),f)) {
522 char *start, *end;
524 end=strchr(buf,'\n');
525 if (end) *end='\0';
527 start = buf;
528 while(isspace(*start)) start++;
529 if(*start == '#' || *start == '\0')
530 continue;
532 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
533 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
534 HeapFree(GetProcessHeap(),0,pent);
535 pent = NULL;
538 if (end && *--end == '\\') {
539 *end = '\0';
540 had_bash = TRUE;
541 } else
542 had_bash = FALSE;
544 if (pent) {
545 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
546 strcat(pent,start);
547 } else {
548 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
549 strcpy(pent,start);
553 if(pent) {
554 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
555 HeapFree(GetProcessHeap(),0,pent);
557 fclose(f);
558 return hadprinter;
561 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
563 if (value)
564 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
565 lstrlenW(value) * sizeof(WCHAR));
566 else
567 return ERROR_FILE_NOT_FOUND;
570 void WINSPOOL_LoadSystemPrinters(void)
572 HKEY hkey, hkeyPrinters;
573 DRIVER_INFO_3A di3a;
574 HANDLE hprn;
575 DWORD needed, num, i;
576 WCHAR PrinterName[256];
577 BOOL done = FALSE;
579 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
580 di3a.pName = "PS Driver";
581 di3a.pEnvironment = NULL; /* NULL means auto */
582 di3a.pDriverPath = "wineps16";
583 di3a.pDataFile = "<datafile?>";
584 di3a.pConfigFile = "wineps16";
585 di3a.pHelpFile = "<helpfile?>";
586 di3a.pDependentFiles = "<dependend files?>";
587 di3a.pMonitorName = "<monitor name?>";
588 di3a.pDefaultDataType = "RAW";
590 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
591 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
592 return;
595 /* This ensures that all printer entries have a valid Name value. If causes
596 problems later if they don't. If one is found to be missed we create one
597 and set it equal to the name of the key */
598 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
599 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
600 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
601 for(i = 0; i < num; i++) {
602 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
603 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
604 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
605 set_reg_szW(hkey, NameW, PrinterName);
607 RegCloseKey(hkey);
612 RegCloseKey(hkeyPrinters);
615 /* We want to avoid calling AddPrinter on printers as much as
616 possible, because on cups printers this will (eventually) lead
617 to a call to cupsGetPPD which takes forever, even with non-cups
618 printers AddPrinter takes a while. So we'll tag all printers that
619 were automatically added last time around, if they still exist
620 we'll leave them be otherwise we'll delete them. */
621 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
622 if(needed) {
623 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
624 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
625 for(i = 0; i < num; i++) {
626 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
627 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
628 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
629 DWORD dw = 1;
630 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
631 RegCloseKey(hkey);
633 ClosePrinter(hprn);
638 HeapFree(GetProcessHeap(), 0, pi);
642 #ifdef HAVE_CUPS_CUPS_H
643 done = CUPS_LoadPrinters();
644 #endif
646 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
647 /* Check for [ppd] section in config file before parsing /etc/printcap */
648 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
649 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
650 &hkey) == ERROR_SUCCESS) {
651 RegCloseKey(hkey);
652 PRINTCAP_LoadPrinters();
656 /* Now enumerate the list again and delete any printers that a still tagged */
657 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
658 if(needed) {
659 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
660 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
661 for(i = 0; i < num; i++) {
662 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
663 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
664 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
665 DWORD dw, type, size = sizeof(dw);
666 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
667 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
668 DeletePrinter(hprn);
670 RegCloseKey(hkey);
672 ClosePrinter(hprn);
677 HeapFree(GetProcessHeap(), 0, pi);
680 return;
684 /*****************************************************************************
685 * enumerate the local monitors (INTERNAL)
687 * returns the needed size (in bytes) for pMonitors
688 * and *lpreturned is set to number of entries returned in pMonitors
691 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
693 HKEY hroot = NULL;
694 HKEY hentry = NULL;
695 LPWSTR ptr;
696 LPMONITOR_INFO_2W mi;
697 WCHAR buffer[MAX_PATH];
698 WCHAR dllname[MAX_PATH];
699 DWORD dllsize;
700 DWORD len;
701 DWORD index = 0;
702 DWORD needed = 0;
703 DWORD numentries;
704 DWORD entrysize;
706 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
708 numentries = *lpreturned; /* this is 0, when we scan the registry */
709 len = entrysize * numentries;
710 ptr = (LPWSTR) &pMonitors[len];
712 numentries = 0;
713 len = sizeof(buffer);
714 buffer[0] = '\0';
716 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
717 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
718 /* Scan all Monitor-Registry-Keys */
719 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
720 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
721 dllsize = sizeof(dllname);
722 dllname[0] = '\0';
724 /* The Monitor must have a Driver-DLL */
725 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
726 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
727 /* We found a valid DLL for this Monitor. */
728 TRACE("using Driver: %s\n", debugstr_w(dllname));
730 RegCloseKey(hentry);
733 /* Windows returns only Port-Monitors here, but to simplify our code,
734 we do no filtering for Language-Monitors */
735 if (dllname[0]) {
736 numentries++;
737 needed += entrysize;
738 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
739 if (level > 1) {
740 /* we install and return only monitors for "Windows NT x86" */
741 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
742 needed += dllsize;
745 /* required size is calculated. Now fill the user-buffer */
746 if (pMonitors && (cbBuf >= needed)){
747 mi = (LPMONITOR_INFO_2W) pMonitors;
748 pMonitors += entrysize;
750 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
751 mi->pName = ptr;
752 lstrcpyW(ptr, buffer); /* Name of the Monitor */
753 ptr += (len+1); /* len is lstrlenW(monitorname) */
754 if (level > 1) {
755 mi->pEnvironment = ptr;
756 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
757 ptr += (lstrlenW(envname_x86W)+1);
759 mi->pDLLName = ptr;
760 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
761 ptr += (dllsize / sizeof(WCHAR));
765 index++;
766 len = sizeof(buffer);
767 buffer[0] = '\0';
769 RegCloseKey(hroot);
771 *lpreturned = numentries;
772 TRACE("need %ld byte for %ld entries\n", needed, numentries);
773 return needed;
776 /******************************************************************
777 * get_opened_printer_entry
778 * Get the first place empty in the opened printer table
780 static HANDLE get_opened_printer_entry( LPCWSTR name )
782 UINT_PTR handle = nb_printer_handles, i;
783 jobqueue_t *queue = NULL;
784 opened_printer_t *printer;
786 EnterCriticalSection(&printer_handles_cs);
788 for (i = 0; i < nb_printer_handles; i++)
790 if (!printer_handles[i])
792 if(handle == nb_printer_handles)
793 handle = i;
795 else if(!queue && !strcmpW(name, printer_handles[i]->name))
796 queue = printer_handles[i]->queue;
799 if (handle >= nb_printer_handles)
801 opened_printer_t **new_array;
802 if (printer_handles)
803 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
804 (nb_printer_handles + 16) * sizeof(*new_array) );
805 else
806 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
807 (nb_printer_handles + 16) * sizeof(*new_array) );
809 if (!new_array)
811 handle = 0;
812 goto end;
814 printer_handles = new_array;
815 nb_printer_handles += 16;
818 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
820 handle = 0;
821 goto end;
824 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
825 strcpyW(printer->name, name);
826 if(queue)
827 printer->queue = queue;
828 else
830 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
831 list_init(&printer->queue->jobs);
832 printer->queue->ref = 0;
834 InterlockedIncrement(&printer->queue->ref);
835 printer->doc = NULL;
837 printer_handles[handle] = printer;
838 handle++;
839 end:
840 LeaveCriticalSection(&printer_handles_cs);
842 return (HANDLE)handle;
845 /******************************************************************
846 * get_opened_printer
847 * Get the pointer to the opened printer referred by the handle
849 static opened_printer_t *get_opened_printer(HANDLE hprn)
851 UINT_PTR idx = (UINT_PTR)hprn;
852 opened_printer_t *ret = NULL;
854 EnterCriticalSection(&printer_handles_cs);
856 if ((idx <= 0) || (idx > nb_printer_handles))
857 goto end;
859 ret = printer_handles[idx - 1];
860 end:
861 LeaveCriticalSection(&printer_handles_cs);
862 return ret;
865 /******************************************************************
866 * get_opened_printer_name
867 * Get the pointer to the opened printer name referred by the handle
869 static LPCWSTR get_opened_printer_name(HANDLE hprn)
871 opened_printer_t *printer = get_opened_printer(hprn);
872 if(!printer) return NULL;
873 return printer->name;
876 /******************************************************************
877 * WINSPOOL_GetOpenedPrinterRegKey
880 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
882 LPCWSTR name = get_opened_printer_name(hPrinter);
883 DWORD ret;
884 HKEY hkeyPrinters;
886 if(!name) return ERROR_INVALID_HANDLE;
888 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
889 ERROR_SUCCESS)
890 return ret;
892 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
894 ERR("Can't find opened printer %s in registry\n",
895 debugstr_w(name));
896 RegCloseKey(hkeyPrinters);
897 return ERROR_INVALID_PRINTER_NAME; /* ? */
899 RegCloseKey(hkeyPrinters);
900 return ERROR_SUCCESS;
903 /******************************************************************
904 * get_job
906 * Get the pointer to the specified job.
907 * Should hold the printer_handles_cs before calling.
909 static job_t *get_job(HANDLE hprn, DWORD JobId)
911 opened_printer_t *printer = get_opened_printer(hprn);
912 job_t *job;
914 if(!printer) return NULL;
915 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
917 if(job->job_id == JobId)
918 return job;
920 return NULL;
923 /***********************************************************
924 * DEVMODEcpyAtoW
926 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
928 BOOL Formname;
929 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
930 DWORD size;
932 Formname = (dmA->dmSize > off_formname);
933 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
934 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
935 dmW->dmDeviceName, CCHDEVICENAME);
936 if(!Formname) {
937 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
938 dmA->dmSize - CCHDEVICENAME);
939 } else {
940 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
941 off_formname - CCHDEVICENAME);
942 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
943 dmW->dmFormName, CCHFORMNAME);
944 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
945 (off_formname + CCHFORMNAME));
947 dmW->dmSize = size;
948 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
949 dmA->dmDriverExtra);
950 return dmW;
953 /***********************************************************
954 * DEVMODEdupWtoA
955 * Creates an ascii copy of supplied devmode on heap
957 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
959 LPDEVMODEA dmA;
960 DWORD size;
961 BOOL Formname;
962 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
964 if(!dmW) return NULL;
965 Formname = (dmW->dmSize > off_formname);
966 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
967 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
968 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
969 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
970 if(!Formname) {
971 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
972 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
973 } else {
974 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
975 off_formname - CCHDEVICENAME * sizeof(WCHAR));
976 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
977 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
978 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
979 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
981 dmA->dmSize = size;
982 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
983 dmW->dmDriverExtra);
984 return dmA;
987 /***********************************************************
988 * PRINTER_INFO_2AtoW
989 * Creates a unicode copy of PRINTER_INFO_2A on heap
991 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
993 LPPRINTER_INFO_2W piW;
994 UNICODE_STRING usBuffer;
996 if(!piA) return NULL;
997 piW = HeapAlloc(heap, 0, sizeof(*piW));
998 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1000 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1001 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1002 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1003 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1004 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1005 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1006 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1007 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1008 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1009 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1010 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1011 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1012 return piW;
1015 /***********************************************************
1016 * FREE_PRINTER_INFO_2W
1017 * Free PRINTER_INFO_2W and all strings
1019 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1021 if(!piW) return;
1023 HeapFree(heap,0,piW->pServerName);
1024 HeapFree(heap,0,piW->pPrinterName);
1025 HeapFree(heap,0,piW->pShareName);
1026 HeapFree(heap,0,piW->pPortName);
1027 HeapFree(heap,0,piW->pDriverName);
1028 HeapFree(heap,0,piW->pComment);
1029 HeapFree(heap,0,piW->pLocation);
1030 HeapFree(heap,0,piW->pDevMode);
1031 HeapFree(heap,0,piW->pSepFile);
1032 HeapFree(heap,0,piW->pPrintProcessor);
1033 HeapFree(heap,0,piW->pDatatype);
1034 HeapFree(heap,0,piW->pParameters);
1035 HeapFree(heap,0,piW);
1036 return;
1039 /******************************************************************
1040 * DeviceCapabilities [WINSPOOL.@]
1041 * DeviceCapabilitiesA [WINSPOOL.@]
1044 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1045 LPSTR pOutput, LPDEVMODEA lpdm)
1047 INT ret;
1049 if (!GDI_CallDeviceCapabilities16)
1051 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1052 (LPCSTR)104 );
1053 if (!GDI_CallDeviceCapabilities16) return -1;
1055 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1057 /* If DC_PAPERSIZE map POINT16s to POINTs */
1058 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1059 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1060 POINT *pt = (POINT *)pOutput;
1061 INT i;
1062 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1063 for(i = 0; i < ret; i++, pt++)
1065 pt->x = tmp[i].x;
1066 pt->y = tmp[i].y;
1068 HeapFree( GetProcessHeap(), 0, tmp );
1070 return ret;
1074 /*****************************************************************************
1075 * DeviceCapabilitiesW [WINSPOOL.@]
1077 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1080 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1081 WORD fwCapability, LPWSTR pOutput,
1082 const DEVMODEW *pDevMode)
1084 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1085 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1086 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1087 INT ret;
1089 if(pOutput && (fwCapability == DC_BINNAMES ||
1090 fwCapability == DC_FILEDEPENDENCIES ||
1091 fwCapability == DC_PAPERNAMES)) {
1092 /* These need A -> W translation */
1093 INT size = 0, i;
1094 LPSTR pOutputA;
1095 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1096 dmA);
1097 if(ret == -1)
1098 return ret;
1099 switch(fwCapability) {
1100 case DC_BINNAMES:
1101 size = 24;
1102 break;
1103 case DC_PAPERNAMES:
1104 case DC_FILEDEPENDENCIES:
1105 size = 64;
1106 break;
1108 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1109 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1110 dmA);
1111 for(i = 0; i < ret; i++)
1112 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1113 pOutput + (i * size), size);
1114 HeapFree(GetProcessHeap(), 0, pOutputA);
1115 } else {
1116 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1117 (LPSTR)pOutput, dmA);
1119 HeapFree(GetProcessHeap(),0,pPortA);
1120 HeapFree(GetProcessHeap(),0,pDeviceA);
1121 HeapFree(GetProcessHeap(),0,dmA);
1122 return ret;
1125 /******************************************************************
1126 * DocumentPropertiesA [WINSPOOL.@]
1128 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1130 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1131 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1132 LPDEVMODEA pDevModeInput,DWORD fMode )
1134 LPSTR lpName = pDeviceName;
1135 LONG ret;
1137 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1138 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1141 if(!pDeviceName) {
1142 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1143 if(!lpNameW) {
1144 ERR("no name from hPrinter?\n");
1145 SetLastError(ERROR_INVALID_HANDLE);
1146 return -1;
1148 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1151 if (!GDI_CallExtDeviceMode16)
1153 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1154 (LPCSTR)102 );
1155 if (!GDI_CallExtDeviceMode16) {
1156 ERR("No CallExtDeviceMode16?\n");
1157 return -1;
1160 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1161 pDevModeInput, NULL, fMode);
1163 if(!pDeviceName)
1164 HeapFree(GetProcessHeap(),0,lpName);
1165 return ret;
1169 /*****************************************************************************
1170 * DocumentPropertiesW (WINSPOOL.@)
1172 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1174 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1175 LPWSTR pDeviceName,
1176 LPDEVMODEW pDevModeOutput,
1177 LPDEVMODEW pDevModeInput, DWORD fMode)
1180 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1181 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1182 LPDEVMODEA pDevModeOutputA = NULL;
1183 LONG ret;
1185 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1186 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1187 fMode);
1188 if(pDevModeOutput) {
1189 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1190 if(ret < 0) return ret;
1191 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1193 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1194 pDevModeInputA, fMode);
1195 if(pDevModeOutput) {
1196 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1197 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1199 if(fMode == 0 && ret > 0)
1200 ret += (CCHDEVICENAME + CCHFORMNAME);
1201 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1202 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1203 return ret;
1206 /******************************************************************
1207 * OpenPrinterA [WINSPOOL.@]
1209 * See OpenPrinterW.
1212 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1213 LPPRINTER_DEFAULTSA pDefault)
1215 UNICODE_STRING lpPrinterNameW;
1216 UNICODE_STRING usBuffer;
1217 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1218 PWSTR pwstrPrinterNameW;
1219 BOOL ret;
1221 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1223 if(pDefault) {
1224 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1225 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1226 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1227 pDefaultW = &DefaultW;
1229 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1230 if(pDefault) {
1231 RtlFreeUnicodeString(&usBuffer);
1232 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1234 RtlFreeUnicodeString(&lpPrinterNameW);
1235 return ret;
1238 /******************************************************************
1239 * OpenPrinterW [WINSPOOL.@]
1241 * Open a Printer / Printserver or a Printer-Object
1243 * PARAMS
1244 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1245 * phPrinter [O] The resulting Handle is stored here
1246 * pDefault [I] PTR to Default Printer Settings or NULL
1248 * RETURNS
1249 * Success: TRUE
1250 * Failure: FALSE
1252 * NOTES
1253 * lpPrinterName is one of:
1254 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1255 *| Printer: "PrinterName"
1256 *| Printer-Object: "PrinterName,Job xxx"
1257 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1258 *| XcvPort: "Servername,XcvPort PortName"
1260 * BUGS
1261 *| Printserver not supported
1262 *| Printer-Object not supported
1263 *| XcvMonitor not supported
1264 *| XcvPort not supported
1265 *| pDefaults not supported
1268 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
1269 LPPRINTER_DEFAULTSW pDefault)
1271 HKEY hkeyPrinters, hkeyPrinter;
1273 if (!lpPrinterName) {
1274 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1275 SetLastError(ERROR_INVALID_PARAMETER);
1276 return FALSE;
1279 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1280 pDefault);
1282 /* Check Printer exists */
1283 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1284 ERROR_SUCCESS) {
1285 ERR("Can't create Printers key\n");
1286 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1287 return FALSE;
1290 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1291 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1292 != ERROR_SUCCESS) {
1293 TRACE("Can't find printer %s in registry\n",
1294 debugstr_w(lpPrinterName));
1295 RegCloseKey(hkeyPrinters);
1296 SetLastError(ERROR_INVALID_PRINTER_NAME);
1297 return FALSE;
1299 RegCloseKey(hkeyPrinter);
1300 RegCloseKey(hkeyPrinters);
1302 if(!phPrinter) /* This seems to be what win95 does anyway */
1303 return TRUE;
1305 /* Get the unique handle of the printer*/
1306 *phPrinter = get_opened_printer_entry( lpPrinterName );
1308 if (pDefault != NULL)
1309 FIXME("Not handling pDefault\n");
1311 return TRUE;
1314 /******************************************************************
1315 * AddMonitorA [WINSPOOL.@]
1317 * See AddMonitorW.
1320 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1322 LPWSTR nameW = NULL;
1323 INT len;
1324 BOOL res;
1325 LPMONITOR_INFO_2A mi2a;
1326 MONITOR_INFO_2W mi2w;
1328 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1329 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1330 mi2a ? debugstr_a(mi2a->pName) : NULL,
1331 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1332 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1334 if (Level != 2) {
1335 SetLastError(ERROR_INVALID_LEVEL);
1336 return FALSE;
1339 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1340 if (mi2a == NULL) {
1341 return FALSE;
1344 if (pName) {
1345 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1346 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1347 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1350 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1351 if (mi2a->pName) {
1352 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1353 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1354 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1356 if (mi2a->pEnvironment) {
1357 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1358 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1359 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1361 if (mi2a->pDLLName) {
1362 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1363 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1364 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1367 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1369 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1370 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1371 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1373 HeapFree(GetProcessHeap(), 0, nameW);
1374 return (res);
1377 /******************************************************************************
1378 * AddMonitorW [WINSPOOL.@]
1380 * Install a Printmonitor
1382 * PARAMS
1383 * pName [I] Servername or NULL (local Computer)
1384 * Level [I] Structure-Level (Must be 2)
1385 * pMonitors [I] PTR to MONITOR_INFO_2
1387 * RETURNS
1388 * Success: TRUE
1389 * Failure: FALSE
1391 * NOTES
1392 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1395 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1397 LPMONITOR_INFO_2W mi2w;
1398 HKEY hroot = NULL;
1399 HKEY hentry = NULL;
1400 HMODULE hdll = NULL;
1401 DWORD disposition;
1402 BOOL res = FALSE;
1404 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1405 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1406 mi2w ? debugstr_w(mi2w->pName) : NULL,
1407 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1408 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1410 if (Level != 2) {
1411 SetLastError(ERROR_INVALID_LEVEL);
1412 return FALSE;
1415 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1416 if (mi2w == NULL) {
1417 return FALSE;
1420 if (pName && (pName[0])) {
1421 FIXME("for server %s not implemented\n", debugstr_w(pName));
1422 SetLastError(ERROR_ACCESS_DENIED);
1423 return FALSE;
1427 if (!mi2w->pName || (! mi2w->pName[0])) {
1428 WARN("pName not valid : %s \n", debugstr_w(mi2w->pName));
1429 SetLastError(ERROR_INVALID_PARAMETER);
1430 return FALSE;
1432 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1433 WARN("Environment %s requested (we support only %s)\n",
1434 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1435 SetLastError(ERROR_INVALID_ENVIRONMENT);
1436 return FALSE;
1439 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1440 WARN("pDLLName not valid : %s \n", debugstr_w(mi2w->pDLLName));
1441 SetLastError(ERROR_INVALID_PARAMETER);
1442 return FALSE;
1445 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1446 return FALSE;
1448 FreeLibrary(hdll);
1450 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1451 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1452 return FALSE;
1455 if(RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1456 KEY_WRITE, NULL, &hentry, &disposition) == ERROR_SUCCESS) {
1458 if (disposition == REG_OPENED_EXISTING_KEY) {
1459 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1460 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1461 9x: ERROR_ALREADY_EXISTS (183) */
1462 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1464 else
1466 INT len;
1467 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1468 res = (RegSetValueExW(hentry, DriverW, 0,
1469 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1471 RegCloseKey(hentry);
1474 RegCloseKey(hroot);
1475 return (res);
1478 /******************************************************************
1479 * DeletePrinterDriverA [WINSPOOL.@]
1482 BOOL WINAPI
1483 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1485 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1486 debugstr_a(pDriverName));
1487 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1488 return FALSE;
1491 /******************************************************************
1492 * DeletePrinterDriverW [WINSPOOL.@]
1495 BOOL WINAPI
1496 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1498 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1499 debugstr_w(pDriverName));
1500 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1501 return FALSE;
1504 /******************************************************************
1505 * DeleteMonitorA [WINSPOOL.@]
1507 * See DeleteMonitorW.
1510 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1512 LPWSTR nameW = NULL;
1513 LPWSTR EnvironmentW = NULL;
1514 LPWSTR MonitorNameW = NULL;
1515 BOOL res;
1516 INT len;
1518 if (pName) {
1519 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1520 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1521 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1524 if (pEnvironment) {
1525 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1526 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1527 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1529 if (pMonitorName) {
1530 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1531 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1532 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1535 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1537 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1538 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1539 HeapFree(GetProcessHeap(), 0, nameW);
1540 return (res);
1543 /******************************************************************
1544 * DeleteMonitorW [WINSPOOL.@]
1546 * Delete a specific Printmonitor from a Printing-Environment
1548 * PARAMS
1549 * pName [I] Servername or NULL (local Computer)
1550 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1551 * pMonitorName [I] Name of the Monitor, that should be deleted
1553 * RETURNS
1554 * Success: TRUE
1555 * Failure: FALSE
1557 * NOTES
1558 * pEnvironment is ignored in Windows for the local Computer.
1562 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1564 HKEY hroot = NULL;
1566 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1567 debugstr_w(pMonitorName));
1569 if (pName && (pName[0])) {
1570 FIXME("for server %s not implemented\n", debugstr_w(pName));
1571 SetLastError(ERROR_ACCESS_DENIED);
1572 return FALSE;
1575 /* pEnvironment is ignored in Windows for the local Computer */
1577 if (!pMonitorName || !pMonitorName[0]) {
1578 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1579 SetLastError(ERROR_INVALID_PARAMETER);
1580 return FALSE;
1583 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1584 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1585 return FALSE;
1588 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1589 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1590 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1591 RegCloseKey(hroot);
1592 return TRUE;
1595 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1596 RegCloseKey(hroot);
1598 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1599 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1600 return (FALSE);
1603 /******************************************************************
1604 * DeletePortA [WINSPOOL.@]
1606 * See DeletePortW.
1609 BOOL WINAPI
1610 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1612 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1613 debugstr_a(pPortName));
1614 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1615 return FALSE;
1618 /******************************************************************
1619 * DeletePortW [WINSPOOL.@]
1621 * Delete a specific Port
1623 * PARAMS
1624 * pName [I] Servername or NULL (local Computer)
1625 * hWnd [I] Handle to parent Window for the Dialog-Box
1626 * pPortName [I] Name of the Port, that should be deleted
1628 * RETURNS
1629 * Success: TRUE
1630 * Failure: FALSE
1632 * BUGS
1633 * only a Stub
1636 BOOL WINAPI
1637 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1639 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1640 debugstr_w(pPortName));
1641 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1642 return FALSE;
1645 /******************************************************************************
1646 * SetPrinterW [WINSPOOL.@]
1648 BOOL WINAPI
1649 SetPrinterW(
1650 HANDLE hPrinter,
1651 DWORD Level,
1652 LPBYTE pPrinter,
1653 DWORD Command) {
1655 FIXME("():stub\n");
1656 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1657 return FALSE;
1660 /******************************************************************************
1661 * WritePrinter [WINSPOOL.@]
1663 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1665 opened_printer_t *printer;
1666 BOOL ret = FALSE;
1668 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1670 EnterCriticalSection(&printer_handles_cs);
1671 printer = get_opened_printer(hPrinter);
1672 if(!printer)
1674 SetLastError(ERROR_INVALID_HANDLE);
1675 goto end;
1678 if(!printer->doc)
1680 SetLastError(ERROR_SPL_NO_STARTDOC);
1681 goto end;
1684 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1685 end:
1686 LeaveCriticalSection(&printer_handles_cs);
1687 return ret;
1690 /*****************************************************************************
1691 * AddFormA [WINSPOOL.@]
1693 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1695 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1696 return 1;
1699 /*****************************************************************************
1700 * AddFormW [WINSPOOL.@]
1702 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1704 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1705 return 1;
1708 /*****************************************************************************
1709 * AddJobA [WINSPOOL.@]
1711 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1713 BOOL ret;
1714 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1715 DWORD needed;
1717 if(Level != 1) {
1718 SetLastError(ERROR_INVALID_LEVEL);
1719 return FALSE;
1722 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1724 if(ret) {
1725 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1726 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1727 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1728 if(*pcbNeeded > cbBuf) {
1729 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1730 ret = FALSE;
1731 } else {
1732 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1733 addjobA->JobId = addjobW->JobId;
1734 addjobA->Path = (char *)(addjobA + 1);
1735 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1738 return ret;
1741 /*****************************************************************************
1742 * AddJobW [WINSPOOL.@]
1744 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1746 opened_printer_t *printer;
1747 job_t *job;
1748 BOOL ret = FALSE;
1749 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1750 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1751 WCHAR path[MAX_PATH], filename[MAX_PATH];
1752 DWORD len;
1753 ADDJOB_INFO_1W *addjob;
1755 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1757 EnterCriticalSection(&printer_handles_cs);
1759 printer = get_opened_printer(hPrinter);
1761 if(!printer) {
1762 SetLastError(ERROR_INVALID_HANDLE);
1763 goto end;
1766 if(Level != 1) {
1767 SetLastError(ERROR_INVALID_LEVEL);
1768 goto end;
1771 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1772 if(!job)
1773 goto end;
1775 job->job_id = InterlockedIncrement(&next_job_id);
1777 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1778 if(path[len - 1] != '\\')
1779 path[len++] = '\\';
1780 memcpy(path + len, spool_path, sizeof(spool_path));
1781 sprintfW(filename, fmtW, path, job->job_id);
1783 len = strlenW(filename);
1784 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1785 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1786 job->document_title = strdupW(default_doc_title);
1787 list_add_tail(&printer->queue->jobs, &job->entry);
1789 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1790 if(*pcbNeeded <= cbBuf) {
1791 addjob = (ADDJOB_INFO_1W*)pData;
1792 addjob->JobId = job->job_id;
1793 addjob->Path = (WCHAR *)(addjob + 1);
1794 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1795 ret = TRUE;
1796 } else
1797 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1799 end:
1800 LeaveCriticalSection(&printer_handles_cs);
1801 return ret;
1804 /*****************************************************************************
1805 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1807 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1808 DWORD level, LPBYTE Info,
1809 DWORD cbBuf, LPDWORD needed)
1811 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1812 level, Info, cbBuf);
1813 return 0;
1816 /*****************************************************************************
1817 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1819 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1820 DWORD level, LPBYTE Info,
1821 DWORD cbBuf, LPDWORD needed)
1823 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1824 level, Info, cbBuf);
1825 return 0;
1828 /*****************************************************************************
1829 * WINSPOOL_OpenDriverReg [internal]
1831 * opens the registry for the printer drivers depending on the given input
1832 * variable pEnvironment
1834 * RETURNS:
1835 * the opened hkey on success
1836 * NULL on error
1838 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1840 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1841 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1842 HKEY retval;
1843 LPWSTR lpKey, buffer = NULL;
1844 LPCWSTR pEnvW;
1846 TRACE("%s\n",
1847 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1849 if(pEnvironment) {
1850 if (unicode) {
1851 pEnvW = pEnvironment;
1852 } else {
1853 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1854 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1855 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1856 pEnvW = buffer;
1858 } else {
1859 OSVERSIONINFOW ver;
1860 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1862 if(!GetVersionExW( &ver))
1863 return 0;
1865 switch (ver.dwPlatformId) {
1866 case VER_PLATFORM_WIN32s:
1867 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1868 return 0;
1869 case VER_PLATFORM_WIN32_NT:
1870 pEnvW = WinNTW;
1871 break;
1872 default:
1873 pEnvW = Win40W;
1874 break;
1876 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1879 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1880 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1881 wsprintfW( lpKey, DriversW, pEnvW);
1883 TRACE("%s\n", debugstr_w(lpKey));
1885 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1886 retval = 0;
1888 HeapFree( GetProcessHeap(), 0, buffer);
1889 HeapFree( GetProcessHeap(), 0, lpKey);
1891 return retval;
1894 /*****************************************************************************
1895 * AddPrinterW [WINSPOOL.@]
1897 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1899 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1900 LPDEVMODEA dmA;
1901 LPDEVMODEW dmW;
1902 HANDLE retval;
1903 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1904 LONG size;
1906 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1908 if(pName != NULL) {
1909 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1910 SetLastError(ERROR_INVALID_PARAMETER);
1911 return 0;
1913 if(Level != 2) {
1914 ERR("Level = %ld, unsupported!\n", Level);
1915 SetLastError(ERROR_INVALID_LEVEL);
1916 return 0;
1918 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1919 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1920 debugstr_w(pi->pPrinterName)
1922 SetLastError(ERROR_INVALID_LEVEL);
1923 return 0;
1925 if(!pPrinter) {
1926 SetLastError(ERROR_INVALID_PARAMETER);
1927 return 0;
1929 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1930 ERROR_SUCCESS) {
1931 ERR("Can't create Printers key\n");
1932 return 0;
1934 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1935 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1936 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1937 RegCloseKey(hkeyPrinter);
1938 RegCloseKey(hkeyPrinters);
1939 return 0;
1941 RegCloseKey(hkeyPrinter);
1943 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1944 if(!hkeyDrivers) {
1945 ERR("Can't create Drivers key\n");
1946 RegCloseKey(hkeyPrinters);
1947 return 0;
1949 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1950 ERROR_SUCCESS) {
1951 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1952 RegCloseKey(hkeyPrinters);
1953 RegCloseKey(hkeyDrivers);
1954 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1955 return 0;
1957 RegCloseKey(hkeyDriver);
1958 RegCloseKey(hkeyDrivers);
1960 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1961 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1962 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1963 RegCloseKey(hkeyPrinters);
1964 return 0;
1967 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1968 ERROR_SUCCESS) {
1969 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1970 SetLastError(ERROR_INVALID_PRINTER_NAME);
1971 RegCloseKey(hkeyPrinters);
1972 return 0;
1974 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1975 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1976 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1978 /* See if we can load the driver. We may need the devmode structure anyway
1980 * FIXME:
1981 * Note that DocumentPropertiesW will briefly try to open the printer we
1982 * just create to find a DEVMODEA struct (it will use the WINEPS default
1983 * one in case it is not there, so we are ok).
1985 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1987 if(size < 0) {
1988 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1989 size = sizeof(DEVMODEW);
1991 if(pi->pDevMode)
1992 dmW = pi->pDevMode;
1993 else
1995 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1996 ZeroMemory(dmW,size);
1997 dmW->dmSize = size;
1998 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2000 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2001 HeapFree(GetProcessHeap(),0,dmW);
2002 dmW=NULL;
2004 else
2006 /* set devmode to printer name */
2007 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
2011 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2012 and we support these drivers. NT writes DEVMODEW so somehow
2013 we'll need to distinguish between these when we support NT
2014 drivers */
2015 if (dmW)
2017 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2018 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2019 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2020 HeapFree(GetProcessHeap(), 0, dmA);
2021 if(!pi->pDevMode)
2022 HeapFree(GetProcessHeap(), 0, dmW);
2024 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2025 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2026 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2027 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2029 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2030 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2031 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2032 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2033 (LPBYTE)&pi->Priority, sizeof(DWORD));
2034 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2035 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2036 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2037 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2038 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2039 (LPBYTE)&pi->Status, sizeof(DWORD));
2040 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2041 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2043 RegCloseKey(hkeyPrinter);
2044 RegCloseKey(hkeyPrinters);
2045 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2046 ERR("OpenPrinter failing\n");
2047 return 0;
2049 return retval;
2052 /*****************************************************************************
2053 * AddPrinterA [WINSPOOL.@]
2055 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2057 UNICODE_STRING pNameW;
2058 PWSTR pwstrNameW;
2059 PRINTER_INFO_2W *piW;
2060 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2061 HANDLE ret;
2063 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2064 if(Level != 2) {
2065 ERR("Level = %ld, unsupported!\n", Level);
2066 SetLastError(ERROR_INVALID_LEVEL);
2067 return 0;
2069 pwstrNameW = asciitounicode(&pNameW,pName);
2070 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2072 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2074 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2075 RtlFreeUnicodeString(&pNameW);
2076 return ret;
2080 /*****************************************************************************
2081 * ClosePrinter [WINSPOOL.@]
2083 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2085 UINT_PTR i = (UINT_PTR)hPrinter;
2086 opened_printer_t *printer = NULL;
2087 BOOL ret = FALSE;
2089 TRACE("Handle %p\n", hPrinter);
2091 EnterCriticalSection(&printer_handles_cs);
2093 if ((i > 0) && (i <= nb_printer_handles))
2094 printer = printer_handles[i - 1];
2096 if(printer)
2098 struct list *cursor, *cursor2;
2100 if(printer->doc)
2101 EndDocPrinter(hPrinter);
2103 if(InterlockedDecrement(&printer->queue->ref) == 0)
2105 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2107 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2108 ScheduleJob(hPrinter, job->job_id);
2110 HeapFree(GetProcessHeap(), 0, printer->queue);
2112 HeapFree(GetProcessHeap(), 0, printer->name);
2113 HeapFree(GetProcessHeap(), 0, printer);
2114 printer_handles[i - 1] = NULL;
2115 ret = TRUE;
2117 LeaveCriticalSection(&printer_handles_cs);
2118 return ret;
2121 /*****************************************************************************
2122 * DeleteFormA [WINSPOOL.@]
2124 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2126 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2127 return 1;
2130 /*****************************************************************************
2131 * DeleteFormW [WINSPOOL.@]
2133 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2135 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2136 return 1;
2139 /*****************************************************************************
2140 * WINSPOOL_SHRegDeleteKey
2142 * Recursively delete subkeys.
2143 * Cut & paste from shlwapi.
2146 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2148 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2149 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2150 HKEY hSubKey = 0;
2152 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2153 if(!dwRet)
2155 /* Find how many subkeys there are */
2156 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2157 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2158 if(!dwRet)
2160 dwMaxSubkeyLen++;
2161 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2162 /* Name too big: alloc a buffer for it */
2163 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2165 if(!lpszName)
2166 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2167 else
2169 /* Recursively delete all the subkeys */
2170 for(i = 0; i < dwKeyCount && !dwRet; i++)
2172 dwSize = dwMaxSubkeyLen;
2173 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2174 if(!dwRet)
2175 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2178 if (lpszName != szNameBuf)
2179 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2183 RegCloseKey(hSubKey);
2184 if(!dwRet)
2185 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2187 return dwRet;
2190 /*****************************************************************************
2191 * DeletePrinter [WINSPOOL.@]
2193 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2195 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2196 HKEY hkeyPrinters, hkey;
2198 if(!lpNameW) {
2199 SetLastError(ERROR_INVALID_HANDLE);
2200 return FALSE;
2202 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
2203 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2204 RegCloseKey(hkeyPrinters);
2206 WriteProfileStringW(devicesW, lpNameW, NULL);
2207 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2208 RegDeleteValueW(hkey, lpNameW);
2209 RegCloseKey(hkey);
2211 return TRUE;
2214 /*****************************************************************************
2215 * SetPrinterA [WINSPOOL.@]
2217 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2218 DWORD Command)
2220 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2221 return FALSE;
2224 /*****************************************************************************
2225 * SetJobA [WINSPOOL.@]
2227 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2228 LPBYTE pJob, DWORD Command)
2230 BOOL ret;
2231 LPBYTE JobW;
2232 UNICODE_STRING usBuffer;
2234 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2236 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2237 are all ignored by SetJob, so we don't bother copying them */
2238 switch(Level)
2240 case 0:
2241 JobW = NULL;
2242 break;
2243 case 1:
2245 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2246 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2248 JobW = (LPBYTE)info1W;
2249 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2250 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2251 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2252 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2253 info1W->Status = info1A->Status;
2254 info1W->Priority = info1A->Priority;
2255 info1W->Position = info1A->Position;
2256 info1W->PagesPrinted = info1A->PagesPrinted;
2257 break;
2259 case 2:
2261 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2262 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2264 JobW = (LPBYTE)info2W;
2265 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2266 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2267 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2268 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2269 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2270 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2271 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2272 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2273 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2274 info2W->Status = info2A->Status;
2275 info2W->Priority = info2A->Priority;
2276 info2W->Position = info2A->Position;
2277 info2W->StartTime = info2A->StartTime;
2278 info2W->UntilTime = info2A->UntilTime;
2279 info2W->PagesPrinted = info2A->PagesPrinted;
2280 break;
2282 case 3:
2283 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2284 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2285 break;
2286 default:
2287 SetLastError(ERROR_INVALID_LEVEL);
2288 return FALSE;
2291 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2293 switch(Level)
2295 case 1:
2297 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2298 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2299 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2300 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2301 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2302 break;
2304 case 2:
2306 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2307 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2308 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2309 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2310 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2311 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2312 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2313 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2314 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2315 break;
2318 HeapFree(GetProcessHeap(), 0, JobW);
2320 return ret;
2323 /*****************************************************************************
2324 * SetJobW [WINSPOOL.@]
2326 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2327 LPBYTE pJob, DWORD Command)
2329 BOOL ret = FALSE;
2330 job_t *job;
2332 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2333 FIXME("Ignoring everything other than document title\n");
2335 EnterCriticalSection(&printer_handles_cs);
2336 job = get_job(hPrinter, JobId);
2337 if(!job)
2338 goto end;
2340 switch(Level)
2342 case 0:
2343 break;
2344 case 1:
2346 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2347 HeapFree(GetProcessHeap(), 0, job->document_title);
2348 job->document_title = strdupW(info1->pDocument);
2349 break;
2351 case 2:
2353 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2354 HeapFree(GetProcessHeap(), 0, job->document_title);
2355 job->document_title = strdupW(info2->pDocument);
2356 break;
2358 case 3:
2359 break;
2360 default:
2361 SetLastError(ERROR_INVALID_LEVEL);
2362 goto end;
2364 ret = TRUE;
2365 end:
2366 LeaveCriticalSection(&printer_handles_cs);
2367 return ret;
2370 /*****************************************************************************
2371 * EndDocPrinter [WINSPOOL.@]
2373 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2375 opened_printer_t *printer;
2376 BOOL ret = FALSE;
2377 TRACE("(%p)\n", hPrinter);
2379 EnterCriticalSection(&printer_handles_cs);
2381 printer = get_opened_printer(hPrinter);
2382 if(!printer)
2384 SetLastError(ERROR_INVALID_HANDLE);
2385 goto end;
2388 if(!printer->doc)
2390 SetLastError(ERROR_SPL_NO_STARTDOC);
2391 goto end;
2394 CloseHandle(printer->doc->hf);
2395 ScheduleJob(hPrinter, printer->doc->job_id);
2396 HeapFree(GetProcessHeap(), 0, printer->doc);
2397 printer->doc = NULL;
2398 ret = TRUE;
2399 end:
2400 LeaveCriticalSection(&printer_handles_cs);
2401 return ret;
2404 /*****************************************************************************
2405 * EndPagePrinter [WINSPOOL.@]
2407 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2409 FIXME("(%p): stub\n", hPrinter);
2410 return TRUE;
2413 /*****************************************************************************
2414 * StartDocPrinterA [WINSPOOL.@]
2416 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2418 UNICODE_STRING usBuffer;
2419 DOC_INFO_2W doc2W;
2420 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2421 DWORD ret;
2423 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2424 or one (DOC_INFO_3) extra DWORDs */
2426 switch(Level) {
2427 case 2:
2428 doc2W.JobId = doc2->JobId;
2429 /* fall through */
2430 case 3:
2431 doc2W.dwMode = doc2->dwMode;
2432 /* fall through */
2433 case 1:
2434 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2435 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2436 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2437 break;
2439 default:
2440 SetLastError(ERROR_INVALID_LEVEL);
2441 return FALSE;
2444 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2446 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2447 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2448 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2450 return ret;
2453 /*****************************************************************************
2454 * StartDocPrinterW [WINSPOOL.@]
2456 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2458 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2459 opened_printer_t *printer;
2460 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2461 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2462 JOB_INFO_1W job_info;
2463 DWORD needed, ret = 0;
2464 HANDLE hf;
2465 WCHAR *filename;
2467 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2468 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2469 debugstr_w(doc->pDatatype));
2471 if(Level < 1 || Level > 3)
2473 SetLastError(ERROR_INVALID_LEVEL);
2474 return 0;
2477 EnterCriticalSection(&printer_handles_cs);
2478 printer = get_opened_printer(hPrinter);
2479 if(!printer)
2481 SetLastError(ERROR_INVALID_HANDLE);
2482 goto end;
2485 if(printer->doc)
2487 SetLastError(ERROR_INVALID_PRINTER_STATE);
2488 goto end;
2491 /* Even if we're printing to a file we still add a print job, we'll
2492 just ignore the spool file name */
2494 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2496 ERR("AddJob failed gle %08lx\n", GetLastError());
2497 goto end;
2500 if(doc->pOutputFile)
2501 filename = doc->pOutputFile;
2502 else
2503 filename = addjob->Path;
2505 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2506 if(hf == INVALID_HANDLE_VALUE)
2507 goto end;
2509 memset(&job_info, 0, sizeof(job_info));
2510 job_info.pDocument = doc->pDocName;
2511 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2513 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2514 printer->doc->hf = hf;
2515 ret = printer->doc->job_id = addjob->JobId;
2516 end:
2517 LeaveCriticalSection(&printer_handles_cs);
2519 return ret;
2522 /*****************************************************************************
2523 * StartPagePrinter [WINSPOOL.@]
2525 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2527 FIXME("(%p): stub\n", hPrinter);
2528 return TRUE;
2531 /*****************************************************************************
2532 * GetFormA [WINSPOOL.@]
2534 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2535 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2537 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2538 Level,pForm,cbBuf,pcbNeeded);
2539 return FALSE;
2542 /*****************************************************************************
2543 * GetFormW [WINSPOOL.@]
2545 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2546 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2548 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2549 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2550 return FALSE;
2553 /*****************************************************************************
2554 * SetFormA [WINSPOOL.@]
2556 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2557 LPBYTE pForm)
2559 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2560 return FALSE;
2563 /*****************************************************************************
2564 * SetFormW [WINSPOOL.@]
2566 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2567 LPBYTE pForm)
2569 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2570 return FALSE;
2573 /*****************************************************************************
2574 * ReadPrinter [WINSPOOL.@]
2576 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2577 LPDWORD pNoBytesRead)
2579 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2580 return FALSE;
2583 /*****************************************************************************
2584 * ResetPrinterA [WINSPOOL.@]
2586 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2588 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2589 return FALSE;
2592 /*****************************************************************************
2593 * ResetPrinterW [WINSPOOL.@]
2595 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2597 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2598 return FALSE;
2601 /*****************************************************************************
2602 * WINSPOOL_GetDWORDFromReg
2604 * Return DWORD associated with ValueName from hkey.
2606 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2608 DWORD sz = sizeof(DWORD), type, value = 0;
2609 LONG ret;
2611 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2613 if(ret != ERROR_SUCCESS) {
2614 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2615 return 0;
2617 if(type != REG_DWORD) {
2618 ERR("Got type %ld\n", type);
2619 return 0;
2621 return value;
2624 /*****************************************************************************
2625 * WINSPOOL_GetStringFromReg
2627 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2628 * String is stored either as unicode or ascii.
2629 * Bit of a hack here to get the ValueName if we want ascii.
2631 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2632 DWORD buflen, DWORD *needed,
2633 BOOL unicode)
2635 DWORD sz = buflen, type;
2636 LONG ret;
2638 if(unicode)
2639 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2640 else {
2641 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2642 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2643 HeapFree(GetProcessHeap(),0,ValueNameA);
2645 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2646 WARN("Got ret = %ld\n", ret);
2647 *needed = 0;
2648 return FALSE;
2650 /* add space for terminating '\0' */
2651 sz += unicode ? sizeof(WCHAR) : 1;
2652 *needed = sz;
2654 if (ptr)
2655 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2657 return TRUE;
2660 /*****************************************************************************
2661 * WINSPOOL_GetDefaultDevMode
2663 * Get a default DevMode values for wineps.
2664 * FIXME - use ppd.
2667 static void WINSPOOL_GetDefaultDevMode(
2668 LPBYTE ptr,
2669 DWORD buflen, DWORD *needed,
2670 BOOL unicode)
2672 DEVMODEA dm;
2673 static const char szwps[] = "wineps.drv";
2675 /* fill default DEVMODE - should be read from ppd... */
2676 ZeroMemory( &dm, sizeof(dm) );
2677 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2678 dm.dmSpecVersion = DM_SPECVERSION;
2679 dm.dmDriverVersion = 1;
2680 dm.dmSize = sizeof(DEVMODEA);
2681 dm.dmDriverExtra = 0;
2682 dm.dmFields =
2683 DM_ORIENTATION | DM_PAPERSIZE |
2684 DM_PAPERLENGTH | DM_PAPERWIDTH |
2685 DM_SCALE |
2686 DM_COPIES |
2687 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2688 DM_YRESOLUTION | DM_TTOPTION;
2690 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2691 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2692 dm.u1.s1.dmPaperLength = 2970;
2693 dm.u1.s1.dmPaperWidth = 2100;
2695 dm.dmScale = 100;
2696 dm.dmCopies = 1;
2697 dm.dmDefaultSource = DMBIN_AUTO;
2698 dm.dmPrintQuality = DMRES_MEDIUM;
2699 /* dm.dmColor */
2700 /* dm.dmDuplex */
2701 dm.dmYResolution = 300; /* 300dpi */
2702 dm.dmTTOption = DMTT_BITMAP;
2703 /* dm.dmCollate */
2704 /* dm.dmFormName */
2705 /* dm.dmLogPixels */
2706 /* dm.dmBitsPerPel */
2707 /* dm.dmPelsWidth */
2708 /* dm.dmPelsHeight */
2709 /* dm.dmDisplayFlags */
2710 /* dm.dmDisplayFrequency */
2711 /* dm.dmICMMethod */
2712 /* dm.dmICMIntent */
2713 /* dm.dmMediaType */
2714 /* dm.dmDitherType */
2715 /* dm.dmReserved1 */
2716 /* dm.dmReserved2 */
2717 /* dm.dmPanningWidth */
2718 /* dm.dmPanningHeight */
2720 if(unicode) {
2721 if(buflen >= sizeof(DEVMODEW)) {
2722 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2723 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2724 HeapFree(GetProcessHeap(),0,pdmW);
2726 *needed = sizeof(DEVMODEW);
2728 else
2730 if(buflen >= sizeof(DEVMODEA)) {
2731 memcpy(ptr, &dm, sizeof(DEVMODEA));
2733 *needed = sizeof(DEVMODEA);
2737 /*****************************************************************************
2738 * WINSPOOL_GetDevModeFromReg
2740 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2741 * DevMode is stored either as unicode or ascii.
2743 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2744 LPBYTE ptr,
2745 DWORD buflen, DWORD *needed,
2746 BOOL unicode)
2748 DWORD sz = buflen, type;
2749 LONG ret;
2751 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2752 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2753 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2754 if (sz < sizeof(DEVMODEA))
2756 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2757 return FALSE;
2759 /* ensures that dmSize is not erratically bogus if registry is invalid */
2760 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2761 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2762 if(unicode) {
2763 sz += (CCHDEVICENAME + CCHFORMNAME);
2764 if(buflen >= sz) {
2765 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2766 memcpy(ptr, dmW, sz);
2767 HeapFree(GetProcessHeap(),0,dmW);
2770 *needed = sz;
2771 return TRUE;
2774 /*********************************************************************
2775 * WINSPOOL_GetPrinter_2
2777 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2778 * The strings are either stored as unicode or ascii.
2780 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2781 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2782 BOOL unicode)
2784 DWORD size, left = cbBuf;
2785 BOOL space = (cbBuf > 0);
2786 LPBYTE ptr = buf;
2788 *pcbNeeded = 0;
2790 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2791 unicode)) {
2792 if(space && size <= left) {
2793 pi2->pPrinterName = (LPWSTR)ptr;
2794 ptr += size;
2795 left -= size;
2796 } else
2797 space = FALSE;
2798 *pcbNeeded += size;
2800 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2801 unicode)) {
2802 if(space && size <= left) {
2803 pi2->pShareName = (LPWSTR)ptr;
2804 ptr += size;
2805 left -= size;
2806 } else
2807 space = FALSE;
2808 *pcbNeeded += size;
2810 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2811 unicode)) {
2812 if(space && size <= left) {
2813 pi2->pPortName = (LPWSTR)ptr;
2814 ptr += size;
2815 left -= size;
2816 } else
2817 space = FALSE;
2818 *pcbNeeded += size;
2820 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2821 &size, unicode)) {
2822 if(space && size <= left) {
2823 pi2->pDriverName = (LPWSTR)ptr;
2824 ptr += size;
2825 left -= size;
2826 } else
2827 space = FALSE;
2828 *pcbNeeded += size;
2830 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2831 unicode)) {
2832 if(space && size <= left) {
2833 pi2->pComment = (LPWSTR)ptr;
2834 ptr += size;
2835 left -= size;
2836 } else
2837 space = FALSE;
2838 *pcbNeeded += size;
2840 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2841 unicode)) {
2842 if(space && size <= left) {
2843 pi2->pLocation = (LPWSTR)ptr;
2844 ptr += size;
2845 left -= size;
2846 } else
2847 space = FALSE;
2848 *pcbNeeded += size;
2850 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2851 &size, unicode)) {
2852 if(space && size <= left) {
2853 pi2->pDevMode = (LPDEVMODEW)ptr;
2854 ptr += size;
2855 left -= size;
2856 } else
2857 space = FALSE;
2858 *pcbNeeded += size;
2860 else
2862 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2863 if(space && size <= left) {
2864 pi2->pDevMode = (LPDEVMODEW)ptr;
2865 ptr += size;
2866 left -= size;
2867 } else
2868 space = FALSE;
2869 *pcbNeeded += size;
2871 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2872 &size, unicode)) {
2873 if(space && size <= left) {
2874 pi2->pSepFile = (LPWSTR)ptr;
2875 ptr += size;
2876 left -= size;
2877 } else
2878 space = FALSE;
2879 *pcbNeeded += size;
2881 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2882 &size, unicode)) {
2883 if(space && size <= left) {
2884 pi2->pPrintProcessor = (LPWSTR)ptr;
2885 ptr += size;
2886 left -= size;
2887 } else
2888 space = FALSE;
2889 *pcbNeeded += size;
2891 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2892 &size, unicode)) {
2893 if(space && size <= left) {
2894 pi2->pDatatype = (LPWSTR)ptr;
2895 ptr += size;
2896 left -= size;
2897 } else
2898 space = FALSE;
2899 *pcbNeeded += size;
2901 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2902 &size, unicode)) {
2903 if(space && size <= left) {
2904 pi2->pParameters = (LPWSTR)ptr;
2905 ptr += size;
2906 left -= size;
2907 } else
2908 space = FALSE;
2909 *pcbNeeded += size;
2911 if(pi2) {
2912 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2913 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2914 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2915 "Default Priority");
2916 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2917 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2920 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2921 memset(pi2, 0, sizeof(*pi2));
2923 return space;
2926 /*********************************************************************
2927 * WINSPOOL_GetPrinter_4
2929 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2931 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2932 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2933 BOOL unicode)
2935 DWORD size, left = cbBuf;
2936 BOOL space = (cbBuf > 0);
2937 LPBYTE ptr = buf;
2939 *pcbNeeded = 0;
2941 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2942 unicode)) {
2943 if(space && size <= left) {
2944 pi4->pPrinterName = (LPWSTR)ptr;
2945 ptr += size;
2946 left -= size;
2947 } else
2948 space = FALSE;
2949 *pcbNeeded += size;
2951 if(pi4) {
2952 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2955 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2956 memset(pi4, 0, sizeof(*pi4));
2958 return space;
2961 /*********************************************************************
2962 * WINSPOOL_GetPrinter_5
2964 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2966 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2967 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2968 BOOL unicode)
2970 DWORD size, left = cbBuf;
2971 BOOL space = (cbBuf > 0);
2972 LPBYTE ptr = buf;
2974 *pcbNeeded = 0;
2976 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2977 unicode)) {
2978 if(space && size <= left) {
2979 pi5->pPrinterName = (LPWSTR)ptr;
2980 ptr += size;
2981 left -= size;
2982 } else
2983 space = FALSE;
2984 *pcbNeeded += size;
2986 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2987 unicode)) {
2988 if(space && size <= left) {
2989 pi5->pPortName = (LPWSTR)ptr;
2990 ptr += size;
2991 left -= size;
2992 } else
2993 space = FALSE;
2994 *pcbNeeded += size;
2996 if(pi5) {
2997 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2998 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2999 "dnsTimeout");
3000 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3001 "txTimeout");
3004 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3005 memset(pi5, 0, sizeof(*pi5));
3007 return space;
3010 /*****************************************************************************
3011 * WINSPOOL_GetPrinter
3013 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3014 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3015 * just a collection of pointers to strings.
3017 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3018 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3020 LPCWSTR name;
3021 DWORD size, needed = 0;
3022 LPBYTE ptr = NULL;
3023 HKEY hkeyPrinter, hkeyPrinters;
3024 BOOL ret;
3026 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3028 if (!(name = get_opened_printer_name(hPrinter))) {
3029 SetLastError(ERROR_INVALID_HANDLE);
3030 return FALSE;
3033 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3034 ERROR_SUCCESS) {
3035 ERR("Can't create Printers key\n");
3036 return FALSE;
3038 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3040 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3041 RegCloseKey(hkeyPrinters);
3042 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3043 return FALSE;
3046 switch(Level) {
3047 case 2:
3049 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3051 size = sizeof(PRINTER_INFO_2W);
3052 if(size <= cbBuf) {
3053 ptr = pPrinter + size;
3054 cbBuf -= size;
3055 memset(pPrinter, 0, size);
3056 } else {
3057 pi2 = NULL;
3058 cbBuf = 0;
3060 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3061 unicode);
3062 needed += size;
3063 break;
3066 case 4:
3068 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3070 size = sizeof(PRINTER_INFO_4W);
3071 if(size <= cbBuf) {
3072 ptr = pPrinter + size;
3073 cbBuf -= size;
3074 memset(pPrinter, 0, size);
3075 } else {
3076 pi4 = NULL;
3077 cbBuf = 0;
3079 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3080 unicode);
3081 needed += size;
3082 break;
3086 case 5:
3088 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3090 size = sizeof(PRINTER_INFO_5W);
3091 if(size <= cbBuf) {
3092 ptr = pPrinter + size;
3093 cbBuf -= size;
3094 memset(pPrinter, 0, size);
3095 } else {
3096 pi5 = NULL;
3097 cbBuf = 0;
3100 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3101 unicode);
3102 needed += size;
3103 break;
3106 default:
3107 FIXME("Unimplemented level %ld\n", Level);
3108 SetLastError(ERROR_INVALID_LEVEL);
3109 RegCloseKey(hkeyPrinters);
3110 RegCloseKey(hkeyPrinter);
3111 return FALSE;
3114 RegCloseKey(hkeyPrinter);
3115 RegCloseKey(hkeyPrinters);
3117 TRACE("returning %d needed = %ld\n", ret, needed);
3118 if(pcbNeeded) *pcbNeeded = needed;
3119 if(!ret)
3120 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3121 return ret;
3124 /*****************************************************************************
3125 * GetPrinterW [WINSPOOL.@]
3127 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3128 DWORD cbBuf, LPDWORD pcbNeeded)
3130 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3131 TRUE);
3134 /*****************************************************************************
3135 * GetPrinterA [WINSPOOL.@]
3137 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3138 DWORD cbBuf, LPDWORD pcbNeeded)
3140 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3141 FALSE);
3144 /*****************************************************************************
3145 * WINSPOOL_EnumPrinters
3147 * Implementation of EnumPrintersA|W
3149 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3150 DWORD dwLevel, LPBYTE lpbPrinters,
3151 DWORD cbBuf, LPDWORD lpdwNeeded,
3152 LPDWORD lpdwReturned, BOOL unicode)
3155 HKEY hkeyPrinters, hkeyPrinter;
3156 WCHAR PrinterName[255];
3157 DWORD needed = 0, number = 0;
3158 DWORD used, i, left;
3159 PBYTE pi, buf;
3161 if(lpbPrinters)
3162 memset(lpbPrinters, 0, cbBuf);
3163 if(lpdwReturned)
3164 *lpdwReturned = 0;
3165 if(lpdwNeeded)
3166 *lpdwNeeded = 0;
3168 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3169 if(dwType == PRINTER_ENUM_DEFAULT)
3170 return TRUE;
3172 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3173 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3174 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3175 if(!dwType) return TRUE;
3178 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3179 FIXME("dwType = %08lx\n", dwType);
3180 SetLastError(ERROR_INVALID_FLAGS);
3181 return FALSE;
3184 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3185 ERROR_SUCCESS) {
3186 ERR("Can't create Printers key\n");
3187 return FALSE;
3190 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3191 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3192 RegCloseKey(hkeyPrinters);
3193 ERR("Can't query Printers key\n");
3194 return FALSE;
3196 TRACE("Found %ld printers\n", number);
3198 switch(dwLevel) {
3199 case 1:
3200 RegCloseKey(hkeyPrinters);
3201 if (lpdwReturned)
3202 *lpdwReturned = number;
3203 return TRUE;
3205 case 2:
3206 used = number * sizeof(PRINTER_INFO_2W);
3207 break;
3208 case 4:
3209 used = number * sizeof(PRINTER_INFO_4W);
3210 break;
3211 case 5:
3212 used = number * sizeof(PRINTER_INFO_5W);
3213 break;
3215 default:
3216 SetLastError(ERROR_INVALID_LEVEL);
3217 RegCloseKey(hkeyPrinters);
3218 return FALSE;
3220 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3222 for(i = 0; i < number; i++) {
3223 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3224 ERROR_SUCCESS) {
3225 ERR("Can't enum key number %ld\n", i);
3226 RegCloseKey(hkeyPrinters);
3227 return FALSE;
3229 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3230 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3231 ERROR_SUCCESS) {
3232 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3233 RegCloseKey(hkeyPrinters);
3234 return FALSE;
3237 if(cbBuf > used) {
3238 buf = lpbPrinters + used;
3239 left = cbBuf - used;
3240 } else {
3241 buf = NULL;
3242 left = 0;
3245 switch(dwLevel) {
3246 case 2:
3247 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3248 left, &needed, unicode);
3249 used += needed;
3250 if(pi) pi += sizeof(PRINTER_INFO_2W);
3251 break;
3252 case 4:
3253 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3254 left, &needed, unicode);
3255 used += needed;
3256 if(pi) pi += sizeof(PRINTER_INFO_4W);
3257 break;
3258 case 5:
3259 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3260 left, &needed, unicode);
3261 used += needed;
3262 if(pi) pi += sizeof(PRINTER_INFO_5W);
3263 break;
3264 default:
3265 ERR("Shouldn't be here!\n");
3266 RegCloseKey(hkeyPrinter);
3267 RegCloseKey(hkeyPrinters);
3268 return FALSE;
3270 RegCloseKey(hkeyPrinter);
3272 RegCloseKey(hkeyPrinters);
3274 if(lpdwNeeded)
3275 *lpdwNeeded = used;
3277 if(used > cbBuf) {
3278 if(lpbPrinters)
3279 memset(lpbPrinters, 0, cbBuf);
3280 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3281 return FALSE;
3283 if(lpdwReturned)
3284 *lpdwReturned = number;
3285 SetLastError(ERROR_SUCCESS);
3286 return TRUE;
3290 /******************************************************************
3291 * EnumPrintersW [WINSPOOL.@]
3293 * Enumerates the available printers, print servers and print
3294 * providers, depending on the specified flags, name and level.
3296 * RETURNS:
3298 * If level is set to 1:
3299 * Not implemented yet!
3300 * Returns TRUE with an empty list.
3302 * If level is set to 2:
3303 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3304 * Returns an array of PRINTER_INFO_2 data structures in the
3305 * lpbPrinters buffer. Note that according to MSDN also an
3306 * OpenPrinter should be performed on every remote printer.
3308 * If level is set to 4 (officially WinNT only):
3309 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3310 * Fast: Only the registry is queried to retrieve printer names,
3311 * no connection to the driver is made.
3312 * Returns an array of PRINTER_INFO_4 data structures in the
3313 * lpbPrinters buffer.
3315 * If level is set to 5 (officially WinNT4/Win9x only):
3316 * Fast: Only the registry is queried to retrieve printer names,
3317 * no connection to the driver is made.
3318 * Returns an array of PRINTER_INFO_5 data structures in the
3319 * lpbPrinters buffer.
3321 * If level set to 3 or 6+:
3322 * returns zero (failure!)
3324 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3325 * for information.
3327 * BUGS:
3328 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3329 * - Only levels 2, 4 and 5 are implemented at the moment.
3330 * - 16-bit printer drivers are not enumerated.
3331 * - Returned amount of bytes used/needed does not match the real Windoze
3332 * implementation (as in this implementation, all strings are part
3333 * of the buffer, whereas Win32 keeps them somewhere else)
3334 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3336 * NOTE:
3337 * - In a regular Wine installation, no registry settings for printers
3338 * exist, which makes this function return an empty list.
3340 BOOL WINAPI EnumPrintersW(
3341 DWORD dwType, /* [in] Types of print objects to enumerate */
3342 LPWSTR lpszName, /* [in] name of objects to enumerate */
3343 DWORD dwLevel, /* [in] type of printer info structure */
3344 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3345 DWORD cbBuf, /* [in] max size of buffer in bytes */
3346 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3347 LPDWORD lpdwReturned /* [out] number of entries returned */
3350 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3351 lpdwNeeded, lpdwReturned, TRUE);
3354 /******************************************************************
3355 * EnumPrintersA [WINSPOOL.@]
3358 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3359 DWORD dwLevel, LPBYTE lpbPrinters,
3360 DWORD cbBuf, LPDWORD lpdwNeeded,
3361 LPDWORD lpdwReturned)
3363 BOOL ret;
3364 UNICODE_STRING lpszNameW;
3365 PWSTR pwstrNameW;
3367 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3368 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3369 lpdwNeeded, lpdwReturned, FALSE);
3370 RtlFreeUnicodeString(&lpszNameW);
3371 return ret;
3374 /*****************************************************************************
3375 * WINSPOOL_GetDriverInfoFromReg [internal]
3377 * Enters the information from the registry into the DRIVER_INFO struct
3379 * RETURNS
3380 * zero if the printer driver does not exist in the registry
3381 * (only if Level > 1) otherwise nonzero
3383 static BOOL WINSPOOL_GetDriverInfoFromReg(
3384 HKEY hkeyDrivers,
3385 LPWSTR DriverName,
3386 LPWSTR pEnvironment,
3387 DWORD Level,
3388 LPBYTE ptr, /* DRIVER_INFO */
3389 LPBYTE pDriverStrings, /* strings buffer */
3390 DWORD cbBuf, /* size of string buffer */
3391 LPDWORD pcbNeeded, /* space needed for str. */
3392 BOOL unicode) /* type of strings */
3394 DWORD size, tmp;
3395 HKEY hkeyDriver;
3396 LPBYTE strPtr = pDriverStrings;
3398 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3399 debugstr_w(DriverName), debugstr_w(pEnvironment),
3400 Level, ptr, pDriverStrings, cbBuf, unicode);
3402 if(unicode) {
3403 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3404 if (*pcbNeeded <= cbBuf)
3405 strcpyW((LPWSTR)strPtr, DriverName);
3406 } else {
3407 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3408 NULL, NULL);
3409 if(*pcbNeeded <= cbBuf)
3410 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3411 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3413 if(Level == 1) {
3414 if(ptr)
3415 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3416 return TRUE;
3417 } else {
3418 if(ptr)
3419 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3420 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3423 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3424 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3425 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3426 return FALSE;
3429 if(ptr)
3430 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3432 if(!pEnvironment)
3433 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3434 if(unicode)
3435 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3436 else
3437 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3438 NULL, NULL);
3439 *pcbNeeded += size;
3440 if(*pcbNeeded <= cbBuf) {
3441 if(unicode)
3442 strcpyW((LPWSTR)strPtr, pEnvironment);
3443 else
3444 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3445 (LPSTR)strPtr, size, NULL, NULL);
3446 if(ptr)
3447 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3448 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3451 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3452 unicode)) {
3453 *pcbNeeded += size;
3454 if(*pcbNeeded <= cbBuf)
3455 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3456 unicode);
3457 if(ptr)
3458 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3459 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3462 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3463 unicode)) {
3464 *pcbNeeded += size;
3465 if(*pcbNeeded <= cbBuf)
3466 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3467 &tmp, unicode);
3468 if(ptr)
3469 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3470 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3473 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3474 0, &size, unicode)) {
3475 *pcbNeeded += size;
3476 if(*pcbNeeded <= cbBuf)
3477 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3478 size, &tmp, unicode);
3479 if(ptr)
3480 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3481 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3484 if(Level == 2 ) {
3485 RegCloseKey(hkeyDriver);
3486 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3487 return TRUE;
3490 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3491 unicode)) {
3492 *pcbNeeded += size;
3493 if(*pcbNeeded <= cbBuf)
3494 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3495 size, &tmp, unicode);
3496 if(ptr)
3497 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3498 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3501 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3502 &size, unicode)) {
3503 *pcbNeeded += size;
3504 if(*pcbNeeded <= cbBuf)
3505 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3506 size, &tmp, unicode);
3507 if(ptr)
3508 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3509 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3512 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3513 unicode)) {
3514 *pcbNeeded += size;
3515 if(*pcbNeeded <= cbBuf)
3516 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3517 size, &tmp, unicode);
3518 if(ptr)
3519 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3520 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3523 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3524 unicode)) {
3525 *pcbNeeded += size;
3526 if(*pcbNeeded <= cbBuf)
3527 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3528 size, &tmp, unicode);
3529 if(ptr)
3530 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3531 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3534 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3535 RegCloseKey(hkeyDriver);
3536 return TRUE;
3539 /*****************************************************************************
3540 * WINSPOOL_GetPrinterDriver
3542 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3543 DWORD Level, LPBYTE pDriverInfo,
3544 DWORD cbBuf, LPDWORD pcbNeeded,
3545 BOOL unicode)
3547 LPCWSTR name;
3548 WCHAR DriverName[100];
3549 DWORD ret, type, size, needed = 0;
3550 LPBYTE ptr = NULL;
3551 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3553 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3554 Level,pDriverInfo,cbBuf, pcbNeeded);
3556 ZeroMemory(pDriverInfo, cbBuf);
3558 if (!(name = get_opened_printer_name(hPrinter))) {
3559 SetLastError(ERROR_INVALID_HANDLE);
3560 return FALSE;
3562 if(Level < 1 || Level > 6) {
3563 SetLastError(ERROR_INVALID_LEVEL);
3564 return FALSE;
3566 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3567 ERROR_SUCCESS) {
3568 ERR("Can't create Printers key\n");
3569 return FALSE;
3571 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3572 != ERROR_SUCCESS) {
3573 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3574 RegCloseKey(hkeyPrinters);
3575 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3576 return FALSE;
3578 size = sizeof(DriverName);
3579 DriverName[0] = 0;
3580 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3581 (LPBYTE)DriverName, &size);
3582 RegCloseKey(hkeyPrinter);
3583 RegCloseKey(hkeyPrinters);
3584 if(ret != ERROR_SUCCESS) {
3585 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3586 return FALSE;
3589 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3590 if(!hkeyDrivers) {
3591 ERR("Can't create Drivers key\n");
3592 return FALSE;
3595 switch(Level) {
3596 case 1:
3597 size = sizeof(DRIVER_INFO_1W);
3598 break;
3599 case 2:
3600 size = sizeof(DRIVER_INFO_2W);
3601 break;
3602 case 3:
3603 size = sizeof(DRIVER_INFO_3W);
3604 break;
3605 case 4:
3606 size = sizeof(DRIVER_INFO_4W);
3607 break;
3608 case 5:
3609 size = sizeof(DRIVER_INFO_5W);
3610 break;
3611 case 6:
3612 size = sizeof(DRIVER_INFO_6W);
3613 break;
3614 default:
3615 ERR("Invalid level\n");
3616 return FALSE;
3619 if(size <= cbBuf)
3620 ptr = pDriverInfo + size;
3622 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3623 pEnvironment, Level, pDriverInfo,
3624 (cbBuf < size) ? NULL : ptr,
3625 (cbBuf < size) ? 0 : cbBuf - size,
3626 &needed, unicode)) {
3627 RegCloseKey(hkeyDrivers);
3628 return FALSE;
3631 RegCloseKey(hkeyDrivers);
3633 if(pcbNeeded) *pcbNeeded = size + needed;
3634 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3635 if(cbBuf >= needed) return TRUE;
3636 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3637 return FALSE;
3640 /*****************************************************************************
3641 * GetPrinterDriverA [WINSPOOL.@]
3643 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3644 DWORD Level, LPBYTE pDriverInfo,
3645 DWORD cbBuf, LPDWORD pcbNeeded)
3647 BOOL ret;
3648 UNICODE_STRING pEnvW;
3649 PWSTR pwstrEnvW;
3651 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3652 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3653 cbBuf, pcbNeeded, FALSE);
3654 RtlFreeUnicodeString(&pEnvW);
3655 return ret;
3657 /*****************************************************************************
3658 * GetPrinterDriverW [WINSPOOL.@]
3660 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3661 DWORD Level, LPBYTE pDriverInfo,
3662 DWORD cbBuf, LPDWORD pcbNeeded)
3664 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3665 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3668 /*****************************************************************************
3669 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3671 * Return the PATH for the Printer-Drivers (UNICODE)
3673 * PARAMS
3674 * pName [I] Servername (NT only) or NULL (local Computer)
3675 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3676 * Level [I] Structure-Level (must be 1)
3677 * pDriverDirectory [O] PTR to Buffer that receives the Result
3678 * cbBuf [I] Size of Buffer at pDriverDirectory
3679 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3680 * required for pDriverDirectory
3682 * RETURNS
3683 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3684 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3685 * if cbBuf is too small
3687 * Native Values returned in pDriverDirectory on Success:
3688 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3689 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3690 *| win9x(Windows 4.0): "%winsysdir%"
3692 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3694 * FIXME
3695 *- Only NULL or "" is supported for pName
3698 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3699 DWORD Level, LPBYTE pDriverDirectory,
3700 DWORD cbBuf, LPDWORD pcbNeeded)
3702 DWORD needed;
3703 const printenv_t * env;
3705 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3706 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3707 if(pName != NULL && pName[0]) {
3708 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3709 SetLastError(ERROR_INVALID_PARAMETER);
3710 return FALSE;
3713 env = validate_envW(pEnvironment);
3714 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3716 if(Level != 1) {
3717 WARN("(Level: %ld) is ignored in win9x\n", Level);
3718 SetLastError(ERROR_INVALID_LEVEL);
3719 return FALSE;
3722 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3723 needed = GetSystemDirectoryW(NULL, 0);
3724 /* add the Size for the Subdirectories */
3725 needed += lstrlenW(spooldriversW);
3726 needed += lstrlenW(env->subdir);
3727 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3729 if(pcbNeeded)
3730 *pcbNeeded = needed;
3731 TRACE("required: 0x%lx/%ld\n", needed, needed);
3732 if(needed > cbBuf) {
3733 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3734 return FALSE;
3736 if(pcbNeeded == NULL) {
3737 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3738 SetLastError(RPC_X_NULL_REF_POINTER);
3739 return FALSE;
3741 if(pDriverDirectory == NULL) {
3742 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3743 SetLastError(ERROR_INVALID_USER_BUFFER);
3744 return FALSE;
3747 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3748 /* add the Subdirectories */
3749 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3750 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3751 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3752 return TRUE;
3756 /*****************************************************************************
3757 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3759 * Return the PATH for the Printer-Drivers (ANSI)
3761 * See GetPrinterDriverDirectoryW.
3763 * NOTES
3764 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3767 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3768 DWORD Level, LPBYTE pDriverDirectory,
3769 DWORD cbBuf, LPDWORD pcbNeeded)
3771 UNICODE_STRING nameW, environmentW;
3772 BOOL ret;
3773 DWORD pcbNeededW;
3774 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3775 WCHAR *driverDirectoryW = NULL;
3777 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3778 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3780 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3782 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3783 else nameW.Buffer = NULL;
3784 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3785 else environmentW.Buffer = NULL;
3787 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3788 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3789 if (ret) {
3790 DWORD needed;
3791 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3792 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3793 if(pcbNeeded)
3794 *pcbNeeded = needed;
3795 ret = (needed <= cbBuf) ? TRUE : FALSE;
3796 } else
3797 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3799 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3801 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3802 RtlFreeUnicodeString(&environmentW);
3803 RtlFreeUnicodeString(&nameW);
3805 return ret;
3808 /*****************************************************************************
3809 * AddPrinterDriverA [WINSPOOL.@]
3811 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3813 DRIVER_INFO_3A di3;
3814 HKEY hkeyDrivers, hkeyName;
3816 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3818 if(level != 2 && level != 3) {
3819 SetLastError(ERROR_INVALID_LEVEL);
3820 return FALSE;
3822 if(pName != NULL) {
3823 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3824 SetLastError(ERROR_INVALID_PARAMETER);
3825 return FALSE;
3827 if(!pDriverInfo) {
3828 WARN("pDriverInfo == NULL\n");
3829 SetLastError(ERROR_INVALID_PARAMETER);
3830 return FALSE;
3833 if(level == 3)
3834 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3835 else {
3836 memset(&di3, 0, sizeof(di3));
3837 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3840 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3841 !di3.pDataFile) {
3842 SetLastError(ERROR_INVALID_PARAMETER);
3843 return FALSE;
3845 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3846 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3847 if(!di3.pHelpFile) di3.pHelpFile = "";
3848 if(!di3.pMonitorName) di3.pMonitorName = "";
3850 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3852 if(!hkeyDrivers) {
3853 ERR("Can't create Drivers key\n");
3854 return FALSE;
3857 if(level == 2) { /* apparently can't overwrite with level2 */
3858 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3859 RegCloseKey(hkeyName);
3860 RegCloseKey(hkeyDrivers);
3861 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3862 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3863 return FALSE;
3866 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3867 RegCloseKey(hkeyDrivers);
3868 ERR("Can't create Name key\n");
3869 return FALSE;
3871 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3873 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3874 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3875 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3876 sizeof(DWORD));
3877 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3878 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3879 (LPBYTE) di3.pDependentFiles, 0);
3880 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3881 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3882 RegCloseKey(hkeyName);
3883 RegCloseKey(hkeyDrivers);
3885 return TRUE;
3888 /*****************************************************************************
3889 * AddPrinterDriverW [WINSPOOL.@]
3891 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3892 LPBYTE pDriverInfo)
3894 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3895 level,pDriverInfo);
3896 return FALSE;
3899 /*****************************************************************************
3900 * AddPrintProcessorA [WINSPOOL.@]
3902 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3903 LPSTR pPrintProcessorName)
3905 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3906 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3907 return FALSE;
3910 /*****************************************************************************
3911 * AddPrintProcessorW [WINSPOOL.@]
3913 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3914 LPWSTR pPrintProcessorName)
3916 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3917 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3918 return FALSE;
3921 /*****************************************************************************
3922 * AddPrintProvidorA [WINSPOOL.@]
3924 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3926 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3927 return FALSE;
3930 /*****************************************************************************
3931 * AddPrintProvidorW [WINSPOOL.@]
3933 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3935 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3936 return FALSE;
3939 /*****************************************************************************
3940 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3942 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3943 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3945 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3946 pDevModeOutput, pDevModeInput);
3947 return 0;
3950 /*****************************************************************************
3951 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3953 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3954 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3956 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3957 pDevModeOutput, pDevModeInput);
3958 return 0;
3961 /*****************************************************************************
3962 * PrinterProperties [WINSPOOL.@]
3964 * Displays a dialog to set the properties of the printer.
3966 * RETURNS
3967 * nonzero on success or zero on failure
3969 * BUGS
3970 * implemented as stub only
3972 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3973 HANDLE hPrinter /* [in] handle to printer object */
3975 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3976 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3977 return FALSE;
3980 /*****************************************************************************
3981 * EnumJobsA [WINSPOOL.@]
3984 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3985 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3986 LPDWORD pcReturned)
3988 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3989 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3991 if(pcbNeeded) *pcbNeeded = 0;
3992 if(pcReturned) *pcReturned = 0;
3993 return FALSE;
3997 /*****************************************************************************
3998 * EnumJobsW [WINSPOOL.@]
4001 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4002 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4003 LPDWORD pcReturned)
4005 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4006 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4008 if(pcbNeeded) *pcbNeeded = 0;
4009 if(pcReturned) *pcReturned = 0;
4010 return FALSE;
4013 /*****************************************************************************
4014 * WINSPOOL_EnumPrinterDrivers [internal]
4016 * Delivers information about all printer drivers installed on the
4017 * localhost or a given server
4019 * RETURNS
4020 * nonzero on success or zero on failure. If the buffer for the returned
4021 * information is too small the function will return an error
4023 * BUGS
4024 * - only implemented for localhost, foreign hosts will return an error
4026 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4027 DWORD Level, LPBYTE pDriverInfo,
4028 DWORD cbBuf, LPDWORD pcbNeeded,
4029 LPDWORD pcReturned, BOOL unicode)
4031 { HKEY hkeyDrivers;
4032 DWORD i, needed, number = 0, size = 0;
4033 WCHAR DriverNameW[255];
4034 PBYTE ptr;
4036 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4037 debugstr_w(pName), debugstr_w(pEnvironment),
4038 Level, pDriverInfo, cbBuf, unicode);
4040 /* check for local drivers */
4041 if(pName) {
4042 ERR("remote drivers unsupported! Current remote host is %s\n",
4043 debugstr_w(pName));
4044 return FALSE;
4047 /* check input parameter */
4048 if((Level < 1) || (Level > 3)) {
4049 ERR("unsupported level %ld\n", Level);
4050 SetLastError(ERROR_INVALID_LEVEL);
4051 return FALSE;
4054 /* initialize return values */
4055 if(pDriverInfo)
4056 memset( pDriverInfo, 0, cbBuf);
4057 *pcbNeeded = 0;
4058 *pcReturned = 0;
4060 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4061 if(!hkeyDrivers) {
4062 ERR("Can't open Drivers key\n");
4063 return FALSE;
4066 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4067 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4068 RegCloseKey(hkeyDrivers);
4069 ERR("Can't query Drivers key\n");
4070 return FALSE;
4072 TRACE("Found %ld Drivers\n", number);
4074 /* get size of single struct
4075 * unicode and ascii structure have the same size
4077 switch (Level) {
4078 case 1:
4079 size = sizeof(DRIVER_INFO_1A);
4080 break;
4081 case 2:
4082 size = sizeof(DRIVER_INFO_2A);
4083 break;
4084 case 3:
4085 size = sizeof(DRIVER_INFO_3A);
4086 break;
4089 /* calculate required buffer size */
4090 *pcbNeeded = size * number;
4092 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4093 i < number;
4094 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4095 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4096 != ERROR_SUCCESS) {
4097 ERR("Can't enum key number %ld\n", i);
4098 RegCloseKey(hkeyDrivers);
4099 return FALSE;
4101 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4102 pEnvironment, Level, ptr,
4103 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4104 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4105 &needed, unicode)) {
4106 RegCloseKey(hkeyDrivers);
4107 return FALSE;
4109 (*pcbNeeded) += needed;
4112 RegCloseKey(hkeyDrivers);
4114 if(cbBuf < *pcbNeeded){
4115 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4116 return FALSE;
4119 *pcReturned = number;
4120 return TRUE;
4123 /*****************************************************************************
4124 * EnumPrinterDriversW [WINSPOOL.@]
4126 * see function EnumPrinterDrivers for RETURNS, BUGS
4128 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4129 LPBYTE pDriverInfo, DWORD cbBuf,
4130 LPDWORD pcbNeeded, LPDWORD pcReturned)
4132 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4133 cbBuf, pcbNeeded, pcReturned, TRUE);
4136 /*****************************************************************************
4137 * EnumPrinterDriversA [WINSPOOL.@]
4139 * see function EnumPrinterDrivers for RETURNS, BUGS
4141 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4142 LPBYTE pDriverInfo, DWORD cbBuf,
4143 LPDWORD pcbNeeded, LPDWORD pcReturned)
4144 { BOOL ret;
4145 UNICODE_STRING pNameW, pEnvironmentW;
4146 PWSTR pwstrNameW, pwstrEnvironmentW;
4148 pwstrNameW = asciitounicode(&pNameW, pName);
4149 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4151 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4152 Level, pDriverInfo, cbBuf, pcbNeeded,
4153 pcReturned, FALSE);
4154 RtlFreeUnicodeString(&pNameW);
4155 RtlFreeUnicodeString(&pEnvironmentW);
4157 return ret;
4160 static CHAR PortMonitor[] = "Wine Port Monitor";
4161 static CHAR PortDescription[] = "Wine Port";
4163 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4165 HANDLE handle;
4167 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4168 NULL, OPEN_EXISTING, 0, NULL );
4169 if (handle == INVALID_HANDLE_VALUE)
4170 return FALSE;
4171 TRACE("Checking %s exists\n", name );
4172 CloseHandle( handle );
4173 return TRUE;
4176 static DWORD WINSPOOL_CountSerialPorts(void)
4178 CHAR name[6];
4179 DWORD n = 0, i;
4181 for (i=0; i<4; i++)
4183 strcpy( name, "COMx:" );
4184 name[3] = '1' + i;
4185 if (WINSPOOL_ComPortExists( name ))
4186 n++;
4189 return n;
4192 /******************************************************************************
4193 * EnumPortsA (WINSPOOL.@)
4195 * See EnumPortsW.
4197 * BUGS
4198 * ANSI-Version did not call the UNICODE-Version
4201 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4202 LPDWORD bufneeded,LPDWORD bufreturned)
4204 CHAR portname[10];
4205 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4206 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4207 HKEY hkey_printer;
4208 BOOL retval = TRUE;
4210 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4211 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4213 switch( level )
4215 case 1:
4216 info_size = sizeof (PORT_INFO_1A);
4217 break;
4218 case 2:
4219 info_size = sizeof (PORT_INFO_2A);
4220 break;
4221 default:
4222 SetLastError(ERROR_INVALID_LEVEL);
4223 return FALSE;
4226 /* see how many exist */
4228 hkey_printer = 0;
4229 serial_count = WINSPOOL_CountSerialPorts();
4230 printer_count = 0;
4232 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4233 if ( r == ERROR_SUCCESS )
4235 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4236 &printer_count, NULL, NULL, NULL, NULL);
4238 count = serial_count + printer_count;
4240 /* then fill in the structure info structure once
4241 we know the offset to the first string */
4243 memset( buffer, 0, bufsize );
4244 n = 0;
4245 ofs = info_size*count;
4246 for ( i=0; i<count; i++)
4248 DWORD vallen = sizeof(portname) - 1;
4250 /* get the serial port values, then the printer values */
4251 if ( i < serial_count )
4253 strcpy( portname, "COMx:" );
4254 portname[3] = '1' + i;
4255 if (!WINSPOOL_ComPortExists( portname ))
4256 continue;
4258 TRACE("Found %s\n", portname );
4259 vallen = strlen( portname );
4261 else
4263 r = RegEnumValueA( hkey_printer, i-serial_count,
4264 portname, &vallen, NULL, NULL, NULL, 0 );
4265 if ( r )
4266 continue;
4269 /* add a colon if necessary, and make it upper case */
4270 CharUpperBuffA(portname,vallen);
4271 if (strcasecmp(portname,"nul")!=0)
4272 if (vallen && (portname[vallen-1] != ':') )
4273 lstrcatA(portname,":");
4275 /* add the port info structure if we can fit it */
4276 if ( info_size*(n+1) < bufsize )
4278 if ( level == 1)
4280 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4281 info->pName = (LPSTR) &buffer[ofs];
4283 else if ( level == 2)
4285 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4286 info->pPortName = (LPSTR) &buffer[ofs];
4287 /* FIXME: fill in more stuff here */
4288 info->pMonitorName = PortMonitor;
4289 info->pDescription = PortDescription;
4290 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4293 /* add the name of the port if we can fit it */
4294 if ( ofs < bufsize )
4295 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4297 n++;
4299 else
4300 retval = FALSE;
4301 ofs += lstrlenA(portname)+1;
4304 RegCloseKey(hkey_printer);
4306 if(bufneeded)
4307 *bufneeded = ofs;
4309 if(bufreturned)
4310 *bufreturned = n;
4312 return retval;
4315 /******************************************************************************
4316 * EnumPortsW (WINSPOOL.@)
4318 * Enumerate available Ports
4320 * PARAMS
4321 * name [I] Servername or NULL (local Computer)
4322 * level [I] Structure-Level (1 or 2)
4323 * buffer [O] PTR to Buffer that receives the Result
4324 * bufsize [I] Size of Buffer at buffer
4325 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4326 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4328 * RETURNS
4329 * Success: TRUE
4330 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4332 * BUGS
4333 * UNICODE-Version is a stub
4336 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4337 LPDWORD bufneeded,LPDWORD bufreturned)
4339 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4340 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4341 return FALSE;
4344 /******************************************************************************
4345 * GetDefaultPrinterW (WINSPOOL.@)
4347 * FIXME
4348 * This function must read the value from data 'device' of key
4349 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4351 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4353 BOOL retval = TRUE;
4354 DWORD insize, len;
4355 WCHAR *buffer, *ptr;
4357 if (!namesize)
4359 SetLastError(ERROR_INVALID_PARAMETER);
4360 return FALSE;
4363 /* make the buffer big enough for the stuff from the profile/registry,
4364 * the content must fit into the local buffer to compute the correct
4365 * size even if the extern buffer is too small or not given.
4366 * (20 for ,driver,port) */
4367 insize = *namesize;
4368 len = max(100, (insize + 20));
4369 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4371 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4373 SetLastError (ERROR_FILE_NOT_FOUND);
4374 retval = FALSE;
4375 goto end;
4377 TRACE("%s\n", debugstr_w(buffer));
4379 if ((ptr = strchrW(buffer, ',')) == NULL)
4381 SetLastError(ERROR_INVALID_NAME);
4382 retval = FALSE;
4383 goto end;
4386 *ptr = 0;
4387 *namesize = strlenW(buffer) + 1;
4388 if(!name || (*namesize > insize))
4390 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4391 retval = FALSE;
4392 goto end;
4394 strcpyW(name, buffer);
4396 end:
4397 HeapFree( GetProcessHeap(), 0, buffer);
4398 return retval;
4402 /******************************************************************************
4403 * GetDefaultPrinterA (WINSPOOL.@)
4405 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4407 BOOL retval = TRUE;
4408 DWORD insize = 0;
4409 WCHAR *bufferW = NULL;
4411 if (!namesize)
4413 SetLastError(ERROR_INVALID_PARAMETER);
4414 return FALSE;
4417 if(name && *namesize) {
4418 insize = *namesize;
4419 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4422 if(!GetDefaultPrinterW( bufferW, namesize)) {
4423 retval = FALSE;
4424 goto end;
4427 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4428 NULL, NULL);
4429 if (!*namesize)
4431 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4432 retval = FALSE;
4434 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4436 end:
4437 HeapFree( GetProcessHeap(), 0, bufferW);
4438 return retval;
4442 /******************************************************************************
4443 * SetDefaultPrinterW (WINSPOOL.204)
4445 * Set the Name of the Default Printer
4447 * PARAMS
4448 * pszPrinter [I] Name of the Printer or NULL
4450 * RETURNS
4451 * Success: True
4452 * Failure: FALSE
4454 * NOTES
4455 * When the Parameter is NULL or points to an Empty String and
4456 * a Default Printer was already present, then this Function changes nothing.
4457 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4458 * the First enumerated local Printer is used.
4461 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4464 TRACE("(%s)\n", debugstr_w(pszPrinter));
4466 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4467 return FALSE;
4470 /******************************************************************************
4471 * SetDefaultPrinterA (WINSPOOL.202)
4473 * See SetDefaultPrinterW.
4476 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4479 TRACE("(%s)\n", debugstr_a(pszPrinter));
4481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4482 return FALSE;
4486 /******************************************************************************
4487 * SetPrinterDataExA (WINSPOOL.@)
4489 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4490 LPCSTR pValueName, DWORD Type,
4491 LPBYTE pData, DWORD cbData)
4493 HKEY hkeyPrinter, hkeySubkey;
4494 DWORD ret;
4496 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4497 debugstr_a(pValueName), Type, pData, cbData);
4499 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4500 != ERROR_SUCCESS)
4501 return ret;
4503 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4504 != ERROR_SUCCESS) {
4505 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4506 RegCloseKey(hkeyPrinter);
4507 return ret;
4509 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4510 RegCloseKey(hkeySubkey);
4511 RegCloseKey(hkeyPrinter);
4512 return ret;
4515 /******************************************************************************
4516 * SetPrinterDataExW (WINSPOOL.@)
4518 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4519 LPCWSTR pValueName, DWORD Type,
4520 LPBYTE pData, DWORD cbData)
4522 HKEY hkeyPrinter, hkeySubkey;
4523 DWORD ret;
4525 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4526 debugstr_w(pValueName), Type, pData, cbData);
4528 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4529 != ERROR_SUCCESS)
4530 return ret;
4532 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4533 != ERROR_SUCCESS) {
4534 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4535 RegCloseKey(hkeyPrinter);
4536 return ret;
4538 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4539 RegCloseKey(hkeySubkey);
4540 RegCloseKey(hkeyPrinter);
4541 return ret;
4544 /******************************************************************************
4545 * SetPrinterDataA (WINSPOOL.@)
4547 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4548 LPBYTE pData, DWORD cbData)
4550 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4551 pData, cbData);
4554 /******************************************************************************
4555 * SetPrinterDataW (WINSPOOL.@)
4557 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4558 LPBYTE pData, DWORD cbData)
4560 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4561 pData, cbData);
4564 /******************************************************************************
4565 * GetPrinterDataExA (WINSPOOL.@)
4567 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4568 LPCSTR pValueName, LPDWORD pType,
4569 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4571 HKEY hkeyPrinter, hkeySubkey;
4572 DWORD ret;
4574 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4575 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4576 pcbNeeded);
4578 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4579 != ERROR_SUCCESS)
4580 return ret;
4582 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4583 != ERROR_SUCCESS) {
4584 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4585 RegCloseKey(hkeyPrinter);
4586 return ret;
4588 *pcbNeeded = nSize;
4589 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4590 RegCloseKey(hkeySubkey);
4591 RegCloseKey(hkeyPrinter);
4592 return ret;
4595 /******************************************************************************
4596 * GetPrinterDataExW (WINSPOOL.@)
4598 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4599 LPCWSTR pValueName, LPDWORD pType,
4600 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4602 HKEY hkeyPrinter, hkeySubkey;
4603 DWORD ret;
4605 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4606 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4607 pcbNeeded);
4609 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4610 != ERROR_SUCCESS)
4611 return ret;
4613 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4614 != ERROR_SUCCESS) {
4615 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4616 RegCloseKey(hkeyPrinter);
4617 return ret;
4619 *pcbNeeded = nSize;
4620 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4621 RegCloseKey(hkeySubkey);
4622 RegCloseKey(hkeyPrinter);
4623 return ret;
4626 /******************************************************************************
4627 * GetPrinterDataA (WINSPOOL.@)
4629 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4630 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4632 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4633 pData, nSize, pcbNeeded);
4636 /******************************************************************************
4637 * GetPrinterDataW (WINSPOOL.@)
4639 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4640 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4642 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4643 pData, nSize, pcbNeeded);
4646 /*******************************************************************************
4647 * EnumPrinterDataExW [WINSPOOL.@]
4649 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4650 LPBYTE pEnumValues, DWORD cbEnumValues,
4651 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4653 HKEY hkPrinter, hkSubKey;
4654 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4655 cbValueNameLen, cbMaxValueLen, cbValueLen,
4656 cbBufSize, dwType;
4657 LPWSTR lpValueName;
4658 HANDLE hHeap;
4659 PBYTE lpValue;
4660 PPRINTER_ENUM_VALUESW ppev;
4662 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4664 if (pKeyName == NULL || *pKeyName == 0)
4665 return ERROR_INVALID_PARAMETER;
4667 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4668 if (ret != ERROR_SUCCESS)
4670 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4671 hPrinter, ret);
4672 return ret;
4675 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4676 if (ret != ERROR_SUCCESS)
4678 r = RegCloseKey (hkPrinter);
4679 if (r != ERROR_SUCCESS)
4680 WARN ("RegCloseKey returned %li\n", r);
4681 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4682 debugstr_w (pKeyName), ret);
4683 return ret;
4686 ret = RegCloseKey (hkPrinter);
4687 if (ret != ERROR_SUCCESS)
4689 ERR ("RegCloseKey returned %li\n", ret);
4690 r = RegCloseKey (hkSubKey);
4691 if (r != ERROR_SUCCESS)
4692 WARN ("RegCloseKey returned %li\n", r);
4693 return ret;
4696 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4697 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4698 if (ret != ERROR_SUCCESS)
4700 r = RegCloseKey (hkSubKey);
4701 if (r != ERROR_SUCCESS)
4702 WARN ("RegCloseKey returned %li\n", r);
4703 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4704 return ret;
4707 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4708 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4710 if (cValues == 0) /* empty key */
4712 r = RegCloseKey (hkSubKey);
4713 if (r != ERROR_SUCCESS)
4714 WARN ("RegCloseKey returned %li\n", r);
4715 *pcbEnumValues = *pnEnumValues = 0;
4716 return ERROR_SUCCESS;
4719 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4721 hHeap = GetProcessHeap ();
4722 if (hHeap == NULL)
4724 ERR ("GetProcessHeap failed\n");
4725 r = RegCloseKey (hkSubKey);
4726 if (r != ERROR_SUCCESS)
4727 WARN ("RegCloseKey returned %li\n", r);
4728 return ERROR_OUTOFMEMORY;
4731 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4732 if (lpValueName == NULL)
4734 ERR ("Failed to allocate %li bytes from process heap\n",
4735 cbMaxValueNameLen * sizeof (WCHAR));
4736 r = RegCloseKey (hkSubKey);
4737 if (r != ERROR_SUCCESS)
4738 WARN ("RegCloseKey returned %li\n", r);
4739 return ERROR_OUTOFMEMORY;
4742 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4743 if (lpValue == NULL)
4745 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4746 if (HeapFree (hHeap, 0, lpValueName) == 0)
4747 WARN ("HeapFree failed with code %li\n", GetLastError ());
4748 r = RegCloseKey (hkSubKey);
4749 if (r != ERROR_SUCCESS)
4750 WARN ("RegCloseKey returned %li\n", r);
4751 return ERROR_OUTOFMEMORY;
4754 TRACE ("pass 1: calculating buffer required for all names and values\n");
4756 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4758 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4760 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4762 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4763 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4764 NULL, NULL, lpValue, &cbValueLen);
4765 if (ret != ERROR_SUCCESS)
4767 if (HeapFree (hHeap, 0, lpValue) == 0)
4768 WARN ("HeapFree failed with code %li\n", GetLastError ());
4769 if (HeapFree (hHeap, 0, lpValueName) == 0)
4770 WARN ("HeapFree failed with code %li\n", GetLastError ());
4771 r = RegCloseKey (hkSubKey);
4772 if (r != ERROR_SUCCESS)
4773 WARN ("RegCloseKey returned %li\n", r);
4774 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4775 return ret;
4778 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4779 debugstr_w (lpValueName), dwIndex,
4780 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4782 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4783 cbBufSize += cbValueLen;
4786 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4788 *pcbEnumValues = cbBufSize;
4789 *pnEnumValues = cValues;
4791 if (cbEnumValues < cbBufSize) /* buffer too small */
4793 if (HeapFree (hHeap, 0, lpValue) == 0)
4794 WARN ("HeapFree failed with code %li\n", GetLastError ());
4795 if (HeapFree (hHeap, 0, lpValueName) == 0)
4796 WARN ("HeapFree failed with code %li\n", GetLastError ());
4797 r = RegCloseKey (hkSubKey);
4798 if (r != ERROR_SUCCESS)
4799 WARN ("RegCloseKey returned %li\n", r);
4800 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4801 return ERROR_MORE_DATA;
4804 TRACE ("pass 2: copying all names and values to buffer\n");
4806 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4807 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4809 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4811 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4812 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4813 NULL, &dwType, lpValue, &cbValueLen);
4814 if (ret != ERROR_SUCCESS)
4816 if (HeapFree (hHeap, 0, lpValue) == 0)
4817 WARN ("HeapFree failed with code %li\n", GetLastError ());
4818 if (HeapFree (hHeap, 0, lpValueName) == 0)
4819 WARN ("HeapFree failed with code %li\n", GetLastError ());
4820 r = RegCloseKey (hkSubKey);
4821 if (r != ERROR_SUCCESS)
4822 WARN ("RegCloseKey returned %li\n", r);
4823 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4824 return ret;
4827 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4828 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4829 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4830 pEnumValues += cbValueNameLen;
4832 /* return # of *bytes* (including trailing \0), not # of chars */
4833 ppev[dwIndex].cbValueName = cbValueNameLen;
4835 ppev[dwIndex].dwType = dwType;
4837 memcpy (pEnumValues, lpValue, cbValueLen);
4838 ppev[dwIndex].pData = pEnumValues;
4839 pEnumValues += cbValueLen;
4841 ppev[dwIndex].cbData = cbValueLen;
4843 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4844 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4847 if (HeapFree (hHeap, 0, lpValue) == 0)
4849 ret = GetLastError ();
4850 ERR ("HeapFree failed with code %li\n", ret);
4851 if (HeapFree (hHeap, 0, lpValueName) == 0)
4852 WARN ("HeapFree failed with code %li\n", GetLastError ());
4853 r = RegCloseKey (hkSubKey);
4854 if (r != ERROR_SUCCESS)
4855 WARN ("RegCloseKey returned %li\n", r);
4856 return ret;
4859 if (HeapFree (hHeap, 0, lpValueName) == 0)
4861 ret = GetLastError ();
4862 ERR ("HeapFree failed with code %li\n", ret);
4863 r = RegCloseKey (hkSubKey);
4864 if (r != ERROR_SUCCESS)
4865 WARN ("RegCloseKey returned %li\n", r);
4866 return ret;
4869 ret = RegCloseKey (hkSubKey);
4870 if (ret != ERROR_SUCCESS)
4872 ERR ("RegCloseKey returned %li\n", ret);
4873 return ret;
4876 return ERROR_SUCCESS;
4879 /*******************************************************************************
4880 * EnumPrinterDataExA [WINSPOOL.@]
4882 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4883 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4884 * what Windows 2000 SP1 does.
4887 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4888 LPBYTE pEnumValues, DWORD cbEnumValues,
4889 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4891 INT len;
4892 LPWSTR pKeyNameW;
4893 DWORD ret, dwIndex, dwBufSize;
4894 HANDLE hHeap;
4895 LPSTR pBuffer;
4897 TRACE ("%p %s\n", hPrinter, pKeyName);
4899 if (pKeyName == NULL || *pKeyName == 0)
4900 return ERROR_INVALID_PARAMETER;
4902 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4903 if (len == 0)
4905 ret = GetLastError ();
4906 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4907 return ret;
4910 hHeap = GetProcessHeap ();
4911 if (hHeap == NULL)
4913 ERR ("GetProcessHeap failed\n");
4914 return ERROR_OUTOFMEMORY;
4917 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4918 if (pKeyNameW == NULL)
4920 ERR ("Failed to allocate %li bytes from process heap\n",
4921 (LONG) len * sizeof (WCHAR));
4922 return ERROR_OUTOFMEMORY;
4925 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4927 ret = GetLastError ();
4928 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4929 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4930 WARN ("HeapFree failed with code %li\n", GetLastError ());
4931 return ret;
4934 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4935 pcbEnumValues, pnEnumValues);
4936 if (ret != ERROR_SUCCESS)
4938 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4939 WARN ("HeapFree failed with code %li\n", GetLastError ());
4940 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4941 return ret;
4944 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4946 ret = GetLastError ();
4947 ERR ("HeapFree failed with code %li\n", ret);
4948 return ret;
4951 if (*pnEnumValues == 0) /* empty key */
4952 return ERROR_SUCCESS;
4954 dwBufSize = 0;
4955 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4957 PPRINTER_ENUM_VALUESW ppev =
4958 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4960 if (dwBufSize < ppev->cbValueName)
4961 dwBufSize = ppev->cbValueName;
4963 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4964 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4965 dwBufSize = ppev->cbData;
4968 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4970 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4971 if (pBuffer == NULL)
4973 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4974 return ERROR_OUTOFMEMORY;
4977 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4979 PPRINTER_ENUM_VALUESW ppev =
4980 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4982 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4983 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4984 NULL);
4985 if (len == 0)
4987 ret = GetLastError ();
4988 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4989 if (HeapFree (hHeap, 0, pBuffer) == 0)
4990 WARN ("HeapFree failed with code %li\n", GetLastError ());
4991 return ret;
4994 memcpy (ppev->pValueName, pBuffer, len);
4996 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4998 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4999 ppev->dwType != REG_MULTI_SZ)
5000 continue;
5002 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5003 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5004 if (len == 0)
5006 ret = GetLastError ();
5007 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5008 if (HeapFree (hHeap, 0, pBuffer) == 0)
5009 WARN ("HeapFree failed with code %li\n", GetLastError ());
5010 return ret;
5013 memcpy (ppev->pData, pBuffer, len);
5015 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5016 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5019 if (HeapFree (hHeap, 0, pBuffer) == 0)
5021 ret = GetLastError ();
5022 ERR ("HeapFree failed with code %li\n", ret);
5023 return ret;
5026 return ERROR_SUCCESS;
5029 /******************************************************************************
5030 * AbortPrinter (WINSPOOL.@)
5032 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5034 FIXME("(%p), stub!\n", hPrinter);
5035 return TRUE;
5038 /******************************************************************************
5039 * AddPortA (WINSPOOL.@)
5041 * See AddPortW.
5044 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5046 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5047 return FALSE;
5050 /******************************************************************************
5051 * AddPortW (WINSPOOL.@)
5053 * Add a Port for a specific Monitor
5055 * PARAMS
5056 * pName [I] Servername or NULL (local Computer)
5057 * hWnd [I] Handle to parent Window for the Dialog-Box
5058 * pMonitorName [I] Name of the Monitor that manage the Port
5060 * RETURNS
5061 * Success: TRUE
5062 * Failure: FALSE
5064 * BUGS
5065 * only a Stub
5068 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5070 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5071 return FALSE;
5074 /******************************************************************************
5075 * AddPortExA (WINSPOOL.@)
5077 * See AddPortExW.
5080 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5082 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5083 lpBuffer, debugstr_a(lpMonitorName));
5084 return FALSE;
5087 /******************************************************************************
5088 * AddPortExW (WINSPOOL.@)
5090 * Add a Port for a specific Monitor, without presenting a user interface
5092 * PARAMS
5093 * hMonitor [I] Handle from InitializePrintMonitor2()
5094 * pName [I] Servername or NULL (local Computer)
5095 * Level [I] Structure-Level (1 or 2) for lpBuffer
5096 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5097 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5099 * RETURNS
5100 * Success: TRUE
5101 * Failure: FALSE
5103 * BUGS
5104 * only a Stub
5107 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5109 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5110 lpBuffer, debugstr_w(lpMonitorName));
5111 return FALSE;
5114 /******************************************************************************
5115 * AddPrinterConnectionA (WINSPOOL.@)
5117 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5119 FIXME("%s\n", debugstr_a(pName));
5120 return FALSE;
5123 /******************************************************************************
5124 * AddPrinterConnectionW (WINSPOOL.@)
5126 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5128 FIXME("%s\n", debugstr_w(pName));
5129 return FALSE;
5132 /******************************************************************************
5133 * AddPrinterDriverExW (WINSPOOL.@)
5135 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5136 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5138 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5139 Level, pDriverInfo, dwFileCopyFlags);
5140 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5141 return FALSE;
5144 /******************************************************************************
5145 * AddPrinterDriverExA (WINSPOOL.@)
5147 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5148 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5150 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5151 Level, pDriverInfo, dwFileCopyFlags);
5152 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5153 return FALSE;
5156 /******************************************************************************
5157 * ConfigurePortA (WINSPOOL.@)
5159 * See ConfigurePortW.
5162 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5164 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5165 return FALSE;
5168 /******************************************************************************
5169 * ConfigurePortW (WINSPOOL.@)
5171 * Display the Configuration-Dialog for a specific Port
5173 * PARAMS
5174 * pName [I] Servername or NULL (local Computer)
5175 * hWnd [I] Handle to parent Window for the Dialog-Box
5176 * pPortName [I] Name of the Port, that should be configured
5178 * RETURNS
5179 * Success: TRUE
5180 * Failure: FALSE
5182 * BUGS
5183 * only a Stub
5186 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5188 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5189 return FALSE;
5192 /******************************************************************************
5193 * ConnectToPrinterDlg (WINSPOOL.@)
5195 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5197 FIXME("%p %lx\n", hWnd, Flags);
5198 return NULL;
5201 /******************************************************************************
5202 * DeletePrinterConnectionA (WINSPOOL.@)
5204 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5206 FIXME("%s\n", debugstr_a(pName));
5207 return TRUE;
5210 /******************************************************************************
5211 * DeletePrinterConnectionW (WINSPOOL.@)
5213 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5215 FIXME("%s\n", debugstr_w(pName));
5216 return TRUE;
5219 /******************************************************************************
5220 * DeletePrinterDriverExW (WINSPOOL.@)
5222 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5223 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5225 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5226 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5227 return TRUE;
5230 /******************************************************************************
5231 * DeletePrinterDriverExA (WINSPOOL.@)
5233 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5234 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5236 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5237 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5238 return TRUE;
5241 /******************************************************************************
5242 * DeletePrinterDataExW (WINSPOOL.@)
5244 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5245 LPCWSTR pValueName)
5247 FIXME("%p %s %s\n", hPrinter,
5248 debugstr_w(pKeyName), debugstr_w(pValueName));
5249 return ERROR_INVALID_PARAMETER;
5252 /******************************************************************************
5253 * DeletePrinterDataExA (WINSPOOL.@)
5255 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5256 LPCSTR pValueName)
5258 FIXME("%p %s %s\n", hPrinter,
5259 debugstr_a(pKeyName), debugstr_a(pValueName));
5260 return ERROR_INVALID_PARAMETER;
5263 /******************************************************************************
5264 * DeletePrintProcessorA (WINSPOOL.@)
5266 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5268 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5269 debugstr_a(pPrintProcessorName));
5270 return TRUE;
5273 /******************************************************************************
5274 * DeletePrintProcessorW (WINSPOOL.@)
5276 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5278 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5279 debugstr_w(pPrintProcessorName));
5280 return TRUE;
5283 /******************************************************************************
5284 * DeletePrintProvidorA (WINSPOOL.@)
5286 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5288 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5289 debugstr_a(pPrintProviderName));
5290 return TRUE;
5293 /******************************************************************************
5294 * DeletePrintProvidorW (WINSPOOL.@)
5296 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5298 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5299 debugstr_w(pPrintProviderName));
5300 return TRUE;
5303 /******************************************************************************
5304 * EnumFormsA (WINSPOOL.@)
5306 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5307 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5309 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5310 return FALSE;
5313 /******************************************************************************
5314 * EnumFormsW (WINSPOOL.@)
5316 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5317 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5319 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5320 return FALSE;
5323 /*****************************************************************************
5324 * EnumMonitorsA [WINSPOOL.@]
5326 * See EnumMonitorsW.
5329 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5330 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5332 BOOL res;
5333 LPBYTE bufferW = NULL;
5334 LPWSTR nameW = NULL;
5335 DWORD needed = 0;
5336 DWORD numentries = 0;
5337 INT len;
5339 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5340 cbBuf, pcbNeeded, pcReturned);
5342 /* convert servername to unicode */
5343 if (pName) {
5344 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5345 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5346 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5348 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5349 needed = cbBuf * sizeof(WCHAR);
5350 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5351 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5353 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5354 if (pcbNeeded) needed = *pcbNeeded;
5355 /* HeapReAlloc return NULL, when bufferW was NULL */
5356 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5357 HeapAlloc(GetProcessHeap(), 0, needed);
5359 /* Try again with the large Buffer */
5360 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5362 numentries = pcReturned ? *pcReturned : 0;
5363 needed = 0;
5365 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5366 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5368 if (res) {
5369 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5370 DWORD entrysize = 0;
5371 DWORD index;
5372 LPSTR ptr;
5373 LPMONITOR_INFO_2W mi2w;
5374 LPMONITOR_INFO_2A mi2a;
5376 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5377 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5379 /* First pass: calculate the size for all Entries */
5380 mi2w = (LPMONITOR_INFO_2W) bufferW;
5381 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5382 index = 0;
5383 while (index < numentries) {
5384 index++;
5385 needed += entrysize; /* MONITOR_INFO_?A */
5386 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5388 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5389 NULL, 0, NULL, NULL);
5390 if (Level > 1) {
5391 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5392 NULL, 0, NULL, NULL);
5393 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5394 NULL, 0, NULL, NULL);
5396 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5397 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5398 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5401 /* check for errors and quit on failure */
5402 if (cbBuf < needed) {
5403 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5404 res = FALSE;
5405 goto emA_cleanup;
5407 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5408 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5409 cbBuf -= len ; /* free Bytes in the user-Buffer */
5410 mi2w = (LPMONITOR_INFO_2W) bufferW;
5411 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5412 index = 0;
5413 /* Second Pass: Fill the User Buffer (if we have one) */
5414 while ((index < numentries) && pMonitors) {
5415 index++;
5416 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5417 mi2a->pName = ptr;
5418 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5419 ptr, cbBuf , NULL, NULL);
5420 ptr += len;
5421 cbBuf -= len;
5422 if (Level > 1) {
5423 mi2a->pEnvironment = ptr;
5424 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5425 ptr, cbBuf, NULL, NULL);
5426 ptr += len;
5427 cbBuf -= len;
5429 mi2a->pDLLName = ptr;
5430 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5431 ptr, cbBuf, NULL, NULL);
5432 ptr += len;
5433 cbBuf -= len;
5435 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5436 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5437 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5440 emA_cleanup:
5441 if (pcbNeeded) *pcbNeeded = needed;
5442 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5444 HeapFree(GetProcessHeap(), 0, nameW);
5445 HeapFree(GetProcessHeap(), 0, bufferW);
5447 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5448 (res), GetLastError(), needed, numentries);
5450 return (res);
5454 /*****************************************************************************
5455 * EnumMonitorsW [WINSPOOL.@]
5457 * Enumerate available Port-Monitors
5459 * PARAMS
5460 * pName [I] Servername or NULL (local Computer)
5461 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5462 * pMonitors [O] PTR to Buffer that receives the Result
5463 * cbBuf [I] Size of Buffer at pMonitors
5464 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5465 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5467 * RETURNS
5468 * Success: TRUE
5469 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5471 * NOTES
5472 * Windows reads the Registry once and cache the Results.
5474 *| Language-Monitors are also installed in the same Registry-Location but
5475 *| they are filtered in Windows (not returned by EnumMonitors).
5476 *| We do no filtering to simplify our Code.
5479 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5480 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5482 DWORD needed = 0;
5483 DWORD numentries = 0;
5484 BOOL res = FALSE;
5486 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5487 cbBuf, pcbNeeded, pcReturned);
5489 if (pName && (lstrlenW(pName))) {
5490 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5491 SetLastError(ERROR_ACCESS_DENIED);
5492 goto emW_cleanup;
5495 /* Level is not checked in win9x */
5496 if (!Level || (Level > 2)) {
5497 WARN("level (%ld) is ignored in win9x\n", Level);
5498 SetLastError(ERROR_INVALID_LEVEL);
5499 goto emW_cleanup;
5501 if (!pcbNeeded) {
5502 SetLastError(RPC_X_NULL_REF_POINTER);
5503 goto emW_cleanup;
5506 /* Scan all Monitor-Keys */
5507 numentries = 0;
5508 needed = get_local_monitors(Level, NULL, 0, &numentries);
5510 /* we calculated the needed buffersize. now do the error-checks */
5511 if (cbBuf < needed) {
5512 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5513 goto emW_cleanup;
5515 else if (!pMonitors || !pcReturned) {
5516 SetLastError(RPC_X_NULL_REF_POINTER);
5517 goto emW_cleanup;
5520 /* fill the Buffer with the Monitor-Keys */
5521 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5522 res = TRUE;
5524 emW_cleanup:
5525 if (pcbNeeded) *pcbNeeded = needed;
5526 if (pcReturned) *pcReturned = numentries;
5528 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5529 res, GetLastError(), needed, numentries);
5531 return (res);
5534 /******************************************************************************
5535 * XcvDataW (WINSPOOL.@)
5537 * Notes:
5538 * There doesn't seem to be an A version...
5540 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5541 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5542 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5544 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5545 pInputData, cbInputData, pOutputData,
5546 cbOutputData, pcbOutputNeeded, pdwStatus);
5547 return FALSE;
5550 /*****************************************************************************
5551 * EnumPrinterDataA [WINSPOOL.@]
5554 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5555 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5556 DWORD cbData, LPDWORD pcbData )
5558 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5559 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5560 return ERROR_NO_MORE_ITEMS;
5563 /*****************************************************************************
5564 * EnumPrinterDataW [WINSPOOL.@]
5567 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5568 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5569 DWORD cbData, LPDWORD pcbData )
5571 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5572 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5573 return ERROR_NO_MORE_ITEMS;
5576 /*****************************************************************************
5577 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5580 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5581 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5582 LPDWORD pcbNeeded, LPDWORD pcReturned)
5584 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5585 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5586 pcbNeeded, pcReturned);
5587 return FALSE;
5590 /*****************************************************************************
5591 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5594 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5595 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5596 LPDWORD pcbNeeded, LPDWORD pcReturned)
5598 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5599 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5600 pcbNeeded, pcReturned);
5601 return FALSE;
5604 /*****************************************************************************
5605 * EnumPrintProcessorsA [WINSPOOL.@]
5608 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5609 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5611 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5612 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5613 return FALSE;
5616 /*****************************************************************************
5617 * EnumPrintProcessorsW [WINSPOOL.@]
5620 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5621 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5623 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5624 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5625 cbBuf, pcbNeeded, pcbReturned);
5626 return FALSE;
5629 /*****************************************************************************
5630 * ExtDeviceMode [WINSPOOL.@]
5633 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5634 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5635 DWORD fMode)
5637 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5638 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5639 debugstr_a(pProfile), fMode);
5640 return -1;
5643 /*****************************************************************************
5644 * FindClosePrinterChangeNotification [WINSPOOL.@]
5647 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5649 FIXME("Stub: %p\n", hChange);
5650 return TRUE;
5653 /*****************************************************************************
5654 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5657 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5658 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5660 FIXME("Stub: %p %lx %lx %p\n",
5661 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5662 return INVALID_HANDLE_VALUE;
5665 /*****************************************************************************
5666 * FindNextPrinterChangeNotification [WINSPOOL.@]
5669 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5670 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5672 FIXME("Stub: %p %p %p %p\n",
5673 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5674 return FALSE;
5677 /*****************************************************************************
5678 * FreePrinterNotifyInfo [WINSPOOL.@]
5681 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5683 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5684 return TRUE;
5687 /*****************************************************************************
5688 * string_to_buf
5690 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5691 * ansi depending on the unicode parameter.
5693 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5695 if(!str)
5697 *size = 0;
5698 return TRUE;
5701 if(unicode)
5703 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5704 if(*size <= cb)
5706 memcpy(ptr, str, *size);
5707 return TRUE;
5709 return FALSE;
5711 else
5713 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5714 if(*size <= cb)
5716 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5717 return TRUE;
5719 return FALSE;
5723 /*****************************************************************************
5724 * get_job_info_1
5726 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5727 LPDWORD pcbNeeded, BOOL unicode)
5729 DWORD size, left = cbBuf;
5730 BOOL space = (cbBuf > 0);
5731 LPBYTE ptr = buf;
5733 *pcbNeeded = 0;
5735 if(space)
5737 ji1->JobId = job->job_id;
5740 string_to_buf(job->document_title, ptr, left, &size, unicode);
5741 if(space && size <= left)
5743 ji1->pDocument = (LPWSTR)ptr;
5744 ptr += size;
5745 left -= size;
5747 else
5748 space = FALSE;
5749 *pcbNeeded += size;
5751 return space;
5754 /*****************************************************************************
5755 * get_job_info_2
5757 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5758 LPDWORD pcbNeeded, BOOL unicode)
5760 DWORD size, left = cbBuf;
5761 BOOL space = (cbBuf > 0);
5762 LPBYTE ptr = buf;
5764 *pcbNeeded = 0;
5766 if(space)
5768 ji2->JobId = job->job_id;
5771 string_to_buf(job->document_title, ptr, left, &size, unicode);
5772 if(space && size <= left)
5774 ji2->pDocument = (LPWSTR)ptr;
5775 ptr += size;
5776 left -= size;
5778 else
5779 space = FALSE;
5780 *pcbNeeded += size;
5782 return space;
5785 /*****************************************************************************
5786 * get_job_info
5788 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5789 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5791 BOOL ret = FALSE;
5792 DWORD needed = 0, size;
5793 job_t *job;
5794 LPBYTE ptr = pJob;
5796 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5798 EnterCriticalSection(&printer_handles_cs);
5799 job = get_job(hPrinter, JobId);
5800 if(!job)
5801 goto end;
5803 switch(Level)
5805 case 1:
5806 size = sizeof(JOB_INFO_1W);
5807 if(cbBuf >= size)
5809 cbBuf -= size;
5810 ptr += size;
5811 memset(pJob, 0, size);
5813 else
5814 cbBuf = 0;
5815 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5816 needed += size;
5817 break;
5819 case 2:
5820 size = sizeof(JOB_INFO_2W);
5821 if(cbBuf >= size)
5823 cbBuf -= size;
5824 ptr += size;
5825 memset(pJob, 0, size);
5827 else
5828 cbBuf = 0;
5829 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5830 needed += size;
5831 break;
5833 case 3:
5834 size = sizeof(JOB_INFO_3);
5835 if(cbBuf >= size)
5837 cbBuf -= size;
5838 memset(pJob, 0, size);
5839 ret = TRUE;
5841 else
5842 cbBuf = 0;
5843 needed = size;
5844 break;
5846 default:
5847 SetLastError(ERROR_INVALID_LEVEL);
5848 goto end;
5850 if(pcbNeeded)
5851 *pcbNeeded = needed;
5852 end:
5853 LeaveCriticalSection(&printer_handles_cs);
5854 return ret;
5857 /*****************************************************************************
5858 * GetJobA [WINSPOOL.@]
5861 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5862 DWORD cbBuf, LPDWORD pcbNeeded)
5864 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5867 /*****************************************************************************
5868 * GetJobW [WINSPOOL.@]
5871 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5872 DWORD cbBuf, LPDWORD pcbNeeded)
5874 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5877 /*****************************************************************************
5878 * schedule_lpr
5880 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5882 char *unixname, *queue, *cmd;
5883 char fmt[] = "lpr -P%s %s";
5884 DWORD len;
5886 if(!(unixname = wine_get_unix_file_name(filename)))
5887 return FALSE;
5889 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5890 queue = HeapAlloc(GetProcessHeap(), 0, len);
5891 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5893 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5894 sprintf(cmd, fmt, queue, unixname);
5896 TRACE("printing with: %s\n", cmd);
5897 system(cmd);
5899 HeapFree(GetProcessHeap(), 0, cmd);
5900 HeapFree(GetProcessHeap(), 0, queue);
5901 HeapFree(GetProcessHeap(), 0, unixname);
5902 return TRUE;
5905 /*****************************************************************************
5906 * schedule_cups
5908 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5910 #if HAVE_CUPS_CUPS_H
5911 if(pcupsPrintFile)
5913 char *unixname, *queue, *doc_titleA;
5914 DWORD len;
5915 BOOL ret;
5917 if(!(unixname = wine_get_unix_file_name(filename)))
5918 return FALSE;
5920 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5921 queue = HeapAlloc(GetProcessHeap(), 0, len);
5922 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5924 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5925 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5926 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5928 TRACE("printing via cups\n");
5929 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5930 HeapFree(GetProcessHeap(), 0, doc_titleA);
5931 HeapFree(GetProcessHeap(), 0, queue);
5932 HeapFree(GetProcessHeap(), 0, unixname);
5933 return ret;
5935 else
5936 #endif
5938 return schedule_lpr(printer_name, filename);
5942 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5944 LPWSTR filename;
5946 switch(msg)
5948 case WM_INITDIALOG:
5949 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5950 return TRUE;
5952 case WM_COMMAND:
5953 if(HIWORD(wparam) == BN_CLICKED)
5955 if(LOWORD(wparam) == IDOK)
5957 HANDLE hf;
5958 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5959 LPWSTR *output;
5961 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5962 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5964 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5966 WCHAR caption[200], message[200];
5967 int mb_ret;
5969 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5970 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5971 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5972 if(mb_ret == IDCANCEL)
5974 HeapFree(GetProcessHeap(), 0, filename);
5975 return TRUE;
5978 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5979 if(hf == INVALID_HANDLE_VALUE)
5981 WCHAR caption[200], message[200];
5983 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5984 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5985 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5986 HeapFree(GetProcessHeap(), 0, filename);
5987 return TRUE;
5989 CloseHandle(hf);
5990 DeleteFileW(filename);
5991 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5992 *output = filename;
5993 EndDialog(hwnd, IDOK);
5994 return TRUE;
5996 if(LOWORD(wparam) == IDCANCEL)
5998 EndDialog(hwnd, IDCANCEL);
5999 return TRUE;
6002 return FALSE;
6004 return FALSE;
6007 /*****************************************************************************
6008 * get_filename
6010 static BOOL get_filename(LPWSTR *filename)
6012 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6013 file_dlg_proc, (LPARAM)filename) == IDOK;
6016 /*****************************************************************************
6017 * schedule_file
6019 static BOOL schedule_file(LPCWSTR filename)
6021 LPWSTR output = NULL;
6023 if(get_filename(&output))
6025 TRACE("copy to %s\n", debugstr_w(output));
6026 CopyFileW(filename, output, FALSE);
6027 HeapFree(GetProcessHeap(), 0, output);
6028 return TRUE;
6030 return FALSE;
6033 /*****************************************************************************
6034 * schedule_pipe
6036 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6038 #ifdef HAVE_FORK
6039 char *unixname, *cmdA;
6040 DWORD len;
6041 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6042 BOOL ret = FALSE;
6043 char buf[1024];
6045 if(!(unixname = wine_get_unix_file_name(filename)))
6046 return FALSE;
6048 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6049 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6050 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6052 TRACE("printing with: %s\n", cmdA);
6054 if((file_fd = open(unixname, O_RDONLY)) == -1)
6055 goto end;
6057 if (pipe(fds))
6059 ERR("pipe() failed!\n");
6060 goto end;
6063 if (fork() == 0)
6065 close(0);
6066 dup2(fds[0], 0);
6067 close(fds[1]);
6069 /* reset signals that we previously set to SIG_IGN */
6070 signal(SIGPIPE, SIG_DFL);
6071 signal(SIGCHLD, SIG_DFL);
6073 system(cmdA);
6074 exit(0);
6077 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6078 write(fds[1], buf, no_read);
6080 ret = TRUE;
6082 end:
6083 if(file_fd != -1) close(file_fd);
6084 if(fds[0] != -1) close(fds[0]);
6085 if(fds[1] != -1) close(fds[1]);
6087 HeapFree(GetProcessHeap(), 0, cmdA);
6088 HeapFree(GetProcessHeap(), 0, unixname);
6089 return ret;
6090 #else
6091 return FALSE;
6092 #endif
6095 /*****************************************************************************
6096 * schedule_unixfile
6098 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6100 int in_fd, out_fd, no_read;
6101 char buf[1024];
6102 BOOL ret = FALSE;
6103 char *unixname, *outputA;
6104 DWORD len;
6106 if(!(unixname = wine_get_unix_file_name(filename)))
6107 return FALSE;
6109 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6110 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6111 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6113 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6114 in_fd = open(unixname, O_RDONLY);
6115 if(out_fd == -1 || in_fd == -1)
6116 goto end;
6118 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6119 write(out_fd, buf, no_read);
6121 ret = TRUE;
6122 end:
6123 if(in_fd != -1) close(in_fd);
6124 if(out_fd != -1) close(out_fd);
6125 HeapFree(GetProcessHeap(), 0, outputA);
6126 HeapFree(GetProcessHeap(), 0, unixname);
6127 return ret;
6130 /*****************************************************************************
6131 * ScheduleJob [WINSPOOL.@]
6134 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6136 opened_printer_t *printer;
6137 BOOL ret = FALSE;
6138 struct list *cursor, *cursor2;
6140 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6141 EnterCriticalSection(&printer_handles_cs);
6142 printer = get_opened_printer(hPrinter);
6143 if(!printer)
6144 goto end;
6146 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6148 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6149 HANDLE hf;
6151 if(job->job_id != dwJobID) continue;
6153 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6154 if(hf != INVALID_HANDLE_VALUE)
6156 PRINTER_INFO_5W *pi5;
6157 DWORD needed;
6158 HKEY hkey;
6159 WCHAR output[1024];
6160 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6161 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6163 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6164 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6165 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6166 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6167 debugstr_w(pi5->pPortName));
6169 output[0] = 0;
6171 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6172 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6174 DWORD type, count = sizeof(output);
6175 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6176 RegCloseKey(hkey);
6178 if(output[0] == '|')
6180 schedule_pipe(output + 1, job->filename);
6182 else if(output[0])
6184 schedule_unixfile(output, job->filename);
6186 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6188 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6190 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6192 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6194 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6196 schedule_file(job->filename);
6198 else
6200 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6202 HeapFree(GetProcessHeap(), 0, pi5);
6203 CloseHandle(hf);
6204 DeleteFileW(job->filename);
6206 list_remove(cursor);
6207 HeapFree(GetProcessHeap(), 0, job->document_title);
6208 HeapFree(GetProcessHeap(), 0, job->filename);
6209 HeapFree(GetProcessHeap(), 0, job);
6210 ret = TRUE;
6211 break;
6213 end:
6214 LeaveCriticalSection(&printer_handles_cs);
6215 return ret;
6218 /*****************************************************************************
6219 * StartDocDlgA [WINSPOOL.@]
6221 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6223 UNICODE_STRING usBuffer;
6224 DOCINFOW docW;
6225 LPWSTR retW;
6226 LPSTR ret = NULL;
6228 docW.cbSize = sizeof(docW);
6229 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6230 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6231 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6232 docW.fwType = doc->fwType;
6234 retW = StartDocDlgW(hPrinter, &docW);
6236 if(retW)
6238 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6239 ret = HeapAlloc(GetProcessHeap(), 0, len);
6240 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6241 HeapFree(GetProcessHeap(), 0, retW);
6244 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6245 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6246 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6248 return ret;
6251 /*****************************************************************************
6252 * StartDocDlgW [WINSPOOL.@]
6254 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6255 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6256 * port is "FILE:". Also returns the full path if passed a relative path.
6258 * The caller should free the returned string from the process heap.
6260 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6262 LPWSTR ret = NULL;
6263 DWORD len, attr;
6265 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6267 PRINTER_INFO_5W *pi5;
6268 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6269 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6270 return NULL;
6271 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6272 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6273 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6275 HeapFree(GetProcessHeap(), 0, pi5);
6276 return NULL;
6278 HeapFree(GetProcessHeap(), 0, pi5);
6281 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6283 LPWSTR name;
6284 get_filename(&name);
6285 if(name)
6287 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6289 HeapFree(GetProcessHeap(), 0, name);
6290 return NULL;
6292 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6293 GetFullPathNameW(name, len, ret, NULL);
6294 HeapFree(GetProcessHeap(), 0, name);
6296 return ret;
6299 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6300 return NULL;
6302 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6303 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6305 attr = GetFileAttributesW(ret);
6306 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6308 HeapFree(GetProcessHeap(), 0, ret);
6309 ret = NULL;
6311 return ret;