Added OLEIVERB_INPLACEACTIVATE implementation in IOleObject::DoVerb.
[wine.git] / dlls / winspool / info.c
blobe7d822d77cd87bf98c89d542f1e4da8d10d510e9
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stddef.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <signal.h>
38 #ifdef HAVE_CUPS_CUPS_H
39 # include <cups/cups.h>
40 # ifndef SONAME_LIBCUPS
41 # define SONAME_LIBCUPS "libcups.so"
42 # endif
43 #endif
45 #define NONAMELESSUNION
46 #define NONAMELESSSTRUCT
47 #include "wine/library.h"
48 #include "windef.h"
49 #include "winbase.h"
50 #include "winuser.h"
51 #include "winerror.h"
52 #include "winreg.h"
53 #include "wingdi.h"
54 #include "winspool.h"
55 #include "winternl.h"
56 #include "wine/windef16.h"
57 #include "wine/unicode.h"
58 #include "wine/debug.h"
59 #include "wine/list.h"
60 #include "heap.h"
61 #include "winnls.h"
63 #include "wspool.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
76 typedef struct {
77 DWORD job_id;
78 HANDLE hf;
79 } started_doc_t;
81 typedef struct {
82 struct list jobs;
83 LONG ref;
84 } jobqueue_t;
86 typedef struct {
87 LPWSTR name;
88 jobqueue_t *queue;
89 started_doc_t *doc;
90 } opened_printer_t;
92 typedef struct {
93 struct list entry;
94 DWORD job_id;
95 WCHAR *filename;
96 WCHAR *document_title;
97 } job_t;
99 static opened_printer_t **printer_handles;
100 static int nb_printer_handles;
101 static LONG next_job_id = 1;
103 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
104 WORD fwCapability, LPSTR lpszOutput,
105 LPDEVMODEA lpdm );
106 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
107 LPSTR lpszDevice, LPSTR lpszPort,
108 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
109 DWORD fwMode );
111 static const char Printers[] =
112 "System\\CurrentControlSet\\control\\Print\\Printers\\";
114 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
115 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
116 'c','o','n','t','r','o','l','\\',
117 'P','r','i','n','t','\\',
118 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
119 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
121 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
122 'M','i','c','r','o','s','o','f','t','\\',
123 'W','i','n','d','o','w','s',' ','N','T','\\',
124 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
125 'W','i','n','d','o','w','s',0};
127 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
128 'M','i','c','r','o','s','o','f','t','\\',
129 'W','i','n','d','o','w','s',' ','N','T','\\',
130 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
131 'D','e','v','i','c','e','s',0};
133 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
135 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
136 'i','o','n',' ','F','i','l','e',0};
137 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
138 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
139 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
140 'M','o','d','e',0};
141 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
142 'i','l','e','s',0};
143 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
144 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
145 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
146 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
147 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
148 static const WCHAR NameW[] = {'N','a','m','e',0};
149 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
150 static const WCHAR PortW[] = {'P','o','r','t',0};
151 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
152 's','s','o','r',0};
153 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
154 'v','e','r',0};
155 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
156 'v','e','r','D','a','t','a',0};
157 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
158 'i','l','e',0};
159 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
160 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
161 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
162 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
163 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
164 static const WCHAR emptyStringW[] = {0};
166 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
168 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
169 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
170 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
172 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
173 'D','o','c','u','m','e','n','t',0};
175 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
176 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
177 DWORD Level, LPBYTE pDriverInfo,
178 DWORD cbBuf, LPDWORD pcbNeeded,
179 BOOL unicode);
180 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
182 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
183 if passed a NULL string. This returns NULLs to the result.
185 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
187 if ( (src) )
189 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
190 return usBufferPtr->Buffer;
192 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
193 return NULL;
196 static LPWSTR strdupW(LPCWSTR p)
198 LPWSTR ret;
199 DWORD len;
201 if(!p) return NULL;
202 len = (strlenW(p) + 1) * sizeof(WCHAR);
203 ret = HeapAlloc(GetProcessHeap(), 0, len);
204 memcpy(ret, p, len);
205 return ret;
208 static void
209 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
210 char qbuf[200];
212 /* If forcing, or no profile string entry for device yet, set the entry
214 * The always change entry if not WINEPS yet is discussable.
216 if (force ||
217 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
218 !strcmp(qbuf,"*") ||
219 !strstr(qbuf,"WINEPS.DRV")
221 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
222 HKEY hkey;
224 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
225 WriteProfileStringA("windows","device",buf);
226 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
227 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
228 RegCloseKey(hkey);
230 HeapFree(GetProcessHeap(),0,buf);
234 #ifdef HAVE_CUPS_CUPS_H
235 static typeof(cupsGetDests) *pcupsGetDests;
236 static typeof(cupsGetPPD) *pcupsGetPPD;
237 static typeof(cupsPrintFile) *pcupsPrintFile;
238 static void *cupshandle;
240 static BOOL CUPS_LoadPrinters(void)
242 int i, nrofdests;
243 BOOL hadprinter = FALSE;
244 cups_dest_t *dests;
245 PRINTER_INFO_2A pinfo2a;
246 char *port,*devline;
247 HKEY hkeyPrinter, hkeyPrinters, hkey;
249 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
250 if (!cupshandle)
251 return FALSE;
252 TRACE("loaded %s\n", SONAME_LIBCUPS);
254 #define DYNCUPS(x) \
255 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
256 if (!p##x) return FALSE;
258 DYNCUPS(cupsGetPPD);
259 DYNCUPS(cupsGetDests);
260 DYNCUPS(cupsPrintFile);
261 #undef DYNCUPS
263 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
264 ERROR_SUCCESS) {
265 ERR("Can't create Printers key\n");
266 return FALSE;
269 nrofdests = pcupsGetDests(&dests);
270 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
271 for (i=0;i<nrofdests;i++) {
272 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
273 sprintf(port,"LPR:%s",dests[i].name);
274 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
275 sprintf(devline,"WINEPS.DRV,%s",port);
276 WriteProfileStringA("devices",dests[i].name,devline);
277 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
278 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
279 RegCloseKey(hkey);
281 HeapFree(GetProcessHeap(),0,devline);
283 TRACE("Printer %d: %s\n", i, dests[i].name);
284 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
285 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
286 and continue */
287 TRACE("Printer already exists\n");
288 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
289 RegCloseKey(hkeyPrinter);
290 } else {
291 memset(&pinfo2a,0,sizeof(pinfo2a));
292 pinfo2a.pPrinterName = dests[i].name;
293 pinfo2a.pDatatype = "RAW";
294 pinfo2a.pPrintProcessor = "WinPrint";
295 pinfo2a.pDriverName = "PS Driver";
296 pinfo2a.pComment = "WINEPS Printer using CUPS";
297 pinfo2a.pLocation = "<physical location of printer>";
298 pinfo2a.pPortName = port;
299 pinfo2a.pParameters = "<parameters?>";
300 pinfo2a.pShareName = "<share name?>";
301 pinfo2a.pSepFile = "<sep file?>";
303 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
304 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
305 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
308 HeapFree(GetProcessHeap(),0,port);
310 hadprinter = TRUE;
311 if (dests[i].is_default)
312 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
314 RegCloseKey(hkeyPrinters);
315 return hadprinter;
317 #endif
319 static BOOL
320 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
321 PRINTER_INFO_2A pinfo2a;
322 char *e,*s,*name,*prettyname,*devname;
323 BOOL ret = FALSE, set_default = FALSE;
324 char *port,*devline,*env_default;
325 HKEY hkeyPrinter, hkeyPrinters, hkey;
327 while (isspace(*pent)) pent++;
328 s = strchr(pent,':');
329 if(s) *s='\0';
330 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
331 strcpy(name,pent);
332 if(s) {
333 *s=':';
334 pent = s;
335 } else
336 pent = "";
338 TRACE("name=%s entry=%s\n",name, pent);
340 if(ispunct(*name)) { /* a tc entry, not a real printer */
341 TRACE("skipping tc entry\n");
342 goto end;
345 if(strstr(pent,":server")) { /* server only version so skip */
346 TRACE("skipping server entry\n");
347 goto end;
350 /* Determine whether this is a postscript printer. */
352 ret = TRUE;
353 env_default = getenv("PRINTER");
354 prettyname = name;
355 /* Get longest name, usually the one at the right for later display. */
356 while((s=strchr(prettyname,'|'))) {
357 *s = '\0';
358 e = s;
359 while(isspace(*--e)) *e = '\0';
360 TRACE("\t%s\n", debugstr_a(prettyname));
361 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
362 for(prettyname = s+1; isspace(*prettyname); prettyname++)
365 e = prettyname + strlen(prettyname);
366 while(isspace(*--e)) *e = '\0';
367 TRACE("\t%s\n", debugstr_a(prettyname));
368 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
370 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
371 * if it is too long, we use it as comment below. */
372 devname = prettyname;
373 if (strlen(devname)>=CCHDEVICENAME-1)
374 devname = name;
375 if (strlen(devname)>=CCHDEVICENAME-1) {
376 ret = FALSE;
377 goto end;
380 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
381 sprintf(port,"LPR:%s",name);
383 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
384 sprintf(devline,"WINEPS.DRV,%s",port);
385 WriteProfileStringA("devices",devname,devline);
386 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
387 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
388 RegCloseKey(hkey);
390 HeapFree(GetProcessHeap(),0,devline);
392 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
393 ERROR_SUCCESS) {
394 ERR("Can't create Printers key\n");
395 ret = FALSE;
396 goto end;
398 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
399 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
400 and continue */
401 TRACE("Printer already exists\n");
402 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
403 RegCloseKey(hkeyPrinter);
404 } else {
405 memset(&pinfo2a,0,sizeof(pinfo2a));
406 pinfo2a.pPrinterName = devname;
407 pinfo2a.pDatatype = "RAW";
408 pinfo2a.pPrintProcessor = "WinPrint";
409 pinfo2a.pDriverName = "PS Driver";
410 pinfo2a.pComment = "WINEPS Printer using LPR";
411 pinfo2a.pLocation = prettyname;
412 pinfo2a.pPortName = port;
413 pinfo2a.pParameters = "<parameters?>";
414 pinfo2a.pShareName = "<share name?>";
415 pinfo2a.pSepFile = "<sep file?>";
417 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
418 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
419 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
422 RegCloseKey(hkeyPrinters);
424 if (isfirst || set_default)
425 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
427 HeapFree(GetProcessHeap(), 0, port);
428 end:
429 HeapFree(GetProcessHeap(), 0, name);
430 return ret;
433 static BOOL
434 PRINTCAP_LoadPrinters(void) {
435 BOOL hadprinter = FALSE;
436 char buf[200];
437 FILE *f;
438 char *pent = NULL;
439 BOOL had_bash = FALSE;
441 f = fopen("/etc/printcap","r");
442 if (!f)
443 return FALSE;
445 while(fgets(buf,sizeof(buf),f)) {
446 char *start, *end;
448 end=strchr(buf,'\n');
449 if (end) *end='\0';
451 start = buf;
452 while(isspace(*start)) start++;
453 if(*start == '#' || *start == '\0')
454 continue;
456 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
457 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
458 HeapFree(GetProcessHeap(),0,pent);
459 pent = NULL;
462 if (end && *--end == '\\') {
463 *end = '\0';
464 had_bash = TRUE;
465 } else
466 had_bash = FALSE;
468 if (pent) {
469 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
470 strcat(pent,start);
471 } else {
472 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
473 strcpy(pent,start);
477 if(pent) {
478 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
479 HeapFree(GetProcessHeap(),0,pent);
481 fclose(f);
482 return hadprinter;
485 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
487 if (value)
488 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
489 lstrlenW(value) * sizeof(WCHAR));
490 else
491 return ERROR_FILE_NOT_FOUND;
494 void WINSPOOL_LoadSystemPrinters(void)
496 HKEY hkey, hkeyPrinters;
497 DRIVER_INFO_3A di3a;
498 HANDLE hprn;
499 DWORD needed, num, i;
500 WCHAR PrinterName[256];
501 BOOL done = FALSE;
503 di3a.cVersion = 0x400;
504 di3a.pName = "PS Driver";
505 di3a.pEnvironment = NULL; /* NULL means auto */
506 di3a.pDriverPath = "wineps16";
507 di3a.pDataFile = "<datafile?>";
508 di3a.pConfigFile = "wineps16";
509 di3a.pHelpFile = "<helpfile?>";
510 di3a.pDependentFiles = "<dependend files?>";
511 di3a.pMonitorName = "<monitor name?>";
512 di3a.pDefaultDataType = "RAW";
514 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
515 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
516 return;
519 /* This ensures that all printer entries have a valid Name value. If causes
520 problems later if they don't. If one is found to be missed we create one
521 and set it equal to the name of the key */
522 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
523 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
524 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
525 for(i = 0; i < num; i++) {
526 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
527 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
528 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
529 set_reg_szW(hkey, NameW, PrinterName);
531 RegCloseKey(hkey);
536 RegCloseKey(hkeyPrinters);
539 /* We want to avoid calling AddPrinter on printers as much as
540 possible, because on cups printers this will (eventually) lead
541 to a call to cupsGetPPD which takes forever, even with non-cups
542 printers AddPrinter takes a while. So we'll tag all printers that
543 were automatically added last time around, if they still exist
544 we'll leave them be otherwise we'll delete them. */
545 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
546 if(needed) {
547 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
548 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
549 for(i = 0; i < num; i++) {
550 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
551 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
552 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
553 DWORD dw = 1;
554 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
555 RegCloseKey(hkey);
557 ClosePrinter(hprn);
562 HeapFree(GetProcessHeap(), 0, pi);
566 #ifdef HAVE_CUPS_CUPS_H
567 done = CUPS_LoadPrinters();
568 #endif
570 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
571 /* Check for [ppd] section in config file before parsing /etc/printcap */
572 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
573 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
574 &hkey) == ERROR_SUCCESS) {
575 RegCloseKey(hkey);
576 PRINTCAP_LoadPrinters();
580 /* Now enumerate the list again and delete any printers that a still tagged */
581 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
582 if(needed) {
583 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
584 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
585 for(i = 0; i < num; i++) {
586 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
587 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
588 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
589 DWORD dw, type, size = sizeof(dw);
590 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
591 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
592 DeletePrinter(hprn);
594 RegCloseKey(hkey);
596 ClosePrinter(hprn);
601 HeapFree(GetProcessHeap(), 0, pi);
604 return;
609 /******************************************************************
610 * get_opened_printer_entry
611 * Get the first place empty in the opened printer table
613 static HANDLE get_opened_printer_entry( LPCWSTR name )
615 UINT_PTR handle = nb_printer_handles, i;
616 jobqueue_t *queue = NULL;
617 opened_printer_t *printer;
619 EnterCriticalSection(&printer_handles_cs);
621 for (i = 0; i < nb_printer_handles; i++)
623 if (!printer_handles[i])
625 if(handle == nb_printer_handles)
626 handle = i;
628 else if(!queue && !strcmpW(name, printer_handles[i]->name))
629 queue = printer_handles[i]->queue;
632 if (handle >= nb_printer_handles)
634 opened_printer_t **new_array;
635 if (printer_handles)
636 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
637 (nb_printer_handles + 16) * sizeof(*new_array) );
638 else
639 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
640 (nb_printer_handles + 16) * sizeof(*new_array) );
642 if (!new_array)
644 handle = 0;
645 goto end;
647 printer_handles = new_array;
648 nb_printer_handles += 16;
651 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
653 handle = 0;
654 goto end;
657 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
658 strcpyW(printer->name, name);
659 if(queue)
660 printer->queue = queue;
661 else
663 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
664 list_init(&printer->queue->jobs);
665 printer->queue->ref = 0;
667 InterlockedIncrement(&printer->queue->ref);
668 printer->doc = NULL;
670 printer_handles[handle] = printer;
671 handle++;
672 end:
673 LeaveCriticalSection(&printer_handles_cs);
675 return (HANDLE)handle;
678 /******************************************************************
679 * get_opened_printer
680 * Get the pointer to the opened printer referred by the handle
682 static opened_printer_t *get_opened_printer(HANDLE hprn)
684 UINT_PTR idx = (UINT_PTR)hprn;
685 opened_printer_t *ret = NULL;
687 EnterCriticalSection(&printer_handles_cs);
689 if ((idx <= 0) || (idx > nb_printer_handles))
690 goto end;
692 ret = printer_handles[idx - 1];
693 end:
694 LeaveCriticalSection(&printer_handles_cs);
695 return ret;
698 /******************************************************************
699 * get_opened_printer_name
700 * Get the pointer to the opened printer name referred by the handle
702 static LPCWSTR get_opened_printer_name(HANDLE hprn)
704 opened_printer_t *printer = get_opened_printer(hprn);
705 if(!printer) return NULL;
706 return printer->name;
709 /******************************************************************
710 * WINSPOOL_GetOpenedPrinterRegKey
713 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
715 LPCWSTR name = get_opened_printer_name(hPrinter);
716 DWORD ret;
717 HKEY hkeyPrinters;
719 if(!name) return ERROR_INVALID_HANDLE;
721 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
722 ERROR_SUCCESS)
723 return ret;
725 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
727 ERR("Can't find opened printer %s in registry\n",
728 debugstr_w(name));
729 RegCloseKey(hkeyPrinters);
730 return ERROR_INVALID_PRINTER_NAME; /* ? */
732 RegCloseKey(hkeyPrinters);
733 return ERROR_SUCCESS;
736 /******************************************************************
737 * get_job
739 * Get the pointer to the specified job.
740 * Should hold the printer_handles_cs before calling.
742 static job_t *get_job(HANDLE hprn, DWORD JobId)
744 opened_printer_t *printer = get_opened_printer(hprn);
745 job_t *job;
747 if(!printer) return NULL;
748 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
750 if(job->job_id == JobId)
751 return job;
753 return NULL;
756 /***********************************************************
757 * DEVMODEcpyAtoW
759 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
761 BOOL Formname;
762 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
763 DWORD size;
765 Formname = (dmA->dmSize > off_formname);
766 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
767 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
768 dmW->dmDeviceName, CCHDEVICENAME);
769 if(!Formname) {
770 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
771 dmA->dmSize - CCHDEVICENAME);
772 } else {
773 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
774 off_formname - CCHDEVICENAME);
775 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
776 dmW->dmFormName, CCHFORMNAME);
777 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
778 (off_formname + CCHFORMNAME));
780 dmW->dmSize = size;
781 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
782 dmA->dmDriverExtra);
783 return dmW;
786 /***********************************************************
787 * DEVMODEdupWtoA
788 * Creates an ascii copy of supplied devmode on heap
790 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
792 LPDEVMODEA dmA;
793 DWORD size;
794 BOOL Formname;
795 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
797 if(!dmW) return NULL;
798 Formname = (dmW->dmSize > off_formname);
799 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
800 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
801 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
802 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
803 if(!Formname) {
804 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
805 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
806 } else {
807 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
808 off_formname - CCHDEVICENAME * sizeof(WCHAR));
809 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
810 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
811 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
812 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
814 dmA->dmSize = size;
815 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
816 dmW->dmDriverExtra);
817 return dmA;
820 /***********************************************************
821 * PRINTER_INFO_2AtoW
822 * Creates a unicode copy of PRINTER_INFO_2A on heap
824 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
826 LPPRINTER_INFO_2W piW;
827 UNICODE_STRING usBuffer;
829 if(!piA) return NULL;
830 piW = HeapAlloc(heap, 0, sizeof(*piW));
831 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
833 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
834 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
835 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
836 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
837 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
838 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
839 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
840 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
841 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
842 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
843 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
844 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
845 return piW;
848 /***********************************************************
849 * FREE_PRINTER_INFO_2W
850 * Free PRINTER_INFO_2W and all strings
852 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
854 if(!piW) return;
856 HeapFree(heap,0,piW->pServerName);
857 HeapFree(heap,0,piW->pPrinterName);
858 HeapFree(heap,0,piW->pShareName);
859 HeapFree(heap,0,piW->pPortName);
860 HeapFree(heap,0,piW->pDriverName);
861 HeapFree(heap,0,piW->pComment);
862 HeapFree(heap,0,piW->pLocation);
863 HeapFree(heap,0,piW->pDevMode);
864 HeapFree(heap,0,piW->pSepFile);
865 HeapFree(heap,0,piW->pPrintProcessor);
866 HeapFree(heap,0,piW->pDatatype);
867 HeapFree(heap,0,piW->pParameters);
868 HeapFree(heap,0,piW);
869 return;
872 /******************************************************************
873 * DeviceCapabilities [WINSPOOL.@]
874 * DeviceCapabilitiesA [WINSPOOL.@]
877 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
878 LPSTR pOutput, LPDEVMODEA lpdm)
880 INT ret;
882 if (!GDI_CallDeviceCapabilities16)
884 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
885 (LPCSTR)104 );
886 if (!GDI_CallDeviceCapabilities16) return -1;
888 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
890 /* If DC_PAPERSIZE map POINT16s to POINTs */
891 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
892 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
893 POINT *pt = (POINT *)pOutput;
894 INT i;
895 memcpy(tmp, pOutput, ret * sizeof(POINT16));
896 for(i = 0; i < ret; i++, pt++)
898 pt->x = tmp[i].x;
899 pt->y = tmp[i].y;
901 HeapFree( GetProcessHeap(), 0, tmp );
903 return ret;
907 /*****************************************************************************
908 * DeviceCapabilitiesW [WINSPOOL.@]
910 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
913 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
914 WORD fwCapability, LPWSTR pOutput,
915 const DEVMODEW *pDevMode)
917 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
918 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
919 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
920 INT ret;
922 if(pOutput && (fwCapability == DC_BINNAMES ||
923 fwCapability == DC_FILEDEPENDENCIES ||
924 fwCapability == DC_PAPERNAMES)) {
925 /* These need A -> W translation */
926 INT size = 0, i;
927 LPSTR pOutputA;
928 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
929 dmA);
930 if(ret == -1)
931 return ret;
932 switch(fwCapability) {
933 case DC_BINNAMES:
934 size = 24;
935 break;
936 case DC_PAPERNAMES:
937 case DC_FILEDEPENDENCIES:
938 size = 64;
939 break;
941 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
942 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
943 dmA);
944 for(i = 0; i < ret; i++)
945 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
946 pOutput + (i * size), size);
947 HeapFree(GetProcessHeap(), 0, pOutputA);
948 } else {
949 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
950 (LPSTR)pOutput, dmA);
952 HeapFree(GetProcessHeap(),0,pPortA);
953 HeapFree(GetProcessHeap(),0,pDeviceA);
954 HeapFree(GetProcessHeap(),0,dmA);
955 return ret;
958 /******************************************************************
959 * DocumentPropertiesA [WINSPOOL.@]
961 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
963 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
964 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
965 LPDEVMODEA pDevModeInput,DWORD fMode )
967 LPSTR lpName = pDeviceName;
968 LONG ret;
970 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
971 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
974 if(!pDeviceName) {
975 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
976 if(!lpNameW) {
977 ERR("no name from hPrinter?\n");
978 SetLastError(ERROR_INVALID_HANDLE);
979 return -1;
981 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
984 if (!GDI_CallExtDeviceMode16)
986 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
987 (LPCSTR)102 );
988 if (!GDI_CallExtDeviceMode16) {
989 ERR("No CallExtDeviceMode16?\n");
990 return -1;
993 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
994 pDevModeInput, NULL, fMode);
996 if(!pDeviceName)
997 HeapFree(GetProcessHeap(),0,lpName);
998 return ret;
1002 /*****************************************************************************
1003 * DocumentPropertiesW (WINSPOOL.@)
1005 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1007 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1008 LPWSTR pDeviceName,
1009 LPDEVMODEW pDevModeOutput,
1010 LPDEVMODEW pDevModeInput, DWORD fMode)
1013 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1014 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1015 LPDEVMODEA pDevModeOutputA = NULL;
1016 LONG ret;
1018 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1019 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1020 fMode);
1021 if(pDevModeOutput) {
1022 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1023 if(ret < 0) return ret;
1024 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1026 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1027 pDevModeInputA, fMode);
1028 if(pDevModeOutput) {
1029 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1030 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1032 if(fMode == 0 && ret > 0)
1033 ret += (CCHDEVICENAME + CCHFORMNAME);
1034 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1035 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1036 return ret;
1039 /******************************************************************
1040 * OpenPrinterA [WINSPOOL.@]
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 UINT_PTR i = (UINT_PTR)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, DatatypeW, 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 *pcReturned = number;
3625 return TRUE;
3628 /*****************************************************************************
3629 * EnumPrinterDriversW [WINSPOOL.@]
3631 * see function EnumPrinterDrivers for RETURNS, BUGS
3633 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3634 LPBYTE pDriverInfo, DWORD cbBuf,
3635 LPDWORD pcbNeeded, LPDWORD pcReturned)
3637 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3638 cbBuf, pcbNeeded, pcReturned, TRUE);
3641 /*****************************************************************************
3642 * EnumPrinterDriversA [WINSPOOL.@]
3644 * see function EnumPrinterDrivers for RETURNS, BUGS
3646 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3647 LPBYTE pDriverInfo, DWORD cbBuf,
3648 LPDWORD pcbNeeded, LPDWORD pcReturned)
3649 { BOOL ret;
3650 UNICODE_STRING pNameW, pEnvironmentW;
3651 PWSTR pwstrNameW, pwstrEnvironmentW;
3653 pwstrNameW = asciitounicode(&pNameW, pName);
3654 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3656 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3657 Level, pDriverInfo, cbBuf, pcbNeeded,
3658 pcReturned, FALSE);
3659 RtlFreeUnicodeString(&pNameW);
3660 RtlFreeUnicodeString(&pEnvironmentW);
3662 return ret;
3665 static CHAR PortMonitor[] = "Wine Port Monitor";
3666 static CHAR PortDescription[] = "Wine Port";
3668 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3670 HANDLE handle;
3672 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3673 NULL, OPEN_EXISTING, 0, NULL );
3674 if (handle == INVALID_HANDLE_VALUE)
3675 return FALSE;
3676 TRACE("Checking %s exists\n", name );
3677 CloseHandle( handle );
3678 return TRUE;
3681 static DWORD WINSPOOL_CountSerialPorts(void)
3683 CHAR name[6];
3684 DWORD n = 0, i;
3686 for (i=0; i<4; i++)
3688 strcpy( name, "COMx:" );
3689 name[3] = '1' + i;
3690 if (WINSPOOL_ComPortExists( name ))
3691 n++;
3694 return n;
3697 /******************************************************************************
3698 * EnumPortsA (WINSPOOL.@)
3700 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3701 LPDWORD bufneeded,LPDWORD bufreturned)
3703 CHAR portname[10];
3704 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3705 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3706 HKEY hkey_printer;
3707 BOOL retval = TRUE;
3709 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3710 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3712 switch( level )
3714 case 1:
3715 info_size = sizeof (PORT_INFO_1A);
3716 break;
3717 case 2:
3718 info_size = sizeof (PORT_INFO_2A);
3719 break;
3720 default:
3721 SetLastError(ERROR_INVALID_LEVEL);
3722 return FALSE;
3725 /* see how many exist */
3727 hkey_printer = 0;
3728 serial_count = WINSPOOL_CountSerialPorts();
3729 printer_count = 0;
3731 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3732 if ( r == ERROR_SUCCESS )
3734 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3735 &printer_count, NULL, NULL, NULL, NULL);
3737 count = serial_count + printer_count;
3739 /* then fill in the structure info structure once
3740 we know the offset to the first string */
3742 memset( buffer, 0, bufsize );
3743 n = 0;
3744 ofs = info_size*count;
3745 for ( i=0; i<count; i++)
3747 DWORD vallen = sizeof(portname) - 1;
3749 /* get the serial port values, then the printer values */
3750 if ( i < serial_count )
3752 strcpy( portname, "COMx:" );
3753 portname[3] = '1' + i;
3754 if (!WINSPOOL_ComPortExists( portname ))
3755 continue;
3757 TRACE("Found %s\n", portname );
3758 vallen = strlen( portname );
3760 else
3762 r = RegEnumValueA( hkey_printer, i-serial_count,
3763 portname, &vallen, NULL, NULL, NULL, 0 );
3764 if ( r )
3765 continue;
3768 /* add a colon if necessary, and make it upper case */
3769 CharUpperBuffA(portname,vallen);
3770 if (strcasecmp(portname,"nul")!=0)
3771 if (vallen && (portname[vallen-1] != ':') )
3772 lstrcatA(portname,":");
3774 /* add the port info structure if we can fit it */
3775 if ( info_size*(n+1) < bufsize )
3777 if ( level == 1)
3779 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3780 info->pName = (LPSTR) &buffer[ofs];
3782 else if ( level == 2)
3784 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3785 info->pPortName = (LPSTR) &buffer[ofs];
3786 /* FIXME: fill in more stuff here */
3787 info->pMonitorName = PortMonitor;
3788 info->pDescription = PortDescription;
3789 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3792 /* add the name of the port if we can fit it */
3793 if ( ofs < bufsize )
3794 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
3796 n++;
3798 else
3799 retval = FALSE;
3800 ofs += lstrlenA(portname)+1;
3803 RegCloseKey(hkey_printer);
3805 if(bufneeded)
3806 *bufneeded = ofs;
3808 if(bufreturned)
3809 *bufreturned = n;
3811 return retval;
3814 /******************************************************************************
3815 * EnumPortsW (WINSPOOL.@)
3817 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3818 LPDWORD bufneeded,LPDWORD bufreturned)
3820 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3821 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3822 return FALSE;
3825 /******************************************************************************
3826 * GetDefaultPrinterW (WINSPOOL.@)
3828 * FIXME
3829 * This function must read the value from data 'device' of key
3830 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3832 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3834 BOOL retval = TRUE;
3835 DWORD insize, len;
3836 WCHAR *buffer, *ptr;
3838 if (!namesize)
3840 SetLastError(ERROR_INVALID_PARAMETER);
3841 return FALSE;
3844 /* make the buffer big enough for the stuff from the profile/registry,
3845 * the content must fit into the local buffer to compute the correct
3846 * size even if the extern buffer is too small or not given.
3847 * (20 for ,driver,port) */
3848 insize = *namesize;
3849 len = max(100, (insize + 20));
3850 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3852 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3854 SetLastError (ERROR_FILE_NOT_FOUND);
3855 retval = FALSE;
3856 goto end;
3858 TRACE("%s\n", debugstr_w(buffer));
3860 if ((ptr = strchrW(buffer, ',')) == NULL)
3862 SetLastError(ERROR_INVALID_NAME);
3863 retval = FALSE;
3864 goto end;
3867 *ptr = 0;
3868 *namesize = strlenW(buffer) + 1;
3869 if(!name || (*namesize > insize))
3871 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3872 retval = FALSE;
3873 goto end;
3875 strcpyW(name, buffer);
3877 end:
3878 HeapFree( GetProcessHeap(), 0, buffer);
3879 return retval;
3883 /******************************************************************************
3884 * GetDefaultPrinterA (WINSPOOL.@)
3886 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3888 BOOL retval = TRUE;
3889 DWORD insize = 0;
3890 WCHAR *bufferW = NULL;
3892 if (!namesize)
3894 SetLastError(ERROR_INVALID_PARAMETER);
3895 return FALSE;
3898 if(name && *namesize) {
3899 insize = *namesize;
3900 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3903 if(!GetDefaultPrinterW( bufferW, namesize)) {
3904 retval = FALSE;
3905 goto end;
3908 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3909 NULL, NULL);
3910 if (!*namesize)
3912 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3913 retval = FALSE;
3915 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3917 end:
3918 HeapFree( GetProcessHeap(), 0, bufferW);
3919 return retval;
3923 /******************************************************************************
3924 * SetPrinterDataExA (WINSPOOL.@)
3926 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3927 LPCSTR pValueName, DWORD Type,
3928 LPBYTE pData, DWORD cbData)
3930 HKEY hkeyPrinter, hkeySubkey;
3931 DWORD ret;
3933 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3934 debugstr_a(pValueName), Type, pData, cbData);
3936 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3937 != ERROR_SUCCESS)
3938 return ret;
3940 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3941 != ERROR_SUCCESS) {
3942 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3943 RegCloseKey(hkeyPrinter);
3944 return ret;
3946 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3947 RegCloseKey(hkeySubkey);
3948 RegCloseKey(hkeyPrinter);
3949 return ret;
3952 /******************************************************************************
3953 * SetPrinterDataExW (WINSPOOL.@)
3955 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3956 LPCWSTR pValueName, DWORD Type,
3957 LPBYTE pData, DWORD cbData)
3959 HKEY hkeyPrinter, hkeySubkey;
3960 DWORD ret;
3962 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
3963 debugstr_w(pValueName), Type, pData, cbData);
3965 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3966 != ERROR_SUCCESS)
3967 return ret;
3969 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
3970 != ERROR_SUCCESS) {
3971 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
3972 RegCloseKey(hkeyPrinter);
3973 return ret;
3975 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
3976 RegCloseKey(hkeySubkey);
3977 RegCloseKey(hkeyPrinter);
3978 return ret;
3981 /******************************************************************************
3982 * SetPrinterDataA (WINSPOOL.@)
3984 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
3985 LPBYTE pData, DWORD cbData)
3987 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
3988 pData, cbData);
3991 /******************************************************************************
3992 * SetPrinterDataW (WINSPOOL.@)
3994 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
3995 LPBYTE pData, DWORD cbData)
3997 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
3998 pData, cbData);
4001 /******************************************************************************
4002 * GetPrinterDataExA (WINSPOOL.@)
4004 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4005 LPCSTR pValueName, LPDWORD pType,
4006 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4008 HKEY hkeyPrinter, hkeySubkey;
4009 DWORD ret;
4011 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4012 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4013 pcbNeeded);
4015 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4016 != ERROR_SUCCESS)
4017 return ret;
4019 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4020 != ERROR_SUCCESS) {
4021 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4022 RegCloseKey(hkeyPrinter);
4023 return ret;
4025 *pcbNeeded = nSize;
4026 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4027 RegCloseKey(hkeySubkey);
4028 RegCloseKey(hkeyPrinter);
4029 return ret;
4032 /******************************************************************************
4033 * GetPrinterDataExW (WINSPOOL.@)
4035 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4036 LPCWSTR pValueName, LPDWORD pType,
4037 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4039 HKEY hkeyPrinter, hkeySubkey;
4040 DWORD ret;
4042 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4043 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4044 pcbNeeded);
4046 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4047 != ERROR_SUCCESS)
4048 return ret;
4050 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4051 != ERROR_SUCCESS) {
4052 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4053 RegCloseKey(hkeyPrinter);
4054 return ret;
4056 *pcbNeeded = nSize;
4057 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4058 RegCloseKey(hkeySubkey);
4059 RegCloseKey(hkeyPrinter);
4060 return ret;
4063 /******************************************************************************
4064 * GetPrinterDataA (WINSPOOL.@)
4066 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4067 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4069 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4070 pData, nSize, pcbNeeded);
4073 /******************************************************************************
4074 * GetPrinterDataW (WINSPOOL.@)
4076 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4077 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4079 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4080 pData, nSize, pcbNeeded);
4083 /*******************************************************************************
4084 * EnumPrinterDataExW [WINSPOOL.@]
4086 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4087 LPBYTE pEnumValues, DWORD cbEnumValues,
4088 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4090 HKEY hkPrinter, hkSubKey;
4091 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4092 cbValueNameLen, cbMaxValueLen, cbValueLen,
4093 cbBufSize, dwType;
4094 LPWSTR lpValueName;
4095 HANDLE hHeap;
4096 PBYTE lpValue;
4097 PPRINTER_ENUM_VALUESW ppev;
4099 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4101 if (pKeyName == NULL || *pKeyName == 0)
4102 return ERROR_INVALID_PARAMETER;
4104 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4105 if (ret != ERROR_SUCCESS)
4107 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4108 hPrinter, ret);
4109 return ret;
4112 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4113 if (ret != ERROR_SUCCESS)
4115 r = RegCloseKey (hkPrinter);
4116 if (r != ERROR_SUCCESS)
4117 WARN ("RegCloseKey returned %li\n", r);
4118 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4119 debugstr_w (pKeyName), ret);
4120 return ret;
4123 ret = RegCloseKey (hkPrinter);
4124 if (ret != ERROR_SUCCESS)
4126 ERR ("RegCloseKey returned %li\n", ret);
4127 r = RegCloseKey (hkSubKey);
4128 if (r != ERROR_SUCCESS)
4129 WARN ("RegCloseKey returned %li\n", r);
4130 return ret;
4133 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4134 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4135 if (ret != ERROR_SUCCESS)
4137 r = RegCloseKey (hkSubKey);
4138 if (r != ERROR_SUCCESS)
4139 WARN ("RegCloseKey returned %li\n", r);
4140 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4141 return ret;
4144 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4145 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4147 if (cValues == 0) /* empty key */
4149 r = RegCloseKey (hkSubKey);
4150 if (r != ERROR_SUCCESS)
4151 WARN ("RegCloseKey returned %li\n", r);
4152 *pcbEnumValues = *pnEnumValues = 0;
4153 return ERROR_SUCCESS;
4156 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4158 hHeap = GetProcessHeap ();
4159 if (hHeap == NULL)
4161 ERR ("GetProcessHeap failed\n");
4162 r = RegCloseKey (hkSubKey);
4163 if (r != ERROR_SUCCESS)
4164 WARN ("RegCloseKey returned %li\n", r);
4165 return ERROR_OUTOFMEMORY;
4168 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4169 if (lpValueName == NULL)
4171 ERR ("Failed to allocate %li bytes from process heap\n",
4172 cbMaxValueNameLen * sizeof (WCHAR));
4173 r = RegCloseKey (hkSubKey);
4174 if (r != ERROR_SUCCESS)
4175 WARN ("RegCloseKey returned %li\n", r);
4176 return ERROR_OUTOFMEMORY;
4179 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4180 if (lpValue == NULL)
4182 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4183 if (HeapFree (hHeap, 0, lpValueName) == 0)
4184 WARN ("HeapFree failed with code %li\n", GetLastError ());
4185 r = RegCloseKey (hkSubKey);
4186 if (r != ERROR_SUCCESS)
4187 WARN ("RegCloseKey returned %li\n", r);
4188 return ERROR_OUTOFMEMORY;
4191 TRACE ("pass 1: calculating buffer required for all names and values\n");
4193 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4195 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4197 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4199 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4200 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4201 NULL, NULL, lpValue, &cbValueLen);
4202 if (ret != ERROR_SUCCESS)
4204 if (HeapFree (hHeap, 0, lpValue) == 0)
4205 WARN ("HeapFree failed with code %li\n", GetLastError ());
4206 if (HeapFree (hHeap, 0, lpValueName) == 0)
4207 WARN ("HeapFree failed with code %li\n", GetLastError ());
4208 r = RegCloseKey (hkSubKey);
4209 if (r != ERROR_SUCCESS)
4210 WARN ("RegCloseKey returned %li\n", r);
4211 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4212 return ret;
4215 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4216 debugstr_w (lpValueName), dwIndex,
4217 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4219 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4220 cbBufSize += cbValueLen;
4223 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4225 *pcbEnumValues = cbBufSize;
4226 *pnEnumValues = cValues;
4228 if (cbEnumValues < cbBufSize) /* buffer too small */
4230 if (HeapFree (hHeap, 0, lpValue) == 0)
4231 WARN ("HeapFree failed with code %li\n", GetLastError ());
4232 if (HeapFree (hHeap, 0, lpValueName) == 0)
4233 WARN ("HeapFree failed with code %li\n", GetLastError ());
4234 r = RegCloseKey (hkSubKey);
4235 if (r != ERROR_SUCCESS)
4236 WARN ("RegCloseKey returned %li\n", r);
4237 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4238 return ERROR_MORE_DATA;
4241 TRACE ("pass 2: copying all names and values to buffer\n");
4243 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4244 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4246 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4248 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4249 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4250 NULL, &dwType, lpValue, &cbValueLen);
4251 if (ret != ERROR_SUCCESS)
4253 if (HeapFree (hHeap, 0, lpValue) == 0)
4254 WARN ("HeapFree failed with code %li\n", GetLastError ());
4255 if (HeapFree (hHeap, 0, lpValueName) == 0)
4256 WARN ("HeapFree failed with code %li\n", GetLastError ());
4257 r = RegCloseKey (hkSubKey);
4258 if (r != ERROR_SUCCESS)
4259 WARN ("RegCloseKey returned %li\n", r);
4260 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4261 return ret;
4264 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4265 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4266 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4267 pEnumValues += cbValueNameLen;
4269 /* return # of *bytes* (including trailing \0), not # of chars */
4270 ppev[dwIndex].cbValueName = cbValueNameLen;
4272 ppev[dwIndex].dwType = dwType;
4274 memcpy (pEnumValues, lpValue, cbValueLen);
4275 ppev[dwIndex].pData = pEnumValues;
4276 pEnumValues += cbValueLen;
4278 ppev[dwIndex].cbData = cbValueLen;
4280 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4281 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4284 if (HeapFree (hHeap, 0, lpValue) == 0)
4286 ret = GetLastError ();
4287 ERR ("HeapFree failed with code %li\n", ret);
4288 if (HeapFree (hHeap, 0, lpValueName) == 0)
4289 WARN ("HeapFree failed with code %li\n", GetLastError ());
4290 r = RegCloseKey (hkSubKey);
4291 if (r != ERROR_SUCCESS)
4292 WARN ("RegCloseKey returned %li\n", r);
4293 return ret;
4296 if (HeapFree (hHeap, 0, lpValueName) == 0)
4298 ret = GetLastError ();
4299 ERR ("HeapFree failed with code %li\n", ret);
4300 r = RegCloseKey (hkSubKey);
4301 if (r != ERROR_SUCCESS)
4302 WARN ("RegCloseKey returned %li\n", r);
4303 return ret;
4306 ret = RegCloseKey (hkSubKey);
4307 if (ret != ERROR_SUCCESS)
4309 ERR ("RegCloseKey returned %li\n", ret);
4310 return ret;
4313 return ERROR_SUCCESS;
4316 /*******************************************************************************
4317 * EnumPrinterDataExA [WINSPOOL.@]
4319 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4320 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4321 * what Windows 2000 SP1 does.
4324 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4325 LPBYTE pEnumValues, DWORD cbEnumValues,
4326 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4328 INT len;
4329 LPWSTR pKeyNameW;
4330 DWORD ret, dwIndex, dwBufSize;
4331 HANDLE hHeap;
4332 LPSTR pBuffer;
4334 TRACE ("%p %s\n", hPrinter, pKeyName);
4336 if (pKeyName == NULL || *pKeyName == 0)
4337 return ERROR_INVALID_PARAMETER;
4339 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4340 if (len == 0)
4342 ret = GetLastError ();
4343 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4344 return ret;
4347 hHeap = GetProcessHeap ();
4348 if (hHeap == NULL)
4350 ERR ("GetProcessHeap failed\n");
4351 return ERROR_OUTOFMEMORY;
4354 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4355 if (pKeyNameW == NULL)
4357 ERR ("Failed to allocate %li bytes from process heap\n",
4358 (LONG) len * sizeof (WCHAR));
4359 return ERROR_OUTOFMEMORY;
4362 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4364 ret = GetLastError ();
4365 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4366 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4367 WARN ("HeapFree failed with code %li\n", GetLastError ());
4368 return ret;
4371 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4372 pcbEnumValues, pnEnumValues);
4373 if (ret != ERROR_SUCCESS)
4375 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4376 WARN ("HeapFree failed with code %li\n", GetLastError ());
4377 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4378 return ret;
4381 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4383 ret = GetLastError ();
4384 ERR ("HeapFree failed with code %li\n", ret);
4385 return ret;
4388 if (*pnEnumValues == 0) /* empty key */
4389 return ERROR_SUCCESS;
4391 dwBufSize = 0;
4392 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4394 PPRINTER_ENUM_VALUESW ppev =
4395 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4397 if (dwBufSize < ppev->cbValueName)
4398 dwBufSize = ppev->cbValueName;
4400 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4401 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4402 dwBufSize = ppev->cbData;
4405 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4407 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4408 if (pBuffer == NULL)
4410 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4411 return ERROR_OUTOFMEMORY;
4414 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4416 PPRINTER_ENUM_VALUESW ppev =
4417 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4419 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4420 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4421 NULL);
4422 if (len == 0)
4424 ret = GetLastError ();
4425 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4426 if (HeapFree (hHeap, 0, pBuffer) == 0)
4427 WARN ("HeapFree failed with code %li\n", GetLastError ());
4428 return ret;
4431 memcpy (ppev->pValueName, pBuffer, len);
4433 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4435 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4436 ppev->dwType != REG_MULTI_SZ)
4437 continue;
4439 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4440 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4441 if (len == 0)
4443 ret = GetLastError ();
4444 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4445 if (HeapFree (hHeap, 0, pBuffer) == 0)
4446 WARN ("HeapFree failed with code %li\n", GetLastError ());
4447 return ret;
4450 memcpy (ppev->pData, pBuffer, len);
4452 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4453 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4456 if (HeapFree (hHeap, 0, pBuffer) == 0)
4458 ret = GetLastError ();
4459 ERR ("HeapFree failed with code %li\n", ret);
4460 return ret;
4463 return ERROR_SUCCESS;
4466 /******************************************************************************
4467 * AbortPrinter (WINSPOOL.@)
4469 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4471 FIXME("(%p), stub!\n", hPrinter);
4472 return TRUE;
4475 /******************************************************************************
4476 * AddPortA (WINSPOOL.@)
4478 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4480 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4481 return FALSE;
4484 /******************************************************************************
4485 * AddPortW (WINSPOOL.@)
4487 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4489 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4490 return FALSE;
4493 /******************************************************************************
4494 * AddPortExA (WINSPOOL.@)
4496 * Adds a print spooler port without presenting a user interface.
4498 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4500 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4501 lpBuffer, debugstr_a(lpMonitorName));
4502 return FALSE;
4505 /******************************************************************************
4506 * AddPortExW (WINSPOOL.@)
4508 * See AddPortExW.
4510 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4512 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4513 lpBuffer, debugstr_w(lpMonitorName));
4514 return FALSE;
4517 /******************************************************************************
4518 * AddPrinterConnectionA (WINSPOOL.@)
4520 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4522 FIXME("%s\n", debugstr_a(pName));
4523 return FALSE;
4526 /******************************************************************************
4527 * AddPrinterConnectionW (WINSPOOL.@)
4529 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4531 FIXME("%s\n", debugstr_w(pName));
4532 return FALSE;
4535 /******************************************************************************
4536 * AddPrinterDriverExW (WINSPOOL.@)
4538 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4539 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4541 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4542 Level, pDriverInfo, dwFileCopyFlags);
4543 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4544 return FALSE;
4547 /******************************************************************************
4548 * AddPrinterDriverExA (WINSPOOL.@)
4550 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4551 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4553 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4554 Level, pDriverInfo, dwFileCopyFlags);
4555 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4556 return FALSE;
4559 /******************************************************************************
4560 * ConfigurePortA (WINSPOOL.@)
4562 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4564 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4565 return FALSE;
4568 /******************************************************************************
4569 * ConfigurePortW (WINSPOOL.@)
4571 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4573 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4574 return FALSE;
4577 /******************************************************************************
4578 * ConnectToPrinterDlg (WINSPOOL.@)
4580 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4582 FIXME("%p %lx\n", hWnd, Flags);
4583 return NULL;
4586 /******************************************************************************
4587 * DeletePrinterConnectionA (WINSPOOL.@)
4589 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4591 FIXME("%s\n", debugstr_a(pName));
4592 return TRUE;
4595 /******************************************************************************
4596 * DeletePrinterConnectionW (WINSPOOL.@)
4598 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4600 FIXME("%s\n", debugstr_w(pName));
4601 return TRUE;
4604 /******************************************************************************
4605 * DeletePrinterDriverExW (WINSPOOL.@)
4607 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4608 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4610 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4611 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4612 return TRUE;
4615 /******************************************************************************
4616 * DeletePrinterDriverExA (WINSPOOL.@)
4618 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4619 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4621 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4622 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4623 return TRUE;
4626 /******************************************************************************
4627 * DeletePrinterDataExW (WINSPOOL.@)
4629 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4630 LPCWSTR pValueName)
4632 FIXME("%p %s %s\n", hPrinter,
4633 debugstr_w(pKeyName), debugstr_w(pValueName));
4634 return ERROR_INVALID_PARAMETER;
4637 /******************************************************************************
4638 * DeletePrinterDataExA (WINSPOOL.@)
4640 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4641 LPCSTR pValueName)
4643 FIXME("%p %s %s\n", hPrinter,
4644 debugstr_a(pKeyName), debugstr_a(pValueName));
4645 return ERROR_INVALID_PARAMETER;
4648 /******************************************************************************
4649 * DeletePrintProcessorA (WINSPOOL.@)
4651 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4653 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4654 debugstr_a(pPrintProcessorName));
4655 return TRUE;
4658 /******************************************************************************
4659 * DeletePrintProcessorW (WINSPOOL.@)
4661 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4663 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4664 debugstr_w(pPrintProcessorName));
4665 return TRUE;
4668 /******************************************************************************
4669 * DeletePrintProvidorA (WINSPOOL.@)
4671 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4673 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4674 debugstr_a(pPrintProviderName));
4675 return TRUE;
4678 /******************************************************************************
4679 * DeletePrintProvidorW (WINSPOOL.@)
4681 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4683 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4684 debugstr_w(pPrintProviderName));
4685 return TRUE;
4688 /******************************************************************************
4689 * EnumFormsA (WINSPOOL.@)
4691 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4692 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4694 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4695 return FALSE;
4698 /******************************************************************************
4699 * EnumFormsW (WINSPOOL.@)
4701 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4702 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4704 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4705 return FALSE;
4708 /*****************************************************************************
4709 * EnumMonitorsA [WINSPOOL.@]
4712 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4713 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4715 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4716 cbBuf, pcbNeeded, pcReturned);
4717 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4718 return 0;
4721 /*****************************************************************************
4722 * EnumMonitorsW [WINSPOOL.@]
4725 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4726 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4728 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4729 cbBuf, pcbNeeded, pcReturned);
4730 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4731 return 0;
4734 /******************************************************************************
4735 * XcvDataW (WINSPOOL.@)
4737 * Notes:
4738 * There doesn't seem to be an A version...
4740 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4741 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4742 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4744 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4745 pInputData, cbInputData, pOutputData,
4746 cbOutputData, pcbOutputNeeded, pdwStatus);
4747 return FALSE;
4750 /*****************************************************************************
4751 * EnumPrinterDataA [WINSPOOL.@]
4754 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4755 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4756 DWORD cbData, LPDWORD pcbData )
4758 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4759 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4760 return ERROR_NO_MORE_ITEMS;
4763 /*****************************************************************************
4764 * EnumPrinterDataW [WINSPOOL.@]
4767 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4768 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4769 DWORD cbData, LPDWORD pcbData )
4771 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4772 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4773 return ERROR_NO_MORE_ITEMS;
4776 /*****************************************************************************
4777 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4780 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4781 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4782 LPDWORD pcbNeeded, LPDWORD pcReturned)
4784 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4785 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4786 pcbNeeded, pcReturned);
4787 return FALSE;
4790 /*****************************************************************************
4791 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4794 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4795 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4796 LPDWORD pcbNeeded, LPDWORD pcReturned)
4798 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4799 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4800 pcbNeeded, pcReturned);
4801 return FALSE;
4804 /*****************************************************************************
4805 * EnumPrintProcessorsA [WINSPOOL.@]
4808 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4809 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4811 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4812 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
4813 return FALSE;
4816 /*****************************************************************************
4817 * EnumPrintProcessorsW [WINSPOOL.@]
4820 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4821 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4823 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4824 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
4825 cbBuf, pcbNeeded, pcbReturned);
4826 return FALSE;
4829 /*****************************************************************************
4830 * ExtDeviceMode [WINSPOOL.@]
4833 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
4834 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
4835 DWORD fMode)
4837 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
4838 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
4839 debugstr_a(pProfile), fMode);
4840 return -1;
4843 /*****************************************************************************
4844 * FindClosePrinterChangeNotification [WINSPOOL.@]
4847 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
4849 FIXME("Stub: %p\n", hChange);
4850 return TRUE;
4853 /*****************************************************************************
4854 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4857 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
4858 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
4860 FIXME("Stub: %p %lx %lx %p\n",
4861 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
4862 return INVALID_HANDLE_VALUE;
4865 /*****************************************************************************
4866 * FindNextPrinterChangeNotification [WINSPOOL.@]
4869 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
4870 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
4872 FIXME("Stub: %p %p %p %p\n",
4873 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
4874 return FALSE;
4877 /*****************************************************************************
4878 * FreePrinterNotifyInfo [WINSPOOL.@]
4881 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
4883 FIXME("Stub: %p\n", pPrinterNotifyInfo);
4884 return TRUE;
4887 /*****************************************************************************
4888 * string_to_buf
4890 * Copies a unicode string into a buffer. The buffer will either contain unicode or
4891 * ansi depending on the unicode parameter.
4893 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
4895 if(!str)
4897 *size = 0;
4898 return TRUE;
4901 if(unicode)
4903 *size = (strlenW(str) + 1) * sizeof(WCHAR);
4904 if(*size <= cb)
4906 memcpy(ptr, str, *size);
4907 return TRUE;
4909 return FALSE;
4911 else
4913 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
4914 if(*size <= cb)
4916 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
4917 return TRUE;
4919 return FALSE;
4923 /*****************************************************************************
4924 * get_job_info_1
4926 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
4927 LPDWORD pcbNeeded, BOOL unicode)
4929 DWORD size, left = cbBuf;
4930 BOOL space = (cbBuf > 0);
4931 LPBYTE ptr = buf;
4933 *pcbNeeded = 0;
4935 if(space)
4937 ji1->JobId = job->job_id;
4940 string_to_buf(job->document_title, ptr, left, &size, unicode);
4941 if(space && size <= left)
4943 ji1->pDocument = (LPWSTR)ptr;
4944 ptr += size;
4945 left -= size;
4947 else
4948 space = FALSE;
4949 *pcbNeeded += size;
4951 return space;
4954 /*****************************************************************************
4955 * get_job_info_2
4957 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
4958 LPDWORD pcbNeeded, BOOL unicode)
4960 DWORD size, left = cbBuf;
4961 BOOL space = (cbBuf > 0);
4962 LPBYTE ptr = buf;
4964 *pcbNeeded = 0;
4966 if(space)
4968 ji2->JobId = job->job_id;
4971 string_to_buf(job->document_title, ptr, left, &size, unicode);
4972 if(space && size <= left)
4974 ji2->pDocument = (LPWSTR)ptr;
4975 ptr += size;
4976 left -= size;
4978 else
4979 space = FALSE;
4980 *pcbNeeded += size;
4982 return space;
4985 /*****************************************************************************
4986 * get_job_info
4988 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
4989 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4991 BOOL ret = FALSE;
4992 DWORD needed = 0, size;
4993 job_t *job;
4994 LPBYTE ptr = pJob;
4996 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
4998 EnterCriticalSection(&printer_handles_cs);
4999 job = get_job(hPrinter, JobId);
5000 if(!job)
5001 goto end;
5003 switch(Level)
5005 case 1:
5006 size = sizeof(JOB_INFO_1W);
5007 if(cbBuf >= size)
5009 cbBuf -= size;
5010 ptr += size;
5011 memset(pJob, 0, size);
5013 else
5014 cbBuf = 0;
5015 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5016 needed += size;
5017 break;
5019 case 2:
5020 size = sizeof(JOB_INFO_2W);
5021 if(cbBuf >= size)
5023 cbBuf -= size;
5024 ptr += size;
5025 memset(pJob, 0, size);
5027 else
5028 cbBuf = 0;
5029 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5030 needed += size;
5031 break;
5033 case 3:
5034 size = sizeof(JOB_INFO_3);
5035 if(cbBuf >= size)
5037 cbBuf -= size;
5038 memset(pJob, 0, size);
5039 ret = TRUE;
5041 else
5042 cbBuf = 0;
5043 needed = size;
5044 break;
5046 default:
5047 SetLastError(ERROR_INVALID_LEVEL);
5048 goto end;
5050 if(pcbNeeded)
5051 *pcbNeeded = needed;
5052 end:
5053 LeaveCriticalSection(&printer_handles_cs);
5054 return ret;
5057 /*****************************************************************************
5058 * GetJobA [WINSPOOL.@]
5061 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5062 DWORD cbBuf, LPDWORD pcbNeeded)
5064 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5067 /*****************************************************************************
5068 * GetJobW [WINSPOOL.@]
5071 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5072 DWORD cbBuf, LPDWORD pcbNeeded)
5074 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5077 /*****************************************************************************
5078 * schedule_lpr
5080 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5082 char *unixname, *queue, *cmd;
5083 char fmt[] = "lpr -P%s %s";
5084 DWORD len;
5086 if(!(unixname = wine_get_unix_file_name(filename)))
5087 return FALSE;
5089 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5090 queue = HeapAlloc(GetProcessHeap(), 0, len);
5091 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5093 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5094 sprintf(cmd, fmt, queue, unixname);
5096 TRACE("printing with: %s\n", cmd);
5097 system(cmd);
5099 HeapFree(GetProcessHeap(), 0, cmd);
5100 HeapFree(GetProcessHeap(), 0, queue);
5101 HeapFree(GetProcessHeap(), 0, unixname);
5102 return TRUE;
5105 /*****************************************************************************
5106 * schedule_cups
5108 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5110 #if HAVE_CUPS_CUPS_H
5111 if(pcupsPrintFile)
5113 char *unixname, *queue, *doc_titleA;
5114 DWORD len;
5115 BOOL ret;
5117 if(!(unixname = wine_get_unix_file_name(filename)))
5118 return FALSE;
5120 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5121 queue = HeapAlloc(GetProcessHeap(), 0, len);
5122 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5124 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5125 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5126 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5128 TRACE("printing via cups\n");
5129 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5130 HeapFree(GetProcessHeap(), 0, doc_titleA);
5131 HeapFree(GetProcessHeap(), 0, queue);
5132 HeapFree(GetProcessHeap(), 0, unixname);
5133 return ret;
5135 else
5136 #endif
5138 return schedule_lpr(printer_name, filename);
5142 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5144 LPWSTR filename;
5146 switch(msg)
5148 case WM_INITDIALOG:
5149 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5150 return TRUE;
5152 case WM_COMMAND:
5153 if(HIWORD(wparam) == BN_CLICKED)
5155 if(LOWORD(wparam) == IDOK)
5157 HANDLE hf;
5158 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5159 LPWSTR *output;
5161 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5162 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5164 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5166 WCHAR caption[200], message[200];
5167 int mb_ret;
5169 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5170 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5171 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5172 if(mb_ret == IDCANCEL)
5174 HeapFree(GetProcessHeap(), 0, filename);
5175 return TRUE;
5178 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5179 if(hf == INVALID_HANDLE_VALUE)
5181 WCHAR caption[200], message[200];
5183 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5184 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5185 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5186 HeapFree(GetProcessHeap(), 0, filename);
5187 return TRUE;
5189 CloseHandle(hf);
5190 DeleteFileW(filename);
5191 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5192 *output = filename;
5193 EndDialog(hwnd, IDOK);
5194 return TRUE;
5196 if(LOWORD(wparam) == IDCANCEL)
5198 EndDialog(hwnd, IDCANCEL);
5199 return TRUE;
5202 return FALSE;
5204 return FALSE;
5207 /*****************************************************************************
5208 * get_filename
5210 static BOOL get_filename(LPWSTR *filename)
5212 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
5213 file_dlg_proc, (LPARAM)filename) == IDOK;
5216 /*****************************************************************************
5217 * schedule_file
5219 static BOOL schedule_file(LPCWSTR filename)
5221 LPWSTR output = NULL;
5223 if(get_filename(&output))
5225 TRACE("copy to %s\n", debugstr_w(output));
5226 CopyFileW(filename, output, FALSE);
5227 HeapFree(GetProcessHeap(), 0, output);
5228 return TRUE;
5230 return FALSE;
5233 /*****************************************************************************
5234 * schedule_pipe
5236 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
5238 #ifdef HAVE_FORK
5239 char *unixname, *cmdA;
5240 DWORD len;
5241 int fds[2] = {-1, -1}, file_fd = -1, no_read;
5242 BOOL ret = FALSE;
5243 char buf[1024];
5245 if(!(unixname = wine_get_unix_file_name(filename)))
5246 return FALSE;
5248 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
5249 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
5250 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
5252 TRACE("printing with: %s\n", cmdA);
5254 if((file_fd = open(unixname, O_RDONLY)) == -1)
5255 goto end;
5257 if (pipe(fds))
5259 ERR("pipe() failed!\n");
5260 goto end;
5263 if (fork() == 0)
5265 close(0);
5266 dup2(fds[0], 0);
5267 close(fds[1]);
5269 /* reset signals that we previously set to SIG_IGN */
5270 signal(SIGPIPE, SIG_DFL);
5271 signal(SIGCHLD, SIG_DFL);
5273 system(cmdA);
5274 exit(0);
5277 while((no_read = read(file_fd, buf, sizeof(buf))))
5278 write(fds[1], buf, no_read);
5280 ret = TRUE;
5282 end:
5283 if(file_fd != -1) close(file_fd);
5284 if(fds[0] != -1) close(fds[0]);
5285 if(fds[1] != -1) close(fds[1]);
5287 HeapFree(GetProcessHeap(), 0, cmdA);
5288 HeapFree(GetProcessHeap(), 0, unixname);
5289 return ret;
5290 #else
5291 return FALSE;
5292 #endif
5295 /*****************************************************************************
5296 * schedule_unixfile
5298 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
5300 int in_fd, out_fd, no_read;
5301 char buf[1024];
5302 BOOL ret = FALSE;
5303 char *unixname, *outputA;
5304 DWORD len;
5306 if(!(unixname = wine_get_unix_file_name(filename)))
5307 return FALSE;
5309 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
5310 outputA = HeapAlloc(GetProcessHeap(), 0, len);
5311 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
5313 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5314 in_fd = open(unixname, O_RDONLY);
5315 if(out_fd == -1 || in_fd == -1)
5316 goto end;
5318 while((no_read = read(in_fd, buf, sizeof(buf))))
5319 write(out_fd, buf, no_read);
5321 ret = TRUE;
5322 end:
5323 if(in_fd != -1) close(in_fd);
5324 if(out_fd != -1) close(out_fd);
5325 HeapFree(GetProcessHeap(), 0, outputA);
5326 HeapFree(GetProcessHeap(), 0, unixname);
5327 return ret;
5330 /*****************************************************************************
5331 * ScheduleJob [WINSPOOL.@]
5334 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
5336 opened_printer_t *printer;
5337 BOOL ret = FALSE;
5338 struct list *cursor, *cursor2;
5340 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
5341 EnterCriticalSection(&printer_handles_cs);
5342 printer = get_opened_printer(hPrinter);
5343 if(!printer)
5344 goto end;
5346 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
5348 job_t *job = LIST_ENTRY(cursor, job_t, entry);
5349 HANDLE hf;
5351 if(job->job_id != dwJobID) continue;
5353 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
5354 if(hf != INVALID_HANDLE_VALUE)
5356 PRINTER_INFO_5W *pi5;
5357 DWORD needed;
5358 HKEY hkey;
5359 WCHAR output[1024];
5360 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5361 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5363 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
5364 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
5365 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
5366 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
5367 debugstr_w(pi5->pPortName));
5369 output[0] = 0;
5371 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5372 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
5374 DWORD type, count = sizeof(output);
5375 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
5376 RegCloseKey(hkey);
5378 if(output[0] == '|')
5380 schedule_pipe(output + 1, job->filename);
5382 else if(output[0])
5384 schedule_unixfile(output, job->filename);
5386 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
5388 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
5390 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
5392 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
5394 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
5396 schedule_file(job->filename);
5398 else
5400 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
5402 HeapFree(GetProcessHeap(), 0, pi5);
5403 CloseHandle(hf);
5404 DeleteFileW(job->filename);
5406 list_remove(cursor);
5407 HeapFree(GetProcessHeap(), 0, job->document_title);
5408 HeapFree(GetProcessHeap(), 0, job->filename);
5409 HeapFree(GetProcessHeap(), 0, job);
5410 ret = TRUE;
5411 break;
5413 end:
5414 LeaveCriticalSection(&printer_handles_cs);
5415 return ret;
5418 /*****************************************************************************
5419 * StartDocDlgA [WINSPOOL.@]
5421 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
5423 UNICODE_STRING usBuffer;
5424 DOCINFOW docW;
5425 LPWSTR retW;
5426 LPSTR ret = NULL;
5428 docW.cbSize = sizeof(docW);
5429 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
5430 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
5431 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
5432 docW.fwType = doc->fwType;
5434 retW = StartDocDlgW(hPrinter, &docW);
5436 if(retW)
5438 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
5439 ret = HeapAlloc(GetProcessHeap(), 0, len);
5440 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
5441 HeapFree(GetProcessHeap(), 0, retW);
5444 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
5445 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
5446 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
5448 return ret;
5451 /*****************************************************************************
5452 * StartDocDlgW [WINSPOOL.@]
5454 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5455 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5456 * port is "FILE:". Also returns the full path if passed a relative path.
5458 * The caller should free the returned string from the process heap.
5460 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
5462 LPWSTR ret = NULL;
5463 DWORD len, attr;
5465 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
5467 PRINTER_INFO_5W *pi5;
5468 GetPrinterW(hPrinter, 5, NULL, 0, &len);
5469 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
5470 return NULL;
5471 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
5472 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
5473 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
5475 HeapFree(GetProcessHeap(), 0, pi5);
5476 return NULL;
5478 HeapFree(GetProcessHeap(), 0, pi5);
5481 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
5483 LPWSTR name;
5484 get_filename(&name);
5485 if(name)
5487 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
5489 HeapFree(GetProcessHeap(), 0, name);
5490 return NULL;
5492 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5493 GetFullPathNameW(name, len, ret, NULL);
5494 HeapFree(GetProcessHeap(), 0, name);
5496 return ret;
5499 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
5500 return NULL;
5502 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5503 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
5505 attr = GetFileAttributesW(ret);
5506 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
5508 HeapFree(GetProcessHeap(), 0, ret);
5509 ret = NULL;
5511 return ret;