ntdll: Add a test for NtNotifyChangeDirectoryFile.
[wine/multimedia.git] / dlls / winspool / info.c
blob9b1771df5ec8fc8531a4cbdc74a69610cc4943b2
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;
99 static opened_printer_t **printer_handles;
100 static int nb_printer_handles;
101 static LONG next_job_id = 1;
103 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
104 WORD fwCapability, LPSTR lpszOutput,
105 LPDEVMODEA lpdm );
106 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
107 LPSTR lpszDevice, LPSTR lpszPort,
108 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
109 DWORD fwMode );
111 static const char Printers[] =
112 "System\\CurrentControlSet\\control\\Print\\Printers\\";
114 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
115 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
116 'c','o','n','t','r','o','l','\\',
117 'P','r','i','n','t','\\',
118 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
119 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
121 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
122 'M','i','c','r','o','s','o','f','t','\\',
123 'W','i','n','d','o','w','s',' ','N','T','\\',
124 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
125 'W','i','n','d','o','w','s',0};
127 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
128 'M','i','c','r','o','s','o','f','t','\\',
129 'W','i','n','d','o','w','s',' ','N','T','\\',
130 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
131 'D','e','v','i','c','e','s',0};
133 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
135 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
136 'i','o','n',' ','F','i','l','e',0};
137 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
138 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
139 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
140 'M','o','d','e',0};
141 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
142 'i','l','e','s',0};
143 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
144 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
145 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
146 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
147 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
148 static const WCHAR NameW[] = {'N','a','m','e',0};
149 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
150 static const WCHAR PortW[] = {'P','o','r','t',0};
151 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
152 's','s','o','r',0};
153 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
154 'v','e','r',0};
155 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
156 'v','e','r','D','a','t','a',0};
157 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
158 'i','l','e',0};
159 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
160 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
161 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
162 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
163 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
164 static const WCHAR emptyStringW[] = {0};
166 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
168 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
169 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
170 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
172 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
173 'D','o','c','u','m','e','n','t',0};
175 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
176 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
177 DWORD Level, LPBYTE pDriverInfo,
178 DWORD cbBuf, LPDWORD pcbNeeded,
179 BOOL unicode);
180 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
182 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
183 if passed a NULL string. This returns NULLs to the result.
185 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
187 if ( (src) )
189 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
190 return usBufferPtr->Buffer;
192 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
193 return NULL;
196 static LPWSTR strdupW(LPCWSTR p)
198 LPWSTR ret;
199 DWORD len;
201 if(!p) return NULL;
202 len = (strlenW(p) + 1) * sizeof(WCHAR);
203 ret = HeapAlloc(GetProcessHeap(), 0, len);
204 memcpy(ret, p, len);
205 return ret;
208 static void
209 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
210 char qbuf[200];
212 /* If forcing, or no profile string entry for device yet, set the entry
214 * The always change entry if not WINEPS yet is discussable.
216 if (force ||
217 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
218 !strcmp(qbuf,"*") ||
219 !strstr(qbuf,"WINEPS.DRV")
221 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
222 HKEY hkey;
224 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
225 WriteProfileStringA("windows","device",buf);
226 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
227 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
228 RegCloseKey(hkey);
230 HeapFree(GetProcessHeap(),0,buf);
234 #ifdef HAVE_CUPS_CUPS_H
235 static typeof(cupsGetDests) *pcupsGetDests;
236 static typeof(cupsGetPPD) *pcupsGetPPD;
237 static typeof(cupsPrintFile) *pcupsPrintFile;
238 static void *cupshandle;
240 static BOOL CUPS_LoadPrinters(void)
242 int i, nrofdests;
243 BOOL hadprinter = FALSE;
244 cups_dest_t *dests;
245 PRINTER_INFO_2A pinfo2a;
246 char *port,*devline;
247 HKEY hkeyPrinter, hkeyPrinters, hkey;
249 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
250 if (!cupshandle)
251 return FALSE;
252 TRACE("loaded %s\n", SONAME_LIBCUPS);
254 #define DYNCUPS(x) \
255 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
256 if (!p##x) return FALSE;
258 DYNCUPS(cupsGetPPD);
259 DYNCUPS(cupsGetDests);
260 DYNCUPS(cupsPrintFile);
261 #undef DYNCUPS
263 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
264 ERROR_SUCCESS) {
265 ERR("Can't create Printers key\n");
266 return FALSE;
269 nrofdests = pcupsGetDests(&dests);
270 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
271 for (i=0;i<nrofdests;i++) {
272 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
273 sprintf(port,"LPR:%s",dests[i].name);
274 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
275 sprintf(devline,"WINEPS.DRV,%s",port);
276 WriteProfileStringA("devices",dests[i].name,devline);
277 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
278 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
279 RegCloseKey(hkey);
281 HeapFree(GetProcessHeap(),0,devline);
283 TRACE("Printer %d: %s\n", i, dests[i].name);
284 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
285 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
286 and continue */
287 TRACE("Printer already exists\n");
288 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
289 RegCloseKey(hkeyPrinter);
290 } else {
291 memset(&pinfo2a,0,sizeof(pinfo2a));
292 pinfo2a.pPrinterName = dests[i].name;
293 pinfo2a.pDatatype = "RAW";
294 pinfo2a.pPrintProcessor = "WinPrint";
295 pinfo2a.pDriverName = "PS Driver";
296 pinfo2a.pComment = "WINEPS Printer using CUPS";
297 pinfo2a.pLocation = "<physical location of printer>";
298 pinfo2a.pPortName = port;
299 pinfo2a.pParameters = "<parameters?>";
300 pinfo2a.pShareName = "<share name?>";
301 pinfo2a.pSepFile = "<sep file?>";
303 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
304 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
305 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
308 HeapFree(GetProcessHeap(),0,port);
310 hadprinter = TRUE;
311 if (dests[i].is_default)
312 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
314 RegCloseKey(hkeyPrinters);
315 return hadprinter;
317 #endif
319 static BOOL
320 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
321 PRINTER_INFO_2A pinfo2a;
322 char *e,*s,*name,*prettyname,*devname;
323 BOOL ret = FALSE, set_default = FALSE;
324 char *port,*devline,*env_default;
325 HKEY hkeyPrinter, hkeyPrinters, hkey;
327 while (isspace(*pent)) pent++;
328 s = strchr(pent,':');
329 if(s) *s='\0';
330 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
331 strcpy(name,pent);
332 if(s) {
333 *s=':';
334 pent = s;
335 } else
336 pent = "";
338 TRACE("name=%s entry=%s\n",name, pent);
340 if(ispunct(*name)) { /* a tc entry, not a real printer */
341 TRACE("skipping tc entry\n");
342 goto end;
345 if(strstr(pent,":server")) { /* server only version so skip */
346 TRACE("skipping server entry\n");
347 goto end;
350 /* Determine whether this is a postscript printer. */
352 ret = TRUE;
353 env_default = getenv("PRINTER");
354 prettyname = name;
355 /* Get longest name, usually the one at the right for later display. */
356 while((s=strchr(prettyname,'|'))) {
357 *s = '\0';
358 e = s;
359 while(isspace(*--e)) *e = '\0';
360 TRACE("\t%s\n", debugstr_a(prettyname));
361 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
362 for(prettyname = s+1; isspace(*prettyname); prettyname++)
365 e = prettyname + strlen(prettyname);
366 while(isspace(*--e)) *e = '\0';
367 TRACE("\t%s\n", debugstr_a(prettyname));
368 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
370 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
371 * if it is too long, we use it as comment below. */
372 devname = prettyname;
373 if (strlen(devname)>=CCHDEVICENAME-1)
374 devname = name;
375 if (strlen(devname)>=CCHDEVICENAME-1) {
376 ret = FALSE;
377 goto end;
380 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
381 sprintf(port,"LPR:%s",name);
383 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
384 sprintf(devline,"WINEPS.DRV,%s",port);
385 WriteProfileStringA("devices",devname,devline);
386 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
387 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
388 RegCloseKey(hkey);
390 HeapFree(GetProcessHeap(),0,devline);
392 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
393 ERROR_SUCCESS) {
394 ERR("Can't create Printers key\n");
395 ret = FALSE;
396 goto end;
398 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
399 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
400 and continue */
401 TRACE("Printer already exists\n");
402 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
403 RegCloseKey(hkeyPrinter);
404 } else {
405 memset(&pinfo2a,0,sizeof(pinfo2a));
406 pinfo2a.pPrinterName = devname;
407 pinfo2a.pDatatype = "RAW";
408 pinfo2a.pPrintProcessor = "WinPrint";
409 pinfo2a.pDriverName = "PS Driver";
410 pinfo2a.pComment = "WINEPS Printer using LPR";
411 pinfo2a.pLocation = prettyname;
412 pinfo2a.pPortName = port;
413 pinfo2a.pParameters = "<parameters?>";
414 pinfo2a.pShareName = "<share name?>";
415 pinfo2a.pSepFile = "<sep file?>";
417 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
418 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
419 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
422 RegCloseKey(hkeyPrinters);
424 if (isfirst || set_default)
425 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
427 HeapFree(GetProcessHeap(), 0, port);
428 end:
429 HeapFree(GetProcessHeap(), 0, name);
430 return ret;
433 static BOOL
434 PRINTCAP_LoadPrinters(void) {
435 BOOL hadprinter = FALSE;
436 char buf[200];
437 FILE *f;
438 char *pent = NULL;
439 BOOL had_bash = FALSE;
441 f = fopen("/etc/printcap","r");
442 if (!f)
443 return FALSE;
445 while(fgets(buf,sizeof(buf),f)) {
446 char *start, *end;
448 end=strchr(buf,'\n');
449 if (end) *end='\0';
451 start = buf;
452 while(isspace(*start)) start++;
453 if(*start == '#' || *start == '\0')
454 continue;
456 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
457 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
458 HeapFree(GetProcessHeap(),0,pent);
459 pent = NULL;
462 if (end && *--end == '\\') {
463 *end = '\0';
464 had_bash = TRUE;
465 } else
466 had_bash = FALSE;
468 if (pent) {
469 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
470 strcat(pent,start);
471 } else {
472 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
473 strcpy(pent,start);
477 if(pent) {
478 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
479 HeapFree(GetProcessHeap(),0,pent);
481 fclose(f);
482 return hadprinter;
485 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
487 if (value)
488 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
489 lstrlenW(value) * sizeof(WCHAR));
490 else
491 return ERROR_FILE_NOT_FOUND;
494 void WINSPOOL_LoadSystemPrinters(void)
496 HKEY hkey, hkeyPrinters;
497 DRIVER_INFO_3A di3a;
498 HANDLE hprn;
499 DWORD needed, num, i;
500 WCHAR PrinterName[256];
501 BOOL done = FALSE;
503 di3a.cVersion = 0x400;
504 di3a.pName = "PS Driver";
505 di3a.pEnvironment = NULL; /* NULL means auto */
506 di3a.pDriverPath = "wineps16";
507 di3a.pDataFile = "<datafile?>";
508 di3a.pConfigFile = "wineps16";
509 di3a.pHelpFile = "<helpfile?>";
510 di3a.pDependentFiles = "<dependend files?>";
511 di3a.pMonitorName = "<monitor name?>";
512 di3a.pDefaultDataType = "RAW";
514 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
515 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
516 return;
519 /* This ensures that all printer entries have a valid Name value. If causes
520 problems later if they don't. If one is found to be missed we create one
521 and set it equal to the name of the key */
522 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
523 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
524 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
525 for(i = 0; i < num; i++) {
526 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
527 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
528 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
529 set_reg_szW(hkey, NameW, PrinterName);
531 RegCloseKey(hkey);
536 RegCloseKey(hkeyPrinters);
539 /* We want to avoid calling AddPrinter on printers as much as
540 possible, because on cups printers this will (eventually) lead
541 to a call to cupsGetPPD which takes forever, even with non-cups
542 printers AddPrinter takes a while. So we'll tag all printers that
543 were automatically added last time around, if they still exist
544 we'll leave them be otherwise we'll delete them. */
545 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
546 if(needed) {
547 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
548 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
549 for(i = 0; i < num; i++) {
550 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
551 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
552 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
553 DWORD dw = 1;
554 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
555 RegCloseKey(hkey);
557 ClosePrinter(hprn);
562 HeapFree(GetProcessHeap(), 0, pi);
566 #ifdef HAVE_CUPS_CUPS_H
567 done = CUPS_LoadPrinters();
568 #endif
570 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
571 /* Check for [ppd] section in config file before parsing /etc/printcap */
572 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
573 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
574 &hkey) == ERROR_SUCCESS) {
575 RegCloseKey(hkey);
576 PRINTCAP_LoadPrinters();
580 /* Now enumerate the list again and delete any printers that a still tagged */
581 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
582 if(needed) {
583 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
584 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
585 for(i = 0; i < num; i++) {
586 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
587 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
588 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
589 DWORD dw, type, size = sizeof(dw);
590 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
591 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
592 DeletePrinter(hprn);
594 RegCloseKey(hkey);
596 ClosePrinter(hprn);
601 HeapFree(GetProcessHeap(), 0, pi);
604 return;
609 /******************************************************************
610 * get_opened_printer_entry
611 * Get the first place empty in the opened printer table
613 static HANDLE get_opened_printer_entry( LPCWSTR name )
615 UINT_PTR handle = nb_printer_handles, i;
616 jobqueue_t *queue = NULL;
617 opened_printer_t *printer;
619 EnterCriticalSection(&printer_handles_cs);
621 for (i = 0; i < nb_printer_handles; i++)
623 if (!printer_handles[i])
625 if(handle == nb_printer_handles)
626 handle = i;
628 else if(!queue && !strcmpW(name, printer_handles[i]->name))
629 queue = printer_handles[i]->queue;
632 if (handle >= nb_printer_handles)
634 opened_printer_t **new_array;
635 if (printer_handles)
636 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
637 (nb_printer_handles + 16) * sizeof(*new_array) );
638 else
639 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
640 (nb_printer_handles + 16) * sizeof(*new_array) );
642 if (!new_array)
644 handle = 0;
645 goto end;
647 printer_handles = new_array;
648 nb_printer_handles += 16;
651 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
653 handle = 0;
654 goto end;
657 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
658 strcpyW(printer->name, name);
659 if(queue)
660 printer->queue = queue;
661 else
663 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
664 list_init(&printer->queue->jobs);
665 printer->queue->ref = 0;
667 InterlockedIncrement(&printer->queue->ref);
668 printer->doc = NULL;
670 printer_handles[handle] = printer;
671 handle++;
672 end:
673 LeaveCriticalSection(&printer_handles_cs);
675 return (HANDLE)handle;
678 /******************************************************************
679 * get_opened_printer
680 * Get the pointer to the opened printer referred by the handle
682 static opened_printer_t *get_opened_printer(HANDLE hprn)
684 UINT_PTR idx = (UINT_PTR)hprn;
685 opened_printer_t *ret = NULL;
687 EnterCriticalSection(&printer_handles_cs);
689 if ((idx <= 0) || (idx > nb_printer_handles))
690 goto end;
692 ret = printer_handles[idx - 1];
693 end:
694 LeaveCriticalSection(&printer_handles_cs);
695 return ret;
698 /******************************************************************
699 * get_opened_printer_name
700 * Get the pointer to the opened printer name referred by the handle
702 static LPCWSTR get_opened_printer_name(HANDLE hprn)
704 opened_printer_t *printer = get_opened_printer(hprn);
705 if(!printer) return NULL;
706 return printer->name;
709 /******************************************************************
710 * WINSPOOL_GetOpenedPrinterRegKey
713 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
715 LPCWSTR name = get_opened_printer_name(hPrinter);
716 DWORD ret;
717 HKEY hkeyPrinters;
719 if(!name) return ERROR_INVALID_HANDLE;
721 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
722 ERROR_SUCCESS)
723 return ret;
725 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
727 ERR("Can't find opened printer %s in registry\n",
728 debugstr_w(name));
729 RegCloseKey(hkeyPrinters);
730 return ERROR_INVALID_PRINTER_NAME; /* ? */
732 RegCloseKey(hkeyPrinters);
733 return ERROR_SUCCESS;
736 /******************************************************************
737 * get_job
739 * Get the pointer to the specified job.
740 * Should hold the printer_handles_cs before calling.
742 static job_t *get_job(HANDLE hprn, DWORD JobId)
744 opened_printer_t *printer = get_opened_printer(hprn);
745 job_t *job;
747 if(!printer) return NULL;
748 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
750 if(job->job_id == JobId)
751 return job;
753 return NULL;
756 /***********************************************************
757 * DEVMODEcpyAtoW
759 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
761 BOOL Formname;
762 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
763 DWORD size;
765 Formname = (dmA->dmSize > off_formname);
766 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
767 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
768 dmW->dmDeviceName, CCHDEVICENAME);
769 if(!Formname) {
770 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
771 dmA->dmSize - CCHDEVICENAME);
772 } else {
773 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
774 off_formname - CCHDEVICENAME);
775 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
776 dmW->dmFormName, CCHFORMNAME);
777 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
778 (off_formname + CCHFORMNAME));
780 dmW->dmSize = size;
781 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
782 dmA->dmDriverExtra);
783 return dmW;
786 /***********************************************************
787 * DEVMODEdupWtoA
788 * Creates an ascii copy of supplied devmode on heap
790 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
792 LPDEVMODEA dmA;
793 DWORD size;
794 BOOL Formname;
795 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
797 if(!dmW) return NULL;
798 Formname = (dmW->dmSize > off_formname);
799 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
800 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
801 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
802 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
803 if(!Formname) {
804 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
805 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
806 } else {
807 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
808 off_formname - CCHDEVICENAME * sizeof(WCHAR));
809 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
810 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
811 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
812 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
814 dmA->dmSize = size;
815 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
816 dmW->dmDriverExtra);
817 return dmA;
820 /***********************************************************
821 * PRINTER_INFO_2AtoW
822 * Creates a unicode copy of PRINTER_INFO_2A on heap
824 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
826 LPPRINTER_INFO_2W piW;
827 UNICODE_STRING usBuffer;
829 if(!piA) return NULL;
830 piW = HeapAlloc(heap, 0, sizeof(*piW));
831 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
833 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
834 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
835 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
836 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
837 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
838 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
839 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
840 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
841 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
842 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
843 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
844 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
845 return piW;
848 /***********************************************************
849 * FREE_PRINTER_INFO_2W
850 * Free PRINTER_INFO_2W and all strings
852 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
854 if(!piW) return;
856 HeapFree(heap,0,piW->pServerName);
857 HeapFree(heap,0,piW->pPrinterName);
858 HeapFree(heap,0,piW->pShareName);
859 HeapFree(heap,0,piW->pPortName);
860 HeapFree(heap,0,piW->pDriverName);
861 HeapFree(heap,0,piW->pComment);
862 HeapFree(heap,0,piW->pLocation);
863 HeapFree(heap,0,piW->pDevMode);
864 HeapFree(heap,0,piW->pSepFile);
865 HeapFree(heap,0,piW->pPrintProcessor);
866 HeapFree(heap,0,piW->pDatatype);
867 HeapFree(heap,0,piW->pParameters);
868 HeapFree(heap,0,piW);
869 return;
872 /******************************************************************
873 * DeviceCapabilities [WINSPOOL.@]
874 * DeviceCapabilitiesA [WINSPOOL.@]
877 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
878 LPSTR pOutput, LPDEVMODEA lpdm)
880 INT ret;
882 if (!GDI_CallDeviceCapabilities16)
884 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
885 (LPCSTR)104 );
886 if (!GDI_CallDeviceCapabilities16) return -1;
888 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
890 /* If DC_PAPERSIZE map POINT16s to POINTs */
891 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
892 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
893 POINT *pt = (POINT *)pOutput;
894 INT i;
895 memcpy(tmp, pOutput, ret * sizeof(POINT16));
896 for(i = 0; i < ret; i++, pt++)
898 pt->x = tmp[i].x;
899 pt->y = tmp[i].y;
901 HeapFree( GetProcessHeap(), 0, tmp );
903 return ret;
907 /*****************************************************************************
908 * DeviceCapabilitiesW [WINSPOOL.@]
910 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
913 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
914 WORD fwCapability, LPWSTR pOutput,
915 const DEVMODEW *pDevMode)
917 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
918 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
919 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
920 INT ret;
922 if(pOutput && (fwCapability == DC_BINNAMES ||
923 fwCapability == DC_FILEDEPENDENCIES ||
924 fwCapability == DC_PAPERNAMES)) {
925 /* These need A -> W translation */
926 INT size = 0, i;
927 LPSTR pOutputA;
928 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
929 dmA);
930 if(ret == -1)
931 return ret;
932 switch(fwCapability) {
933 case DC_BINNAMES:
934 size = 24;
935 break;
936 case DC_PAPERNAMES:
937 case DC_FILEDEPENDENCIES:
938 size = 64;
939 break;
941 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
942 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
943 dmA);
944 for(i = 0; i < ret; i++)
945 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
946 pOutput + (i * size), size);
947 HeapFree(GetProcessHeap(), 0, pOutputA);
948 } else {
949 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
950 (LPSTR)pOutput, dmA);
952 HeapFree(GetProcessHeap(),0,pPortA);
953 HeapFree(GetProcessHeap(),0,pDeviceA);
954 HeapFree(GetProcessHeap(),0,dmA);
955 return ret;
958 /******************************************************************
959 * DocumentPropertiesA [WINSPOOL.@]
961 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
963 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
964 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
965 LPDEVMODEA pDevModeInput,DWORD fMode )
967 LPSTR lpName = pDeviceName;
968 LONG ret;
970 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
971 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
974 if(!pDeviceName) {
975 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
976 if(!lpNameW) {
977 ERR("no name from hPrinter?\n");
978 SetLastError(ERROR_INVALID_HANDLE);
979 return -1;
981 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
984 if (!GDI_CallExtDeviceMode16)
986 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
987 (LPCSTR)102 );
988 if (!GDI_CallExtDeviceMode16) {
989 ERR("No CallExtDeviceMode16?\n");
990 return -1;
993 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
994 pDevModeInput, NULL, fMode);
996 if(!pDeviceName)
997 HeapFree(GetProcessHeap(),0,lpName);
998 return ret;
1002 /*****************************************************************************
1003 * DocumentPropertiesW (WINSPOOL.@)
1005 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1007 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1008 LPWSTR pDeviceName,
1009 LPDEVMODEW pDevModeOutput,
1010 LPDEVMODEW pDevModeInput, DWORD fMode)
1013 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1014 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1015 LPDEVMODEA pDevModeOutputA = NULL;
1016 LONG ret;
1018 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1019 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1020 fMode);
1021 if(pDevModeOutput) {
1022 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1023 if(ret < 0) return ret;
1024 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1026 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1027 pDevModeInputA, fMode);
1028 if(pDevModeOutput) {
1029 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1030 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1032 if(fMode == 0 && ret > 0)
1033 ret += (CCHDEVICENAME + CCHFORMNAME);
1034 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1035 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1036 return ret;
1039 /******************************************************************
1040 * OpenPrinterA [WINSPOOL.@]
1042 * See OpenPrinterW.
1045 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1046 LPPRINTER_DEFAULTSA pDefault)
1048 UNICODE_STRING lpPrinterNameW;
1049 UNICODE_STRING usBuffer;
1050 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1051 PWSTR pwstrPrinterNameW;
1052 BOOL ret;
1054 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1056 if(pDefault) {
1057 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1058 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1059 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1060 pDefaultW = &DefaultW;
1062 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1063 if(pDefault) {
1064 RtlFreeUnicodeString(&usBuffer);
1065 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1067 RtlFreeUnicodeString(&lpPrinterNameW);
1068 return ret;
1071 /******************************************************************
1072 * OpenPrinterW [WINSPOOL.@]
1074 * Open a Printer / Printserver or a Printer-Object
1076 * PARAMS
1077 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1078 * phPrinter [O] The resulting Handle is stored here
1079 * pDefault [I] PTR to Default Printer Settings or NULL
1081 * RETURNS
1082 * Success: TRUE
1083 * Failure: FALSE
1085 * NOTES
1086 * lpPrinterName is one of:
1087 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1088 *| Printer: "PrinterName"
1089 *| Printer-Object: "PrinterName,Job xxx"
1090 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1091 *| XcvPort: "Servername,XcvPort PortName"
1093 * BUGS
1094 *| Printserver not supported
1095 *| Printer-Object not supported
1096 *| XcvMonitor not supported
1097 *| XcvPort not supported
1098 *| pDefaults not supported
1101 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
1102 LPPRINTER_DEFAULTSW pDefault)
1104 HKEY hkeyPrinters, hkeyPrinter;
1106 if (!lpPrinterName) {
1107 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1108 SetLastError(ERROR_INVALID_PARAMETER);
1109 return FALSE;
1112 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1113 pDefault);
1115 /* Check Printer exists */
1116 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1117 ERROR_SUCCESS) {
1118 ERR("Can't create Printers key\n");
1119 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1120 return FALSE;
1123 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1124 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1125 != ERROR_SUCCESS) {
1126 TRACE("Can't find printer %s in registry\n",
1127 debugstr_w(lpPrinterName));
1128 RegCloseKey(hkeyPrinters);
1129 SetLastError(ERROR_INVALID_PRINTER_NAME);
1130 return FALSE;
1132 RegCloseKey(hkeyPrinter);
1133 RegCloseKey(hkeyPrinters);
1135 if(!phPrinter) /* This seems to be what win95 does anyway */
1136 return TRUE;
1138 /* Get the unique handle of the printer*/
1139 *phPrinter = get_opened_printer_entry( lpPrinterName );
1141 if (pDefault != NULL)
1142 FIXME("Not handling pDefault\n");
1144 return TRUE;
1147 /******************************************************************
1148 * AddMonitorA [WINSPOOL.@]
1150 * See AddMonitorW.
1153 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1155 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
1156 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1157 return FALSE;
1160 /******************************************************************************
1161 * AddMonitorW [WINSPOOL.@]
1163 * Install a Printmonitor
1165 * PARAMS
1166 * pName [I] Servername or NULL (local Computer)
1167 * Level [I] Structure-Level (Must be 2)
1168 * pMonitors [I] PTR to MONITOR_INFO_2
1170 * RETURNS
1171 * Success: TRUE
1172 * Failure: FALSE
1174 * NOTES
1175 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1177 * BUGS
1178 * only a Stub
1181 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1183 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1184 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1185 return FALSE;
1188 /******************************************************************
1189 * DeletePrinterDriverA [WINSPOOL.@]
1192 BOOL WINAPI
1193 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1195 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1196 debugstr_a(pDriverName));
1197 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1198 return FALSE;
1201 /******************************************************************
1202 * DeletePrinterDriverW [WINSPOOL.@]
1205 BOOL WINAPI
1206 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1208 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1209 debugstr_w(pDriverName));
1210 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1211 return FALSE;
1214 /******************************************************************
1215 * DeleteMonitorA [WINSPOOL.@]
1217 * See DeleteMonitorW.
1220 BOOL WINAPI
1221 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1223 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1224 debugstr_a(pMonitorName));
1225 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1226 return FALSE;
1229 /******************************************************************
1230 * DeleteMonitorW [WINSPOOL.@]
1232 * Delete a specific Printmonitor from a Printing-Environment
1234 * PARAMS
1235 * pName [I] Servername or NULL (local Computer)
1236 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1237 * pMonitorName [I] Name of the Monitor, that should be deleted
1239 * RETURNS
1240 * Success: TRUE
1241 * Failure: FALSE
1243 * BUGS
1244 * only a Stub
1247 BOOL WINAPI
1248 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1250 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1251 debugstr_w(pMonitorName));
1252 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1253 return FALSE;
1256 /******************************************************************
1257 * DeletePortA [WINSPOOL.@]
1259 * See DeletePortW.
1262 BOOL WINAPI
1263 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1265 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1266 debugstr_a(pPortName));
1267 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1268 return FALSE;
1271 /******************************************************************
1272 * DeletePortW [WINSPOOL.@]
1274 * Delete a specific Port
1276 * PARAMS
1277 * pName [I] Servername or NULL (local Computer)
1278 * hWnd [I] Handle to parent Window for the Dialog-Box
1279 * pPortName [I] Name of the Port, that should be deleted
1281 * RETURNS
1282 * Success: TRUE
1283 * Failure: FALSE
1285 * BUGS
1286 * only a Stub
1289 BOOL WINAPI
1290 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1292 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1293 debugstr_w(pPortName));
1294 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1295 return FALSE;
1298 /******************************************************************************
1299 * SetPrinterW [WINSPOOL.@]
1301 BOOL WINAPI
1302 SetPrinterW(
1303 HANDLE hPrinter,
1304 DWORD Level,
1305 LPBYTE pPrinter,
1306 DWORD Command) {
1308 FIXME("():stub\n");
1309 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1310 return FALSE;
1313 /******************************************************************************
1314 * WritePrinter [WINSPOOL.@]
1316 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1318 opened_printer_t *printer;
1319 BOOL ret = FALSE;
1321 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1323 EnterCriticalSection(&printer_handles_cs);
1324 printer = get_opened_printer(hPrinter);
1325 if(!printer)
1327 SetLastError(ERROR_INVALID_HANDLE);
1328 goto end;
1331 if(!printer->doc)
1333 SetLastError(ERROR_SPL_NO_STARTDOC);
1334 goto end;
1337 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1338 end:
1339 LeaveCriticalSection(&printer_handles_cs);
1340 return ret;
1343 /*****************************************************************************
1344 * AddFormA [WINSPOOL.@]
1346 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1348 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1349 return 1;
1352 /*****************************************************************************
1353 * AddFormW [WINSPOOL.@]
1355 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1357 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1358 return 1;
1361 /*****************************************************************************
1362 * AddJobA [WINSPOOL.@]
1364 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1366 BOOL ret;
1367 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1368 DWORD needed;
1370 if(Level != 1) {
1371 SetLastError(ERROR_INVALID_LEVEL);
1372 return FALSE;
1375 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1377 if(ret) {
1378 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1379 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1380 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1381 if(*pcbNeeded > cbBuf) {
1382 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1383 ret = FALSE;
1384 } else {
1385 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1386 addjobA->JobId = addjobW->JobId;
1387 addjobA->Path = (char *)(addjobA + 1);
1388 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1391 return ret;
1394 /*****************************************************************************
1395 * AddJobW [WINSPOOL.@]
1397 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1399 opened_printer_t *printer;
1400 job_t *job;
1401 BOOL ret = FALSE;
1402 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1403 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1404 WCHAR path[MAX_PATH], filename[MAX_PATH];
1405 DWORD len;
1406 ADDJOB_INFO_1W *addjob;
1408 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1410 EnterCriticalSection(&printer_handles_cs);
1412 printer = get_opened_printer(hPrinter);
1414 if(!printer) {
1415 SetLastError(ERROR_INVALID_HANDLE);
1416 goto end;
1419 if(Level != 1) {
1420 SetLastError(ERROR_INVALID_LEVEL);
1421 goto end;
1424 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1425 if(!job)
1426 goto end;
1428 job->job_id = InterlockedIncrement(&next_job_id);
1430 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1431 if(path[len - 1] != '\\')
1432 path[len++] = '\\';
1433 memcpy(path + len, spool_path, sizeof(spool_path));
1434 sprintfW(filename, fmtW, path, job->job_id);
1436 len = strlenW(filename);
1437 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1438 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1439 job->document_title = strdupW(default_doc_title);
1440 list_add_tail(&printer->queue->jobs, &job->entry);
1442 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1443 if(*pcbNeeded <= cbBuf) {
1444 addjob = (ADDJOB_INFO_1W*)pData;
1445 addjob->JobId = job->job_id;
1446 addjob->Path = (WCHAR *)(addjob + 1);
1447 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1448 ret = TRUE;
1449 } else
1450 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1452 end:
1453 LeaveCriticalSection(&printer_handles_cs);
1454 return ret;
1457 /*****************************************************************************
1458 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1460 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1461 DWORD level, LPBYTE Info,
1462 DWORD cbBuf, LPDWORD needed)
1464 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1465 level, Info, cbBuf);
1466 return 0;
1469 /*****************************************************************************
1470 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1472 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1473 DWORD level, LPBYTE Info,
1474 DWORD cbBuf, LPDWORD needed)
1476 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1477 level, Info, cbBuf);
1478 return 0;
1481 /*****************************************************************************
1482 * WINSPOOL_OpenDriverReg [internal]
1484 * opens the registry for the printer drivers depending on the given input
1485 * variable pEnvironment
1487 * RETURNS:
1488 * the opened hkey on success
1489 * NULL on error
1491 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1493 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1494 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1495 HKEY retval;
1496 LPWSTR lpKey, buffer = NULL;
1497 LPCWSTR pEnvW;
1499 TRACE("%s\n",
1500 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1502 if(pEnvironment) {
1503 if (unicode) {
1504 pEnvW = pEnvironment;
1505 } else {
1506 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1507 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1508 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1509 pEnvW = buffer;
1511 } else {
1512 OSVERSIONINFOW ver;
1513 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1515 if(!GetVersionExW( &ver))
1516 return 0;
1518 switch (ver.dwPlatformId) {
1519 case VER_PLATFORM_WIN32s:
1520 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1521 return 0;
1522 case VER_PLATFORM_WIN32_NT:
1523 pEnvW = WinNTW;
1524 break;
1525 default:
1526 pEnvW = Win40W;
1527 break;
1529 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1532 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1533 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1534 wsprintfW( lpKey, DriversW, pEnvW);
1536 TRACE("%s\n", debugstr_w(lpKey));
1538 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1539 retval = 0;
1541 HeapFree( GetProcessHeap(), 0, buffer);
1542 HeapFree( GetProcessHeap(), 0, lpKey);
1544 return retval;
1547 /*****************************************************************************
1548 * AddPrinterW [WINSPOOL.@]
1550 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1552 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1553 LPDEVMODEA dmA;
1554 LPDEVMODEW dmW;
1555 HANDLE retval;
1556 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1557 LONG size;
1559 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1561 if(pName != NULL) {
1562 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1563 SetLastError(ERROR_INVALID_PARAMETER);
1564 return 0;
1566 if(Level != 2) {
1567 ERR("Level = %ld, unsupported!\n", Level);
1568 SetLastError(ERROR_INVALID_LEVEL);
1569 return 0;
1571 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1572 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1573 debugstr_w(pi->pPrinterName)
1575 SetLastError(ERROR_INVALID_LEVEL);
1576 return 0;
1578 if(!pPrinter) {
1579 SetLastError(ERROR_INVALID_PARAMETER);
1580 return 0;
1582 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1583 ERROR_SUCCESS) {
1584 ERR("Can't create Printers key\n");
1585 return 0;
1587 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1588 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1589 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1590 RegCloseKey(hkeyPrinter);
1591 RegCloseKey(hkeyPrinters);
1592 return 0;
1594 RegCloseKey(hkeyPrinter);
1596 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1597 if(!hkeyDrivers) {
1598 ERR("Can't create Drivers key\n");
1599 RegCloseKey(hkeyPrinters);
1600 return 0;
1602 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1603 ERROR_SUCCESS) {
1604 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1605 RegCloseKey(hkeyPrinters);
1606 RegCloseKey(hkeyDrivers);
1607 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1608 return 0;
1610 RegCloseKey(hkeyDriver);
1611 RegCloseKey(hkeyDrivers);
1613 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1614 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1615 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1616 RegCloseKey(hkeyPrinters);
1617 return 0;
1620 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1621 ERROR_SUCCESS) {
1622 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1623 SetLastError(ERROR_INVALID_PRINTER_NAME);
1624 RegCloseKey(hkeyPrinters);
1625 return 0;
1627 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1628 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1629 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1631 /* See if we can load the driver. We may need the devmode structure anyway
1633 * FIXME:
1634 * Note that DocumentPropertiesW will briefly try to open the printer we
1635 * just create to find a DEVMODEA struct (it will use the WINEPS default
1636 * one in case it is not there, so we are ok).
1638 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1640 if(size < 0) {
1641 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1642 size = sizeof(DEVMODEW);
1644 if(pi->pDevMode)
1645 dmW = pi->pDevMode;
1646 else
1648 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1649 ZeroMemory(dmW,size);
1650 dmW->dmSize = size;
1651 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1653 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1654 HeapFree(GetProcessHeap(),0,dmW);
1655 dmW=NULL;
1657 else
1659 /* set devmode to printer name */
1660 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1664 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1665 and we support these drivers. NT writes DEVMODEW so somehow
1666 we'll need to distinguish between these when we support NT
1667 drivers */
1668 if (dmW)
1670 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1671 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1672 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1673 HeapFree(GetProcessHeap(), 0, dmA);
1674 if(!pi->pDevMode)
1675 HeapFree(GetProcessHeap(), 0, dmW);
1677 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1678 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1679 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1680 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1682 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1683 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1684 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1685 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1686 (LPBYTE)&pi->Priority, sizeof(DWORD));
1687 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1688 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1689 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1690 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1691 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1692 (LPBYTE)&pi->Status, sizeof(DWORD));
1693 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1694 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1696 RegCloseKey(hkeyPrinter);
1697 RegCloseKey(hkeyPrinters);
1698 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1699 ERR("OpenPrinter failing\n");
1700 return 0;
1702 return retval;
1705 /*****************************************************************************
1706 * AddPrinterA [WINSPOOL.@]
1708 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1710 UNICODE_STRING pNameW;
1711 PWSTR pwstrNameW;
1712 PRINTER_INFO_2W *piW;
1713 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1714 HANDLE ret;
1716 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1717 if(Level != 2) {
1718 ERR("Level = %ld, unsupported!\n", Level);
1719 SetLastError(ERROR_INVALID_LEVEL);
1720 return 0;
1722 pwstrNameW = asciitounicode(&pNameW,pName);
1723 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1725 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1727 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1728 RtlFreeUnicodeString(&pNameW);
1729 return ret;
1733 /*****************************************************************************
1734 * ClosePrinter [WINSPOOL.@]
1736 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1738 UINT_PTR i = (UINT_PTR)hPrinter;
1739 opened_printer_t *printer = NULL;
1740 BOOL ret = FALSE;
1742 TRACE("Handle %p\n", hPrinter);
1744 EnterCriticalSection(&printer_handles_cs);
1746 if ((i > 0) && (i <= nb_printer_handles))
1747 printer = printer_handles[i - 1];
1749 if(printer)
1751 struct list *cursor, *cursor2;
1753 if(printer->doc)
1754 EndDocPrinter(hPrinter);
1756 if(InterlockedDecrement(&printer->queue->ref) == 0)
1758 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
1760 job_t *job = LIST_ENTRY(cursor, job_t, entry);
1761 ScheduleJob(hPrinter, job->job_id);
1763 HeapFree(GetProcessHeap(), 0, printer->queue);
1765 HeapFree(GetProcessHeap(), 0, printer->name);
1766 HeapFree(GetProcessHeap(), 0, printer);
1767 printer_handles[i - 1] = NULL;
1768 ret = TRUE;
1770 LeaveCriticalSection(&printer_handles_cs);
1771 return ret;
1774 /*****************************************************************************
1775 * DeleteFormA [WINSPOOL.@]
1777 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1779 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1780 return 1;
1783 /*****************************************************************************
1784 * DeleteFormW [WINSPOOL.@]
1786 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1788 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1789 return 1;
1792 /*****************************************************************************
1793 * WINSPOOL_SHRegDeleteKey
1795 * Recursively delete subkeys.
1796 * Cut & paste from shlwapi.
1799 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1801 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1802 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1803 HKEY hSubKey = 0;
1805 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1806 if(!dwRet)
1808 /* Find how many subkeys there are */
1809 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1810 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1811 if(!dwRet)
1813 dwMaxSubkeyLen++;
1814 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1815 /* Name too big: alloc a buffer for it */
1816 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1818 if(!lpszName)
1819 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1820 else
1822 /* Recursively delete all the subkeys */
1823 for(i = 0; i < dwKeyCount && !dwRet; i++)
1825 dwSize = dwMaxSubkeyLen;
1826 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1827 if(!dwRet)
1828 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1831 if (lpszName != szNameBuf)
1832 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1836 RegCloseKey(hSubKey);
1837 if(!dwRet)
1838 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1840 return dwRet;
1843 /*****************************************************************************
1844 * DeletePrinter [WINSPOOL.@]
1846 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1848 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1849 HKEY hkeyPrinters, hkey;
1851 if(!lpNameW) {
1852 SetLastError(ERROR_INVALID_HANDLE);
1853 return FALSE;
1855 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1856 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1857 RegCloseKey(hkeyPrinters);
1859 WriteProfileStringW(devicesW, lpNameW, NULL);
1860 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1861 RegDeleteValueW(hkey, lpNameW);
1862 RegCloseKey(hkey);
1864 return TRUE;
1867 /*****************************************************************************
1868 * SetPrinterA [WINSPOOL.@]
1870 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1871 DWORD Command)
1873 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1874 return FALSE;
1877 /*****************************************************************************
1878 * SetJobA [WINSPOOL.@]
1880 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1881 LPBYTE pJob, DWORD Command)
1883 BOOL ret;
1884 LPBYTE JobW;
1885 UNICODE_STRING usBuffer;
1887 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
1889 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1890 are all ignored by SetJob, so we don't bother copying them */
1891 switch(Level)
1893 case 0:
1894 JobW = NULL;
1895 break;
1896 case 1:
1898 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
1899 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
1901 JobW = (LPBYTE)info1W;
1902 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
1903 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
1904 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
1905 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
1906 info1W->Status = info1A->Status;
1907 info1W->Priority = info1A->Priority;
1908 info1W->Position = info1A->Position;
1909 info1W->PagesPrinted = info1A->PagesPrinted;
1910 break;
1912 case 2:
1914 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
1915 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
1917 JobW = (LPBYTE)info2W;
1918 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
1919 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
1920 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
1921 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
1922 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
1923 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
1924 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
1925 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
1926 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
1927 info2W->Status = info2A->Status;
1928 info2W->Priority = info2A->Priority;
1929 info2W->Position = info2A->Position;
1930 info2W->StartTime = info2A->StartTime;
1931 info2W->UntilTime = info2A->UntilTime;
1932 info2W->PagesPrinted = info2A->PagesPrinted;
1933 break;
1935 case 3:
1936 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
1937 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
1938 break;
1939 default:
1940 SetLastError(ERROR_INVALID_LEVEL);
1941 return FALSE;
1944 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
1946 switch(Level)
1948 case 1:
1950 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
1951 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
1952 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
1953 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
1954 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
1955 break;
1957 case 2:
1959 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
1960 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
1961 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
1962 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
1963 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
1964 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
1965 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
1966 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
1967 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
1968 break;
1971 HeapFree(GetProcessHeap(), 0, JobW);
1973 return ret;
1976 /*****************************************************************************
1977 * SetJobW [WINSPOOL.@]
1979 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1980 LPBYTE pJob, DWORD Command)
1982 BOOL ret = FALSE;
1983 job_t *job;
1985 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
1986 FIXME("Ignoring everything other than document title\n");
1988 EnterCriticalSection(&printer_handles_cs);
1989 job = get_job(hPrinter, JobId);
1990 if(!job)
1991 goto end;
1993 switch(Level)
1995 case 0:
1996 break;
1997 case 1:
1999 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2000 HeapFree(GetProcessHeap(), 0, job->document_title);
2001 job->document_title = strdupW(info1->pDocument);
2002 break;
2004 case 2:
2006 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2007 HeapFree(GetProcessHeap(), 0, job->document_title);
2008 job->document_title = strdupW(info2->pDocument);
2009 break;
2011 case 3:
2012 break;
2013 default:
2014 SetLastError(ERROR_INVALID_LEVEL);
2015 goto end;
2017 ret = TRUE;
2018 end:
2019 LeaveCriticalSection(&printer_handles_cs);
2020 return ret;
2023 /*****************************************************************************
2024 * EndDocPrinter [WINSPOOL.@]
2026 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2028 opened_printer_t *printer;
2029 BOOL ret = FALSE;
2030 TRACE("(%p)\n", hPrinter);
2032 EnterCriticalSection(&printer_handles_cs);
2034 printer = get_opened_printer(hPrinter);
2035 if(!printer)
2037 SetLastError(ERROR_INVALID_HANDLE);
2038 goto end;
2041 if(!printer->doc)
2043 SetLastError(ERROR_SPL_NO_STARTDOC);
2044 goto end;
2047 CloseHandle(printer->doc->hf);
2048 ScheduleJob(hPrinter, printer->doc->job_id);
2049 HeapFree(GetProcessHeap(), 0, printer->doc);
2050 printer->doc = NULL;
2051 ret = TRUE;
2052 end:
2053 LeaveCriticalSection(&printer_handles_cs);
2054 return ret;
2057 /*****************************************************************************
2058 * EndPagePrinter [WINSPOOL.@]
2060 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2062 FIXME("(%p): stub\n", hPrinter);
2063 return TRUE;
2066 /*****************************************************************************
2067 * StartDocPrinterA [WINSPOOL.@]
2069 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2071 UNICODE_STRING usBuffer;
2072 DOC_INFO_2W doc2W;
2073 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2074 DWORD ret;
2076 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2077 or one (DOC_INFO_3) extra DWORDs */
2079 switch(Level) {
2080 case 2:
2081 doc2W.JobId = doc2->JobId;
2082 /* fall through */
2083 case 3:
2084 doc2W.dwMode = doc2->dwMode;
2085 /* fall through */
2086 case 1:
2087 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2088 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2089 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2090 break;
2092 default:
2093 SetLastError(ERROR_INVALID_LEVEL);
2094 return FALSE;
2097 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2099 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2100 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2101 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2103 return ret;
2106 /*****************************************************************************
2107 * StartDocPrinterW [WINSPOOL.@]
2109 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2111 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2112 opened_printer_t *printer;
2113 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2114 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2115 JOB_INFO_1W job_info;
2116 DWORD needed, ret = 0;
2117 HANDLE hf;
2118 WCHAR *filename;
2120 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2121 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2122 debugstr_w(doc->pDatatype));
2124 if(Level < 1 || Level > 3)
2126 SetLastError(ERROR_INVALID_LEVEL);
2127 return 0;
2130 EnterCriticalSection(&printer_handles_cs);
2131 printer = get_opened_printer(hPrinter);
2132 if(!printer)
2134 SetLastError(ERROR_INVALID_HANDLE);
2135 goto end;
2138 if(printer->doc)
2140 SetLastError(ERROR_INVALID_PRINTER_STATE);
2141 goto end;
2144 /* Even if we're printing to a file we still add a print job, we'll
2145 just ignore the spool file name */
2147 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2149 ERR("AddJob failed gle %08lx\n", GetLastError());
2150 goto end;
2153 if(doc->pOutputFile)
2154 filename = doc->pOutputFile;
2155 else
2156 filename = addjob->Path;
2158 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2159 if(hf == INVALID_HANDLE_VALUE)
2160 goto end;
2162 memset(&job_info, 0, sizeof(job_info));
2163 job_info.pDocument = doc->pDocName;
2164 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2166 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2167 printer->doc->hf = hf;
2168 ret = printer->doc->job_id = addjob->JobId;
2169 end:
2170 LeaveCriticalSection(&printer_handles_cs);
2172 return ret;
2175 /*****************************************************************************
2176 * StartPagePrinter [WINSPOOL.@]
2178 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2180 FIXME("(%p): stub\n", hPrinter);
2181 return TRUE;
2184 /*****************************************************************************
2185 * GetFormA [WINSPOOL.@]
2187 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2188 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2190 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2191 Level,pForm,cbBuf,pcbNeeded);
2192 return FALSE;
2195 /*****************************************************************************
2196 * GetFormW [WINSPOOL.@]
2198 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2199 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2201 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2202 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2203 return FALSE;
2206 /*****************************************************************************
2207 * SetFormA [WINSPOOL.@]
2209 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2210 LPBYTE pForm)
2212 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2213 return FALSE;
2216 /*****************************************************************************
2217 * SetFormW [WINSPOOL.@]
2219 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2220 LPBYTE pForm)
2222 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2223 return FALSE;
2226 /*****************************************************************************
2227 * ReadPrinter [WINSPOOL.@]
2229 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2230 LPDWORD pNoBytesRead)
2232 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2233 return FALSE;
2236 /*****************************************************************************
2237 * ResetPrinterA [WINSPOOL.@]
2239 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2241 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2242 return FALSE;
2245 /*****************************************************************************
2246 * ResetPrinterW [WINSPOOL.@]
2248 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2250 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2251 return FALSE;
2254 /*****************************************************************************
2255 * WINSPOOL_GetDWORDFromReg
2257 * Return DWORD associated with ValueName from hkey.
2259 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2261 DWORD sz = sizeof(DWORD), type, value = 0;
2262 LONG ret;
2264 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2266 if(ret != ERROR_SUCCESS) {
2267 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2268 return 0;
2270 if(type != REG_DWORD) {
2271 ERR("Got type %ld\n", type);
2272 return 0;
2274 return value;
2277 /*****************************************************************************
2278 * WINSPOOL_GetStringFromReg
2280 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2281 * String is stored either as unicode or ascii.
2282 * Bit of a hack here to get the ValueName if we want ascii.
2284 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2285 DWORD buflen, DWORD *needed,
2286 BOOL unicode)
2288 DWORD sz = buflen, type;
2289 LONG ret;
2291 if(unicode)
2292 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2293 else {
2294 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2295 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2296 HeapFree(GetProcessHeap(),0,ValueNameA);
2298 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2299 WARN("Got ret = %ld\n", ret);
2300 *needed = 0;
2301 return FALSE;
2303 *needed = sz;
2304 return TRUE;
2307 /*****************************************************************************
2308 * WINSPOOL_GetDefaultDevMode
2310 * Get a default DevMode values for wineps.
2311 * FIXME - use ppd.
2314 static void WINSPOOL_GetDefaultDevMode(
2315 LPBYTE ptr,
2316 DWORD buflen, DWORD *needed,
2317 BOOL unicode)
2319 DEVMODEA dm;
2320 static const char szwps[] = "wineps.drv";
2322 /* fill default DEVMODE - should be read from ppd... */
2323 ZeroMemory( &dm, sizeof(dm) );
2324 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2325 dm.dmSpecVersion = DM_SPECVERSION;
2326 dm.dmDriverVersion = 1;
2327 dm.dmSize = sizeof(DEVMODEA);
2328 dm.dmDriverExtra = 0;
2329 dm.dmFields =
2330 DM_ORIENTATION | DM_PAPERSIZE |
2331 DM_PAPERLENGTH | DM_PAPERWIDTH |
2332 DM_SCALE |
2333 DM_COPIES |
2334 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2335 DM_YRESOLUTION | DM_TTOPTION;
2337 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2338 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2339 dm.u1.s1.dmPaperLength = 2970;
2340 dm.u1.s1.dmPaperWidth = 2100;
2342 dm.dmScale = 100;
2343 dm.dmCopies = 1;
2344 dm.dmDefaultSource = DMBIN_AUTO;
2345 dm.dmPrintQuality = DMRES_MEDIUM;
2346 /* dm.dmColor */
2347 /* dm.dmDuplex */
2348 dm.dmYResolution = 300; /* 300dpi */
2349 dm.dmTTOption = DMTT_BITMAP;
2350 /* dm.dmCollate */
2351 /* dm.dmFormName */
2352 /* dm.dmLogPixels */
2353 /* dm.dmBitsPerPel */
2354 /* dm.dmPelsWidth */
2355 /* dm.dmPelsHeight */
2356 /* dm.dmDisplayFlags */
2357 /* dm.dmDisplayFrequency */
2358 /* dm.dmICMMethod */
2359 /* dm.dmICMIntent */
2360 /* dm.dmMediaType */
2361 /* dm.dmDitherType */
2362 /* dm.dmReserved1 */
2363 /* dm.dmReserved2 */
2364 /* dm.dmPanningWidth */
2365 /* dm.dmPanningHeight */
2367 if(unicode) {
2368 if(buflen >= sizeof(DEVMODEW)) {
2369 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2370 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2371 HeapFree(GetProcessHeap(),0,pdmW);
2373 *needed = sizeof(DEVMODEW);
2375 else
2377 if(buflen >= sizeof(DEVMODEA)) {
2378 memcpy(ptr, &dm, sizeof(DEVMODEA));
2380 *needed = sizeof(DEVMODEA);
2384 /*****************************************************************************
2385 * WINSPOOL_GetDevModeFromReg
2387 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2388 * DevMode is stored either as unicode or ascii.
2390 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2391 LPBYTE ptr,
2392 DWORD buflen, DWORD *needed,
2393 BOOL unicode)
2395 DWORD sz = buflen, type;
2396 LONG ret;
2398 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2399 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2400 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2401 if (sz < sizeof(DEVMODEA))
2403 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2404 return FALSE;
2406 /* ensures that dmSize is not erratically bogus if registry is invalid */
2407 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2408 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2409 if(unicode) {
2410 sz += (CCHDEVICENAME + CCHFORMNAME);
2411 if(buflen >= sz) {
2412 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2413 memcpy(ptr, dmW, sz);
2414 HeapFree(GetProcessHeap(),0,dmW);
2417 *needed = sz;
2418 return TRUE;
2421 /*********************************************************************
2422 * WINSPOOL_GetPrinter_2
2424 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2425 * The strings are either stored as unicode or ascii.
2427 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2428 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2429 BOOL unicode)
2431 DWORD size, left = cbBuf;
2432 BOOL space = (cbBuf > 0);
2433 LPBYTE ptr = buf;
2435 *pcbNeeded = 0;
2437 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2438 unicode)) {
2439 if(space && size <= left) {
2440 pi2->pPrinterName = (LPWSTR)ptr;
2441 ptr += size;
2442 left -= size;
2443 } else
2444 space = FALSE;
2445 *pcbNeeded += size;
2447 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2448 unicode)) {
2449 if(space && size <= left) {
2450 pi2->pShareName = (LPWSTR)ptr;
2451 ptr += size;
2452 left -= size;
2453 } else
2454 space = FALSE;
2455 *pcbNeeded += size;
2457 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2458 unicode)) {
2459 if(space && size <= left) {
2460 pi2->pPortName = (LPWSTR)ptr;
2461 ptr += size;
2462 left -= size;
2463 } else
2464 space = FALSE;
2465 *pcbNeeded += size;
2467 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2468 &size, unicode)) {
2469 if(space && size <= left) {
2470 pi2->pDriverName = (LPWSTR)ptr;
2471 ptr += size;
2472 left -= size;
2473 } else
2474 space = FALSE;
2475 *pcbNeeded += size;
2477 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2478 unicode)) {
2479 if(space && size <= left) {
2480 pi2->pComment = (LPWSTR)ptr;
2481 ptr += size;
2482 left -= size;
2483 } else
2484 space = FALSE;
2485 *pcbNeeded += size;
2487 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2488 unicode)) {
2489 if(space && size <= left) {
2490 pi2->pLocation = (LPWSTR)ptr;
2491 ptr += size;
2492 left -= size;
2493 } else
2494 space = FALSE;
2495 *pcbNeeded += size;
2497 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2498 &size, unicode)) {
2499 if(space && size <= left) {
2500 pi2->pDevMode = (LPDEVMODEW)ptr;
2501 ptr += size;
2502 left -= size;
2503 } else
2504 space = FALSE;
2505 *pcbNeeded += size;
2507 else
2509 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2510 if(space && size <= left) {
2511 pi2->pDevMode = (LPDEVMODEW)ptr;
2512 ptr += size;
2513 left -= size;
2514 } else
2515 space = FALSE;
2516 *pcbNeeded += size;
2518 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2519 &size, unicode)) {
2520 if(space && size <= left) {
2521 pi2->pSepFile = (LPWSTR)ptr;
2522 ptr += size;
2523 left -= size;
2524 } else
2525 space = FALSE;
2526 *pcbNeeded += size;
2528 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2529 &size, unicode)) {
2530 if(space && size <= left) {
2531 pi2->pPrintProcessor = (LPWSTR)ptr;
2532 ptr += size;
2533 left -= size;
2534 } else
2535 space = FALSE;
2536 *pcbNeeded += size;
2538 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2539 &size, unicode)) {
2540 if(space && size <= left) {
2541 pi2->pDatatype = (LPWSTR)ptr;
2542 ptr += size;
2543 left -= size;
2544 } else
2545 space = FALSE;
2546 *pcbNeeded += size;
2548 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2549 &size, unicode)) {
2550 if(space && size <= left) {
2551 pi2->pParameters = (LPWSTR)ptr;
2552 ptr += size;
2553 left -= size;
2554 } else
2555 space = FALSE;
2556 *pcbNeeded += size;
2558 if(pi2) {
2559 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2560 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2561 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2562 "Default Priority");
2563 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2564 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2567 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2568 memset(pi2, 0, sizeof(*pi2));
2570 return space;
2573 /*********************************************************************
2574 * WINSPOOL_GetPrinter_4
2576 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2578 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2579 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2580 BOOL unicode)
2582 DWORD size, left = cbBuf;
2583 BOOL space = (cbBuf > 0);
2584 LPBYTE ptr = buf;
2586 *pcbNeeded = 0;
2588 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2589 unicode)) {
2590 if(space && size <= left) {
2591 pi4->pPrinterName = (LPWSTR)ptr;
2592 ptr += size;
2593 left -= size;
2594 } else
2595 space = FALSE;
2596 *pcbNeeded += size;
2598 if(pi4) {
2599 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2602 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2603 memset(pi4, 0, sizeof(*pi4));
2605 return space;
2608 /*********************************************************************
2609 * WINSPOOL_GetPrinter_5
2611 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2613 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2614 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2615 BOOL unicode)
2617 DWORD size, left = cbBuf;
2618 BOOL space = (cbBuf > 0);
2619 LPBYTE ptr = buf;
2621 *pcbNeeded = 0;
2623 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2624 unicode)) {
2625 if(space && size <= left) {
2626 pi5->pPrinterName = (LPWSTR)ptr;
2627 ptr += size;
2628 left -= size;
2629 } else
2630 space = FALSE;
2631 *pcbNeeded += size;
2633 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2634 unicode)) {
2635 if(space && size <= left) {
2636 pi5->pPortName = (LPWSTR)ptr;
2637 ptr += size;
2638 left -= size;
2639 } else
2640 space = FALSE;
2641 *pcbNeeded += size;
2643 if(pi5) {
2644 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2645 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2646 "dnsTimeout");
2647 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2648 "txTimeout");
2651 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2652 memset(pi5, 0, sizeof(*pi5));
2654 return space;
2657 /*****************************************************************************
2658 * WINSPOOL_GetPrinter
2660 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2661 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2662 * just a collection of pointers to strings.
2664 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2665 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2667 LPCWSTR name;
2668 DWORD size, needed = 0;
2669 LPBYTE ptr = NULL;
2670 HKEY hkeyPrinter, hkeyPrinters;
2671 BOOL ret;
2673 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2675 if (!(name = get_opened_printer_name(hPrinter))) {
2676 SetLastError(ERROR_INVALID_HANDLE);
2677 return FALSE;
2680 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2681 ERROR_SUCCESS) {
2682 ERR("Can't create Printers key\n");
2683 return FALSE;
2685 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2687 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2688 RegCloseKey(hkeyPrinters);
2689 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2690 return FALSE;
2693 switch(Level) {
2694 case 2:
2696 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2698 size = sizeof(PRINTER_INFO_2W);
2699 if(size <= cbBuf) {
2700 ptr = pPrinter + size;
2701 cbBuf -= size;
2702 memset(pPrinter, 0, size);
2703 } else {
2704 pi2 = NULL;
2705 cbBuf = 0;
2707 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2708 unicode);
2709 needed += size;
2710 break;
2713 case 4:
2715 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2717 size = sizeof(PRINTER_INFO_4W);
2718 if(size <= cbBuf) {
2719 ptr = pPrinter + size;
2720 cbBuf -= size;
2721 memset(pPrinter, 0, size);
2722 } else {
2723 pi4 = NULL;
2724 cbBuf = 0;
2726 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2727 unicode);
2728 needed += size;
2729 break;
2733 case 5:
2735 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2737 size = sizeof(PRINTER_INFO_5W);
2738 if(size <= cbBuf) {
2739 ptr = pPrinter + size;
2740 cbBuf -= size;
2741 memset(pPrinter, 0, size);
2742 } else {
2743 pi5 = NULL;
2744 cbBuf = 0;
2747 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2748 unicode);
2749 needed += size;
2750 break;
2753 default:
2754 FIXME("Unimplemented level %ld\n", Level);
2755 SetLastError(ERROR_INVALID_LEVEL);
2756 RegCloseKey(hkeyPrinters);
2757 RegCloseKey(hkeyPrinter);
2758 return FALSE;
2761 RegCloseKey(hkeyPrinter);
2762 RegCloseKey(hkeyPrinters);
2764 TRACE("returning %d needed = %ld\n", ret, needed);
2765 if(pcbNeeded) *pcbNeeded = needed;
2766 if(!ret)
2767 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2768 return ret;
2771 /*****************************************************************************
2772 * GetPrinterW [WINSPOOL.@]
2774 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2775 DWORD cbBuf, LPDWORD pcbNeeded)
2777 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2778 TRUE);
2781 /*****************************************************************************
2782 * GetPrinterA [WINSPOOL.@]
2784 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2785 DWORD cbBuf, LPDWORD pcbNeeded)
2787 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2788 FALSE);
2791 /*****************************************************************************
2792 * WINSPOOL_EnumPrinters
2794 * Implementation of EnumPrintersA|W
2796 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2797 DWORD dwLevel, LPBYTE lpbPrinters,
2798 DWORD cbBuf, LPDWORD lpdwNeeded,
2799 LPDWORD lpdwReturned, BOOL unicode)
2802 HKEY hkeyPrinters, hkeyPrinter;
2803 WCHAR PrinterName[255];
2804 DWORD needed = 0, number = 0;
2805 DWORD used, i, left;
2806 PBYTE pi, buf;
2808 if(lpbPrinters)
2809 memset(lpbPrinters, 0, cbBuf);
2810 if(lpdwReturned)
2811 *lpdwReturned = 0;
2812 if(lpdwNeeded)
2813 *lpdwNeeded = 0;
2815 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2816 if(dwType == PRINTER_ENUM_DEFAULT)
2817 return TRUE;
2819 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2820 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2821 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2822 if(!dwType) return TRUE;
2825 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2826 FIXME("dwType = %08lx\n", dwType);
2827 SetLastError(ERROR_INVALID_FLAGS);
2828 return FALSE;
2831 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2832 ERROR_SUCCESS) {
2833 ERR("Can't create Printers key\n");
2834 return FALSE;
2837 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2838 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2839 RegCloseKey(hkeyPrinters);
2840 ERR("Can't query Printers key\n");
2841 return FALSE;
2843 TRACE("Found %ld printers\n", number);
2845 switch(dwLevel) {
2846 case 1:
2847 RegCloseKey(hkeyPrinters);
2848 if (lpdwReturned)
2849 *lpdwReturned = number;
2850 return TRUE;
2852 case 2:
2853 used = number * sizeof(PRINTER_INFO_2W);
2854 break;
2855 case 4:
2856 used = number * sizeof(PRINTER_INFO_4W);
2857 break;
2858 case 5:
2859 used = number * sizeof(PRINTER_INFO_5W);
2860 break;
2862 default:
2863 SetLastError(ERROR_INVALID_LEVEL);
2864 RegCloseKey(hkeyPrinters);
2865 return FALSE;
2867 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2869 for(i = 0; i < number; i++) {
2870 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2871 ERROR_SUCCESS) {
2872 ERR("Can't enum key number %ld\n", i);
2873 RegCloseKey(hkeyPrinters);
2874 return FALSE;
2876 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2877 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2878 ERROR_SUCCESS) {
2879 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2880 RegCloseKey(hkeyPrinters);
2881 return FALSE;
2884 if(cbBuf > used) {
2885 buf = lpbPrinters + used;
2886 left = cbBuf - used;
2887 } else {
2888 buf = NULL;
2889 left = 0;
2892 switch(dwLevel) {
2893 case 2:
2894 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2895 left, &needed, unicode);
2896 used += needed;
2897 if(pi) pi += sizeof(PRINTER_INFO_2W);
2898 break;
2899 case 4:
2900 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2901 left, &needed, unicode);
2902 used += needed;
2903 if(pi) pi += sizeof(PRINTER_INFO_4W);
2904 break;
2905 case 5:
2906 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2907 left, &needed, unicode);
2908 used += needed;
2909 if(pi) pi += sizeof(PRINTER_INFO_5W);
2910 break;
2911 default:
2912 ERR("Shouldn't be here!\n");
2913 RegCloseKey(hkeyPrinter);
2914 RegCloseKey(hkeyPrinters);
2915 return FALSE;
2917 RegCloseKey(hkeyPrinter);
2919 RegCloseKey(hkeyPrinters);
2921 if(lpdwNeeded)
2922 *lpdwNeeded = used;
2924 if(used > cbBuf) {
2925 if(lpbPrinters)
2926 memset(lpbPrinters, 0, cbBuf);
2927 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2928 return FALSE;
2930 if(lpdwReturned)
2931 *lpdwReturned = number;
2932 SetLastError(ERROR_SUCCESS);
2933 return TRUE;
2937 /******************************************************************
2938 * EnumPrintersW [WINSPOOL.@]
2940 * Enumerates the available printers, print servers and print
2941 * providers, depending on the specified flags, name and level.
2943 * RETURNS:
2945 * If level is set to 1:
2946 * Not implemented yet!
2947 * Returns TRUE with an empty list.
2949 * If level is set to 2:
2950 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2951 * Returns an array of PRINTER_INFO_2 data structures in the
2952 * lpbPrinters buffer. Note that according to MSDN also an
2953 * OpenPrinter should be performed on every remote printer.
2955 * If level is set to 4 (officially WinNT only):
2956 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2957 * Fast: Only the registry is queried to retrieve printer names,
2958 * no connection to the driver is made.
2959 * Returns an array of PRINTER_INFO_4 data structures in the
2960 * lpbPrinters buffer.
2962 * If level is set to 5 (officially WinNT4/Win9x only):
2963 * Fast: Only the registry is queried to retrieve printer names,
2964 * no connection to the driver is made.
2965 * Returns an array of PRINTER_INFO_5 data structures in the
2966 * lpbPrinters buffer.
2968 * If level set to 3 or 6+:
2969 * returns zero (failure!)
2971 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2972 * for information.
2974 * BUGS:
2975 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2976 * - Only levels 2, 4 and 5 are implemented at the moment.
2977 * - 16-bit printer drivers are not enumerated.
2978 * - Returned amount of bytes used/needed does not match the real Windoze
2979 * implementation (as in this implementation, all strings are part
2980 * of the buffer, whereas Win32 keeps them somewhere else)
2981 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2983 * NOTE:
2984 * - In a regular Wine installation, no registry settings for printers
2985 * exist, which makes this function return an empty list.
2987 BOOL WINAPI EnumPrintersW(
2988 DWORD dwType, /* [in] Types of print objects to enumerate */
2989 LPWSTR lpszName, /* [in] name of objects to enumerate */
2990 DWORD dwLevel, /* [in] type of printer info structure */
2991 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2992 DWORD cbBuf, /* [in] max size of buffer in bytes */
2993 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2994 LPDWORD lpdwReturned /* [out] number of entries returned */
2997 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2998 lpdwNeeded, lpdwReturned, TRUE);
3001 /******************************************************************
3002 * EnumPrintersA [WINSPOOL.@]
3005 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3006 DWORD dwLevel, LPBYTE lpbPrinters,
3007 DWORD cbBuf, LPDWORD lpdwNeeded,
3008 LPDWORD lpdwReturned)
3010 BOOL ret;
3011 UNICODE_STRING lpszNameW;
3012 PWSTR pwstrNameW;
3014 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3015 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3016 lpdwNeeded, lpdwReturned, FALSE);
3017 RtlFreeUnicodeString(&lpszNameW);
3018 return ret;
3021 /*****************************************************************************
3022 * WINSPOOL_GetDriverInfoFromReg [internal]
3024 * Enters the information from the registry into the DRIVER_INFO struct
3026 * RETURNS
3027 * zero if the printer driver does not exist in the registry
3028 * (only if Level > 1) otherwise nonzero
3030 static BOOL WINSPOOL_GetDriverInfoFromReg(
3031 HKEY hkeyDrivers,
3032 LPWSTR DriverName,
3033 LPWSTR pEnvironment,
3034 DWORD Level,
3035 LPBYTE ptr, /* DRIVER_INFO */
3036 LPBYTE pDriverStrings, /* strings buffer */
3037 DWORD cbBuf, /* size of string buffer */
3038 LPDWORD pcbNeeded, /* space needed for str. */
3039 BOOL unicode) /* type of strings */
3040 { DWORD dw, size, tmp, type;
3041 HKEY hkeyDriver;
3042 LPBYTE strPtr = pDriverStrings;
3044 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3045 debugstr_w(DriverName), debugstr_w(pEnvironment),
3046 Level, ptr, pDriverStrings, cbBuf, unicode);
3048 if(unicode) {
3049 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3050 if (*pcbNeeded <= cbBuf)
3051 strcpyW((LPWSTR)strPtr, DriverName);
3052 } else {
3053 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3054 NULL, NULL);
3055 if(*pcbNeeded <= cbBuf)
3056 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3057 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3059 if(Level == 1) {
3060 if(ptr)
3061 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3062 return TRUE;
3063 } else {
3064 if(ptr)
3065 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
3066 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3069 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3070 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3071 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3072 return FALSE;
3075 size = sizeof(dw);
3076 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
3077 ERROR_SUCCESS)
3078 WARN("Can't get Version\n");
3079 else if(ptr)
3080 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
3082 if(!pEnvironment)
3083 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3084 if(unicode)
3085 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3086 else
3087 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3088 NULL, NULL);
3089 *pcbNeeded += size;
3090 if(*pcbNeeded <= cbBuf) {
3091 if(unicode)
3092 strcpyW((LPWSTR)strPtr, pEnvironment);
3093 else
3094 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3095 (LPSTR)strPtr, size, NULL, NULL);
3096 if(ptr)
3097 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
3098 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3101 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3102 unicode)) {
3103 *pcbNeeded += size;
3104 if(*pcbNeeded <= cbBuf)
3105 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3106 unicode);
3107 if(ptr)
3108 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
3109 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3112 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3113 unicode)) {
3114 *pcbNeeded += size;
3115 if(*pcbNeeded <= cbBuf)
3116 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3117 &tmp, unicode);
3118 if(ptr)
3119 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
3120 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3123 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3124 0, &size, unicode)) {
3125 *pcbNeeded += size;
3126 if(*pcbNeeded <= cbBuf)
3127 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3128 size, &tmp, unicode);
3129 if(ptr)
3130 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
3131 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3134 if(Level == 2 ) {
3135 RegCloseKey(hkeyDriver);
3136 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3137 return TRUE;
3140 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3141 unicode)) {
3142 *pcbNeeded += size;
3143 if(*pcbNeeded <= cbBuf)
3144 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3145 size, &tmp, unicode);
3146 if(ptr)
3147 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3148 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3151 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3152 &size, unicode)) {
3153 *pcbNeeded += size;
3154 if(*pcbNeeded <= cbBuf)
3155 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3156 size, &tmp, unicode);
3157 if(ptr)
3158 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3159 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3162 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3163 unicode)) {
3164 *pcbNeeded += size;
3165 if(*pcbNeeded <= cbBuf)
3166 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3167 size, &tmp, unicode);
3168 if(ptr)
3169 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3170 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3173 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3174 unicode)) {
3175 *pcbNeeded += size;
3176 if(*pcbNeeded <= cbBuf)
3177 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3178 size, &tmp, unicode);
3179 if(ptr)
3180 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3181 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3184 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3185 RegCloseKey(hkeyDriver);
3186 return TRUE;
3189 /*****************************************************************************
3190 * WINSPOOL_GetPrinterDriver
3192 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3193 DWORD Level, LPBYTE pDriverInfo,
3194 DWORD cbBuf, LPDWORD pcbNeeded,
3195 BOOL unicode)
3197 LPCWSTR name;
3198 WCHAR DriverName[100];
3199 DWORD ret, type, size, needed = 0;
3200 LPBYTE ptr = NULL;
3201 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3203 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3204 Level,pDriverInfo,cbBuf, pcbNeeded);
3206 ZeroMemory(pDriverInfo, cbBuf);
3208 if (!(name = get_opened_printer_name(hPrinter))) {
3209 SetLastError(ERROR_INVALID_HANDLE);
3210 return FALSE;
3212 if(Level < 1 || Level > 3) {
3213 SetLastError(ERROR_INVALID_LEVEL);
3214 return FALSE;
3216 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3217 ERROR_SUCCESS) {
3218 ERR("Can't create Printers key\n");
3219 return FALSE;
3221 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3222 != ERROR_SUCCESS) {
3223 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3224 RegCloseKey(hkeyPrinters);
3225 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3226 return FALSE;
3228 size = sizeof(DriverName);
3229 DriverName[0] = 0;
3230 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3231 (LPBYTE)DriverName, &size);
3232 RegCloseKey(hkeyPrinter);
3233 RegCloseKey(hkeyPrinters);
3234 if(ret != ERROR_SUCCESS) {
3235 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3236 return FALSE;
3239 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3240 if(!hkeyDrivers) {
3241 ERR("Can't create Drivers key\n");
3242 return FALSE;
3245 switch(Level) {
3246 case 1:
3247 size = sizeof(DRIVER_INFO_1W);
3248 break;
3249 case 2:
3250 size = sizeof(DRIVER_INFO_2W);
3251 break;
3252 case 3:
3253 size = sizeof(DRIVER_INFO_3W);
3254 break;
3255 default:
3256 ERR("Invalid level\n");
3257 return FALSE;
3260 if(size <= cbBuf)
3261 ptr = pDriverInfo + size;
3263 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3264 pEnvironment, Level, pDriverInfo,
3265 (cbBuf < size) ? NULL : ptr,
3266 (cbBuf < size) ? 0 : cbBuf - size,
3267 &needed, unicode)) {
3268 RegCloseKey(hkeyDrivers);
3269 return FALSE;
3272 RegCloseKey(hkeyDrivers);
3274 if(pcbNeeded) *pcbNeeded = size + needed;
3275 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3276 if(cbBuf >= needed) return TRUE;
3277 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3278 return FALSE;
3281 /*****************************************************************************
3282 * GetPrinterDriverA [WINSPOOL.@]
3284 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3285 DWORD Level, LPBYTE pDriverInfo,
3286 DWORD cbBuf, LPDWORD pcbNeeded)
3288 BOOL ret;
3289 UNICODE_STRING pEnvW;
3290 PWSTR pwstrEnvW;
3292 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3293 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3294 cbBuf, pcbNeeded, FALSE);
3295 RtlFreeUnicodeString(&pEnvW);
3296 return ret;
3298 /*****************************************************************************
3299 * GetPrinterDriverW [WINSPOOL.@]
3301 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3302 DWORD Level, LPBYTE pDriverInfo,
3303 DWORD cbBuf, LPDWORD pcbNeeded)
3305 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3306 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3309 /*****************************************************************************
3310 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3312 * Return the PATH for the Printer-Drivers (UNICODE)
3314 * PARAMS
3315 * pName [I] Servername (NT only) or NULL (local Computer)
3316 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3317 * Level [I] Structure-Level (must be 1)
3318 * pDriverDirectory [O] PTR to Buffer that receives the Result
3319 * cbBuf [I] Size of Buffer at pDriverDirectory
3320 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3321 * required for pDriverDirectory
3323 * RETURNS
3324 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3325 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3326 * if cbBuf is too small
3328 * Native Values returned in pDriverDirectory on Success:
3329 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3330 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3331 *| win9x(Windows 4.0): "%winsysdir%"
3333 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3335 * FIXME
3336 *- pName != NULL not supported
3337 *- pEnvironment != NULL not supported
3338 *- Current Implementation returns always "%winsysdir%"
3341 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3342 DWORD Level, LPBYTE pDriverDirectory,
3343 DWORD cbBuf, LPDWORD pcbNeeded)
3345 DWORD needed;
3347 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3348 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3349 if(pName != NULL) {
3350 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
3351 SetLastError(ERROR_INVALID_PARAMETER);
3352 return FALSE;
3354 if(pEnvironment != NULL) {
3355 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
3356 SetLastError(ERROR_INVALID_ENVIRONMENT);
3357 return FALSE;
3359 if(Level != 1) /* win95 ignores this so we just carry on */
3360 WARN("Level = %ld - assuming 1\n", Level);
3362 /* FIXME should read from registry */
3363 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
3364 /* GetSystemDirectoryW returns number of TCHAR without '\0'
3365 * adjust this now
3367 needed++;
3368 needed*=sizeof(WCHAR);
3370 if(pcbNeeded)
3371 *pcbNeeded = needed;
3372 TRACE("required <%08lx>\n", *pcbNeeded);
3373 if(needed > cbBuf) {
3374 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3375 return FALSE;
3377 return TRUE;
3381 /*****************************************************************************
3382 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3384 * Return the PATH for the Printer-Drivers (ANSI)
3386 * See GetPrinterDriverDirectoryW.
3388 * NOTES
3389 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3392 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3393 DWORD Level, LPBYTE pDriverDirectory,
3394 DWORD cbBuf, LPDWORD pcbNeeded)
3396 UNICODE_STRING nameW, environmentW;
3397 BOOL ret;
3398 DWORD pcbNeededW;
3399 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3400 WCHAR *driverDirectoryW = NULL;
3402 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3404 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3405 else nameW.Buffer = NULL;
3406 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3407 else environmentW.Buffer = NULL;
3409 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3410 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3411 if (ret) {
3412 DWORD needed;
3413 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3414 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3415 if(pcbNeeded)
3416 *pcbNeeded = needed;
3417 ret = (needed <= cbBuf) ? TRUE : FALSE;
3418 } else
3419 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3421 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
3423 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3424 RtlFreeUnicodeString(&environmentW);
3425 RtlFreeUnicodeString(&nameW);
3427 return ret;
3430 /*****************************************************************************
3431 * AddPrinterDriverA [WINSPOOL.@]
3433 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3435 DRIVER_INFO_3A di3;
3436 HKEY hkeyDrivers, hkeyName;
3438 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3440 if(level != 2 && level != 3) {
3441 SetLastError(ERROR_INVALID_LEVEL);
3442 return FALSE;
3444 if(pName != NULL) {
3445 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3446 SetLastError(ERROR_INVALID_PARAMETER);
3447 return FALSE;
3449 if(!pDriverInfo) {
3450 WARN("pDriverInfo == NULL\n");
3451 SetLastError(ERROR_INVALID_PARAMETER);
3452 return FALSE;
3455 if(level == 3)
3456 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3457 else {
3458 memset(&di3, 0, sizeof(di3));
3459 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3462 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3463 !di3.pDataFile) {
3464 SetLastError(ERROR_INVALID_PARAMETER);
3465 return FALSE;
3467 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3468 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3469 if(!di3.pHelpFile) di3.pHelpFile = "";
3470 if(!di3.pMonitorName) di3.pMonitorName = "";
3472 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3474 if(!hkeyDrivers) {
3475 ERR("Can't create Drivers key\n");
3476 return FALSE;
3479 if(level == 2) { /* apparently can't overwrite with level2 */
3480 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3481 RegCloseKey(hkeyName);
3482 RegCloseKey(hkeyDrivers);
3483 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3484 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3485 return FALSE;
3488 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3489 RegCloseKey(hkeyDrivers);
3490 ERR("Can't create Name key\n");
3491 return FALSE;
3493 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3495 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3496 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3497 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3498 sizeof(DWORD));
3499 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3500 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3501 (LPBYTE) di3.pDependentFiles, 0);
3502 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3503 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3504 RegCloseKey(hkeyName);
3505 RegCloseKey(hkeyDrivers);
3507 return TRUE;
3510 /*****************************************************************************
3511 * AddPrinterDriverW [WINSPOOL.@]
3513 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3514 LPBYTE pDriverInfo)
3516 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3517 level,pDriverInfo);
3518 return FALSE;
3521 /*****************************************************************************
3522 * AddPrintProcessorA [WINSPOOL.@]
3524 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3525 LPSTR pPrintProcessorName)
3527 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3528 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3529 return FALSE;
3532 /*****************************************************************************
3533 * AddPrintProcessorW [WINSPOOL.@]
3535 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3536 LPWSTR pPrintProcessorName)
3538 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3539 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3540 return FALSE;
3543 /*****************************************************************************
3544 * AddPrintProvidorA [WINSPOOL.@]
3546 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3548 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3549 return FALSE;
3552 /*****************************************************************************
3553 * AddPrintProvidorW [WINSPOOL.@]
3555 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3557 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3558 return FALSE;
3561 /*****************************************************************************
3562 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3564 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3565 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3567 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3568 pDevModeOutput, pDevModeInput);
3569 return 0;
3572 /*****************************************************************************
3573 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3575 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3576 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3578 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3579 pDevModeOutput, pDevModeInput);
3580 return 0;
3583 /*****************************************************************************
3584 * PrinterProperties [WINSPOOL.@]
3586 * Displays a dialog to set the properties of the printer.
3588 * RETURNS
3589 * nonzero on success or zero on failure
3591 * BUGS
3592 * implemented as stub only
3594 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3595 HANDLE hPrinter /* [in] handle to printer object */
3597 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3598 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3599 return FALSE;
3602 /*****************************************************************************
3603 * EnumJobsA [WINSPOOL.@]
3606 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3607 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3608 LPDWORD pcReturned)
3610 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3611 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3613 if(pcbNeeded) *pcbNeeded = 0;
3614 if(pcReturned) *pcReturned = 0;
3615 return FALSE;
3619 /*****************************************************************************
3620 * EnumJobsW [WINSPOOL.@]
3623 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3624 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3625 LPDWORD pcReturned)
3627 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3628 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3630 if(pcbNeeded) *pcbNeeded = 0;
3631 if(pcReturned) *pcReturned = 0;
3632 return FALSE;
3635 /*****************************************************************************
3636 * WINSPOOL_EnumPrinterDrivers [internal]
3638 * Delivers information about all printer drivers installed on the
3639 * localhost or a given server
3641 * RETURNS
3642 * nonzero on success or zero on failure. If the buffer for the returned
3643 * information is too small the function will return an error
3645 * BUGS
3646 * - only implemented for localhost, foreign hosts will return an error
3648 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3649 DWORD Level, LPBYTE pDriverInfo,
3650 DWORD cbBuf, LPDWORD pcbNeeded,
3651 LPDWORD pcReturned, BOOL unicode)
3653 { HKEY hkeyDrivers;
3654 DWORD i, needed, number = 0, size = 0;
3655 WCHAR DriverNameW[255];
3656 PBYTE ptr;
3658 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3659 debugstr_w(pName), debugstr_w(pEnvironment),
3660 Level, pDriverInfo, cbBuf, unicode);
3662 /* check for local drivers */
3663 if(pName) {
3664 ERR("remote drivers unsupported! Current remote host is %s\n",
3665 debugstr_w(pName));
3666 return FALSE;
3669 /* check input parameter */
3670 if((Level < 1) || (Level > 3)) {
3671 ERR("unsupported level %ld\n", Level);
3672 SetLastError(ERROR_INVALID_LEVEL);
3673 return FALSE;
3676 /* initialize return values */
3677 if(pDriverInfo)
3678 memset( pDriverInfo, 0, cbBuf);
3679 *pcbNeeded = 0;
3680 *pcReturned = 0;
3682 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3683 if(!hkeyDrivers) {
3684 ERR("Can't open Drivers key\n");
3685 return FALSE;
3688 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3689 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3690 RegCloseKey(hkeyDrivers);
3691 ERR("Can't query Drivers key\n");
3692 return FALSE;
3694 TRACE("Found %ld Drivers\n", number);
3696 /* get size of single struct
3697 * unicode and ascii structure have the same size
3699 switch (Level) {
3700 case 1:
3701 size = sizeof(DRIVER_INFO_1A);
3702 break;
3703 case 2:
3704 size = sizeof(DRIVER_INFO_2A);
3705 break;
3706 case 3:
3707 size = sizeof(DRIVER_INFO_3A);
3708 break;
3711 /* calculate required buffer size */
3712 *pcbNeeded = size * number;
3714 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3715 i < number;
3716 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3717 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3718 != ERROR_SUCCESS) {
3719 ERR("Can't enum key number %ld\n", i);
3720 RegCloseKey(hkeyDrivers);
3721 return FALSE;
3723 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3724 pEnvironment, Level, ptr,
3725 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3726 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3727 &needed, unicode)) {
3728 RegCloseKey(hkeyDrivers);
3729 return FALSE;
3731 (*pcbNeeded) += needed;
3734 RegCloseKey(hkeyDrivers);
3736 if(cbBuf < *pcbNeeded){
3737 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3738 return FALSE;
3741 *pcReturned = number;
3742 return TRUE;
3745 /*****************************************************************************
3746 * EnumPrinterDriversW [WINSPOOL.@]
3748 * see function EnumPrinterDrivers for RETURNS, BUGS
3750 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3751 LPBYTE pDriverInfo, DWORD cbBuf,
3752 LPDWORD pcbNeeded, LPDWORD pcReturned)
3754 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3755 cbBuf, pcbNeeded, pcReturned, TRUE);
3758 /*****************************************************************************
3759 * EnumPrinterDriversA [WINSPOOL.@]
3761 * see function EnumPrinterDrivers for RETURNS, BUGS
3763 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3764 LPBYTE pDriverInfo, DWORD cbBuf,
3765 LPDWORD pcbNeeded, LPDWORD pcReturned)
3766 { BOOL ret;
3767 UNICODE_STRING pNameW, pEnvironmentW;
3768 PWSTR pwstrNameW, pwstrEnvironmentW;
3770 pwstrNameW = asciitounicode(&pNameW, pName);
3771 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3773 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3774 Level, pDriverInfo, cbBuf, pcbNeeded,
3775 pcReturned, FALSE);
3776 RtlFreeUnicodeString(&pNameW);
3777 RtlFreeUnicodeString(&pEnvironmentW);
3779 return ret;
3782 static CHAR PortMonitor[] = "Wine Port Monitor";
3783 static CHAR PortDescription[] = "Wine Port";
3785 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3787 HANDLE handle;
3789 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3790 NULL, OPEN_EXISTING, 0, NULL );
3791 if (handle == INVALID_HANDLE_VALUE)
3792 return FALSE;
3793 TRACE("Checking %s exists\n", name );
3794 CloseHandle( handle );
3795 return TRUE;
3798 static DWORD WINSPOOL_CountSerialPorts(void)
3800 CHAR name[6];
3801 DWORD n = 0, i;
3803 for (i=0; i<4; i++)
3805 strcpy( name, "COMx:" );
3806 name[3] = '1' + i;
3807 if (WINSPOOL_ComPortExists( name ))
3808 n++;
3811 return n;
3814 /******************************************************************************
3815 * EnumPortsA (WINSPOOL.@)
3817 * See EnumPortsW.
3819 * BUGS
3820 * ANSI-Version did not call the UNICODE-Version
3823 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3824 LPDWORD bufneeded,LPDWORD bufreturned)
3826 CHAR portname[10];
3827 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3828 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3829 HKEY hkey_printer;
3830 BOOL retval = TRUE;
3832 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3833 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3835 switch( level )
3837 case 1:
3838 info_size = sizeof (PORT_INFO_1A);
3839 break;
3840 case 2:
3841 info_size = sizeof (PORT_INFO_2A);
3842 break;
3843 default:
3844 SetLastError(ERROR_INVALID_LEVEL);
3845 return FALSE;
3848 /* see how many exist */
3850 hkey_printer = 0;
3851 serial_count = WINSPOOL_CountSerialPorts();
3852 printer_count = 0;
3854 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3855 if ( r == ERROR_SUCCESS )
3857 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3858 &printer_count, NULL, NULL, NULL, NULL);
3860 count = serial_count + printer_count;
3862 /* then fill in the structure info structure once
3863 we know the offset to the first string */
3865 memset( buffer, 0, bufsize );
3866 n = 0;
3867 ofs = info_size*count;
3868 for ( i=0; i<count; i++)
3870 DWORD vallen = sizeof(portname) - 1;
3872 /* get the serial port values, then the printer values */
3873 if ( i < serial_count )
3875 strcpy( portname, "COMx:" );
3876 portname[3] = '1' + i;
3877 if (!WINSPOOL_ComPortExists( portname ))
3878 continue;
3880 TRACE("Found %s\n", portname );
3881 vallen = strlen( portname );
3883 else
3885 r = RegEnumValueA( hkey_printer, i-serial_count,
3886 portname, &vallen, NULL, NULL, NULL, 0 );
3887 if ( r )
3888 continue;
3891 /* add a colon if necessary, and make it upper case */
3892 CharUpperBuffA(portname,vallen);
3893 if (strcasecmp(portname,"nul")!=0)
3894 if (vallen && (portname[vallen-1] != ':') )
3895 lstrcatA(portname,":");
3897 /* add the port info structure if we can fit it */
3898 if ( info_size*(n+1) < bufsize )
3900 if ( level == 1)
3902 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3903 info->pName = (LPSTR) &buffer[ofs];
3905 else if ( level == 2)
3907 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3908 info->pPortName = (LPSTR) &buffer[ofs];
3909 /* FIXME: fill in more stuff here */
3910 info->pMonitorName = PortMonitor;
3911 info->pDescription = PortDescription;
3912 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3915 /* add the name of the port if we can fit it */
3916 if ( ofs < bufsize )
3917 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
3919 n++;
3921 else
3922 retval = FALSE;
3923 ofs += lstrlenA(portname)+1;
3926 RegCloseKey(hkey_printer);
3928 if(bufneeded)
3929 *bufneeded = ofs;
3931 if(bufreturned)
3932 *bufreturned = n;
3934 return retval;
3937 /******************************************************************************
3938 * EnumPortsW (WINSPOOL.@)
3940 * Enumerate available Ports
3942 * PARAMS
3943 * name [I] Servername or NULL (local Computer)
3944 * level [I] Structure-Level (1 or 2)
3945 * buffer [O] PTR to Buffer that receives the Result
3946 * bufsize [I] Size of Buffer at buffer
3947 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
3948 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
3950 * RETURNS
3951 * Success: TRUE
3952 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
3954 * BUGS
3955 * UNICODE-Version is a stub
3958 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3959 LPDWORD bufneeded,LPDWORD bufreturned)
3961 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3962 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3963 return FALSE;
3966 /******************************************************************************
3967 * GetDefaultPrinterW (WINSPOOL.@)
3969 * FIXME
3970 * This function must read the value from data 'device' of key
3971 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3973 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3975 BOOL retval = TRUE;
3976 DWORD insize, len;
3977 WCHAR *buffer, *ptr;
3979 if (!namesize)
3981 SetLastError(ERROR_INVALID_PARAMETER);
3982 return FALSE;
3985 /* make the buffer big enough for the stuff from the profile/registry,
3986 * the content must fit into the local buffer to compute the correct
3987 * size even if the extern buffer is too small or not given.
3988 * (20 for ,driver,port) */
3989 insize = *namesize;
3990 len = max(100, (insize + 20));
3991 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3993 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3995 SetLastError (ERROR_FILE_NOT_FOUND);
3996 retval = FALSE;
3997 goto end;
3999 TRACE("%s\n", debugstr_w(buffer));
4001 if ((ptr = strchrW(buffer, ',')) == NULL)
4003 SetLastError(ERROR_INVALID_NAME);
4004 retval = FALSE;
4005 goto end;
4008 *ptr = 0;
4009 *namesize = strlenW(buffer) + 1;
4010 if(!name || (*namesize > insize))
4012 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4013 retval = FALSE;
4014 goto end;
4016 strcpyW(name, buffer);
4018 end:
4019 HeapFree( GetProcessHeap(), 0, buffer);
4020 return retval;
4024 /******************************************************************************
4025 * GetDefaultPrinterA (WINSPOOL.@)
4027 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4029 BOOL retval = TRUE;
4030 DWORD insize = 0;
4031 WCHAR *bufferW = NULL;
4033 if (!namesize)
4035 SetLastError(ERROR_INVALID_PARAMETER);
4036 return FALSE;
4039 if(name && *namesize) {
4040 insize = *namesize;
4041 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4044 if(!GetDefaultPrinterW( bufferW, namesize)) {
4045 retval = FALSE;
4046 goto end;
4049 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4050 NULL, NULL);
4051 if (!*namesize)
4053 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4054 retval = FALSE;
4056 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4058 end:
4059 HeapFree( GetProcessHeap(), 0, bufferW);
4060 return retval;
4064 /******************************************************************************
4065 * SetPrinterDataExA (WINSPOOL.@)
4067 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4068 LPCSTR pValueName, DWORD Type,
4069 LPBYTE pData, DWORD cbData)
4071 HKEY hkeyPrinter, hkeySubkey;
4072 DWORD ret;
4074 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4075 debugstr_a(pValueName), Type, pData, cbData);
4077 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4078 != ERROR_SUCCESS)
4079 return ret;
4081 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4082 != ERROR_SUCCESS) {
4083 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4084 RegCloseKey(hkeyPrinter);
4085 return ret;
4087 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4088 RegCloseKey(hkeySubkey);
4089 RegCloseKey(hkeyPrinter);
4090 return ret;
4093 /******************************************************************************
4094 * SetPrinterDataExW (WINSPOOL.@)
4096 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4097 LPCWSTR pValueName, DWORD Type,
4098 LPBYTE pData, DWORD cbData)
4100 HKEY hkeyPrinter, hkeySubkey;
4101 DWORD ret;
4103 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4104 debugstr_w(pValueName), Type, pData, cbData);
4106 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4107 != ERROR_SUCCESS)
4108 return ret;
4110 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4111 != ERROR_SUCCESS) {
4112 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4113 RegCloseKey(hkeyPrinter);
4114 return ret;
4116 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4117 RegCloseKey(hkeySubkey);
4118 RegCloseKey(hkeyPrinter);
4119 return ret;
4122 /******************************************************************************
4123 * SetPrinterDataA (WINSPOOL.@)
4125 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4126 LPBYTE pData, DWORD cbData)
4128 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4129 pData, cbData);
4132 /******************************************************************************
4133 * SetPrinterDataW (WINSPOOL.@)
4135 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4136 LPBYTE pData, DWORD cbData)
4138 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4139 pData, cbData);
4142 /******************************************************************************
4143 * GetPrinterDataExA (WINSPOOL.@)
4145 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4146 LPCSTR pValueName, LPDWORD pType,
4147 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4149 HKEY hkeyPrinter, hkeySubkey;
4150 DWORD ret;
4152 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4153 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4154 pcbNeeded);
4156 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4157 != ERROR_SUCCESS)
4158 return ret;
4160 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4161 != ERROR_SUCCESS) {
4162 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4163 RegCloseKey(hkeyPrinter);
4164 return ret;
4166 *pcbNeeded = nSize;
4167 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4168 RegCloseKey(hkeySubkey);
4169 RegCloseKey(hkeyPrinter);
4170 return ret;
4173 /******************************************************************************
4174 * GetPrinterDataExW (WINSPOOL.@)
4176 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4177 LPCWSTR pValueName, LPDWORD pType,
4178 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4180 HKEY hkeyPrinter, hkeySubkey;
4181 DWORD ret;
4183 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4184 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4185 pcbNeeded);
4187 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4188 != ERROR_SUCCESS)
4189 return ret;
4191 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4192 != ERROR_SUCCESS) {
4193 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4194 RegCloseKey(hkeyPrinter);
4195 return ret;
4197 *pcbNeeded = nSize;
4198 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4199 RegCloseKey(hkeySubkey);
4200 RegCloseKey(hkeyPrinter);
4201 return ret;
4204 /******************************************************************************
4205 * GetPrinterDataA (WINSPOOL.@)
4207 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4208 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4210 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4211 pData, nSize, pcbNeeded);
4214 /******************************************************************************
4215 * GetPrinterDataW (WINSPOOL.@)
4217 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4218 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4220 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4221 pData, nSize, pcbNeeded);
4224 /*******************************************************************************
4225 * EnumPrinterDataExW [WINSPOOL.@]
4227 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4228 LPBYTE pEnumValues, DWORD cbEnumValues,
4229 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4231 HKEY hkPrinter, hkSubKey;
4232 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4233 cbValueNameLen, cbMaxValueLen, cbValueLen,
4234 cbBufSize, dwType;
4235 LPWSTR lpValueName;
4236 HANDLE hHeap;
4237 PBYTE lpValue;
4238 PPRINTER_ENUM_VALUESW ppev;
4240 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4242 if (pKeyName == NULL || *pKeyName == 0)
4243 return ERROR_INVALID_PARAMETER;
4245 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4246 if (ret != ERROR_SUCCESS)
4248 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4249 hPrinter, ret);
4250 return ret;
4253 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4254 if (ret != ERROR_SUCCESS)
4256 r = RegCloseKey (hkPrinter);
4257 if (r != ERROR_SUCCESS)
4258 WARN ("RegCloseKey returned %li\n", r);
4259 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4260 debugstr_w (pKeyName), ret);
4261 return ret;
4264 ret = RegCloseKey (hkPrinter);
4265 if (ret != ERROR_SUCCESS)
4267 ERR ("RegCloseKey returned %li\n", ret);
4268 r = RegCloseKey (hkSubKey);
4269 if (r != ERROR_SUCCESS)
4270 WARN ("RegCloseKey returned %li\n", r);
4271 return ret;
4274 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4275 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4276 if (ret != ERROR_SUCCESS)
4278 r = RegCloseKey (hkSubKey);
4279 if (r != ERROR_SUCCESS)
4280 WARN ("RegCloseKey returned %li\n", r);
4281 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4282 return ret;
4285 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4286 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4288 if (cValues == 0) /* empty key */
4290 r = RegCloseKey (hkSubKey);
4291 if (r != ERROR_SUCCESS)
4292 WARN ("RegCloseKey returned %li\n", r);
4293 *pcbEnumValues = *pnEnumValues = 0;
4294 return ERROR_SUCCESS;
4297 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4299 hHeap = GetProcessHeap ();
4300 if (hHeap == NULL)
4302 ERR ("GetProcessHeap failed\n");
4303 r = RegCloseKey (hkSubKey);
4304 if (r != ERROR_SUCCESS)
4305 WARN ("RegCloseKey returned %li\n", r);
4306 return ERROR_OUTOFMEMORY;
4309 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4310 if (lpValueName == NULL)
4312 ERR ("Failed to allocate %li bytes from process heap\n",
4313 cbMaxValueNameLen * sizeof (WCHAR));
4314 r = RegCloseKey (hkSubKey);
4315 if (r != ERROR_SUCCESS)
4316 WARN ("RegCloseKey returned %li\n", r);
4317 return ERROR_OUTOFMEMORY;
4320 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4321 if (lpValue == NULL)
4323 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4324 if (HeapFree (hHeap, 0, lpValueName) == 0)
4325 WARN ("HeapFree failed with code %li\n", GetLastError ());
4326 r = RegCloseKey (hkSubKey);
4327 if (r != ERROR_SUCCESS)
4328 WARN ("RegCloseKey returned %li\n", r);
4329 return ERROR_OUTOFMEMORY;
4332 TRACE ("pass 1: calculating buffer required for all names and values\n");
4334 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4336 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4338 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4340 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4341 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4342 NULL, NULL, lpValue, &cbValueLen);
4343 if (ret != ERROR_SUCCESS)
4345 if (HeapFree (hHeap, 0, lpValue) == 0)
4346 WARN ("HeapFree failed with code %li\n", GetLastError ());
4347 if (HeapFree (hHeap, 0, lpValueName) == 0)
4348 WARN ("HeapFree failed with code %li\n", GetLastError ());
4349 r = RegCloseKey (hkSubKey);
4350 if (r != ERROR_SUCCESS)
4351 WARN ("RegCloseKey returned %li\n", r);
4352 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4353 return ret;
4356 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4357 debugstr_w (lpValueName), dwIndex,
4358 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4360 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4361 cbBufSize += cbValueLen;
4364 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4366 *pcbEnumValues = cbBufSize;
4367 *pnEnumValues = cValues;
4369 if (cbEnumValues < cbBufSize) /* buffer too small */
4371 if (HeapFree (hHeap, 0, lpValue) == 0)
4372 WARN ("HeapFree failed with code %li\n", GetLastError ());
4373 if (HeapFree (hHeap, 0, lpValueName) == 0)
4374 WARN ("HeapFree failed with code %li\n", GetLastError ());
4375 r = RegCloseKey (hkSubKey);
4376 if (r != ERROR_SUCCESS)
4377 WARN ("RegCloseKey returned %li\n", r);
4378 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4379 return ERROR_MORE_DATA;
4382 TRACE ("pass 2: copying all names and values to buffer\n");
4384 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4385 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4387 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4389 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4390 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4391 NULL, &dwType, lpValue, &cbValueLen);
4392 if (ret != ERROR_SUCCESS)
4394 if (HeapFree (hHeap, 0, lpValue) == 0)
4395 WARN ("HeapFree failed with code %li\n", GetLastError ());
4396 if (HeapFree (hHeap, 0, lpValueName) == 0)
4397 WARN ("HeapFree failed with code %li\n", GetLastError ());
4398 r = RegCloseKey (hkSubKey);
4399 if (r != ERROR_SUCCESS)
4400 WARN ("RegCloseKey returned %li\n", r);
4401 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4402 return ret;
4405 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4406 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4407 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4408 pEnumValues += cbValueNameLen;
4410 /* return # of *bytes* (including trailing \0), not # of chars */
4411 ppev[dwIndex].cbValueName = cbValueNameLen;
4413 ppev[dwIndex].dwType = dwType;
4415 memcpy (pEnumValues, lpValue, cbValueLen);
4416 ppev[dwIndex].pData = pEnumValues;
4417 pEnumValues += cbValueLen;
4419 ppev[dwIndex].cbData = cbValueLen;
4421 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4422 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4425 if (HeapFree (hHeap, 0, lpValue) == 0)
4427 ret = GetLastError ();
4428 ERR ("HeapFree failed with code %li\n", ret);
4429 if (HeapFree (hHeap, 0, lpValueName) == 0)
4430 WARN ("HeapFree failed with code %li\n", GetLastError ());
4431 r = RegCloseKey (hkSubKey);
4432 if (r != ERROR_SUCCESS)
4433 WARN ("RegCloseKey returned %li\n", r);
4434 return ret;
4437 if (HeapFree (hHeap, 0, lpValueName) == 0)
4439 ret = GetLastError ();
4440 ERR ("HeapFree failed with code %li\n", ret);
4441 r = RegCloseKey (hkSubKey);
4442 if (r != ERROR_SUCCESS)
4443 WARN ("RegCloseKey returned %li\n", r);
4444 return ret;
4447 ret = RegCloseKey (hkSubKey);
4448 if (ret != ERROR_SUCCESS)
4450 ERR ("RegCloseKey returned %li\n", ret);
4451 return ret;
4454 return ERROR_SUCCESS;
4457 /*******************************************************************************
4458 * EnumPrinterDataExA [WINSPOOL.@]
4460 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4461 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4462 * what Windows 2000 SP1 does.
4465 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4466 LPBYTE pEnumValues, DWORD cbEnumValues,
4467 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4469 INT len;
4470 LPWSTR pKeyNameW;
4471 DWORD ret, dwIndex, dwBufSize;
4472 HANDLE hHeap;
4473 LPSTR pBuffer;
4475 TRACE ("%p %s\n", hPrinter, pKeyName);
4477 if (pKeyName == NULL || *pKeyName == 0)
4478 return ERROR_INVALID_PARAMETER;
4480 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4481 if (len == 0)
4483 ret = GetLastError ();
4484 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4485 return ret;
4488 hHeap = GetProcessHeap ();
4489 if (hHeap == NULL)
4491 ERR ("GetProcessHeap failed\n");
4492 return ERROR_OUTOFMEMORY;
4495 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4496 if (pKeyNameW == NULL)
4498 ERR ("Failed to allocate %li bytes from process heap\n",
4499 (LONG) len * sizeof (WCHAR));
4500 return ERROR_OUTOFMEMORY;
4503 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4505 ret = GetLastError ();
4506 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4507 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4508 WARN ("HeapFree failed with code %li\n", GetLastError ());
4509 return ret;
4512 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4513 pcbEnumValues, pnEnumValues);
4514 if (ret != ERROR_SUCCESS)
4516 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4517 WARN ("HeapFree failed with code %li\n", GetLastError ());
4518 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4519 return ret;
4522 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4524 ret = GetLastError ();
4525 ERR ("HeapFree failed with code %li\n", ret);
4526 return ret;
4529 if (*pnEnumValues == 0) /* empty key */
4530 return ERROR_SUCCESS;
4532 dwBufSize = 0;
4533 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4535 PPRINTER_ENUM_VALUESW ppev =
4536 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4538 if (dwBufSize < ppev->cbValueName)
4539 dwBufSize = ppev->cbValueName;
4541 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4542 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4543 dwBufSize = ppev->cbData;
4546 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4548 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4549 if (pBuffer == NULL)
4551 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4552 return ERROR_OUTOFMEMORY;
4555 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4557 PPRINTER_ENUM_VALUESW ppev =
4558 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4560 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4561 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4562 NULL);
4563 if (len == 0)
4565 ret = GetLastError ();
4566 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4567 if (HeapFree (hHeap, 0, pBuffer) == 0)
4568 WARN ("HeapFree failed with code %li\n", GetLastError ());
4569 return ret;
4572 memcpy (ppev->pValueName, pBuffer, len);
4574 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4576 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4577 ppev->dwType != REG_MULTI_SZ)
4578 continue;
4580 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4581 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4582 if (len == 0)
4584 ret = GetLastError ();
4585 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4586 if (HeapFree (hHeap, 0, pBuffer) == 0)
4587 WARN ("HeapFree failed with code %li\n", GetLastError ());
4588 return ret;
4591 memcpy (ppev->pData, pBuffer, len);
4593 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4594 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4597 if (HeapFree (hHeap, 0, pBuffer) == 0)
4599 ret = GetLastError ();
4600 ERR ("HeapFree failed with code %li\n", ret);
4601 return ret;
4604 return ERROR_SUCCESS;
4607 /******************************************************************************
4608 * AbortPrinter (WINSPOOL.@)
4610 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4612 FIXME("(%p), stub!\n", hPrinter);
4613 return TRUE;
4616 /******************************************************************************
4617 * AddPortA (WINSPOOL.@)
4619 * See AddPortW.
4622 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4624 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4625 return FALSE;
4628 /******************************************************************************
4629 * AddPortW (WINSPOOL.@)
4631 * Add a Port for a specific Monitor
4633 * PARAMS
4634 * pName [I] Servername or NULL (local Computer)
4635 * hWnd [I] Handle to parent Window for the Dialog-Box
4636 * pMonitorName [I] Name of the Monitor that manage the Port
4638 * RETURNS
4639 * Success: TRUE
4640 * Failure: FALSE
4642 * BUGS
4643 * only a Stub
4646 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4648 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4649 return FALSE;
4652 /******************************************************************************
4653 * AddPortExA (WINSPOOL.@)
4655 * See AddPortExW.
4658 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4660 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4661 lpBuffer, debugstr_a(lpMonitorName));
4662 return FALSE;
4665 /******************************************************************************
4666 * AddPortExW (WINSPOOL.@)
4668 * Add a Port for a specific Monitor, without presenting a user interface
4670 * PARAMS
4671 * hMonitor [I] Handle from InitializePrintMonitor2()
4672 * pName [I] Servername or NULL (local Computer)
4673 * Level [I] Structure-Level (1 or 2) for lpBuffer
4674 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
4675 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
4677 * RETURNS
4678 * Success: TRUE
4679 * Failure: FALSE
4681 * BUGS
4682 * only a Stub
4685 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4687 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4688 lpBuffer, debugstr_w(lpMonitorName));
4689 return FALSE;
4692 /******************************************************************************
4693 * AddPrinterConnectionA (WINSPOOL.@)
4695 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4697 FIXME("%s\n", debugstr_a(pName));
4698 return FALSE;
4701 /******************************************************************************
4702 * AddPrinterConnectionW (WINSPOOL.@)
4704 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4706 FIXME("%s\n", debugstr_w(pName));
4707 return FALSE;
4710 /******************************************************************************
4711 * AddPrinterDriverExW (WINSPOOL.@)
4713 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4714 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4716 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4717 Level, pDriverInfo, dwFileCopyFlags);
4718 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4719 return FALSE;
4722 /******************************************************************************
4723 * AddPrinterDriverExA (WINSPOOL.@)
4725 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4726 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4728 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4729 Level, pDriverInfo, dwFileCopyFlags);
4730 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4731 return FALSE;
4734 /******************************************************************************
4735 * ConfigurePortA (WINSPOOL.@)
4737 * See ConfigurePortW.
4740 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4742 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4743 return FALSE;
4746 /******************************************************************************
4747 * ConfigurePortW (WINSPOOL.@)
4749 * Display the Configuration-Dialog for a specific Port
4751 * PARAMS
4752 * pName [I] Servername or NULL (local Computer)
4753 * hWnd [I] Handle to parent Window for the Dialog-Box
4754 * pPortName [I] Name of the Port, that should be configured
4756 * RETURNS
4757 * Success: TRUE
4758 * Failure: FALSE
4760 * BUGS
4761 * only a Stub
4764 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4766 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4767 return FALSE;
4770 /******************************************************************************
4771 * ConnectToPrinterDlg (WINSPOOL.@)
4773 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4775 FIXME("%p %lx\n", hWnd, Flags);
4776 return NULL;
4779 /******************************************************************************
4780 * DeletePrinterConnectionA (WINSPOOL.@)
4782 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4784 FIXME("%s\n", debugstr_a(pName));
4785 return TRUE;
4788 /******************************************************************************
4789 * DeletePrinterConnectionW (WINSPOOL.@)
4791 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4793 FIXME("%s\n", debugstr_w(pName));
4794 return TRUE;
4797 /******************************************************************************
4798 * DeletePrinterDriverExW (WINSPOOL.@)
4800 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4801 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4803 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4804 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4805 return TRUE;
4808 /******************************************************************************
4809 * DeletePrinterDriverExA (WINSPOOL.@)
4811 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4812 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4814 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4815 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4816 return TRUE;
4819 /******************************************************************************
4820 * DeletePrinterDataExW (WINSPOOL.@)
4822 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4823 LPCWSTR pValueName)
4825 FIXME("%p %s %s\n", hPrinter,
4826 debugstr_w(pKeyName), debugstr_w(pValueName));
4827 return ERROR_INVALID_PARAMETER;
4830 /******************************************************************************
4831 * DeletePrinterDataExA (WINSPOOL.@)
4833 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4834 LPCSTR pValueName)
4836 FIXME("%p %s %s\n", hPrinter,
4837 debugstr_a(pKeyName), debugstr_a(pValueName));
4838 return ERROR_INVALID_PARAMETER;
4841 /******************************************************************************
4842 * DeletePrintProcessorA (WINSPOOL.@)
4844 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4846 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4847 debugstr_a(pPrintProcessorName));
4848 return TRUE;
4851 /******************************************************************************
4852 * DeletePrintProcessorW (WINSPOOL.@)
4854 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4856 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4857 debugstr_w(pPrintProcessorName));
4858 return TRUE;
4861 /******************************************************************************
4862 * DeletePrintProvidorA (WINSPOOL.@)
4864 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4866 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4867 debugstr_a(pPrintProviderName));
4868 return TRUE;
4871 /******************************************************************************
4872 * DeletePrintProvidorW (WINSPOOL.@)
4874 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4876 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4877 debugstr_w(pPrintProviderName));
4878 return TRUE;
4881 /******************************************************************************
4882 * EnumFormsA (WINSPOOL.@)
4884 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4885 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4887 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4888 return FALSE;
4891 /******************************************************************************
4892 * EnumFormsW (WINSPOOL.@)
4894 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4895 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4897 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4898 return FALSE;
4901 /*****************************************************************************
4902 * EnumMonitorsA [WINSPOOL.@]
4904 * See EnumMonitorsW.
4907 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4908 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4910 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4911 cbBuf, pcbNeeded, pcReturned);
4912 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4913 return 0;
4916 /*****************************************************************************
4917 * EnumMonitorsW [WINSPOOL.@]
4919 * Enumerate available Monitors
4921 * PARAMS
4922 * pName [I] Servername or NULL (local Computer)
4923 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
4924 * pMonitors [O] PTR to Buffer that receives the Result
4925 * cbBuf [I] Size of Buffer at pMonitors
4926 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
4927 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
4929 * RETURNS
4930 * Success: TRUE
4931 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4933 * BUGS
4934 * only a Stub
4937 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4938 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4940 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4941 cbBuf, pcbNeeded, pcReturned);
4942 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4943 return 0;
4946 /******************************************************************************
4947 * XcvDataW (WINSPOOL.@)
4949 * Notes:
4950 * There doesn't seem to be an A version...
4952 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4953 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4954 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4956 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4957 pInputData, cbInputData, pOutputData,
4958 cbOutputData, pcbOutputNeeded, pdwStatus);
4959 return FALSE;
4962 /*****************************************************************************
4963 * EnumPrinterDataA [WINSPOOL.@]
4966 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4967 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4968 DWORD cbData, LPDWORD pcbData )
4970 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4971 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4972 return ERROR_NO_MORE_ITEMS;
4975 /*****************************************************************************
4976 * EnumPrinterDataW [WINSPOOL.@]
4979 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4980 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4981 DWORD cbData, LPDWORD pcbData )
4983 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4984 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4985 return ERROR_NO_MORE_ITEMS;
4988 /*****************************************************************************
4989 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4992 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4993 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4994 LPDWORD pcbNeeded, LPDWORD pcReturned)
4996 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4997 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4998 pcbNeeded, pcReturned);
4999 return FALSE;
5002 /*****************************************************************************
5003 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5006 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5007 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5008 LPDWORD pcbNeeded, LPDWORD pcReturned)
5010 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5011 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5012 pcbNeeded, pcReturned);
5013 return FALSE;
5016 /*****************************************************************************
5017 * EnumPrintProcessorsA [WINSPOOL.@]
5020 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5021 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5023 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5024 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5025 return FALSE;
5028 /*****************************************************************************
5029 * EnumPrintProcessorsW [WINSPOOL.@]
5032 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5033 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5035 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5036 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5037 cbBuf, pcbNeeded, pcbReturned);
5038 return FALSE;
5041 /*****************************************************************************
5042 * ExtDeviceMode [WINSPOOL.@]
5045 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5046 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5047 DWORD fMode)
5049 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5050 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5051 debugstr_a(pProfile), fMode);
5052 return -1;
5055 /*****************************************************************************
5056 * FindClosePrinterChangeNotification [WINSPOOL.@]
5059 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5061 FIXME("Stub: %p\n", hChange);
5062 return TRUE;
5065 /*****************************************************************************
5066 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5069 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5070 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5072 FIXME("Stub: %p %lx %lx %p\n",
5073 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5074 return INVALID_HANDLE_VALUE;
5077 /*****************************************************************************
5078 * FindNextPrinterChangeNotification [WINSPOOL.@]
5081 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5082 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5084 FIXME("Stub: %p %p %p %p\n",
5085 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5086 return FALSE;
5089 /*****************************************************************************
5090 * FreePrinterNotifyInfo [WINSPOOL.@]
5093 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5095 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5096 return TRUE;
5099 /*****************************************************************************
5100 * string_to_buf
5102 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5103 * ansi depending on the unicode parameter.
5105 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5107 if(!str)
5109 *size = 0;
5110 return TRUE;
5113 if(unicode)
5115 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5116 if(*size <= cb)
5118 memcpy(ptr, str, *size);
5119 return TRUE;
5121 return FALSE;
5123 else
5125 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5126 if(*size <= cb)
5128 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5129 return TRUE;
5131 return FALSE;
5135 /*****************************************************************************
5136 * get_job_info_1
5138 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5139 LPDWORD pcbNeeded, BOOL unicode)
5141 DWORD size, left = cbBuf;
5142 BOOL space = (cbBuf > 0);
5143 LPBYTE ptr = buf;
5145 *pcbNeeded = 0;
5147 if(space)
5149 ji1->JobId = job->job_id;
5152 string_to_buf(job->document_title, ptr, left, &size, unicode);
5153 if(space && size <= left)
5155 ji1->pDocument = (LPWSTR)ptr;
5156 ptr += size;
5157 left -= size;
5159 else
5160 space = FALSE;
5161 *pcbNeeded += size;
5163 return space;
5166 /*****************************************************************************
5167 * get_job_info_2
5169 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5170 LPDWORD pcbNeeded, BOOL unicode)
5172 DWORD size, left = cbBuf;
5173 BOOL space = (cbBuf > 0);
5174 LPBYTE ptr = buf;
5176 *pcbNeeded = 0;
5178 if(space)
5180 ji2->JobId = job->job_id;
5183 string_to_buf(job->document_title, ptr, left, &size, unicode);
5184 if(space && size <= left)
5186 ji2->pDocument = (LPWSTR)ptr;
5187 ptr += size;
5188 left -= size;
5190 else
5191 space = FALSE;
5192 *pcbNeeded += size;
5194 return space;
5197 /*****************************************************************************
5198 * get_job_info
5200 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5201 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5203 BOOL ret = FALSE;
5204 DWORD needed = 0, size;
5205 job_t *job;
5206 LPBYTE ptr = pJob;
5208 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5210 EnterCriticalSection(&printer_handles_cs);
5211 job = get_job(hPrinter, JobId);
5212 if(!job)
5213 goto end;
5215 switch(Level)
5217 case 1:
5218 size = sizeof(JOB_INFO_1W);
5219 if(cbBuf >= size)
5221 cbBuf -= size;
5222 ptr += size;
5223 memset(pJob, 0, size);
5225 else
5226 cbBuf = 0;
5227 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5228 needed += size;
5229 break;
5231 case 2:
5232 size = sizeof(JOB_INFO_2W);
5233 if(cbBuf >= size)
5235 cbBuf -= size;
5236 ptr += size;
5237 memset(pJob, 0, size);
5239 else
5240 cbBuf = 0;
5241 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5242 needed += size;
5243 break;
5245 case 3:
5246 size = sizeof(JOB_INFO_3);
5247 if(cbBuf >= size)
5249 cbBuf -= size;
5250 memset(pJob, 0, size);
5251 ret = TRUE;
5253 else
5254 cbBuf = 0;
5255 needed = size;
5256 break;
5258 default:
5259 SetLastError(ERROR_INVALID_LEVEL);
5260 goto end;
5262 if(pcbNeeded)
5263 *pcbNeeded = needed;
5264 end:
5265 LeaveCriticalSection(&printer_handles_cs);
5266 return ret;
5269 /*****************************************************************************
5270 * GetJobA [WINSPOOL.@]
5273 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5274 DWORD cbBuf, LPDWORD pcbNeeded)
5276 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5279 /*****************************************************************************
5280 * GetJobW [WINSPOOL.@]
5283 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5284 DWORD cbBuf, LPDWORD pcbNeeded)
5286 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5289 /*****************************************************************************
5290 * schedule_lpr
5292 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5294 char *unixname, *queue, *cmd;
5295 char fmt[] = "lpr -P%s %s";
5296 DWORD len;
5298 if(!(unixname = wine_get_unix_file_name(filename)))
5299 return FALSE;
5301 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5302 queue = HeapAlloc(GetProcessHeap(), 0, len);
5303 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5305 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5306 sprintf(cmd, fmt, queue, unixname);
5308 TRACE("printing with: %s\n", cmd);
5309 system(cmd);
5311 HeapFree(GetProcessHeap(), 0, cmd);
5312 HeapFree(GetProcessHeap(), 0, queue);
5313 HeapFree(GetProcessHeap(), 0, unixname);
5314 return TRUE;
5317 /*****************************************************************************
5318 * schedule_cups
5320 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5322 #if HAVE_CUPS_CUPS_H
5323 if(pcupsPrintFile)
5325 char *unixname, *queue, *doc_titleA;
5326 DWORD len;
5327 BOOL ret;
5329 if(!(unixname = wine_get_unix_file_name(filename)))
5330 return FALSE;
5332 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5333 queue = HeapAlloc(GetProcessHeap(), 0, len);
5334 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5336 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5337 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5338 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5340 TRACE("printing via cups\n");
5341 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5342 HeapFree(GetProcessHeap(), 0, doc_titleA);
5343 HeapFree(GetProcessHeap(), 0, queue);
5344 HeapFree(GetProcessHeap(), 0, unixname);
5345 return ret;
5347 else
5348 #endif
5350 return schedule_lpr(printer_name, filename);
5354 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5356 LPWSTR filename;
5358 switch(msg)
5360 case WM_INITDIALOG:
5361 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5362 return TRUE;
5364 case WM_COMMAND:
5365 if(HIWORD(wparam) == BN_CLICKED)
5367 if(LOWORD(wparam) == IDOK)
5369 HANDLE hf;
5370 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5371 LPWSTR *output;
5373 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5374 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5376 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5378 WCHAR caption[200], message[200];
5379 int mb_ret;
5381 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5382 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5383 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5384 if(mb_ret == IDCANCEL)
5386 HeapFree(GetProcessHeap(), 0, filename);
5387 return TRUE;
5390 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5391 if(hf == INVALID_HANDLE_VALUE)
5393 WCHAR caption[200], message[200];
5395 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5396 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5397 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5398 HeapFree(GetProcessHeap(), 0, filename);
5399 return TRUE;
5401 CloseHandle(hf);
5402 DeleteFileW(filename);
5403 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5404 *output = filename;
5405 EndDialog(hwnd, IDOK);
5406 return TRUE;
5408 if(LOWORD(wparam) == IDCANCEL)
5410 EndDialog(hwnd, IDCANCEL);
5411 return TRUE;
5414 return FALSE;
5416 return FALSE;
5419 /*****************************************************************************
5420 * get_filename
5422 static BOOL get_filename(LPWSTR *filename)
5424 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
5425 file_dlg_proc, (LPARAM)filename) == IDOK;
5428 /*****************************************************************************
5429 * schedule_file
5431 static BOOL schedule_file(LPCWSTR filename)
5433 LPWSTR output = NULL;
5435 if(get_filename(&output))
5437 TRACE("copy to %s\n", debugstr_w(output));
5438 CopyFileW(filename, output, FALSE);
5439 HeapFree(GetProcessHeap(), 0, output);
5440 return TRUE;
5442 return FALSE;
5445 /*****************************************************************************
5446 * schedule_pipe
5448 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
5450 #ifdef HAVE_FORK
5451 char *unixname, *cmdA;
5452 DWORD len;
5453 int fds[2] = {-1, -1}, file_fd = -1, no_read;
5454 BOOL ret = FALSE;
5455 char buf[1024];
5457 if(!(unixname = wine_get_unix_file_name(filename)))
5458 return FALSE;
5460 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
5461 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
5462 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
5464 TRACE("printing with: %s\n", cmdA);
5466 if((file_fd = open(unixname, O_RDONLY)) == -1)
5467 goto end;
5469 if (pipe(fds))
5471 ERR("pipe() failed!\n");
5472 goto end;
5475 if (fork() == 0)
5477 close(0);
5478 dup2(fds[0], 0);
5479 close(fds[1]);
5481 /* reset signals that we previously set to SIG_IGN */
5482 signal(SIGPIPE, SIG_DFL);
5483 signal(SIGCHLD, SIG_DFL);
5485 system(cmdA);
5486 exit(0);
5489 while((no_read = read(file_fd, buf, sizeof(buf))))
5490 write(fds[1], buf, no_read);
5492 ret = TRUE;
5494 end:
5495 if(file_fd != -1) close(file_fd);
5496 if(fds[0] != -1) close(fds[0]);
5497 if(fds[1] != -1) close(fds[1]);
5499 HeapFree(GetProcessHeap(), 0, cmdA);
5500 HeapFree(GetProcessHeap(), 0, unixname);
5501 return ret;
5502 #else
5503 return FALSE;
5504 #endif
5507 /*****************************************************************************
5508 * schedule_unixfile
5510 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
5512 int in_fd, out_fd, no_read;
5513 char buf[1024];
5514 BOOL ret = FALSE;
5515 char *unixname, *outputA;
5516 DWORD len;
5518 if(!(unixname = wine_get_unix_file_name(filename)))
5519 return FALSE;
5521 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
5522 outputA = HeapAlloc(GetProcessHeap(), 0, len);
5523 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
5525 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5526 in_fd = open(unixname, O_RDONLY);
5527 if(out_fd == -1 || in_fd == -1)
5528 goto end;
5530 while((no_read = read(in_fd, buf, sizeof(buf))))
5531 write(out_fd, buf, no_read);
5533 ret = TRUE;
5534 end:
5535 if(in_fd != -1) close(in_fd);
5536 if(out_fd != -1) close(out_fd);
5537 HeapFree(GetProcessHeap(), 0, outputA);
5538 HeapFree(GetProcessHeap(), 0, unixname);
5539 return ret;
5542 /*****************************************************************************
5543 * ScheduleJob [WINSPOOL.@]
5546 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
5548 opened_printer_t *printer;
5549 BOOL ret = FALSE;
5550 struct list *cursor, *cursor2;
5552 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
5553 EnterCriticalSection(&printer_handles_cs);
5554 printer = get_opened_printer(hPrinter);
5555 if(!printer)
5556 goto end;
5558 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
5560 job_t *job = LIST_ENTRY(cursor, job_t, entry);
5561 HANDLE hf;
5563 if(job->job_id != dwJobID) continue;
5565 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
5566 if(hf != INVALID_HANDLE_VALUE)
5568 PRINTER_INFO_5W *pi5;
5569 DWORD needed;
5570 HKEY hkey;
5571 WCHAR output[1024];
5572 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5573 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5575 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
5576 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
5577 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
5578 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
5579 debugstr_w(pi5->pPortName));
5581 output[0] = 0;
5583 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5584 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
5586 DWORD type, count = sizeof(output);
5587 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
5588 RegCloseKey(hkey);
5590 if(output[0] == '|')
5592 schedule_pipe(output + 1, job->filename);
5594 else if(output[0])
5596 schedule_unixfile(output, job->filename);
5598 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
5600 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
5602 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
5604 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
5606 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
5608 schedule_file(job->filename);
5610 else
5612 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
5614 HeapFree(GetProcessHeap(), 0, pi5);
5615 CloseHandle(hf);
5616 DeleteFileW(job->filename);
5618 list_remove(cursor);
5619 HeapFree(GetProcessHeap(), 0, job->document_title);
5620 HeapFree(GetProcessHeap(), 0, job->filename);
5621 HeapFree(GetProcessHeap(), 0, job);
5622 ret = TRUE;
5623 break;
5625 end:
5626 LeaveCriticalSection(&printer_handles_cs);
5627 return ret;
5630 /*****************************************************************************
5631 * StartDocDlgA [WINSPOOL.@]
5633 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
5635 UNICODE_STRING usBuffer;
5636 DOCINFOW docW;
5637 LPWSTR retW;
5638 LPSTR ret = NULL;
5640 docW.cbSize = sizeof(docW);
5641 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
5642 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
5643 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
5644 docW.fwType = doc->fwType;
5646 retW = StartDocDlgW(hPrinter, &docW);
5648 if(retW)
5650 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
5651 ret = HeapAlloc(GetProcessHeap(), 0, len);
5652 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
5653 HeapFree(GetProcessHeap(), 0, retW);
5656 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
5657 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
5658 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
5660 return ret;
5663 /*****************************************************************************
5664 * StartDocDlgW [WINSPOOL.@]
5666 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5667 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5668 * port is "FILE:". Also returns the full path if passed a relative path.
5670 * The caller should free the returned string from the process heap.
5672 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
5674 LPWSTR ret = NULL;
5675 DWORD len, attr;
5677 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
5679 PRINTER_INFO_5W *pi5;
5680 GetPrinterW(hPrinter, 5, NULL, 0, &len);
5681 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
5682 return NULL;
5683 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
5684 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
5685 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
5687 HeapFree(GetProcessHeap(), 0, pi5);
5688 return NULL;
5690 HeapFree(GetProcessHeap(), 0, pi5);
5693 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
5695 LPWSTR name;
5696 get_filename(&name);
5697 if(name)
5699 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
5701 HeapFree(GetProcessHeap(), 0, name);
5702 return NULL;
5704 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5705 GetFullPathNameW(name, len, ret, NULL);
5706 HeapFree(GetProcessHeap(), 0, name);
5708 return ret;
5711 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
5712 return NULL;
5714 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5715 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
5717 attr = GetFileAttributesW(ret);
5718 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
5720 HeapFree(GetProcessHeap(), 0, ret);
5721 ret = NULL;
5723 return ret;