Fix gcc 4.0 warnings.
[wine.git] / dlls / winspool / info.c
blobd5af30ae46c4717fd9523571c5ab4ec6ac238a56
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, { 0, (DWORD)(__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 } queue_t;
86 typedef struct {
87 LPWSTR name;
88 queue_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 handle = nb_printer_handles, i;
616 queue_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 int idx = (int)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.@]
1043 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1044 LPPRINTER_DEFAULTSA pDefault)
1046 UNICODE_STRING lpPrinterNameW;
1047 UNICODE_STRING usBuffer;
1048 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1049 PWSTR pwstrPrinterNameW;
1050 BOOL ret;
1052 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1054 if(pDefault) {
1055 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1056 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1057 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1058 pDefaultW = &DefaultW;
1060 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1061 if(pDefault) {
1062 RtlFreeUnicodeString(&usBuffer);
1063 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1065 RtlFreeUnicodeString(&lpPrinterNameW);
1066 return ret;
1069 /******************************************************************
1070 * OpenPrinterW [WINSPOOL.@]
1073 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
1074 LPPRINTER_DEFAULTSW pDefault)
1076 HKEY hkeyPrinters, hkeyPrinter;
1078 if (!lpPrinterName) {
1079 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1080 SetLastError(ERROR_INVALID_PARAMETER);
1081 return FALSE;
1084 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1085 pDefault);
1087 /* Check Printer exists */
1088 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1089 ERROR_SUCCESS) {
1090 ERR("Can't create Printers key\n");
1091 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1092 return FALSE;
1095 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1096 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1097 != ERROR_SUCCESS) {
1098 TRACE("Can't find printer %s in registry\n",
1099 debugstr_w(lpPrinterName));
1100 RegCloseKey(hkeyPrinters);
1101 SetLastError(ERROR_INVALID_PRINTER_NAME);
1102 return FALSE;
1104 RegCloseKey(hkeyPrinter);
1105 RegCloseKey(hkeyPrinters);
1107 if(!phPrinter) /* This seems to be what win95 does anyway */
1108 return TRUE;
1110 /* Get the unique handle of the printer*/
1111 *phPrinter = get_opened_printer_entry( lpPrinterName );
1113 if (pDefault != NULL)
1114 FIXME("Not handling pDefault\n");
1116 return TRUE;
1119 /******************************************************************
1120 * AddMonitorA [WINSPOOL.@]
1123 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1125 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
1126 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1127 return FALSE;
1130 /******************************************************************************
1131 * AddMonitorW [WINSPOOL.@]
1133 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1135 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1136 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1137 return FALSE;
1140 /******************************************************************
1141 * DeletePrinterDriverA [WINSPOOL.@]
1144 BOOL WINAPI
1145 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1147 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1148 debugstr_a(pDriverName));
1149 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1150 return FALSE;
1153 /******************************************************************
1154 * DeletePrinterDriverW [WINSPOOL.@]
1157 BOOL WINAPI
1158 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1160 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1161 debugstr_w(pDriverName));
1162 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1163 return FALSE;
1166 /******************************************************************
1167 * DeleteMonitorA [WINSPOOL.@]
1170 BOOL WINAPI
1171 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1173 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1174 debugstr_a(pMonitorName));
1175 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1176 return FALSE;
1179 /******************************************************************
1180 * DeleteMonitorW [WINSPOOL.@]
1183 BOOL WINAPI
1184 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1186 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1187 debugstr_w(pMonitorName));
1188 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1189 return FALSE;
1192 /******************************************************************
1193 * DeletePortA [WINSPOOL.@]
1196 BOOL WINAPI
1197 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1199 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1200 debugstr_a(pPortName));
1201 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1202 return FALSE;
1205 /******************************************************************
1206 * DeletePortW [WINSPOOL.@]
1209 BOOL WINAPI
1210 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1212 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1213 debugstr_w(pPortName));
1214 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1215 return FALSE;
1218 /******************************************************************************
1219 * SetPrinterW [WINSPOOL.@]
1221 BOOL WINAPI
1222 SetPrinterW(
1223 HANDLE hPrinter,
1224 DWORD Level,
1225 LPBYTE pPrinter,
1226 DWORD Command) {
1228 FIXME("():stub\n");
1229 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1230 return FALSE;
1233 /******************************************************************************
1234 * WritePrinter [WINSPOOL.@]
1236 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1238 opened_printer_t *printer;
1239 BOOL ret = FALSE;
1241 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1243 EnterCriticalSection(&printer_handles_cs);
1244 printer = get_opened_printer(hPrinter);
1245 if(!printer)
1247 SetLastError(ERROR_INVALID_HANDLE);
1248 goto end;
1251 if(!printer->doc)
1253 SetLastError(ERROR_SPL_NO_STARTDOC);
1254 goto end;
1257 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1258 end:
1259 LeaveCriticalSection(&printer_handles_cs);
1260 return ret;
1263 /*****************************************************************************
1264 * AddFormA [WINSPOOL.@]
1266 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1268 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1269 return 1;
1272 /*****************************************************************************
1273 * AddFormW [WINSPOOL.@]
1275 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1277 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1278 return 1;
1281 /*****************************************************************************
1282 * AddJobA [WINSPOOL.@]
1284 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1286 BOOL ret;
1287 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1288 DWORD needed;
1290 if(Level != 1) {
1291 SetLastError(ERROR_INVALID_LEVEL);
1292 return FALSE;
1295 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1297 if(ret) {
1298 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1299 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1300 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1301 if(*pcbNeeded > cbBuf) {
1302 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1303 ret = FALSE;
1304 } else {
1305 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1306 addjobA->JobId = addjobW->JobId;
1307 addjobA->Path = (char *)(addjobA + 1);
1308 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1311 return ret;
1314 /*****************************************************************************
1315 * AddJobW [WINSPOOL.@]
1317 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1319 opened_printer_t *printer;
1320 job_t *job;
1321 BOOL ret = FALSE;
1322 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1323 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1324 WCHAR path[MAX_PATH], filename[MAX_PATH];
1325 DWORD len;
1326 ADDJOB_INFO_1W *addjob;
1328 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1330 EnterCriticalSection(&printer_handles_cs);
1332 printer = get_opened_printer(hPrinter);
1334 if(!printer) {
1335 SetLastError(ERROR_INVALID_HANDLE);
1336 goto end;
1339 if(Level != 1) {
1340 SetLastError(ERROR_INVALID_LEVEL);
1341 goto end;
1344 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1345 if(!job)
1346 goto end;
1348 job->job_id = InterlockedIncrement(&next_job_id);
1350 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1351 if(path[len - 1] != '\\')
1352 path[len++] = '\\';
1353 memcpy(path + len, spool_path, sizeof(spool_path));
1354 sprintfW(filename, fmtW, path, job->job_id);
1356 len = strlenW(filename);
1357 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1358 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1359 job->document_title = strdupW(default_doc_title);
1360 list_add_tail(&printer->queue->jobs, &job->entry);
1362 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1363 if(*pcbNeeded <= cbBuf) {
1364 addjob = (ADDJOB_INFO_1W*)pData;
1365 addjob->JobId = job->job_id;
1366 addjob->Path = (WCHAR *)(addjob + 1);
1367 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1368 ret = TRUE;
1369 } else
1370 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1372 end:
1373 LeaveCriticalSection(&printer_handles_cs);
1374 return ret;
1377 /*****************************************************************************
1378 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1380 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1381 DWORD level, LPBYTE Info,
1382 DWORD cbBuf, LPDWORD needed)
1384 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1385 level, Info, cbBuf);
1386 return 0;
1389 /*****************************************************************************
1390 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1392 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1393 DWORD level, LPBYTE Info,
1394 DWORD cbBuf, LPDWORD needed)
1396 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1397 level, Info, cbBuf);
1398 return 0;
1401 /*****************************************************************************
1402 * WINSPOOL_OpenDriverReg [internal]
1404 * opens the registry for the printer drivers depending on the given input
1405 * variable pEnvironment
1407 * RETURNS:
1408 * the opened hkey on success
1409 * NULL on error
1411 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1413 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1414 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1415 HKEY retval;
1416 LPWSTR lpKey, buffer = NULL;
1417 LPCWSTR pEnvW;
1419 TRACE("%s\n",
1420 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1422 if(pEnvironment) {
1423 if (unicode) {
1424 pEnvW = pEnvironment;
1425 } else {
1426 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1427 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1428 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1429 pEnvW = buffer;
1431 } else {
1432 OSVERSIONINFOW ver;
1433 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1435 if(!GetVersionExW( &ver))
1436 return 0;
1438 switch (ver.dwPlatformId) {
1439 case VER_PLATFORM_WIN32s:
1440 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1441 return 0;
1442 case VER_PLATFORM_WIN32_NT:
1443 pEnvW = WinNTW;
1444 break;
1445 default:
1446 pEnvW = Win40W;
1447 break;
1449 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1452 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1453 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1454 wsprintfW( lpKey, DriversW, pEnvW);
1456 TRACE("%s\n", debugstr_w(lpKey));
1458 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1459 retval = 0;
1461 HeapFree( GetProcessHeap(), 0, buffer);
1462 HeapFree( GetProcessHeap(), 0, lpKey);
1464 return retval;
1467 /*****************************************************************************
1468 * AddPrinterW [WINSPOOL.@]
1470 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1472 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1473 LPDEVMODEA dmA;
1474 LPDEVMODEW dmW;
1475 HANDLE retval;
1476 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1477 LONG size;
1479 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1481 if(pName != NULL) {
1482 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1483 SetLastError(ERROR_INVALID_PARAMETER);
1484 return 0;
1486 if(Level != 2) {
1487 ERR("Level = %ld, unsupported!\n", Level);
1488 SetLastError(ERROR_INVALID_LEVEL);
1489 return 0;
1491 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1492 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1493 debugstr_w(pi->pPrinterName)
1495 SetLastError(ERROR_INVALID_LEVEL);
1496 return 0;
1498 if(!pPrinter) {
1499 SetLastError(ERROR_INVALID_PARAMETER);
1500 return 0;
1502 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1503 ERROR_SUCCESS) {
1504 ERR("Can't create Printers key\n");
1505 return 0;
1507 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1508 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1509 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1510 RegCloseKey(hkeyPrinter);
1511 RegCloseKey(hkeyPrinters);
1512 return 0;
1514 RegCloseKey(hkeyPrinter);
1516 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1517 if(!hkeyDrivers) {
1518 ERR("Can't create Drivers key\n");
1519 RegCloseKey(hkeyPrinters);
1520 return 0;
1522 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1523 ERROR_SUCCESS) {
1524 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1525 RegCloseKey(hkeyPrinters);
1526 RegCloseKey(hkeyDrivers);
1527 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1528 return 0;
1530 RegCloseKey(hkeyDriver);
1531 RegCloseKey(hkeyDrivers);
1533 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1534 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1535 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1536 RegCloseKey(hkeyPrinters);
1537 return 0;
1540 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1541 ERROR_SUCCESS) {
1542 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1543 SetLastError(ERROR_INVALID_PRINTER_NAME);
1544 RegCloseKey(hkeyPrinters);
1545 return 0;
1547 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1548 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1549 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1551 /* See if we can load the driver. We may need the devmode structure anyway
1553 * FIXME:
1554 * Note that DocumentPropertiesW will briefly try to open the printer we
1555 * just create to find a DEVMODEA struct (it will use the WINEPS default
1556 * one in case it is not there, so we are ok).
1558 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1560 if(size < 0) {
1561 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1562 size = sizeof(DEVMODEW);
1564 if(pi->pDevMode)
1565 dmW = pi->pDevMode;
1566 else
1568 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1569 ZeroMemory(dmW,size);
1570 dmW->dmSize = size;
1571 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1573 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1574 HeapFree(GetProcessHeap(),0,dmW);
1575 dmW=NULL;
1577 else
1579 /* set devmode to printer name */
1580 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1584 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1585 and we support these drivers. NT writes DEVMODEW so somehow
1586 we'll need to distinguish between these when we support NT
1587 drivers */
1588 if (dmW)
1590 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1591 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1592 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1593 HeapFree(GetProcessHeap(), 0, dmA);
1594 if(!pi->pDevMode)
1595 HeapFree(GetProcessHeap(), 0, dmW);
1597 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1598 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1599 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1600 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1602 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1603 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1604 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1605 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1606 (LPBYTE)&pi->Priority, sizeof(DWORD));
1607 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1608 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1609 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1610 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1611 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1612 (LPBYTE)&pi->Status, sizeof(DWORD));
1613 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1614 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1616 RegCloseKey(hkeyPrinter);
1617 RegCloseKey(hkeyPrinters);
1618 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1619 ERR("OpenPrinter failing\n");
1620 return 0;
1622 return retval;
1625 /*****************************************************************************
1626 * AddPrinterA [WINSPOOL.@]
1628 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1630 UNICODE_STRING pNameW;
1631 PWSTR pwstrNameW;
1632 PRINTER_INFO_2W *piW;
1633 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1634 HANDLE ret;
1636 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1637 if(Level != 2) {
1638 ERR("Level = %ld, unsupported!\n", Level);
1639 SetLastError(ERROR_INVALID_LEVEL);
1640 return 0;
1642 pwstrNameW = asciitounicode(&pNameW,pName);
1643 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1645 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1647 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1648 RtlFreeUnicodeString(&pNameW);
1649 return ret;
1653 /*****************************************************************************
1654 * ClosePrinter [WINSPOOL.@]
1656 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1658 int i = (int)hPrinter;
1659 opened_printer_t *printer = NULL;
1660 BOOL ret = FALSE;
1662 TRACE("Handle %p\n", hPrinter);
1664 EnterCriticalSection(&printer_handles_cs);
1666 if ((i > 0) && (i <= nb_printer_handles))
1667 printer = printer_handles[i - 1];
1669 if(printer)
1671 struct list *cursor, *cursor2;
1673 if(printer->doc)
1674 EndDocPrinter(hPrinter);
1676 if(InterlockedDecrement(&printer->queue->ref) == 0)
1678 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
1680 job_t *job = LIST_ENTRY(cursor, job_t, entry);
1681 ScheduleJob(hPrinter, job->job_id);
1683 HeapFree(GetProcessHeap(), 0, printer->queue);
1685 HeapFree(GetProcessHeap(), 0, printer->name);
1686 HeapFree(GetProcessHeap(), 0, printer);
1687 printer_handles[i - 1] = NULL;
1688 ret = TRUE;
1690 LeaveCriticalSection(&printer_handles_cs);
1691 return ret;
1694 /*****************************************************************************
1695 * DeleteFormA [WINSPOOL.@]
1697 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1699 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1700 return 1;
1703 /*****************************************************************************
1704 * DeleteFormW [WINSPOOL.@]
1706 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1708 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1709 return 1;
1712 /*****************************************************************************
1713 * WINSPOOL_SHRegDeleteKey
1715 * Recursively delete subkeys.
1716 * Cut & paste from shlwapi.
1719 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1721 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1722 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1723 HKEY hSubKey = 0;
1725 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1726 if(!dwRet)
1728 /* Find how many subkeys there are */
1729 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1730 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1731 if(!dwRet)
1733 dwMaxSubkeyLen++;
1734 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1735 /* Name too big: alloc a buffer for it */
1736 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1738 if(!lpszName)
1739 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1740 else
1742 /* Recursively delete all the subkeys */
1743 for(i = 0; i < dwKeyCount && !dwRet; i++)
1745 dwSize = dwMaxSubkeyLen;
1746 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1747 if(!dwRet)
1748 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1751 if (lpszName != szNameBuf)
1752 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1756 RegCloseKey(hSubKey);
1757 if(!dwRet)
1758 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1760 return dwRet;
1763 /*****************************************************************************
1764 * DeletePrinter [WINSPOOL.@]
1766 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1768 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1769 HKEY hkeyPrinters, hkey;
1771 if(!lpNameW) {
1772 SetLastError(ERROR_INVALID_HANDLE);
1773 return FALSE;
1775 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1776 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1777 RegCloseKey(hkeyPrinters);
1779 WriteProfileStringW(devicesW, lpNameW, NULL);
1780 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1781 RegDeleteValueW(hkey, lpNameW);
1782 RegCloseKey(hkey);
1784 return TRUE;
1787 /*****************************************************************************
1788 * SetPrinterA [WINSPOOL.@]
1790 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1791 DWORD Command)
1793 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1794 return FALSE;
1797 /*****************************************************************************
1798 * SetJobA [WINSPOOL.@]
1800 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1801 LPBYTE pJob, DWORD Command)
1803 BOOL ret;
1804 LPBYTE JobW;
1805 UNICODE_STRING usBuffer;
1807 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
1809 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1810 are all ignored by SetJob, so we don't bother copying them */
1811 switch(Level)
1813 case 0:
1814 JobW = NULL;
1815 break;
1816 case 1:
1818 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
1819 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
1821 JobW = (LPBYTE)info1W;
1822 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
1823 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
1824 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
1825 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
1826 info1W->Status = info1A->Status;
1827 info1W->Priority = info1A->Priority;
1828 info1W->Position = info1A->Position;
1829 info1W->PagesPrinted = info1A->PagesPrinted;
1830 break;
1832 case 2:
1834 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
1835 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
1837 JobW = (LPBYTE)info2W;
1838 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
1839 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
1840 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
1841 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
1842 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
1843 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
1844 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
1845 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
1846 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
1847 info2W->Status = info2A->Status;
1848 info2W->Priority = info2A->Priority;
1849 info2W->Position = info2A->Position;
1850 info2W->StartTime = info2A->StartTime;
1851 info2W->UntilTime = info2A->UntilTime;
1852 info2W->PagesPrinted = info2A->PagesPrinted;
1853 break;
1855 case 3:
1856 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
1857 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
1858 break;
1859 default:
1860 SetLastError(ERROR_INVALID_LEVEL);
1861 return FALSE;
1864 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
1866 switch(Level)
1868 case 1:
1870 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
1871 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
1872 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
1873 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
1874 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
1875 break;
1877 case 2:
1879 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
1880 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
1881 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
1882 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
1883 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
1884 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
1885 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
1886 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
1887 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
1888 break;
1891 HeapFree(GetProcessHeap(), 0, JobW);
1893 return ret;
1896 /*****************************************************************************
1897 * SetJobW [WINSPOOL.@]
1899 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1900 LPBYTE pJob, DWORD Command)
1902 BOOL ret = FALSE;
1903 job_t *job;
1905 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
1906 FIXME("Ignoring everything other than document title\n");
1908 EnterCriticalSection(&printer_handles_cs);
1909 job = get_job(hPrinter, JobId);
1910 if(!job)
1911 goto end;
1913 switch(Level)
1915 case 0:
1916 break;
1917 case 1:
1919 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
1920 HeapFree(GetProcessHeap(), 0, job->document_title);
1921 job->document_title = strdupW(info1->pDocument);
1922 break;
1924 case 2:
1926 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
1927 HeapFree(GetProcessHeap(), 0, job->document_title);
1928 job->document_title = strdupW(info2->pDocument);
1929 break;
1931 case 3:
1932 break;
1933 default:
1934 SetLastError(ERROR_INVALID_LEVEL);
1935 goto end;
1937 ret = TRUE;
1938 end:
1939 LeaveCriticalSection(&printer_handles_cs);
1940 return ret;
1943 /*****************************************************************************
1944 * EndDocPrinter [WINSPOOL.@]
1946 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1948 opened_printer_t *printer;
1949 BOOL ret = FALSE;
1950 TRACE("(%p)\n", hPrinter);
1952 EnterCriticalSection(&printer_handles_cs);
1954 printer = get_opened_printer(hPrinter);
1955 if(!printer)
1957 SetLastError(ERROR_INVALID_HANDLE);
1958 goto end;
1961 if(!printer->doc)
1963 SetLastError(ERROR_SPL_NO_STARTDOC);
1964 goto end;
1967 CloseHandle(printer->doc->hf);
1968 ScheduleJob(hPrinter, printer->doc->job_id);
1969 HeapFree(GetProcessHeap(), 0, printer->doc);
1970 printer->doc = NULL;
1971 ret = TRUE;
1972 end:
1973 LeaveCriticalSection(&printer_handles_cs);
1974 return ret;
1977 /*****************************************************************************
1978 * EndPagePrinter [WINSPOOL.@]
1980 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1982 FIXME("(%p): stub\n", hPrinter);
1983 return TRUE;
1986 /*****************************************************************************
1987 * StartDocPrinterA [WINSPOOL.@]
1989 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1991 UNICODE_STRING usBuffer;
1992 DOC_INFO_2W doc2W;
1993 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
1994 DWORD ret;
1996 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
1997 or one (DOC_INFO_3) extra DWORDs */
1999 switch(Level) {
2000 case 2:
2001 doc2W.JobId = doc2->JobId;
2002 /* fall through */
2003 case 3:
2004 doc2W.dwMode = doc2->dwMode;
2005 /* fall through */
2006 case 1:
2007 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2008 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2009 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2010 break;
2012 default:
2013 SetLastError(ERROR_INVALID_LEVEL);
2014 return FALSE;
2017 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2019 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2020 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2021 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2023 return ret;
2026 /*****************************************************************************
2027 * StartDocPrinterW [WINSPOOL.@]
2029 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2031 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2032 opened_printer_t *printer;
2033 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2034 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2035 JOB_INFO_1W job_info;
2036 DWORD needed, ret = 0;
2037 HANDLE hf;
2038 WCHAR *filename;
2040 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2041 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2042 debugstr_w(doc->pDatatype));
2044 if(Level < 1 || Level > 3)
2046 SetLastError(ERROR_INVALID_LEVEL);
2047 return 0;
2050 EnterCriticalSection(&printer_handles_cs);
2051 printer = get_opened_printer(hPrinter);
2052 if(!printer)
2054 SetLastError(ERROR_INVALID_HANDLE);
2055 goto end;
2058 if(printer->doc)
2060 SetLastError(ERROR_INVALID_PRINTER_STATE);
2061 goto end;
2064 /* Even if we're printing to a file we still add a print job, we'll
2065 just ignore the spool file name */
2067 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2069 ERR("AddJob failed gle %08lx\n", GetLastError());
2070 goto end;
2073 if(doc->pOutputFile)
2074 filename = doc->pOutputFile;
2075 else
2076 filename = addjob->Path;
2078 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2079 if(hf == INVALID_HANDLE_VALUE)
2080 goto end;
2082 memset(&job_info, 0, sizeof(job_info));
2083 job_info.pDocument = doc->pDocName;
2084 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2086 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2087 printer->doc->hf = hf;
2088 ret = printer->doc->job_id = addjob->JobId;
2089 end:
2090 LeaveCriticalSection(&printer_handles_cs);
2092 return ret;
2095 /*****************************************************************************
2096 * StartPagePrinter [WINSPOOL.@]
2098 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2100 FIXME("(%p): stub\n", hPrinter);
2101 return TRUE;
2104 /*****************************************************************************
2105 * GetFormA [WINSPOOL.@]
2107 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2108 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2110 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2111 Level,pForm,cbBuf,pcbNeeded);
2112 return FALSE;
2115 /*****************************************************************************
2116 * GetFormW [WINSPOOL.@]
2118 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2119 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2121 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2122 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2123 return FALSE;
2126 /*****************************************************************************
2127 * SetFormA [WINSPOOL.@]
2129 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2130 LPBYTE pForm)
2132 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2133 return FALSE;
2136 /*****************************************************************************
2137 * SetFormW [WINSPOOL.@]
2139 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2140 LPBYTE pForm)
2142 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2143 return FALSE;
2146 /*****************************************************************************
2147 * ReadPrinter [WINSPOOL.@]
2149 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2150 LPDWORD pNoBytesRead)
2152 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2153 return FALSE;
2156 /*****************************************************************************
2157 * ResetPrinterA [WINSPOOL.@]
2159 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2161 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2162 return FALSE;
2165 /*****************************************************************************
2166 * ResetPrinterW [WINSPOOL.@]
2168 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2170 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2171 return FALSE;
2174 /*****************************************************************************
2175 * WINSPOOL_GetDWORDFromReg
2177 * Return DWORD associated with ValueName from hkey.
2179 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2181 DWORD sz = sizeof(DWORD), type, value = 0;
2182 LONG ret;
2184 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2186 if(ret != ERROR_SUCCESS) {
2187 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2188 return 0;
2190 if(type != REG_DWORD) {
2191 ERR("Got type %ld\n", type);
2192 return 0;
2194 return value;
2197 /*****************************************************************************
2198 * WINSPOOL_GetStringFromReg
2200 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2201 * String is stored either as unicode or ascii.
2202 * Bit of a hack here to get the ValueName if we want ascii.
2204 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2205 DWORD buflen, DWORD *needed,
2206 BOOL unicode)
2208 DWORD sz = buflen, type;
2209 LONG ret;
2211 if(unicode)
2212 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2213 else {
2214 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2215 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2216 HeapFree(GetProcessHeap(),0,ValueNameA);
2218 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2219 WARN("Got ret = %ld\n", ret);
2220 *needed = 0;
2221 return FALSE;
2223 *needed = sz;
2224 return TRUE;
2227 /*****************************************************************************
2228 * WINSPOOL_GetDefaultDevMode
2230 * Get a default DevMode values for wineps.
2231 * FIXME - use ppd.
2234 static void WINSPOOL_GetDefaultDevMode(
2235 LPBYTE ptr,
2236 DWORD buflen, DWORD *needed,
2237 BOOL unicode)
2239 DEVMODEA dm;
2240 static const char szwps[] = "wineps.drv";
2242 /* fill default DEVMODE - should be read from ppd... */
2243 ZeroMemory( &dm, sizeof(dm) );
2244 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2245 dm.dmSpecVersion = DM_SPECVERSION;
2246 dm.dmDriverVersion = 1;
2247 dm.dmSize = sizeof(DEVMODEA);
2248 dm.dmDriverExtra = 0;
2249 dm.dmFields =
2250 DM_ORIENTATION | DM_PAPERSIZE |
2251 DM_PAPERLENGTH | DM_PAPERWIDTH |
2252 DM_SCALE |
2253 DM_COPIES |
2254 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2255 DM_YRESOLUTION | DM_TTOPTION;
2257 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2258 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2259 dm.u1.s1.dmPaperLength = 2970;
2260 dm.u1.s1.dmPaperWidth = 2100;
2262 dm.dmScale = 100;
2263 dm.dmCopies = 1;
2264 dm.dmDefaultSource = DMBIN_AUTO;
2265 dm.dmPrintQuality = DMRES_MEDIUM;
2266 /* dm.dmColor */
2267 /* dm.dmDuplex */
2268 dm.dmYResolution = 300; /* 300dpi */
2269 dm.dmTTOption = DMTT_BITMAP;
2270 /* dm.dmCollate */
2271 /* dm.dmFormName */
2272 /* dm.dmLogPixels */
2273 /* dm.dmBitsPerPel */
2274 /* dm.dmPelsWidth */
2275 /* dm.dmPelsHeight */
2276 /* dm.dmDisplayFlags */
2277 /* dm.dmDisplayFrequency */
2278 /* dm.dmICMMethod */
2279 /* dm.dmICMIntent */
2280 /* dm.dmMediaType */
2281 /* dm.dmDitherType */
2282 /* dm.dmReserved1 */
2283 /* dm.dmReserved2 */
2284 /* dm.dmPanningWidth */
2285 /* dm.dmPanningHeight */
2287 if(unicode) {
2288 if(buflen >= sizeof(DEVMODEW)) {
2289 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2290 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2291 HeapFree(GetProcessHeap(),0,pdmW);
2293 *needed = sizeof(DEVMODEW);
2295 else
2297 if(buflen >= sizeof(DEVMODEA)) {
2298 memcpy(ptr, &dm, sizeof(DEVMODEA));
2300 *needed = sizeof(DEVMODEA);
2304 /*****************************************************************************
2305 * WINSPOOL_GetDevModeFromReg
2307 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2308 * DevMode is stored either as unicode or ascii.
2310 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2311 LPBYTE ptr,
2312 DWORD buflen, DWORD *needed,
2313 BOOL unicode)
2315 DWORD sz = buflen, type;
2316 LONG ret;
2318 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2319 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2320 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2321 if (sz < sizeof(DEVMODEA))
2323 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2324 return FALSE;
2326 /* ensures that dmSize is not erratically bogus if registry is invalid */
2327 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2328 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2329 if(unicode) {
2330 sz += (CCHDEVICENAME + CCHFORMNAME);
2331 if(buflen >= sz) {
2332 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2333 memcpy(ptr, dmW, sz);
2334 HeapFree(GetProcessHeap(),0,dmW);
2337 *needed = sz;
2338 return TRUE;
2341 /*********************************************************************
2342 * WINSPOOL_GetPrinter_2
2344 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2345 * The strings are either stored as unicode or ascii.
2347 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2348 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2349 BOOL unicode)
2351 DWORD size, left = cbBuf;
2352 BOOL space = (cbBuf > 0);
2353 LPBYTE ptr = buf;
2355 *pcbNeeded = 0;
2357 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2358 unicode)) {
2359 if(space && size <= left) {
2360 pi2->pPrinterName = (LPWSTR)ptr;
2361 ptr += size;
2362 left -= size;
2363 } else
2364 space = FALSE;
2365 *pcbNeeded += size;
2367 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2368 unicode)) {
2369 if(space && size <= left) {
2370 pi2->pShareName = (LPWSTR)ptr;
2371 ptr += size;
2372 left -= size;
2373 } else
2374 space = FALSE;
2375 *pcbNeeded += size;
2377 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2378 unicode)) {
2379 if(space && size <= left) {
2380 pi2->pPortName = (LPWSTR)ptr;
2381 ptr += size;
2382 left -= size;
2383 } else
2384 space = FALSE;
2385 *pcbNeeded += size;
2387 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2388 &size, unicode)) {
2389 if(space && size <= left) {
2390 pi2->pDriverName = (LPWSTR)ptr;
2391 ptr += size;
2392 left -= size;
2393 } else
2394 space = FALSE;
2395 *pcbNeeded += size;
2397 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2398 unicode)) {
2399 if(space && size <= left) {
2400 pi2->pComment = (LPWSTR)ptr;
2401 ptr += size;
2402 left -= size;
2403 } else
2404 space = FALSE;
2405 *pcbNeeded += size;
2407 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2408 unicode)) {
2409 if(space && size <= left) {
2410 pi2->pLocation = (LPWSTR)ptr;
2411 ptr += size;
2412 left -= size;
2413 } else
2414 space = FALSE;
2415 *pcbNeeded += size;
2417 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2418 &size, unicode)) {
2419 if(space && size <= left) {
2420 pi2->pDevMode = (LPDEVMODEW)ptr;
2421 ptr += size;
2422 left -= size;
2423 } else
2424 space = FALSE;
2425 *pcbNeeded += size;
2427 else
2429 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2430 if(space && size <= left) {
2431 pi2->pDevMode = (LPDEVMODEW)ptr;
2432 ptr += size;
2433 left -= size;
2434 } else
2435 space = FALSE;
2436 *pcbNeeded += size;
2438 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2439 &size, unicode)) {
2440 if(space && size <= left) {
2441 pi2->pSepFile = (LPWSTR)ptr;
2442 ptr += size;
2443 left -= size;
2444 } else
2445 space = FALSE;
2446 *pcbNeeded += size;
2448 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2449 &size, unicode)) {
2450 if(space && size <= left) {
2451 pi2->pPrintProcessor = (LPWSTR)ptr;
2452 ptr += size;
2453 left -= size;
2454 } else
2455 space = FALSE;
2456 *pcbNeeded += size;
2458 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2459 &size, unicode)) {
2460 if(space && size <= left) {
2461 pi2->pDatatype = (LPWSTR)ptr;
2462 ptr += size;
2463 left -= size;
2464 } else
2465 space = FALSE;
2466 *pcbNeeded += size;
2468 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2469 &size, unicode)) {
2470 if(space && size <= left) {
2471 pi2->pParameters = (LPWSTR)ptr;
2472 ptr += size;
2473 left -= size;
2474 } else
2475 space = FALSE;
2476 *pcbNeeded += size;
2478 if(pi2) {
2479 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2480 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2481 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2482 "Default Priority");
2483 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2484 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2487 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2488 memset(pi2, 0, sizeof(*pi2));
2490 return space;
2493 /*********************************************************************
2494 * WINSPOOL_GetPrinter_4
2496 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2498 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2499 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2500 BOOL unicode)
2502 DWORD size, left = cbBuf;
2503 BOOL space = (cbBuf > 0);
2504 LPBYTE ptr = buf;
2506 *pcbNeeded = 0;
2508 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2509 unicode)) {
2510 if(space && size <= left) {
2511 pi4->pPrinterName = (LPWSTR)ptr;
2512 ptr += size;
2513 left -= size;
2514 } else
2515 space = FALSE;
2516 *pcbNeeded += size;
2518 if(pi4) {
2519 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2522 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2523 memset(pi4, 0, sizeof(*pi4));
2525 return space;
2528 /*********************************************************************
2529 * WINSPOOL_GetPrinter_5
2531 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2533 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2534 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2535 BOOL unicode)
2537 DWORD size, left = cbBuf;
2538 BOOL space = (cbBuf > 0);
2539 LPBYTE ptr = buf;
2541 *pcbNeeded = 0;
2543 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2544 unicode)) {
2545 if(space && size <= left) {
2546 pi5->pPrinterName = (LPWSTR)ptr;
2547 ptr += size;
2548 left -= size;
2549 } else
2550 space = FALSE;
2551 *pcbNeeded += size;
2553 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2554 unicode)) {
2555 if(space && size <= left) {
2556 pi5->pPortName = (LPWSTR)ptr;
2557 ptr += size;
2558 left -= size;
2559 } else
2560 space = FALSE;
2561 *pcbNeeded += size;
2563 if(pi5) {
2564 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2565 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2566 "dnsTimeout");
2567 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2568 "txTimeout");
2571 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2572 memset(pi5, 0, sizeof(*pi5));
2574 return space;
2577 /*****************************************************************************
2578 * WINSPOOL_GetPrinter
2580 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2581 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2582 * just a collection of pointers to strings.
2584 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2585 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2587 LPCWSTR name;
2588 DWORD size, needed = 0;
2589 LPBYTE ptr = NULL;
2590 HKEY hkeyPrinter, hkeyPrinters;
2591 BOOL ret;
2593 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2595 if (!(name = get_opened_printer_name(hPrinter))) {
2596 SetLastError(ERROR_INVALID_HANDLE);
2597 return FALSE;
2600 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2601 ERROR_SUCCESS) {
2602 ERR("Can't create Printers key\n");
2603 return FALSE;
2605 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2607 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2608 RegCloseKey(hkeyPrinters);
2609 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2610 return FALSE;
2613 switch(Level) {
2614 case 2:
2616 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2618 size = sizeof(PRINTER_INFO_2W);
2619 if(size <= cbBuf) {
2620 ptr = pPrinter + size;
2621 cbBuf -= size;
2622 memset(pPrinter, 0, size);
2623 } else {
2624 pi2 = NULL;
2625 cbBuf = 0;
2627 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2628 unicode);
2629 needed += size;
2630 break;
2633 case 4:
2635 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2637 size = sizeof(PRINTER_INFO_4W);
2638 if(size <= cbBuf) {
2639 ptr = pPrinter + size;
2640 cbBuf -= size;
2641 memset(pPrinter, 0, size);
2642 } else {
2643 pi4 = NULL;
2644 cbBuf = 0;
2646 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2647 unicode);
2648 needed += size;
2649 break;
2653 case 5:
2655 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2657 size = sizeof(PRINTER_INFO_5W);
2658 if(size <= cbBuf) {
2659 ptr = pPrinter + size;
2660 cbBuf -= size;
2661 memset(pPrinter, 0, size);
2662 } else {
2663 pi5 = NULL;
2664 cbBuf = 0;
2667 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2668 unicode);
2669 needed += size;
2670 break;
2673 default:
2674 FIXME("Unimplemented level %ld\n", Level);
2675 SetLastError(ERROR_INVALID_LEVEL);
2676 RegCloseKey(hkeyPrinters);
2677 RegCloseKey(hkeyPrinter);
2678 return FALSE;
2681 RegCloseKey(hkeyPrinter);
2682 RegCloseKey(hkeyPrinters);
2684 TRACE("returning %d needed = %ld\n", ret, needed);
2685 if(pcbNeeded) *pcbNeeded = needed;
2686 if(!ret)
2687 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2688 return ret;
2691 /*****************************************************************************
2692 * GetPrinterW [WINSPOOL.@]
2694 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2695 DWORD cbBuf, LPDWORD pcbNeeded)
2697 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2698 TRUE);
2701 /*****************************************************************************
2702 * GetPrinterA [WINSPOOL.@]
2704 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2705 DWORD cbBuf, LPDWORD pcbNeeded)
2707 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2708 FALSE);
2711 /*****************************************************************************
2712 * WINSPOOL_EnumPrinters
2714 * Implementation of EnumPrintersA|W
2716 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2717 DWORD dwLevel, LPBYTE lpbPrinters,
2718 DWORD cbBuf, LPDWORD lpdwNeeded,
2719 LPDWORD lpdwReturned, BOOL unicode)
2722 HKEY hkeyPrinters, hkeyPrinter;
2723 WCHAR PrinterName[255];
2724 DWORD needed = 0, number = 0;
2725 DWORD used, i, left;
2726 PBYTE pi, buf;
2728 if(lpbPrinters)
2729 memset(lpbPrinters, 0, cbBuf);
2730 if(lpdwReturned)
2731 *lpdwReturned = 0;
2732 if(lpdwNeeded)
2733 *lpdwNeeded = 0;
2735 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2736 if(dwType == PRINTER_ENUM_DEFAULT)
2737 return TRUE;
2739 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2740 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2741 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2742 if(!dwType) return TRUE;
2745 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2746 FIXME("dwType = %08lx\n", dwType);
2747 SetLastError(ERROR_INVALID_FLAGS);
2748 return FALSE;
2751 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2752 ERROR_SUCCESS) {
2753 ERR("Can't create Printers key\n");
2754 return FALSE;
2757 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2758 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2759 RegCloseKey(hkeyPrinters);
2760 ERR("Can't query Printers key\n");
2761 return FALSE;
2763 TRACE("Found %ld printers\n", number);
2765 switch(dwLevel) {
2766 case 1:
2767 RegCloseKey(hkeyPrinters);
2768 if (lpdwReturned)
2769 *lpdwReturned = number;
2770 return TRUE;
2772 case 2:
2773 used = number * sizeof(PRINTER_INFO_2W);
2774 break;
2775 case 4:
2776 used = number * sizeof(PRINTER_INFO_4W);
2777 break;
2778 case 5:
2779 used = number * sizeof(PRINTER_INFO_5W);
2780 break;
2782 default:
2783 SetLastError(ERROR_INVALID_LEVEL);
2784 RegCloseKey(hkeyPrinters);
2785 return FALSE;
2787 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2789 for(i = 0; i < number; i++) {
2790 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2791 ERROR_SUCCESS) {
2792 ERR("Can't enum key number %ld\n", i);
2793 RegCloseKey(hkeyPrinters);
2794 return FALSE;
2796 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2797 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2798 ERROR_SUCCESS) {
2799 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2800 RegCloseKey(hkeyPrinters);
2801 return FALSE;
2804 if(cbBuf > used) {
2805 buf = lpbPrinters + used;
2806 left = cbBuf - used;
2807 } else {
2808 buf = NULL;
2809 left = 0;
2812 switch(dwLevel) {
2813 case 2:
2814 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2815 left, &needed, unicode);
2816 used += needed;
2817 if(pi) pi += sizeof(PRINTER_INFO_2W);
2818 break;
2819 case 4:
2820 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2821 left, &needed, unicode);
2822 used += needed;
2823 if(pi) pi += sizeof(PRINTER_INFO_4W);
2824 break;
2825 case 5:
2826 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2827 left, &needed, unicode);
2828 used += needed;
2829 if(pi) pi += sizeof(PRINTER_INFO_5W);
2830 break;
2831 default:
2832 ERR("Shouldn't be here!\n");
2833 RegCloseKey(hkeyPrinter);
2834 RegCloseKey(hkeyPrinters);
2835 return FALSE;
2837 RegCloseKey(hkeyPrinter);
2839 RegCloseKey(hkeyPrinters);
2841 if(lpdwNeeded)
2842 *lpdwNeeded = used;
2844 if(used > cbBuf) {
2845 if(lpbPrinters)
2846 memset(lpbPrinters, 0, cbBuf);
2847 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2848 return FALSE;
2850 if(lpdwReturned)
2851 *lpdwReturned = number;
2852 SetLastError(ERROR_SUCCESS);
2853 return TRUE;
2857 /******************************************************************
2858 * EnumPrintersW [WINSPOOL.@]
2860 * Enumerates the available printers, print servers and print
2861 * providers, depending on the specified flags, name and level.
2863 * RETURNS:
2865 * If level is set to 1:
2866 * Not implemented yet!
2867 * Returns TRUE with an empty list.
2869 * If level is set to 2:
2870 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2871 * Returns an array of PRINTER_INFO_2 data structures in the
2872 * lpbPrinters buffer. Note that according to MSDN also an
2873 * OpenPrinter should be performed on every remote printer.
2875 * If level is set to 4 (officially WinNT only):
2876 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2877 * Fast: Only the registry is queried to retrieve printer names,
2878 * no connection to the driver is made.
2879 * Returns an array of PRINTER_INFO_4 data structures in the
2880 * lpbPrinters buffer.
2882 * If level is set to 5 (officially WinNT4/Win9x only):
2883 * Fast: Only the registry is queried to retrieve printer names,
2884 * no connection to the driver is made.
2885 * Returns an array of PRINTER_INFO_5 data structures in the
2886 * lpbPrinters buffer.
2888 * If level set to 3 or 6+:
2889 * returns zero (failure!)
2891 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2892 * for information.
2894 * BUGS:
2895 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2896 * - Only levels 2, 4 and 5 are implemented at the moment.
2897 * - 16-bit printer drivers are not enumerated.
2898 * - Returned amount of bytes used/needed does not match the real Windoze
2899 * implementation (as in this implementation, all strings are part
2900 * of the buffer, whereas Win32 keeps them somewhere else)
2901 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2903 * NOTE:
2904 * - In a regular Wine installation, no registry settings for printers
2905 * exist, which makes this function return an empty list.
2907 BOOL WINAPI EnumPrintersW(
2908 DWORD dwType, /* [in] Types of print objects to enumerate */
2909 LPWSTR lpszName, /* [in] name of objects to enumerate */
2910 DWORD dwLevel, /* [in] type of printer info structure */
2911 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2912 DWORD cbBuf, /* [in] max size of buffer in bytes */
2913 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2914 LPDWORD lpdwReturned /* [out] number of entries returned */
2917 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2918 lpdwNeeded, lpdwReturned, TRUE);
2921 /******************************************************************
2922 * EnumPrintersA [WINSPOOL.@]
2925 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2926 DWORD dwLevel, LPBYTE lpbPrinters,
2927 DWORD cbBuf, LPDWORD lpdwNeeded,
2928 LPDWORD lpdwReturned)
2930 BOOL ret;
2931 UNICODE_STRING lpszNameW;
2932 PWSTR pwstrNameW;
2934 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2935 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2936 lpdwNeeded, lpdwReturned, FALSE);
2937 RtlFreeUnicodeString(&lpszNameW);
2938 return ret;
2941 /*****************************************************************************
2942 * WINSPOOL_GetDriverInfoFromReg [internal]
2944 * Enters the information from the registry into the DRIVER_INFO struct
2946 * RETURNS
2947 * zero if the printer driver does not exist in the registry
2948 * (only if Level > 1) otherwise nonzero
2950 static BOOL WINSPOOL_GetDriverInfoFromReg(
2951 HKEY hkeyDrivers,
2952 LPWSTR DriverName,
2953 LPWSTR pEnvironment,
2954 DWORD Level,
2955 LPBYTE ptr, /* DRIVER_INFO */
2956 LPBYTE pDriverStrings, /* strings buffer */
2957 DWORD cbBuf, /* size of string buffer */
2958 LPDWORD pcbNeeded, /* space needed for str. */
2959 BOOL unicode) /* type of strings */
2960 { DWORD dw, size, tmp, type;
2961 HKEY hkeyDriver;
2962 LPBYTE strPtr = pDriverStrings;
2964 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2965 debugstr_w(DriverName), debugstr_w(pEnvironment),
2966 Level, ptr, pDriverStrings, cbBuf, unicode);
2968 if(unicode) {
2969 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2970 if (*pcbNeeded <= cbBuf)
2971 strcpyW((LPWSTR)strPtr, DriverName);
2972 } else {
2973 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2974 NULL, NULL);
2975 if(*pcbNeeded <= cbBuf)
2976 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
2977 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
2979 if(Level == 1) {
2980 if(ptr)
2981 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2982 return TRUE;
2983 } else {
2984 if(ptr)
2985 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2986 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2989 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2990 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2991 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2992 return FALSE;
2995 size = sizeof(dw);
2996 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2997 ERROR_SUCCESS)
2998 WARN("Can't get Version\n");
2999 else if(ptr)
3000 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
3002 if(!pEnvironment)
3003 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3004 if(unicode)
3005 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3006 else
3007 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3008 NULL, NULL);
3009 *pcbNeeded += size;
3010 if(*pcbNeeded <= cbBuf) {
3011 if(unicode)
3012 strcpyW((LPWSTR)strPtr, pEnvironment);
3013 else
3014 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3015 (LPSTR)strPtr, size, NULL, NULL);
3016 if(ptr)
3017 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
3018 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3021 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3022 unicode)) {
3023 *pcbNeeded += size;
3024 if(*pcbNeeded <= cbBuf)
3025 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3026 unicode);
3027 if(ptr)
3028 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
3029 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3032 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3033 unicode)) {
3034 *pcbNeeded += size;
3035 if(*pcbNeeded <= cbBuf)
3036 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3037 &tmp, unicode);
3038 if(ptr)
3039 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
3040 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3043 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3044 0, &size, unicode)) {
3045 *pcbNeeded += size;
3046 if(*pcbNeeded <= cbBuf)
3047 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3048 size, &tmp, unicode);
3049 if(ptr)
3050 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
3051 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3054 if(Level == 2 ) {
3055 RegCloseKey(hkeyDriver);
3056 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3057 return TRUE;
3060 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3061 unicode)) {
3062 *pcbNeeded += size;
3063 if(*pcbNeeded <= cbBuf)
3064 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3065 size, &tmp, unicode);
3066 if(ptr)
3067 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3068 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3071 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3072 &size, unicode)) {
3073 *pcbNeeded += size;
3074 if(*pcbNeeded <= cbBuf)
3075 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3076 size, &tmp, unicode);
3077 if(ptr)
3078 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3079 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3082 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3083 unicode)) {
3084 *pcbNeeded += size;
3085 if(*pcbNeeded <= cbBuf)
3086 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3087 size, &tmp, unicode);
3088 if(ptr)
3089 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3090 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3093 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3094 unicode)) {
3095 *pcbNeeded += size;
3096 if(*pcbNeeded <= cbBuf)
3097 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3098 size, &tmp, unicode);
3099 if(ptr)
3100 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3101 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3104 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3105 RegCloseKey(hkeyDriver);
3106 return TRUE;
3109 /*****************************************************************************
3110 * WINSPOOL_GetPrinterDriver
3112 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3113 DWORD Level, LPBYTE pDriverInfo,
3114 DWORD cbBuf, LPDWORD pcbNeeded,
3115 BOOL unicode)
3117 LPCWSTR name;
3118 WCHAR DriverName[100];
3119 DWORD ret, type, size, needed = 0;
3120 LPBYTE ptr = NULL;
3121 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3123 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3124 Level,pDriverInfo,cbBuf, pcbNeeded);
3126 ZeroMemory(pDriverInfo, cbBuf);
3128 if (!(name = get_opened_printer_name(hPrinter))) {
3129 SetLastError(ERROR_INVALID_HANDLE);
3130 return FALSE;
3132 if(Level < 1 || Level > 3) {
3133 SetLastError(ERROR_INVALID_LEVEL);
3134 return FALSE;
3136 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3137 ERROR_SUCCESS) {
3138 ERR("Can't create Printers key\n");
3139 return FALSE;
3141 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3142 != ERROR_SUCCESS) {
3143 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3144 RegCloseKey(hkeyPrinters);
3145 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3146 return FALSE;
3148 size = sizeof(DriverName);
3149 DriverName[0] = 0;
3150 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3151 (LPBYTE)DriverName, &size);
3152 RegCloseKey(hkeyPrinter);
3153 RegCloseKey(hkeyPrinters);
3154 if(ret != ERROR_SUCCESS) {
3155 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3156 return FALSE;
3159 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3160 if(!hkeyDrivers) {
3161 ERR("Can't create Drivers key\n");
3162 return FALSE;
3165 switch(Level) {
3166 case 1:
3167 size = sizeof(DRIVER_INFO_1W);
3168 break;
3169 case 2:
3170 size = sizeof(DRIVER_INFO_2W);
3171 break;
3172 case 3:
3173 size = sizeof(DRIVER_INFO_3W);
3174 break;
3175 default:
3176 ERR("Invalid level\n");
3177 return FALSE;
3180 if(size <= cbBuf)
3181 ptr = pDriverInfo + size;
3183 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3184 pEnvironment, Level, pDriverInfo,
3185 (cbBuf < size) ? NULL : ptr,
3186 (cbBuf < size) ? 0 : cbBuf - size,
3187 &needed, unicode)) {
3188 RegCloseKey(hkeyDrivers);
3189 return FALSE;
3192 RegCloseKey(hkeyDrivers);
3194 if(pcbNeeded) *pcbNeeded = size + needed;
3195 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3196 if(cbBuf >= needed) return TRUE;
3197 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3198 return FALSE;
3201 /*****************************************************************************
3202 * GetPrinterDriverA [WINSPOOL.@]
3204 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3205 DWORD Level, LPBYTE pDriverInfo,
3206 DWORD cbBuf, LPDWORD pcbNeeded)
3208 BOOL ret;
3209 UNICODE_STRING pEnvW;
3210 PWSTR pwstrEnvW;
3212 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3213 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3214 cbBuf, pcbNeeded, FALSE);
3215 RtlFreeUnicodeString(&pEnvW);
3216 return ret;
3218 /*****************************************************************************
3219 * GetPrinterDriverW [WINSPOOL.@]
3221 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3222 DWORD Level, LPBYTE pDriverInfo,
3223 DWORD cbBuf, LPDWORD pcbNeeded)
3225 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3226 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3229 /*****************************************************************************
3230 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3232 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3233 DWORD Level, LPBYTE pDriverDirectory,
3234 DWORD cbBuf, LPDWORD pcbNeeded)
3236 DWORD needed;
3238 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3239 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3240 if(pName != NULL) {
3241 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
3242 SetLastError(ERROR_INVALID_PARAMETER);
3243 return FALSE;
3245 if(pEnvironment != NULL) {
3246 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
3247 SetLastError(ERROR_INVALID_ENVIRONMENT);
3248 return FALSE;
3250 if(Level != 1) /* win95 ignores this so we just carry on */
3251 WARN("Level = %ld - assuming 1\n", Level);
3253 /* FIXME should read from registry */
3254 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
3255 /* GetSystemDirectoryW returns number of TCHAR without '\0'
3256 * adjust this now
3258 needed++;
3259 needed*=sizeof(WCHAR);
3261 if(pcbNeeded)
3262 *pcbNeeded = needed;
3263 TRACE("required <%08lx>\n", *pcbNeeded);
3264 if(needed > cbBuf) {
3265 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3266 return FALSE;
3268 return TRUE;
3272 /*****************************************************************************
3273 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3275 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3276 DWORD Level, LPBYTE pDriverDirectory,
3277 DWORD cbBuf, LPDWORD pcbNeeded)
3279 UNICODE_STRING nameW, environmentW;
3280 BOOL ret;
3281 DWORD pcbNeededW;
3282 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3283 WCHAR *driverDirectoryW = NULL;
3285 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3287 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3288 else nameW.Buffer = NULL;
3289 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3290 else environmentW.Buffer = NULL;
3292 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3293 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3294 if (ret) {
3295 DWORD needed;
3296 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3297 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3298 if(pcbNeeded)
3299 *pcbNeeded = needed;
3300 ret = (needed <= cbBuf) ? TRUE : FALSE;
3301 } else
3302 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3304 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
3306 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3307 RtlFreeUnicodeString(&environmentW);
3308 RtlFreeUnicodeString(&nameW);
3310 return ret;
3313 /*****************************************************************************
3314 * AddPrinterDriverA [WINSPOOL.@]
3316 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3318 DRIVER_INFO_3A di3;
3319 HKEY hkeyDrivers, hkeyName;
3321 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3323 if(level != 2 && level != 3) {
3324 SetLastError(ERROR_INVALID_LEVEL);
3325 return FALSE;
3327 if(pName != NULL) {
3328 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3329 SetLastError(ERROR_INVALID_PARAMETER);
3330 return FALSE;
3332 if(!pDriverInfo) {
3333 WARN("pDriverInfo == NULL\n");
3334 SetLastError(ERROR_INVALID_PARAMETER);
3335 return FALSE;
3338 if(level == 3)
3339 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3340 else {
3341 memset(&di3, 0, sizeof(di3));
3342 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3345 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3346 !di3.pDataFile) {
3347 SetLastError(ERROR_INVALID_PARAMETER);
3348 return FALSE;
3350 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3351 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3352 if(!di3.pHelpFile) di3.pHelpFile = "";
3353 if(!di3.pMonitorName) di3.pMonitorName = "";
3355 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3357 if(!hkeyDrivers) {
3358 ERR("Can't create Drivers key\n");
3359 return FALSE;
3362 if(level == 2) { /* apparently can't overwrite with level2 */
3363 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3364 RegCloseKey(hkeyName);
3365 RegCloseKey(hkeyDrivers);
3366 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3367 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3368 return FALSE;
3371 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3372 RegCloseKey(hkeyDrivers);
3373 ERR("Can't create Name key\n");
3374 return FALSE;
3376 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3378 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3379 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3380 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3381 sizeof(DWORD));
3382 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3383 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3384 (LPBYTE) di3.pDependentFiles, 0);
3385 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3386 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3387 RegCloseKey(hkeyName);
3388 RegCloseKey(hkeyDrivers);
3390 return TRUE;
3393 /*****************************************************************************
3394 * AddPrinterDriverW [WINSPOOL.@]
3396 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3397 LPBYTE pDriverInfo)
3399 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3400 level,pDriverInfo);
3401 return FALSE;
3404 /*****************************************************************************
3405 * AddPrintProcessorA [WINSPOOL.@]
3407 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3408 LPSTR pPrintProcessorName)
3410 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3411 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3412 return FALSE;
3415 /*****************************************************************************
3416 * AddPrintProcessorW [WINSPOOL.@]
3418 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3419 LPWSTR pPrintProcessorName)
3421 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3422 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3423 return FALSE;
3426 /*****************************************************************************
3427 * AddPrintProvidorA [WINSPOOL.@]
3429 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3431 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3432 return FALSE;
3435 /*****************************************************************************
3436 * AddPrintProvidorW [WINSPOOL.@]
3438 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3440 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3441 return FALSE;
3444 /*****************************************************************************
3445 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3447 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3448 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3450 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3451 pDevModeOutput, pDevModeInput);
3452 return 0;
3455 /*****************************************************************************
3456 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3458 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3459 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3461 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3462 pDevModeOutput, pDevModeInput);
3463 return 0;
3466 /*****************************************************************************
3467 * PrinterProperties [WINSPOOL.@]
3469 * Displays a dialog to set the properties of the printer.
3471 * RETURNS
3472 * nonzero on success or zero on failure
3474 * BUGS
3475 * implemented as stub only
3477 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3478 HANDLE hPrinter /* [in] handle to printer object */
3480 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3482 return FALSE;
3485 /*****************************************************************************
3486 * EnumJobsA [WINSPOOL.@]
3489 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3490 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3491 LPDWORD pcReturned)
3493 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3494 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3496 if(pcbNeeded) *pcbNeeded = 0;
3497 if(pcReturned) *pcReturned = 0;
3498 return FALSE;
3502 /*****************************************************************************
3503 * EnumJobsW [WINSPOOL.@]
3506 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3507 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3508 LPDWORD pcReturned)
3510 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3511 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3513 if(pcbNeeded) *pcbNeeded = 0;
3514 if(pcReturned) *pcReturned = 0;
3515 return FALSE;
3518 /*****************************************************************************
3519 * WINSPOOL_EnumPrinterDrivers [internal]
3521 * Delivers information about all printer drivers installed on the
3522 * localhost or a given server
3524 * RETURNS
3525 * nonzero on success or zero on failure. If the buffer for the returned
3526 * information is too small the function will return an error
3528 * BUGS
3529 * - only implemented for localhost, foreign hosts will return an error
3531 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3532 DWORD Level, LPBYTE pDriverInfo,
3533 DWORD cbBuf, LPDWORD pcbNeeded,
3534 LPDWORD pcReturned, BOOL unicode)
3536 { HKEY hkeyDrivers;
3537 DWORD i, needed, number = 0, size = 0;
3538 WCHAR DriverNameW[255];
3539 PBYTE ptr;
3541 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3542 debugstr_w(pName), debugstr_w(pEnvironment),
3543 Level, pDriverInfo, cbBuf, unicode);
3545 /* check for local drivers */
3546 if(pName) {
3547 ERR("remote drivers unsupported! Current remote host is %s\n",
3548 debugstr_w(pName));
3549 return FALSE;
3552 /* check input parameter */
3553 if((Level < 1) || (Level > 3)) {
3554 ERR("unsupported level %ld\n", Level);
3555 SetLastError(ERROR_INVALID_LEVEL);
3556 return FALSE;
3559 /* initialize return values */
3560 if(pDriverInfo)
3561 memset( pDriverInfo, 0, cbBuf);
3562 *pcbNeeded = 0;
3563 *pcReturned = 0;
3565 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3566 if(!hkeyDrivers) {
3567 ERR("Can't open Drivers key\n");
3568 return FALSE;
3571 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3572 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3573 RegCloseKey(hkeyDrivers);
3574 ERR("Can't query Drivers key\n");
3575 return FALSE;
3577 TRACE("Found %ld Drivers\n", number);
3579 /* get size of single struct
3580 * unicode and ascii structure have the same size
3582 switch (Level) {
3583 case 1:
3584 size = sizeof(DRIVER_INFO_1A);
3585 break;
3586 case 2:
3587 size = sizeof(DRIVER_INFO_2A);
3588 break;
3589 case 3:
3590 size = sizeof(DRIVER_INFO_3A);
3591 break;
3594 /* calculate required buffer size */
3595 *pcbNeeded = size * number;
3597 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3598 i < number;
3599 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3600 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3601 != ERROR_SUCCESS) {
3602 ERR("Can't enum key number %ld\n", i);
3603 RegCloseKey(hkeyDrivers);
3604 return FALSE;
3606 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3607 pEnvironment, Level, ptr,
3608 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3609 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3610 &needed, unicode)) {
3611 RegCloseKey(hkeyDrivers);
3612 return FALSE;
3614 (*pcbNeeded) += needed;
3617 RegCloseKey(hkeyDrivers);
3619 if(cbBuf < *pcbNeeded){
3620 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3621 return FALSE;
3624 return TRUE;
3627 /*****************************************************************************
3628 * EnumPrinterDriversW [WINSPOOL.@]
3630 * see function EnumPrinterDrivers for RETURNS, BUGS
3632 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3633 LPBYTE pDriverInfo, DWORD cbBuf,
3634 LPDWORD pcbNeeded, LPDWORD pcReturned)
3636 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3637 cbBuf, pcbNeeded, pcReturned, TRUE);
3640 /*****************************************************************************
3641 * EnumPrinterDriversA [WINSPOOL.@]
3643 * see function EnumPrinterDrivers for RETURNS, BUGS
3645 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3646 LPBYTE pDriverInfo, DWORD cbBuf,
3647 LPDWORD pcbNeeded, LPDWORD pcReturned)
3648 { BOOL ret;
3649 UNICODE_STRING pNameW, pEnvironmentW;
3650 PWSTR pwstrNameW, pwstrEnvironmentW;
3652 pwstrNameW = asciitounicode(&pNameW, pName);
3653 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3655 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3656 Level, pDriverInfo, cbBuf, pcbNeeded,
3657 pcReturned, FALSE);
3658 RtlFreeUnicodeString(&pNameW);
3659 RtlFreeUnicodeString(&pEnvironmentW);
3661 return ret;
3664 static CHAR PortMonitor[] = "Wine Port Monitor";
3665 static CHAR PortDescription[] = "Wine Port";
3667 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3669 HANDLE handle;
3671 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3672 NULL, OPEN_EXISTING, 0, NULL );
3673 if (handle == INVALID_HANDLE_VALUE)
3674 return FALSE;
3675 TRACE("Checking %s exists\n", name );
3676 CloseHandle( handle );
3677 return TRUE;
3680 static DWORD WINSPOOL_CountSerialPorts(void)
3682 CHAR name[6];
3683 DWORD n = 0, i;
3685 for (i=0; i<4; i++)
3687 strcpy( name, "COMx:" );
3688 name[3] = '1' + i;
3689 if (WINSPOOL_ComPortExists( name ))
3690 n++;
3693 return n;
3696 /******************************************************************************
3697 * EnumPortsA (WINSPOOL.@)
3699 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3700 LPDWORD bufneeded,LPDWORD bufreturned)
3702 CHAR portname[10];
3703 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3704 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3705 HKEY hkey_printer;
3706 BOOL retval = TRUE;
3708 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3709 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3711 switch( level )
3713 case 1:
3714 info_size = sizeof (PORT_INFO_1A);
3715 break;
3716 case 2:
3717 info_size = sizeof (PORT_INFO_2A);
3718 break;
3719 default:
3720 SetLastError(ERROR_INVALID_LEVEL);
3721 return FALSE;
3724 /* see how many exist */
3726 hkey_printer = 0;
3727 serial_count = WINSPOOL_CountSerialPorts();
3728 printer_count = 0;
3730 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3731 if ( r == ERROR_SUCCESS )
3733 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3734 &printer_count, NULL, NULL, NULL, NULL);
3736 count = serial_count + printer_count;
3738 /* then fill in the structure info structure once
3739 we know the offset to the first string */
3741 memset( buffer, 0, bufsize );
3742 n = 0;
3743 ofs = info_size*count;
3744 for ( i=0; i<count; i++)
3746 DWORD vallen = sizeof(portname) - 1;
3748 /* get the serial port values, then the printer values */
3749 if ( i < serial_count )
3751 strcpy( portname, "COMx:" );
3752 portname[3] = '1' + i;
3753 if (!WINSPOOL_ComPortExists( portname ))
3754 continue;
3756 TRACE("Found %s\n", portname );
3757 vallen = strlen( portname );
3759 else
3761 r = RegEnumValueA( hkey_printer, i-serial_count,
3762 portname, &vallen, NULL, NULL, NULL, 0 );
3763 if ( r )
3764 continue;
3767 /* add a colon if necessary, and make it upper case */
3768 CharUpperBuffA(portname,vallen);
3769 if (strcasecmp(portname,"nul")!=0)
3770 if (vallen && (portname[vallen-1] != ':') )
3771 lstrcatA(portname,":");
3773 /* add the port info structure if we can fit it */
3774 if ( info_size*(n+1) < bufsize )
3776 if ( level == 1)
3778 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3779 info->pName = (LPSTR) &buffer[ofs];
3781 else if ( level == 2)
3783 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3784 info->pPortName = (LPSTR) &buffer[ofs];
3785 /* FIXME: fill in more stuff here */
3786 info->pMonitorName = PortMonitor;
3787 info->pDescription = PortDescription;
3788 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3791 /* add the name of the port if we can fit it */
3792 if ( ofs < bufsize )
3793 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
3795 n++;
3797 else
3798 retval = FALSE;
3799 ofs += lstrlenA(portname)+1;
3802 RegCloseKey(hkey_printer);
3804 if(bufneeded)
3805 *bufneeded = ofs;
3807 if(bufreturned)
3808 *bufreturned = n;
3810 return retval;
3813 /******************************************************************************
3814 * EnumPortsW (WINSPOOL.@)
3816 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3817 LPDWORD bufneeded,LPDWORD bufreturned)
3819 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3820 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3821 return FALSE;
3824 /******************************************************************************
3825 * GetDefaultPrinterW (WINSPOOL.@)
3827 * FIXME
3828 * This function must read the value from data 'device' of key
3829 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3831 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3833 BOOL retval = TRUE;
3834 DWORD insize, len;
3835 WCHAR *buffer, *ptr;
3837 if (!namesize)
3839 SetLastError(ERROR_INVALID_PARAMETER);
3840 return FALSE;
3843 /* make the buffer big enough for the stuff from the profile/registry,
3844 * the content must fit into the local buffer to compute the correct
3845 * size even if the extern buffer is too small or not given.
3846 * (20 for ,driver,port) */
3847 insize = *namesize;
3848 len = max(100, (insize + 20));
3849 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3851 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3853 SetLastError (ERROR_FILE_NOT_FOUND);
3854 retval = FALSE;
3855 goto end;
3857 TRACE("%s\n", debugstr_w(buffer));
3859 if ((ptr = strchrW(buffer, ',')) == NULL)
3861 SetLastError(ERROR_INVALID_NAME);
3862 retval = FALSE;
3863 goto end;
3866 *ptr = 0;
3867 *namesize = strlenW(buffer) + 1;
3868 if(!name || (*namesize > insize))
3870 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3871 retval = FALSE;
3872 goto end;
3874 strcpyW(name, buffer);
3876 end:
3877 HeapFree( GetProcessHeap(), 0, buffer);
3878 return retval;
3882 /******************************************************************************
3883 * GetDefaultPrinterA (WINSPOOL.@)
3885 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3887 BOOL retval = TRUE;
3888 DWORD insize = 0;
3889 WCHAR *bufferW = NULL;
3891 if (!namesize)
3893 SetLastError(ERROR_INVALID_PARAMETER);
3894 return FALSE;
3897 if(name && *namesize) {
3898 insize = *namesize;
3899 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3902 if(!GetDefaultPrinterW( bufferW, namesize)) {
3903 retval = FALSE;
3904 goto end;
3907 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3908 NULL, NULL);
3909 if (!*namesize)
3911 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3912 retval = FALSE;
3914 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3916 end:
3917 HeapFree( GetProcessHeap(), 0, bufferW);
3918 return retval;
3922 /******************************************************************************
3923 * SetPrinterDataExA (WINSPOOL.@)
3925 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3926 LPCSTR pValueName, DWORD Type,
3927 LPBYTE pData, DWORD cbData)
3929 HKEY hkeyPrinter, hkeySubkey;
3930 DWORD ret;
3932 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3933 debugstr_a(pValueName), Type, pData, cbData);
3935 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3936 != ERROR_SUCCESS)
3937 return ret;
3939 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3940 != ERROR_SUCCESS) {
3941 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3942 RegCloseKey(hkeyPrinter);
3943 return ret;
3945 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3946 RegCloseKey(hkeySubkey);
3947 RegCloseKey(hkeyPrinter);
3948 return ret;
3951 /******************************************************************************
3952 * SetPrinterDataExW (WINSPOOL.@)
3954 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3955 LPCWSTR pValueName, DWORD Type,
3956 LPBYTE pData, DWORD cbData)
3958 HKEY hkeyPrinter, hkeySubkey;
3959 DWORD ret;
3961 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3962 debugstr_w(pValueName), Type, pData, cbData);
3964 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3965 != ERROR_SUCCESS)
3966 return ret;
3968 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3969 != ERROR_SUCCESS) {
3970 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3971 RegCloseKey(hkeyPrinter);
3972 return ret;
3974 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3975 RegCloseKey(hkeySubkey);
3976 RegCloseKey(hkeyPrinter);
3977 return ret;
3980 /******************************************************************************
3981 * SetPrinterDataA (WINSPOOL.@)
3983 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3984 LPBYTE pData, DWORD cbData)
3986 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3987 pData, cbData);
3990 /******************************************************************************
3991 * SetPrinterDataW (WINSPOOL.@)
3993 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3994 LPBYTE pData, DWORD cbData)
3996 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3997 pData, cbData);
4000 /******************************************************************************
4001 * GetPrinterDataExA (WINSPOOL.@)
4003 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4004 LPCSTR pValueName, LPDWORD pType,
4005 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4007 HKEY hkeyPrinter, hkeySubkey;
4008 DWORD ret;
4010 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4011 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4012 pcbNeeded);
4014 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4015 != ERROR_SUCCESS)
4016 return ret;
4018 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4019 != ERROR_SUCCESS) {
4020 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4021 RegCloseKey(hkeyPrinter);
4022 return ret;
4024 *pcbNeeded = nSize;
4025 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4026 RegCloseKey(hkeySubkey);
4027 RegCloseKey(hkeyPrinter);
4028 return ret;
4031 /******************************************************************************
4032 * GetPrinterDataExW (WINSPOOL.@)
4034 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4035 LPCWSTR pValueName, LPDWORD pType,
4036 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4038 HKEY hkeyPrinter, hkeySubkey;
4039 DWORD ret;
4041 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4042 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4043 pcbNeeded);
4045 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4046 != ERROR_SUCCESS)
4047 return ret;
4049 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4050 != ERROR_SUCCESS) {
4051 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4052 RegCloseKey(hkeyPrinter);
4053 return ret;
4055 *pcbNeeded = nSize;
4056 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4057 RegCloseKey(hkeySubkey);
4058 RegCloseKey(hkeyPrinter);
4059 return ret;
4062 /******************************************************************************
4063 * GetPrinterDataA (WINSPOOL.@)
4065 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4066 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4068 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4069 pData, nSize, pcbNeeded);
4072 /******************************************************************************
4073 * GetPrinterDataW (WINSPOOL.@)
4075 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4076 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4078 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4079 pData, nSize, pcbNeeded);
4082 /*******************************************************************************
4083 * EnumPrinterDataExW [WINSPOOL.@]
4085 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4086 LPBYTE pEnumValues, DWORD cbEnumValues,
4087 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4089 HKEY hkPrinter, hkSubKey;
4090 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4091 cbValueNameLen, cbMaxValueLen, cbValueLen,
4092 cbBufSize, dwType;
4093 LPWSTR lpValueName;
4094 HANDLE hHeap;
4095 PBYTE lpValue;
4096 PPRINTER_ENUM_VALUESW ppev;
4098 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4100 if (pKeyName == NULL || *pKeyName == 0)
4101 return ERROR_INVALID_PARAMETER;
4103 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4104 if (ret != ERROR_SUCCESS)
4106 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4107 hPrinter, ret);
4108 return ret;
4111 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4112 if (ret != ERROR_SUCCESS)
4114 r = RegCloseKey (hkPrinter);
4115 if (r != ERROR_SUCCESS)
4116 WARN ("RegCloseKey returned %li\n", r);
4117 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4118 debugstr_w (pKeyName), ret);
4119 return ret;
4122 ret = RegCloseKey (hkPrinter);
4123 if (ret != ERROR_SUCCESS)
4125 ERR ("RegCloseKey returned %li\n", ret);
4126 r = RegCloseKey (hkSubKey);
4127 if (r != ERROR_SUCCESS)
4128 WARN ("RegCloseKey returned %li\n", r);
4129 return ret;
4132 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4133 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4134 if (ret != ERROR_SUCCESS)
4136 r = RegCloseKey (hkSubKey);
4137 if (r != ERROR_SUCCESS)
4138 WARN ("RegCloseKey returned %li\n", r);
4139 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4140 return ret;
4143 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4144 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4146 if (cValues == 0) /* empty key */
4148 r = RegCloseKey (hkSubKey);
4149 if (r != ERROR_SUCCESS)
4150 WARN ("RegCloseKey returned %li\n", r);
4151 *pcbEnumValues = *pnEnumValues = 0;
4152 return ERROR_SUCCESS;
4155 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4157 hHeap = GetProcessHeap ();
4158 if (hHeap == NULL)
4160 ERR ("GetProcessHeap failed\n");
4161 r = RegCloseKey (hkSubKey);
4162 if (r != ERROR_SUCCESS)
4163 WARN ("RegCloseKey returned %li\n", r);
4164 return ERROR_OUTOFMEMORY;
4167 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4168 if (lpValueName == NULL)
4170 ERR ("Failed to allocate %li bytes from process heap\n",
4171 cbMaxValueNameLen * sizeof (WCHAR));
4172 r = RegCloseKey (hkSubKey);
4173 if (r != ERROR_SUCCESS)
4174 WARN ("RegCloseKey returned %li\n", r);
4175 return ERROR_OUTOFMEMORY;
4178 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4179 if (lpValue == NULL)
4181 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4182 if (HeapFree (hHeap, 0, lpValueName) == 0)
4183 WARN ("HeapFree failed with code %li\n", GetLastError ());
4184 r = RegCloseKey (hkSubKey);
4185 if (r != ERROR_SUCCESS)
4186 WARN ("RegCloseKey returned %li\n", r);
4187 return ERROR_OUTOFMEMORY;
4190 TRACE ("pass 1: calculating buffer required for all names and values\n");
4192 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4194 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4196 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4198 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4199 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4200 NULL, NULL, lpValue, &cbValueLen);
4201 if (ret != ERROR_SUCCESS)
4203 if (HeapFree (hHeap, 0, lpValue) == 0)
4204 WARN ("HeapFree failed with code %li\n", GetLastError ());
4205 if (HeapFree (hHeap, 0, lpValueName) == 0)
4206 WARN ("HeapFree failed with code %li\n", GetLastError ());
4207 r = RegCloseKey (hkSubKey);
4208 if (r != ERROR_SUCCESS)
4209 WARN ("RegCloseKey returned %li\n", r);
4210 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4211 return ret;
4214 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4215 debugstr_w (lpValueName), dwIndex,
4216 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4218 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4219 cbBufSize += cbValueLen;
4222 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4224 *pcbEnumValues = cbBufSize;
4225 *pnEnumValues = cValues;
4227 if (cbEnumValues < cbBufSize) /* buffer too small */
4229 if (HeapFree (hHeap, 0, lpValue) == 0)
4230 WARN ("HeapFree failed with code %li\n", GetLastError ());
4231 if (HeapFree (hHeap, 0, lpValueName) == 0)
4232 WARN ("HeapFree failed with code %li\n", GetLastError ());
4233 r = RegCloseKey (hkSubKey);
4234 if (r != ERROR_SUCCESS)
4235 WARN ("RegCloseKey returned %li\n", r);
4236 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4237 return ERROR_MORE_DATA;
4240 TRACE ("pass 2: copying all names and values to buffer\n");
4242 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4243 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4245 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4247 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4248 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4249 NULL, &dwType, lpValue, &cbValueLen);
4250 if (ret != ERROR_SUCCESS)
4252 if (HeapFree (hHeap, 0, lpValue) == 0)
4253 WARN ("HeapFree failed with code %li\n", GetLastError ());
4254 if (HeapFree (hHeap, 0, lpValueName) == 0)
4255 WARN ("HeapFree failed with code %li\n", GetLastError ());
4256 r = RegCloseKey (hkSubKey);
4257 if (r != ERROR_SUCCESS)
4258 WARN ("RegCloseKey returned %li\n", r);
4259 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4260 return ret;
4263 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4264 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4265 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4266 pEnumValues += cbValueNameLen;
4268 /* return # of *bytes* (including trailing \0), not # of chars */
4269 ppev[dwIndex].cbValueName = cbValueNameLen;
4271 ppev[dwIndex].dwType = dwType;
4273 memcpy (pEnumValues, lpValue, cbValueLen);
4274 ppev[dwIndex].pData = pEnumValues;
4275 pEnumValues += cbValueLen;
4277 ppev[dwIndex].cbData = cbValueLen;
4279 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4280 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4283 if (HeapFree (hHeap, 0, lpValue) == 0)
4285 ret = GetLastError ();
4286 ERR ("HeapFree failed with code %li\n", ret);
4287 if (HeapFree (hHeap, 0, lpValueName) == 0)
4288 WARN ("HeapFree failed with code %li\n", GetLastError ());
4289 r = RegCloseKey (hkSubKey);
4290 if (r != ERROR_SUCCESS)
4291 WARN ("RegCloseKey returned %li\n", r);
4292 return ret;
4295 if (HeapFree (hHeap, 0, lpValueName) == 0)
4297 ret = GetLastError ();
4298 ERR ("HeapFree failed with code %li\n", ret);
4299 r = RegCloseKey (hkSubKey);
4300 if (r != ERROR_SUCCESS)
4301 WARN ("RegCloseKey returned %li\n", r);
4302 return ret;
4305 ret = RegCloseKey (hkSubKey);
4306 if (ret != ERROR_SUCCESS)
4308 ERR ("RegCloseKey returned %li\n", ret);
4309 return ret;
4312 return ERROR_SUCCESS;
4315 /*******************************************************************************
4316 * EnumPrinterDataExA [WINSPOOL.@]
4318 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4319 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4320 * what Windows 2000 SP1 does.
4323 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4324 LPBYTE pEnumValues, DWORD cbEnumValues,
4325 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4327 INT len;
4328 LPWSTR pKeyNameW;
4329 DWORD ret, dwIndex, dwBufSize;
4330 HANDLE hHeap;
4331 LPSTR pBuffer;
4333 TRACE ("%p %s\n", hPrinter, pKeyName);
4335 if (pKeyName == NULL || *pKeyName == 0)
4336 return ERROR_INVALID_PARAMETER;
4338 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4339 if (len == 0)
4341 ret = GetLastError ();
4342 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4343 return ret;
4346 hHeap = GetProcessHeap ();
4347 if (hHeap == NULL)
4349 ERR ("GetProcessHeap failed\n");
4350 return ERROR_OUTOFMEMORY;
4353 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4354 if (pKeyNameW == NULL)
4356 ERR ("Failed to allocate %li bytes from process heap\n",
4357 (LONG) len * sizeof (WCHAR));
4358 return ERROR_OUTOFMEMORY;
4361 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4363 ret = GetLastError ();
4364 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4365 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4366 WARN ("HeapFree failed with code %li\n", GetLastError ());
4367 return ret;
4370 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4371 pcbEnumValues, pnEnumValues);
4372 if (ret != ERROR_SUCCESS)
4374 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4375 WARN ("HeapFree failed with code %li\n", GetLastError ());
4376 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4377 return ret;
4380 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4382 ret = GetLastError ();
4383 ERR ("HeapFree failed with code %li\n", ret);
4384 return ret;
4387 if (*pnEnumValues == 0) /* empty key */
4388 return ERROR_SUCCESS;
4390 dwBufSize = 0;
4391 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4393 PPRINTER_ENUM_VALUESW ppev =
4394 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4396 if (dwBufSize < ppev->cbValueName)
4397 dwBufSize = ppev->cbValueName;
4399 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4400 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4401 dwBufSize = ppev->cbData;
4404 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4406 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4407 if (pBuffer == NULL)
4409 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4410 return ERROR_OUTOFMEMORY;
4413 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4415 PPRINTER_ENUM_VALUESW ppev =
4416 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4418 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4419 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4420 NULL);
4421 if (len == 0)
4423 ret = GetLastError ();
4424 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4425 if (HeapFree (hHeap, 0, pBuffer) == 0)
4426 WARN ("HeapFree failed with code %li\n", GetLastError ());
4427 return ret;
4430 memcpy (ppev->pValueName, pBuffer, len);
4432 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4434 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4435 ppev->dwType != REG_MULTI_SZ)
4436 continue;
4438 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4439 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4440 if (len == 0)
4442 ret = GetLastError ();
4443 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4444 if (HeapFree (hHeap, 0, pBuffer) == 0)
4445 WARN ("HeapFree failed with code %li\n", GetLastError ());
4446 return ret;
4449 memcpy (ppev->pData, pBuffer, len);
4451 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4452 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4455 if (HeapFree (hHeap, 0, pBuffer) == 0)
4457 ret = GetLastError ();
4458 ERR ("HeapFree failed with code %li\n", ret);
4459 return ret;
4462 return ERROR_SUCCESS;
4465 /******************************************************************************
4466 * AbortPrinter (WINSPOOL.@)
4468 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4470 FIXME("(%p), stub!\n", hPrinter);
4471 return TRUE;
4474 /******************************************************************************
4475 * AddPortA (WINSPOOL.@)
4477 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4479 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4480 return FALSE;
4483 /******************************************************************************
4484 * AddPortW (WINSPOOL.@)
4486 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4488 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4489 return FALSE;
4492 /******************************************************************************
4493 * AddPortExA (WINSPOOL.@)
4495 * Adds a print spooler port without presenting a user interface.
4497 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4499 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4500 lpBuffer, debugstr_a(lpMonitorName));
4501 return FALSE;
4504 /******************************************************************************
4505 * AddPortExW (WINSPOOL.@)
4507 * See AddPortExW.
4509 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4511 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4512 lpBuffer, debugstr_w(lpMonitorName));
4513 return FALSE;
4516 /******************************************************************************
4517 * AddPrinterConnectionA (WINSPOOL.@)
4519 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4521 FIXME("%s\n", debugstr_a(pName));
4522 return FALSE;
4525 /******************************************************************************
4526 * AddPrinterConnectionW (WINSPOOL.@)
4528 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4530 FIXME("%s\n", debugstr_w(pName));
4531 return FALSE;
4534 /******************************************************************************
4535 * AddPrinterDriverExW (WINSPOOL.@)
4537 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4538 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4540 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4541 Level, pDriverInfo, dwFileCopyFlags);
4542 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4543 return FALSE;
4546 /******************************************************************************
4547 * AddPrinterDriverExA (WINSPOOL.@)
4549 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4550 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4552 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4553 Level, pDriverInfo, dwFileCopyFlags);
4554 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4555 return FALSE;
4558 /******************************************************************************
4559 * ConfigurePortA (WINSPOOL.@)
4561 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4563 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4564 return FALSE;
4567 /******************************************************************************
4568 * ConfigurePortW (WINSPOOL.@)
4570 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4572 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4573 return FALSE;
4576 /******************************************************************************
4577 * ConnectToPrinterDlg (WINSPOOL.@)
4579 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4581 FIXME("%p %lx\n", hWnd, Flags);
4582 return NULL;
4585 /******************************************************************************
4586 * DeletePrinterConnectionA (WINSPOOL.@)
4588 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4590 FIXME("%s\n", debugstr_a(pName));
4591 return TRUE;
4594 /******************************************************************************
4595 * DeletePrinterConnectionW (WINSPOOL.@)
4597 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4599 FIXME("%s\n", debugstr_w(pName));
4600 return TRUE;
4603 /******************************************************************************
4604 * DeletePrinterDriverExW (WINSPOOL.@)
4606 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4607 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4609 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4610 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4611 return TRUE;
4614 /******************************************************************************
4615 * DeletePrinterDriverExA (WINSPOOL.@)
4617 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4618 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4620 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4621 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4622 return TRUE;
4625 /******************************************************************************
4626 * DeletePrinterDataExW (WINSPOOL.@)
4628 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4629 LPCWSTR pValueName)
4631 FIXME("%p %s %s\n", hPrinter,
4632 debugstr_w(pKeyName), debugstr_w(pValueName));
4633 return ERROR_INVALID_PARAMETER;
4636 /******************************************************************************
4637 * DeletePrinterDataExA (WINSPOOL.@)
4639 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4640 LPCSTR pValueName)
4642 FIXME("%p %s %s\n", hPrinter,
4643 debugstr_a(pKeyName), debugstr_a(pValueName));
4644 return ERROR_INVALID_PARAMETER;
4647 /******************************************************************************
4648 * DeletePrintProcessorA (WINSPOOL.@)
4650 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4652 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4653 debugstr_a(pPrintProcessorName));
4654 return TRUE;
4657 /******************************************************************************
4658 * DeletePrintProcessorW (WINSPOOL.@)
4660 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4662 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4663 debugstr_w(pPrintProcessorName));
4664 return TRUE;
4667 /******************************************************************************
4668 * DeletePrintProvidorA (WINSPOOL.@)
4670 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4672 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4673 debugstr_a(pPrintProviderName));
4674 return TRUE;
4677 /******************************************************************************
4678 * DeletePrintProvidorW (WINSPOOL.@)
4680 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4682 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4683 debugstr_w(pPrintProviderName));
4684 return TRUE;
4687 /******************************************************************************
4688 * EnumFormsA (WINSPOOL.@)
4690 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4691 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4693 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4694 return FALSE;
4697 /******************************************************************************
4698 * EnumFormsW (WINSPOOL.@)
4700 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4701 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4703 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4704 return FALSE;
4707 /*****************************************************************************
4708 * EnumMonitorsA [WINSPOOL.@]
4711 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4712 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4714 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4715 cbBuf, pcbNeeded, pcReturned);
4716 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4717 return 0;
4720 /*****************************************************************************
4721 * EnumMonitorsW [WINSPOOL.@]
4724 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4725 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4727 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4728 cbBuf, pcbNeeded, pcReturned);
4729 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4730 return 0;
4733 /******************************************************************************
4734 * XcvDataW (WINSPOOL.@)
4736 * Notes:
4737 * There doesn't seem to be an A version...
4739 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4740 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4741 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4743 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4744 pInputData, cbInputData, pOutputData,
4745 cbOutputData, pcbOutputNeeded, pdwStatus);
4746 return FALSE;
4749 /*****************************************************************************
4750 * EnumPrinterDataA [WINSPOOL.@]
4753 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4754 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4755 DWORD cbData, LPDWORD pcbData )
4757 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4758 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4759 return ERROR_NO_MORE_ITEMS;
4762 /*****************************************************************************
4763 * EnumPrinterDataW [WINSPOOL.@]
4766 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4767 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4768 DWORD cbData, LPDWORD pcbData )
4770 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4771 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4772 return ERROR_NO_MORE_ITEMS;
4775 /*****************************************************************************
4776 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4779 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4780 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4781 LPDWORD pcbNeeded, LPDWORD pcReturned)
4783 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4784 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4785 pcbNeeded, pcReturned);
4786 return FALSE;
4789 /*****************************************************************************
4790 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4793 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4794 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4795 LPDWORD pcbNeeded, LPDWORD pcReturned)
4797 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4798 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4799 pcbNeeded, pcReturned);
4800 return FALSE;
4803 /*****************************************************************************
4804 * EnumPrintProcessorsA [WINSPOOL.@]
4807 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4808 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4810 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4811 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
4812 return FALSE;
4815 /*****************************************************************************
4816 * EnumPrintProcessorsW [WINSPOOL.@]
4819 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4820 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4822 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4823 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
4824 cbBuf, pcbNeeded, pcbReturned);
4825 return FALSE;
4828 /*****************************************************************************
4829 * ExtDeviceMode [WINSPOOL.@]
4832 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
4833 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
4834 DWORD fMode)
4836 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
4837 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
4838 debugstr_a(pProfile), fMode);
4839 return -1;
4842 /*****************************************************************************
4843 * FindClosePrinterChangeNotification [WINSPOOL.@]
4846 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
4848 FIXME("Stub: %p\n", hChange);
4849 return TRUE;
4852 /*****************************************************************************
4853 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4856 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
4857 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
4859 FIXME("Stub: %p %lx %lx %p\n",
4860 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
4861 return INVALID_HANDLE_VALUE;
4864 /*****************************************************************************
4865 * FindNextPrinterChangeNotification [WINSPOOL.@]
4868 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
4869 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
4871 FIXME("Stub: %p %p %p %p\n",
4872 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
4873 return FALSE;
4876 /*****************************************************************************
4877 * FreePrinterNotifyInfo [WINSPOOL.@]
4880 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
4882 FIXME("Stub: %p\n", pPrinterNotifyInfo);
4883 return TRUE;
4886 /*****************************************************************************
4887 * string_to_buf
4889 * Copies a unicode string into a buffer. The buffer will either contain unicode or
4890 * ansi depending on the unicode parameter.
4892 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
4894 if(!str)
4896 *size = 0;
4897 return TRUE;
4900 if(unicode)
4902 *size = (strlenW(str) + 1) * sizeof(WCHAR);
4903 if(*size <= cb)
4905 memcpy(ptr, str, *size);
4906 return TRUE;
4908 return FALSE;
4910 else
4912 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
4913 if(*size <= cb)
4915 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
4916 return TRUE;
4918 return FALSE;
4922 /*****************************************************************************
4923 * get_job_info_1
4925 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
4926 LPDWORD pcbNeeded, BOOL unicode)
4928 DWORD size, left = cbBuf;
4929 BOOL space = (cbBuf > 0);
4930 LPBYTE ptr = buf;
4932 *pcbNeeded = 0;
4934 if(space)
4936 ji1->JobId = job->job_id;
4939 string_to_buf(job->document_title, ptr, left, &size, unicode);
4940 if(space && size <= left)
4942 ji1->pDocument = (LPWSTR)ptr;
4943 ptr += size;
4944 left -= size;
4946 else
4947 space = FALSE;
4948 *pcbNeeded += size;
4950 return space;
4953 /*****************************************************************************
4954 * get_job_info_2
4956 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
4957 LPDWORD pcbNeeded, BOOL unicode)
4959 DWORD size, left = cbBuf;
4960 BOOL space = (cbBuf > 0);
4961 LPBYTE ptr = buf;
4963 *pcbNeeded = 0;
4965 if(space)
4967 ji2->JobId = job->job_id;
4970 string_to_buf(job->document_title, ptr, left, &size, unicode);
4971 if(space && size <= left)
4973 ji2->pDocument = (LPWSTR)ptr;
4974 ptr += size;
4975 left -= size;
4977 else
4978 space = FALSE;
4979 *pcbNeeded += size;
4981 return space;
4984 /*****************************************************************************
4985 * get_job_info
4987 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4988 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4990 BOOL ret = FALSE;
4991 DWORD needed = 0, size;
4992 job_t *job;
4993 LPBYTE ptr = pJob;
4995 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
4997 EnterCriticalSection(&printer_handles_cs);
4998 job = get_job(hPrinter, JobId);
4999 if(!job)
5000 goto end;
5002 switch(Level)
5004 case 1:
5005 size = sizeof(JOB_INFO_1W);
5006 if(cbBuf >= size)
5008 cbBuf -= size;
5009 ptr += size;
5010 memset(pJob, 0, size);
5012 else
5013 cbBuf = 0;
5014 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5015 needed += size;
5016 break;
5018 case 2:
5019 size = sizeof(JOB_INFO_2W);
5020 if(cbBuf >= size)
5022 cbBuf -= size;
5023 ptr += size;
5024 memset(pJob, 0, size);
5026 else
5027 cbBuf = 0;
5028 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5029 needed += size;
5030 break;
5032 case 3:
5033 size = sizeof(JOB_INFO_3);
5034 if(cbBuf >= size)
5036 cbBuf -= size;
5037 memset(pJob, 0, size);
5038 ret = TRUE;
5040 else
5041 cbBuf = 0;
5042 needed = size;
5043 break;
5045 default:
5046 SetLastError(ERROR_INVALID_LEVEL);
5047 goto end;
5049 if(pcbNeeded)
5050 *pcbNeeded = needed;
5051 end:
5052 LeaveCriticalSection(&printer_handles_cs);
5053 return ret;
5056 /*****************************************************************************
5057 * GetJobA [WINSPOOL.@]
5060 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5061 DWORD cbBuf, LPDWORD pcbNeeded)
5063 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5066 /*****************************************************************************
5067 * GetJobW [WINSPOOL.@]
5070 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5071 DWORD cbBuf, LPDWORD pcbNeeded)
5073 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5076 /*****************************************************************************
5077 * schedule_lpr
5079 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5081 char *unixname, *queue, *cmd;
5082 char fmt[] = "lpr -P%s %s";
5083 DWORD len;
5085 if(!(unixname = wine_get_unix_file_name(filename)))
5086 return FALSE;
5088 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5089 queue = HeapAlloc(GetProcessHeap(), 0, len);
5090 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5092 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5093 sprintf(cmd, fmt, queue, unixname);
5095 TRACE("printing with: %s\n", cmd);
5096 system(cmd);
5098 HeapFree(GetProcessHeap(), 0, cmd);
5099 HeapFree(GetProcessHeap(), 0, queue);
5100 HeapFree(GetProcessHeap(), 0, unixname);
5101 return TRUE;
5104 /*****************************************************************************
5105 * schedule_cups
5107 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5109 #if HAVE_CUPS_CUPS_H
5110 if(pcupsPrintFile)
5112 char *unixname, *queue, *doc_titleA;
5113 DWORD len;
5114 BOOL ret;
5116 if(!(unixname = wine_get_unix_file_name(filename)))
5117 return FALSE;
5119 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5120 queue = HeapAlloc(GetProcessHeap(), 0, len);
5121 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5123 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5124 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5125 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5127 TRACE("printing via cups\n");
5128 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5129 HeapFree(GetProcessHeap(), 0, doc_titleA);
5130 HeapFree(GetProcessHeap(), 0, queue);
5131 HeapFree(GetProcessHeap(), 0, unixname);
5132 return ret;
5134 else
5135 #endif
5137 return schedule_lpr(printer_name, filename);
5141 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5143 LPWSTR filename;
5145 switch(msg)
5147 case WM_INITDIALOG:
5148 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5149 return TRUE;
5151 case WM_COMMAND:
5152 if(HIWORD(wparam) == BN_CLICKED)
5154 if(LOWORD(wparam) == IDOK)
5156 HANDLE hf;
5157 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5158 LPWSTR *output;
5160 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5161 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5163 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5165 WCHAR caption[200], message[200];
5166 int mb_ret;
5168 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5169 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5170 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5171 if(mb_ret == IDCANCEL)
5173 HeapFree(GetProcessHeap(), 0, filename);
5174 return TRUE;
5177 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5178 if(hf == INVALID_HANDLE_VALUE)
5180 WCHAR caption[200], message[200];
5182 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5183 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5184 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5185 HeapFree(GetProcessHeap(), 0, filename);
5186 return TRUE;
5188 CloseHandle(hf);
5189 DeleteFileW(filename);
5190 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5191 *output = filename;
5192 EndDialog(hwnd, IDOK);
5193 return TRUE;
5195 if(LOWORD(wparam) == IDCANCEL)
5197 EndDialog(hwnd, IDCANCEL);
5198 return TRUE;
5201 return FALSE;
5203 return FALSE;
5206 /*****************************************************************************
5207 * get_filename
5209 static BOOL get_filename(LPWSTR *filename)
5211 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
5212 file_dlg_proc, (LPARAM)filename) == IDOK;
5215 /*****************************************************************************
5216 * schedule_file
5218 static BOOL schedule_file(LPCWSTR filename)
5220 LPWSTR output = NULL;
5222 if(get_filename(&output))
5224 TRACE("copy to %s\n", debugstr_w(output));
5225 CopyFileW(filename, output, FALSE);
5226 HeapFree(GetProcessHeap(), 0, output);
5227 return TRUE;
5229 return FALSE;
5232 /*****************************************************************************
5233 * schedule_pipe
5235 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
5237 #ifdef HAVE_FORK
5238 char *unixname, *cmdA;
5239 DWORD len;
5240 int fds[2] = {-1, -1}, file_fd = -1, no_read;
5241 BOOL ret = FALSE;
5242 char buf[1024];
5244 if(!(unixname = wine_get_unix_file_name(filename)))
5245 return FALSE;
5247 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
5248 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
5249 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
5251 TRACE("printing with: %s\n", cmdA);
5253 if((file_fd = open(unixname, O_RDONLY)) == -1)
5254 goto end;
5256 if (pipe(fds))
5258 ERR("pipe() failed!\n");
5259 goto end;
5262 if (fork() == 0)
5264 close(0);
5265 dup2(fds[0], 0);
5266 close(fds[1]);
5268 /* reset signals that we previously set to SIG_IGN */
5269 signal(SIGPIPE, SIG_DFL);
5270 signal(SIGCHLD, SIG_DFL);
5272 system(cmdA);
5273 exit(0);
5276 while((no_read = read(file_fd, buf, sizeof(buf))))
5277 write(fds[1], buf, no_read);
5279 ret = TRUE;
5281 end:
5282 if(file_fd != -1) close(file_fd);
5283 if(fds[0] != -1) close(fds[0]);
5284 if(fds[1] != -1) close(fds[1]);
5286 HeapFree(GetProcessHeap(), 0, cmdA);
5287 HeapFree(GetProcessHeap(), 0, unixname);
5288 return ret;
5289 #else
5290 return FALSE;
5291 #endif
5294 /*****************************************************************************
5295 * schedule_unixfile
5297 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
5299 int in_fd, out_fd, no_read;
5300 char buf[1024];
5301 BOOL ret = FALSE;
5302 char *unixname, *outputA;
5303 DWORD len;
5305 if(!(unixname = wine_get_unix_file_name(filename)))
5306 return FALSE;
5308 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
5309 outputA = HeapAlloc(GetProcessHeap(), 0, len);
5310 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
5312 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5313 in_fd = open(unixname, O_RDONLY);
5314 if(out_fd == -1 || in_fd == -1)
5315 goto end;
5317 while((no_read = read(in_fd, buf, sizeof(buf))))
5318 write(out_fd, buf, no_read);
5320 ret = TRUE;
5321 end:
5322 if(in_fd != -1) close(in_fd);
5323 if(out_fd != -1) close(out_fd);
5324 HeapFree(GetProcessHeap(), 0, outputA);
5325 HeapFree(GetProcessHeap(), 0, unixname);
5326 return ret;
5329 /*****************************************************************************
5330 * ScheduleJob [WINSPOOL.@]
5333 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
5335 opened_printer_t *printer;
5336 BOOL ret = FALSE;
5337 struct list *cursor, *cursor2;
5339 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
5340 EnterCriticalSection(&printer_handles_cs);
5341 printer = get_opened_printer(hPrinter);
5342 if(!printer)
5343 goto end;
5345 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
5347 job_t *job = LIST_ENTRY(cursor, job_t, entry);
5348 HANDLE hf;
5350 if(job->job_id != dwJobID) continue;
5352 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
5353 if(hf != INVALID_HANDLE_VALUE)
5355 PRINTER_INFO_5W *pi5;
5356 DWORD needed;
5357 HKEY hkey;
5358 WCHAR output[1024];
5359 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5360 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5362 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
5363 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
5364 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
5365 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
5366 debugstr_w(pi5->pPortName));
5368 output[0] = 0;
5370 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5371 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
5373 DWORD type, count = sizeof(output);
5374 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
5375 RegCloseKey(hkey);
5377 if(output[0] == '|')
5379 schedule_pipe(output + 1, job->filename);
5381 else if(output[0])
5383 schedule_unixfile(output, job->filename);
5385 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
5387 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
5389 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
5391 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
5393 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
5395 schedule_file(job->filename);
5397 else
5399 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
5401 HeapFree(GetProcessHeap(), 0, pi5);
5402 CloseHandle(hf);
5403 DeleteFileW(job->filename);
5405 list_remove(cursor);
5406 HeapFree(GetProcessHeap(), 0, job->document_title);
5407 HeapFree(GetProcessHeap(), 0, job->filename);
5408 HeapFree(GetProcessHeap(), 0, job);
5409 ret = TRUE;
5410 break;
5412 end:
5413 LeaveCriticalSection(&printer_handles_cs);
5414 return ret;
5417 /*****************************************************************************
5418 * StartDocDlgA [WINSPOOL.@]
5420 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
5422 UNICODE_STRING usBuffer;
5423 DOCINFOW docW;
5424 LPWSTR retW;
5425 LPSTR ret = NULL;
5427 docW.cbSize = sizeof(docW);
5428 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
5429 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
5430 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
5431 docW.fwType = doc->fwType;
5433 retW = StartDocDlgW(hPrinter, &docW);
5435 if(retW)
5437 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
5438 ret = HeapAlloc(GetProcessHeap(), 0, len);
5439 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
5440 HeapFree(GetProcessHeap(), 0, retW);
5443 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
5444 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
5445 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
5447 return ret;
5450 /*****************************************************************************
5451 * StartDocDlgW [WINSPOOL.@]
5453 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5454 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5455 * port is "FILE:". Also returns the full path if passed a relative path.
5457 * The caller should free the returned string from the process heap.
5459 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
5461 LPWSTR ret = NULL;
5462 DWORD len, attr;
5464 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
5466 PRINTER_INFO_5W *pi5;
5467 GetPrinterW(hPrinter, 5, NULL, 0, &len);
5468 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
5469 return NULL;
5470 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
5471 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
5472 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
5474 HeapFree(GetProcessHeap(), 0, pi5);
5475 return NULL;
5477 HeapFree(GetProcessHeap(), 0, pi5);
5480 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
5482 LPWSTR name;
5483 get_filename(&name);
5484 if(name)
5486 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
5488 HeapFree(GetProcessHeap(), 0, name);
5489 return NULL;
5491 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5492 GetFullPathNameW(name, len, ret, NULL);
5493 HeapFree(GetProcessHeap(), 0, name);
5495 return ret;
5498 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
5499 return NULL;
5501 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5502 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
5504 attr = GetFileAttributesW(ret);
5505 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
5507 HeapFree(GetProcessHeap(), 0, ret);
5508 ret = NULL;
5510 return ret;